xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_cfg80211.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file moal_cfg80211.c
2  *
3  * @brief This file contains the functions for CFG80211.
4  *
5  *
6  * Copyright 2011-2022 NXP
7  *
8  * This software file (the File) is distributed by NXP
9  * under the terms of the GNU General Public License Version 2, June 1991
10  * (the License).  You may use, redistribute and/or modify the File in
11  * accordance with the terms and conditions of the License, a copy of which
12  * is available by writing to the Free Software Foundation, Inc.,
13  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15  *
16  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19  * this warranty disclaimer.
20  *
21  */
22 
23 #include "moal_cfg80211.h"
24 #ifdef UAP_CFG80211
25 #ifdef UAP_SUPPORT
26 #include "moal_uap.h"
27 #endif
28 #endif
29 
30 /********************************************************
31  *				Local Variables
32  ********************************************************/
33 /** Supported rates to be advertised to the cfg80211 */
34 static struct ieee80211_rate cfg80211_rates[] = {
35 	{
36 		.bitrate = 10,
37 		.hw_value = 2,
38 	},
39 	{
40 		.bitrate = 20,
41 		.hw_value = 4,
42 	},
43 	{
44 		.bitrate = 55,
45 		.hw_value = 11,
46 	},
47 	{
48 		.bitrate = 110,
49 		.hw_value = 22,
50 	},
51 	{
52 		.bitrate = 60,
53 		.hw_value = 12,
54 	},
55 	{
56 		.bitrate = 90,
57 		.hw_value = 18,
58 	},
59 	{
60 		.bitrate = 120,
61 		.hw_value = 24,
62 	},
63 	{
64 		.bitrate = 180,
65 		.hw_value = 36,
66 	},
67 	{
68 		.bitrate = 240,
69 		.hw_value = 48,
70 	},
71 	{
72 		.bitrate = 360,
73 		.hw_value = 72,
74 	},
75 	{
76 		.bitrate = 480,
77 		.hw_value = 96,
78 	},
79 	{
80 		.bitrate = 540,
81 		.hw_value = 108,
82 	},
83 };
84 
85 /** Channel definitions for 2 GHz to be advertised to cfg80211 */
86 static struct ieee80211_channel cfg80211_channels_2ghz[] = {
87 	{.center_freq = 2412, .hw_value = 1, .max_power = 20},
88 	{.center_freq = 2417, .hw_value = 2, .max_power = 20},
89 	{.center_freq = 2422, .hw_value = 3, .max_power = 20},
90 	{.center_freq = 2427, .hw_value = 4, .max_power = 20},
91 	{.center_freq = 2432, .hw_value = 5, .max_power = 20},
92 	{.center_freq = 2437, .hw_value = 6, .max_power = 20},
93 	{.center_freq = 2442, .hw_value = 7, .max_power = 20},
94 	{.center_freq = 2447, .hw_value = 8, .max_power = 20},
95 	{.center_freq = 2452, .hw_value = 9, .max_power = 20},
96 	{.center_freq = 2457, .hw_value = 10, .max_power = 20},
97 	{.center_freq = 2462, .hw_value = 11, .max_power = 20},
98 	{.center_freq = 2467, .hw_value = 12, .max_power = 20},
99 	{.center_freq = 2472, .hw_value = 13, .max_power = 20},
100 	{.center_freq = 2484, .hw_value = 14, .max_power = 20},
101 };
102 
103 /** Channel definitions for 5 GHz to be advertised to cfg80211 */
104 static struct ieee80211_channel cfg80211_channels_5ghz[] = {
105 	{.center_freq = 5180, .hw_value = 36, .max_power = 20},
106 	{.center_freq = 5200, .hw_value = 40, .max_power = 20},
107 	{.center_freq = 5220, .hw_value = 44, .max_power = 20},
108 	{.center_freq = 5240, .hw_value = 48, .max_power = 20},
109 	{.center_freq = 5260, .hw_value = 52, .max_power = 20},
110 	{.center_freq = 5280, .hw_value = 56, .max_power = 20},
111 	{.center_freq = 5300, .hw_value = 60, .max_power = 20},
112 	{.center_freq = 5320, .hw_value = 64, .max_power = 20},
113 	{.center_freq = 5500, .hw_value = 100, .max_power = 20},
114 	{.center_freq = 5520, .hw_value = 104, .max_power = 20},
115 	{.center_freq = 5540, .hw_value = 108, .max_power = 20},
116 	{.center_freq = 5560, .hw_value = 112, .max_power = 20},
117 	{.center_freq = 5580, .hw_value = 116, .max_power = 20},
118 	{.center_freq = 5600, .hw_value = 120, .max_power = 20},
119 	{.center_freq = 5620, .hw_value = 124, .max_power = 20},
120 	{.center_freq = 5640, .hw_value = 128, .max_power = 20},
121 	{.center_freq = 5660, .hw_value = 132, .max_power = 20},
122 	{.center_freq = 5680, .hw_value = 136, .max_power = 20},
123 	{.center_freq = 5700, .hw_value = 140, .max_power = 20},
124 	{.center_freq = 5720, .hw_value = 144, .max_power = 20},
125 	{.center_freq = 5745, .hw_value = 149, .max_power = 20},
126 	{.center_freq = 5765, .hw_value = 153, .max_power = 20},
127 	{.center_freq = 5785, .hw_value = 157, .max_power = 20},
128 	{.center_freq = 5805, .hw_value = 161, .max_power = 20},
129 	{.center_freq = 5825, .hw_value = 165, .max_power = 20},
130 	{.center_freq = 5845, .hw_value = 169, .max_power = 20},
131 	{.center_freq = 5865, .hw_value = 173, .max_power = 20},
132 	{.center_freq = 5885, .hw_value = 177, .max_power = 20},
133 };
134 
135 struct ieee80211_supported_band cfg80211_band_2ghz = {
136 	.channels = cfg80211_channels_2ghz,
137 	.band = IEEE80211_BAND_2GHZ,
138 	.n_channels = ARRAY_SIZE(cfg80211_channels_2ghz),
139 	.bitrates = cfg80211_rates,
140 	.n_bitrates = ARRAY_SIZE(cfg80211_rates),
141 };
142 
143 struct ieee80211_supported_band cfg80211_band_5ghz = {
144 	.channels = cfg80211_channels_5ghz,
145 	.band = IEEE80211_BAND_5GHZ,
146 	.n_channels = ARRAY_SIZE(cfg80211_channels_5ghz),
147 	.bitrates = cfg80211_rates + 4,
148 	.n_bitrates = ARRAY_SIZE(cfg80211_rates) - 4,
149 };
150 
151 extern pmoal_handle m_handle[];
152 
153 #if KERNEL_VERSION(2, 6, 29) < LINUX_VERSION_CODE
154 #ifdef UAP_SUPPORT
155 /** Network device handlers for uAP */
156 extern const struct net_device_ops woal_uap_netdev_ops;
157 #endif
158 #ifdef STA_SUPPORT
159 /** Network device handlers for STA */
160 extern const struct net_device_ops woal_netdev_ops;
161 #endif
162 #endif
163 /********************************************************
164  *				Local Functions
165  ********************************************************/
166 
167 /********************************************************
168  *				Global Functions
169  ********************************************************/
170 #ifdef UAP_SUPPORT
171 #if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 20, 0)
172 int woal_11ax_cfg(moal_private *priv, t_u8 action, mlan_ds_11ax_he_cfg *he_cfg);
173 #endif
174 #endif
175 
176 /**
177  * @brief Get the private structure from wiphy
178  *
179  * @param wiphy     A pointer to wiphy structure
180  *
181  * @return          Pointer to moal_private
182  */
woal_get_wiphy_priv(struct wiphy * wiphy)183 void *woal_get_wiphy_priv(struct wiphy *wiphy)
184 {
185 	return (void *)(*(unsigned long *)wiphy_priv(wiphy));
186 }
187 
188 /**
189  * @brief Get the private structure from net device
190  *
191  * @param dev       A pointer to net_device structure
192  *
193  * @return          Pointer to moal_private
194  */
woal_get_netdev_priv(struct net_device * dev)195 void *woal_get_netdev_priv(struct net_device *dev)
196 {
197 	return (void *)netdev_priv(dev);
198 }
199 
200 /**
201  *  @brief Get current frequency of active interface
202  *
203  *  @param priv        A pointer to moal_private
204  *
205  *  @return              channel frequency
206  */
woal_get_active_intf_freq(moal_private * priv)207 int woal_get_active_intf_freq(moal_private *priv)
208 {
209 	moal_handle *handle = priv->phandle;
210 	int i;
211 
212 	if (priv->media_connected == MTRUE
213 #ifdef UAP_SUPPORT
214 	    || priv->bss_started == MTRUE
215 #endif
216 	)
217 		return ieee80211_channel_to_frequency(
218 			priv->channel
219 #if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
220 			,
221 			(priv->channel <= 14 ? IEEE80211_BAND_2GHZ :
222 					       IEEE80211_BAND_5GHZ)
223 #endif
224 		);
225 
226 	for (i = 0; i < handle->priv_num; i++) {
227 #ifdef STA_SUPPORT
228 		if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
229 			if (handle->priv[i]->media_connected == MTRUE)
230 				return ieee80211_channel_to_frequency(
231 					handle->priv[i]->channel
232 #if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
233 					,
234 					(handle->priv[i]->channel <= 14 ?
235 						 IEEE80211_BAND_2GHZ :
236 						 IEEE80211_BAND_5GHZ)
237 #endif
238 				);
239 		}
240 #endif
241 #ifdef UAP_SUPPORT
242 		if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
243 			if (handle->priv[i]->bss_started == MTRUE)
244 				return ieee80211_channel_to_frequency(
245 					handle->priv[i]->channel
246 #if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
247 					,
248 					(handle->priv[i]->channel <= 14 ?
249 						 IEEE80211_BAND_2GHZ :
250 						 IEEE80211_BAND_5GHZ)
251 #endif
252 				);
253 		}
254 #endif
255 	}
256 	return 0;
257 }
258 
259 /**
260  *  @brief Convert driver band configuration to IEEE band type
261  *
262  *  @param band     Driver band configuration
263  *
264  *  @return         IEEE band type
265  */
woal_band_cfg_to_ieee_band(t_u32 band)266 t_u8 woal_band_cfg_to_ieee_band(t_u32 band)
267 {
268 	t_u8 ret_radio_type;
269 
270 	ENTER();
271 
272 	switch (band) {
273 	case BAND_A:
274 	case BAND_AN:
275 	case BAND_A | BAND_AN:
276 		ret_radio_type = IEEE80211_BAND_5GHZ;
277 		break;
278 	case BAND_B:
279 	case BAND_G:
280 	case BAND_B | BAND_G:
281 	case BAND_GN:
282 	case BAND_B | BAND_GN:
283 	/* Fall Through */
284 	default:
285 		ret_radio_type = IEEE80211_BAND_2GHZ;
286 		break;
287 	}
288 
289 	LEAVE();
290 	return ret_radio_type;
291 }
292 
293 /**
294  *  @brief Convert IEEE band type to radio_type
295  *
296  *  @param ieeeband     IEEE band
297  *
298  *  @return           radio_type
299  */
woal_ieee_band_to_radio_type(t_u8 ieee_band)300 t_u8 woal_ieee_band_to_radio_type(t_u8 ieee_band)
301 {
302 	t_u8 radio_type = 0;
303 
304 	ENTER();
305 
306 	switch (ieee_band) {
307 	case IEEE80211_BAND_5GHZ:
308 		radio_type = BAND_5GHZ;
309 		break;
310 	case IEEE80211_BAND_2GHZ:
311 	default:
312 		radio_type = BAND_2GHZ;
313 		break;
314 	}
315 	LEAVE();
316 	return radio_type;
317 }
318 
319 /**
320  *  @brief Set/Enable encryption key
321  *
322  *  @param priv             A pointer to moal_private structure
323  *  @param is_enable_wep    Enable WEP default key
324  *  @param cipher           Cipher suite selector
325  *  @param key              A pointer to key
326  *  @param key_len          Key length
327  *  @param seq              A pointer to sequence
328  *  @param seq_len          Sequence length
329  *  @param key_index        Key index
330  *  @param addr             Mac for which key is to be set
331  *  @param disable          Key disabled or not
332  *  @param wait_option      wait option
333  *
334  *  @return                 MLAN_STATUS_SUCCESS -- success, otherwise fail
335  */
woal_cfg80211_set_key(moal_private * priv,t_u8 is_enable_wep,t_u32 cipher,const t_u8 * key,int key_len,const t_u8 * seq,int seq_len,t_u8 key_index,const t_u8 * addr,int disable,t_u8 wait_option)336 mlan_status woal_cfg80211_set_key(moal_private *priv, t_u8 is_enable_wep,
337 				  t_u32 cipher, const t_u8 *key, int key_len,
338 				  const t_u8 *seq, int seq_len, t_u8 key_index,
339 				  const t_u8 *addr, int disable,
340 				  t_u8 wait_option)
341 {
342 	mlan_ioctl_req *req = NULL;
343 	mlan_ds_sec_cfg *sec = NULL;
344 	mlan_status ret = MLAN_STATUS_SUCCESS;
345 	t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
346 
347 	ENTER();
348 
349 #ifdef UAP_CFG80211
350 #ifdef UAP_SUPPORT
351 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
352 		if (is_enable_wep) {
353 			PRINTM(MIOCTL, "Enable UAP default key=%d\n",
354 			       key_index);
355 			priv->uap_wep_key[key_index].is_default = MTRUE;
356 			goto done;
357 		}
358 		if (key && key_len &&
359 		    ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
360 		     (cipher == WLAN_CIPHER_SUITE_WEP104))) {
361 			priv->uap_wep_key[key_index].length = key_len;
362 			moal_memcpy_ext(
363 				priv->phandle, priv->uap_wep_key[key_index].key,
364 				key, key_len,
365 				sizeof(priv->uap_wep_key[key_index].key));
366 			priv->cipher = cipher;
367 			priv->uap_wep_key[key_index].key_index = key_index;
368 			priv->uap_wep_key[key_index].is_default = MFALSE;
369 			PRINTM(MIOCTL, "Set UAP WEP key: key_index=%d len=%d\n",
370 			       key_index, key_len);
371 			goto done;
372 		}
373 	}
374 #endif
375 #endif
376 
377 	/* Allocate an IOCTL request buffer */
378 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
379 	if (req == NULL) {
380 		ret = MLAN_STATUS_FAILURE;
381 		goto done;
382 	}
383 
384 	/* Fill request buffer */
385 	sec = (mlan_ds_sec_cfg *)req->pbuf;
386 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
387 	req->req_id = MLAN_IOCTL_SEC_CFG;
388 	req->action = MLAN_ACT_SET;
389 
390 	if (is_enable_wep) {
391 		sec->param.encrypt_key.key_index = key_index;
392 		sec->param.encrypt_key.is_current_wep_key = MTRUE;
393 	} else if (!disable) {
394 		if (cipher != WLAN_CIPHER_SUITE_WEP40 &&
395 		    cipher != WLAN_CIPHER_SUITE_WEP104 &&
396 		    cipher != WLAN_CIPHER_SUITE_TKIP &&
397 		    cipher != WLAN_CIPHER_SUITE_SMS4 &&
398 		    cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
399 #if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
400 		    cipher != WLAN_CIPHER_SUITE_CCMP_256 &&
401 #endif
402 #if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
403 		    cipher != WLAN_CIPHER_SUITE_GCMP &&
404 #endif
405 #if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
406 		    cipher != WLAN_CIPHER_SUITE_BIP_GMAC_128 &&
407 		    cipher != WLAN_CIPHER_SUITE_BIP_GMAC_256 &&
408 		    cipher != WLAN_CIPHER_SUITE_GCMP_256 &&
409 #endif
410 		    cipher != WLAN_CIPHER_SUITE_CCMP) {
411 			PRINTM(MERROR, "Invalid cipher suite specified\n");
412 			ret = MLAN_STATUS_FAILURE;
413 			goto done;
414 		}
415 		sec->param.encrypt_key.key_index = key_index;
416 		if (key && key_len) {
417 			moal_memcpy_ext(priv->phandle,
418 					sec->param.encrypt_key.key_material,
419 					key, key_len, MLAN_MAX_KEY_LENGTH);
420 			sec->param.encrypt_key.key_len = key_len;
421 		}
422 		/* Set WAPI key */
423 		if (cipher == WLAN_CIPHER_SUITE_SMS4) {
424 			sec->param.encrypt_key.is_wapi_key = MTRUE;
425 			if (seq_len) {
426 				moal_memcpy_ext(priv->phandle,
427 						sec->param.encrypt_key.pn, seq,
428 						PN_SIZE, PN_SIZE);
429 				DBG_HEXDUMP(MCMD_D, "WAPI PN",
430 					    sec->param.encrypt_key.pn, seq_len);
431 			}
432 		}
433 		if (addr) {
434 			moal_memcpy_ext(priv->phandle,
435 					sec->param.encrypt_key.mac_addr, addr,
436 					ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
437 			if (memcmp(sec->param.encrypt_key.mac_addr, bcast_addr,
438 				   ETH_ALEN) == 0)
439 				sec->param.encrypt_key.key_flags =
440 					KEY_FLAG_GROUP_KEY;
441 			else
442 				sec->param.encrypt_key.key_flags =
443 					KEY_FLAG_SET_TX_KEY;
444 		} else {
445 			moal_memcpy_ext(priv->phandle,
446 					sec->param.encrypt_key.mac_addr,
447 					bcast_addr, ETH_ALEN,
448 					MLAN_MAC_ADDR_LENGTH);
449 			sec->param.encrypt_key.key_flags =
450 				KEY_FLAG_GROUP_KEY | KEY_FLAG_SET_TX_KEY;
451 		}
452 		if (seq && seq_len) {
453 			moal_memcpy_ext(priv->phandle,
454 					sec->param.encrypt_key.pn, seq, seq_len,
455 					PN_SIZE);
456 			sec->param.encrypt_key.key_flags |=
457 				KEY_FLAG_RX_SEQ_VALID;
458 		}
459 
460 #if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
461 		if (cipher == WLAN_CIPHER_SUITE_GCMP)
462 			sec->param.encrypt_key.key_flags |= KEY_FLAG_GCMP;
463 #endif
464 #if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
465 		else if (cipher == WLAN_CIPHER_SUITE_GCMP_256)
466 			sec->param.encrypt_key.key_flags |= KEY_FLAG_GCMP_256;
467 #endif
468 #if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
469 		if (cipher == WLAN_CIPHER_SUITE_CCMP_256)
470 			sec->param.encrypt_key.key_flags |= KEY_FLAG_CCMP_256;
471 #endif
472 
473 		if (cipher == WLAN_CIPHER_SUITE_AES_CMAC
474 #if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
475 		    || cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
476 		    cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256
477 #endif
478 		) {
479 			sec->param.encrypt_key.key_flags |=
480 				KEY_FLAG_AES_MCAST_IGTK;
481 
482 #if KERNEL_VERSION(4, 0, 0) <= CFG80211_VERSION_CODE
483 			if (cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128)
484 				sec->param.encrypt_key.key_flags |=
485 					KEY_FLAG_GMAC_128;
486 			else if (cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256)
487 				sec->param.encrypt_key.key_flags |=
488 					KEY_FLAG_GMAC_256;
489 #endif
490 		}
491 	} else {
492 		if (key_index == KEY_INDEX_CLEAR_ALL)
493 			sec->param.encrypt_key.key_disable = MTRUE;
494 		else {
495 			sec->param.encrypt_key.key_remove = MTRUE;
496 			sec->param.encrypt_key.key_index = key_index;
497 		}
498 		sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
499 		if (addr)
500 			moal_memcpy_ext(priv->phandle,
501 					sec->param.encrypt_key.mac_addr, addr,
502 					ETH_ALEN, MLAN_MAC_ADDR_LENGTH);
503 	}
504 
505 	/* Send IOCTL request to MLAN */
506 	ret = woal_request_ioctl(priv, req, wait_option);
507 
508 done:
509 	if (ret != MLAN_STATUS_PENDING)
510 		kfree(req);
511 	LEAVE();
512 	return ret;
513 }
514 
515 /**
516  * @brief Set/Enable the WEP key to driver
517  *
518  * @param priv      A pointer to moal_private structure
519  * @param key       A pointer to key data
520  * @param key_len   Length of the key data
521  * @param index     Key index
522  * @param wait_option wait_option
523  *
524  * @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
525  */
woal_cfg80211_set_wep_keys(moal_private * priv,const t_u8 * key,int key_len,t_u8 index,t_u8 wait_option)526 mlan_status woal_cfg80211_set_wep_keys(moal_private *priv, const t_u8 *key,
527 				       int key_len, t_u8 index,
528 				       t_u8 wait_option)
529 {
530 	mlan_status ret = MLAN_STATUS_SUCCESS;
531 	t_u32 cipher = 0;
532 
533 	ENTER();
534 
535 	if (key_len) {
536 		if (key_len == 5)
537 			cipher = WLAN_CIPHER_SUITE_WEP40;
538 		else
539 			cipher = WLAN_CIPHER_SUITE_WEP104;
540 		ret = woal_cfg80211_set_key(priv, 0, cipher, key, key_len, NULL,
541 					    0, index, NULL, 0, wait_option);
542 	} else {
543 		/* No key provided so it is enable key. We
544 		 * want to just set the transmit key index
545 		 */
546 		ret = woal_cfg80211_set_key(priv, 1, cipher, key, key_len, NULL,
547 					    0, index, NULL, 0, wait_option);
548 	}
549 	if (ret != MLAN_STATUS_SUCCESS)
550 		PRINTM(MERROR, "woal_cfg80211_set_wep_keys Fail\n");
551 
552 	LEAVE();
553 	return ret;
554 }
555 
556 /**
557  * @brief clear all mgmt ies
558  *
559  * @param priv              A pointer to moal private structure
560  * @param wait_option       wait_option
561  * @return                  N/A
562  */
woal_clear_all_mgmt_ies(moal_private * priv,t_u8 wait_option)563 void woal_clear_all_mgmt_ies(moal_private *priv, t_u8 wait_option)
564 {
565 	t_u16 mask = 0;
566 	/* clear BEACON WPS/P2P IE */
567 	if (priv->beacon_wps_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
568 		PRINTM(MCMND, "Clear BEACON WPS ie\n");
569 		if (woal_cfg80211_mgmt_frame_ie(
570 			    priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
571 			    MGMT_MASK_BEACON_WPS_P2P, wait_option))
572 			PRINTM(MERROR, "%s: clear beacon wps ie failed \n",
573 			       __func__);
574 		priv->beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
575 	}
576 	if (priv->assocresp_qos_map_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
577 		PRINTM(MCMND, "Clear associate response QOS map ie\n");
578 		if (woal_cfg80211_mgmt_frame_ie(
579 			    priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
580 			    MGMT_MASK_ASSOC_RESP_QOS_MAP, wait_option))
581 			PRINTM(MERROR,
582 			       "%s: Clear associate response QOS map ie failed \n",
583 			       __func__);
584 		priv->assocresp_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
585 	}
586 	/* clear mgmt frame ies */
587 	if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
588 		mask |= MGMT_MASK_PROBE_REQ;
589 	if (priv->beacon_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
590 		mask |= MGMT_MASK_BEACON;
591 	if (priv->proberesp_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
592 		mask |= MGMT_MASK_PROBE_RESP;
593 	if (priv->assocresp_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
594 		mask |= MGMT_MASK_ASSOC_RESP;
595 	if (priv->proberesp_p2p_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
596 		mask |= MGMT_MASK_PROBE_RESP;
597 	if (priv->beacon_vendor_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
598 		mask |= MGMT_MASK_BEACON;
599 	if (mask) {
600 		PRINTM(MCMND, "Clear IES: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
601 		       priv->beacon_index, priv->probereq_index,
602 		       priv->proberesp_index, priv->assocresp_index,
603 		       priv->proberesp_p2p_index, priv->beacon_vendor_index);
604 		if (woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0,
605 						NULL, 0, mask, wait_option))
606 			PRINTM(MERROR, "%s: Clear ies failed, mask=0x%x\n",
607 			       __func__, mask);
608 	}
609 	priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
610 	priv->beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
611 	priv->proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
612 	priv->assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
613 	priv->proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
614 	priv->beacon_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
615 }
616 
617 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
618 /**
619  * @brief set bss role
620  *
621  * @param priv              A pointer to moal private structure
622  * @param action            Action: set or get
623  * @param role              A pointer to bss role
624  *
625  * @return                  0 -- success, otherwise fail
626  */
woal_cfg80211_bss_role_cfg(moal_private * priv,t_u16 action,t_u8 * bss_role)627 int woal_cfg80211_bss_role_cfg(moal_private *priv, t_u16 action, t_u8 *bss_role)
628 {
629 	int ret = 0;
630 
631 	ENTER();
632 
633 	if (action == MLAN_ACT_SET) {
634 		/* Reset interface */
635 		if (MLAN_STATUS_SUCCESS !=
636 		    woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE)) {
637 			PRINTM(MERROR, "woal_reset_intf fail\n");
638 			ret = -EFAULT;
639 			goto done;
640 		}
641 	}
642 
643 	if (MLAN_STATUS_SUCCESS !=
644 	    woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, bss_role)) {
645 		PRINTM(MERROR, "woal_bss_role_cfg fail\n");
646 		ret = -EFAULT;
647 		goto done;
648 	}
649 
650 	if (action == MLAN_ACT_SET) {
651 		/* set back the mac address */
652 		if (MLAN_STATUS_SUCCESS !=
653 		    woal_request_set_mac_address(priv, MOAL_IOCTL_WAIT)) {
654 			PRINTM(MERROR, "woal_request_set_mac_address fail\n");
655 			ret = -EFAULT;
656 			goto done;
657 		}
658 		/* clear the mgmt ies */
659 		woal_clear_all_mgmt_ies(priv, MOAL_IOCTL_WAIT);
660 		/* Initialize private structures */
661 		woal_init_priv(priv, MOAL_IOCTL_WAIT);
662 
663 		/* Enable interfaces */
664 		netif_device_attach(priv->netdev);
665 		woal_start_queue(priv->netdev);
666 	}
667 
668 done:
669 	LEAVE();
670 	return ret;
671 }
672 #endif
673 
674 #ifdef WIFI_DIRECT_SUPPORT
675 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
676 /**
677  *  @brief This function display P2P public action frame type
678  *
679  *  @param  buf      A buffer to a management frame
680  *  @param  len      buffer len
681  *  @param chan      the channel
682  *  @param flag      Tx/Rx flag. Tx:flag = 1;Rx:flag = 0;
683  *
684  *  @return          N/A
685  */
woal_cfg80211_display_p2p_actframe(const t_u8 * buf,int len,struct ieee80211_channel * chan,const t_u8 flag)686 void woal_cfg80211_display_p2p_actframe(const t_u8 *buf, int len,
687 					struct ieee80211_channel *chan,
688 					const t_u8 flag)
689 {
690 	const t_u8 p2p_oui[] = {0x50, 0x6f, 0x9a, 0x09};
691 	t_u8 subtype;
692 
693 	ENTER();
694 
695 	if (!buf || len < (P2P_ACT_FRAME_OUI_SUBTYPE_OFFSET + 1)) {
696 		LEAVE();
697 		return;
698 	}
699 
700 	if (((struct ieee80211_mgmt *)buf)->u.action.category ==
701 		    P2P_ACT_FRAME_CATEGORY &&
702 	    !memcmp(buf + P2P_ACT_FRAME_OUI_OFFSET, p2p_oui, sizeof(p2p_oui))) {
703 		subtype = *(buf + P2P_ACT_FRAME_OUI_SUBTYPE_OFFSET);
704 		switch (subtype) {
705 		case P2P_GO_NEG_REQ:
706 			PRINTM(MMSG,
707 			       "wlan: %s P2P Group Owner Negotiation Req Frame, channel=%d\n",
708 			       (flag) ? "TX" : "RX",
709 			       (chan) ? chan->hw_value : 0);
710 			break;
711 		case P2P_GO_NEG_RSP:
712 			PRINTM(MMSG,
713 			       "wlan: %s P2P Group Owner Negotiation Rsp Frame, channel=%d\n",
714 			       (flag) ? "TX" : "RX",
715 			       (chan) ? chan->hw_value : 0);
716 			break;
717 		case P2P_GO_NEG_CONF:
718 			PRINTM(MMSG,
719 			       "wlan: %s P2P Group Owner Negotiation Confirm Frame, channel=%d\n",
720 			       (flag) ? "TX" : "RX",
721 			       (chan) ? chan->hw_value : 0);
722 			break;
723 		case P2P_INVITE_REQ:
724 			PRINTM(MMSG,
725 			       "wlan: %s P2P Invitation Request, channel=%d\n",
726 			       (flag) ? "TX" : "RX",
727 			       (chan) ? chan->hw_value : 0);
728 			break;
729 		case P2P_INVITE_RSP:
730 			PRINTM(MMSG,
731 			       "wlan: %s P2P Invitation Response, channel=%d\n",
732 			       (flag) ? "TX" : "RX",
733 			       (chan) ? chan->hw_value : 0);
734 			break;
735 		case P2P_DEVDIS_REQ:
736 			PRINTM(MMSG,
737 			       "wlan: %s P2P Device Discoverability Request, channel=%d\n",
738 			       (flag) ? "TX" : "RX",
739 			       (chan) ? chan->hw_value : 0);
740 			break;
741 		case P2P_DEVDIS_RSP:
742 			PRINTM(MIOCTL,
743 			       "wlan: %s P2P Device Discoverability Response, channel=%d\n",
744 			       (flag) ? "TX" : "RX",
745 			       (chan) ? chan->hw_value : 0);
746 			break;
747 		case P2P_PROVDIS_REQ:
748 			PRINTM(MMSG,
749 			       "wlan: %s P2P Provision Discovery Request, channel=%d\n",
750 			       (flag) ? "TX" : "RX",
751 			       (chan) ? chan->hw_value : 0);
752 			break;
753 		case P2P_PROVDIS_RSP:
754 			PRINTM(MMSG,
755 			       "wlan: %s P2P Provision Discovery Response, channel=%d\n",
756 			       (flag) ? "TX" : "RX",
757 			       (chan) ? chan->hw_value : 0);
758 			break;
759 		default:
760 			PRINTM(MMSG,
761 			       "wlan: %s Unknown P2P Action Frame, channel=%d, subtype=%d\n",
762 			       (flag) ? "TX" : "RX",
763 			       (chan) ? chan->hw_value : 0, subtype);
764 			break;
765 		}
766 	}
767 
768 	LEAVE();
769 }
770 
771 /**
772  * @brief initialize p2p client for wpa_supplicant
773  *
774  * @param priv			A pointer to moal private structure
775  *
776  * @return              0 -- success, otherwise fail
777  */
woal_cfg80211_init_p2p_client(moal_private * priv)778 int woal_cfg80211_init_p2p_client(moal_private *priv)
779 {
780 	int ret = MLAN_STATUS_SUCCESS;
781 	t_u16 wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
782 	t_u8 bss_role;
783 
784 	ENTER();
785 
786 	/* bss type check */
787 	if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
788 		PRINTM(MERROR, "Unexpected bss type when init p2p client\n");
789 		ret = -EFAULT;
790 		goto done;
791 	}
792 
793 	/* get the bss role */
794 	if (MLAN_STATUS_SUCCESS !=
795 	    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
796 		ret = -EFAULT;
797 		goto done;
798 	}
799 
800 	if (bss_role != MLAN_BSS_ROLE_STA) {
801 		bss_role = MLAN_BSS_ROLE_STA;
802 		if (MLAN_STATUS_SUCCESS !=
803 		    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
804 			ret = -EFAULT;
805 			goto done;
806 		}
807 	}
808 
809 	wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
810 	if (MLAN_STATUS_SUCCESS !=
811 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
812 		ret = -EFAULT;
813 		goto done;
814 	}
815 
816 	/* first, init wifi direct to listen mode */
817 	wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
818 	if (MLAN_STATUS_SUCCESS !=
819 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
820 		ret = -EFAULT;
821 		goto done;
822 	}
823 
824 	/* second, init wifi direct client  */
825 	wifi_direct_mode = WIFI_DIRECT_MODE_CLIENT;
826 	if (MLAN_STATUS_SUCCESS !=
827 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
828 		ret = -EFAULT;
829 		goto done;
830 	}
831 done:
832 	LEAVE();
833 	return ret;
834 }
835 
836 /**
837  * @brief initialize p2p GO for wpa_supplicant
838  *
839  * @param priv			A pointer to moal private structure
840  *
841  * @return              0 -- success, otherwise fail
842  */
woal_cfg80211_init_p2p_go(moal_private * priv)843 int woal_cfg80211_init_p2p_go(moal_private *priv)
844 {
845 	int ret = MLAN_STATUS_SUCCESS;
846 	t_u16 wifi_direct_mode;
847 	t_u8 bss_role;
848 	mlan_ds_wifi_direct_config p2p_config;
849 	mlan_ds_ps_mgmt ps_mgmt;
850 
851 	ENTER();
852 
853 	/* bss type check */
854 	if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
855 		PRINTM(MERROR, "Unexpected bss type when init p2p GO\n");
856 		ret = -EFAULT;
857 		goto done;
858 	}
859 
860 	wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
861 	if (MLAN_STATUS_SUCCESS !=
862 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
863 		ret = -EFAULT;
864 		goto done;
865 	}
866 
867 	/* first, init wifi direct to listen mode */
868 	wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
869 	if (MLAN_STATUS_SUCCESS !=
870 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
871 		ret = -EFAULT;
872 		goto done;
873 	}
874 
875 	/* second, init wifi direct to GO mode  */
876 	wifi_direct_mode = WIFI_DIRECT_MODE_GO;
877 	if (MLAN_STATUS_SUCCESS !=
878 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
879 		ret = -EFAULT;
880 		goto done;
881 	}
882 
883 	/* get the bss role, and set it to uAP */
884 	if (MLAN_STATUS_SUCCESS !=
885 	    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
886 		ret = -EFAULT;
887 		goto done;
888 	}
889 
890 	if (bss_role != MLAN_BSS_ROLE_UAP) {
891 		bss_role = MLAN_BSS_ROLE_UAP;
892 		if (MLAN_STATUS_SUCCESS !=
893 		    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
894 			ret = -EFAULT;
895 			goto done;
896 		}
897 	}
898 /* NoA:-- Interval = 100TUs and Duration= 50TUs, count=255*/
899 #define DEF_NOA_COUNT 255
900 	if (priv->phandle->noa_duration && priv->phandle->card_info->go_noa) {
901 		memset(&p2p_config, 0, sizeof(p2p_config));
902 		p2p_config.noa_enable = MTRUE;
903 		p2p_config.index = 0;
904 		p2p_config.noa_count = DEF_NOA_COUNT;
905 		p2p_config.noa_duration = priv->phandle->noa_duration;
906 		p2p_config.noa_interval = priv->phandle->noa_interval;
907 		p2p_config.flags = WIFI_DIRECT_NOA;
908 		if (MLAN_STATUS_SUCCESS !=
909 		    woal_p2p_config(priv, MLAN_ACT_SET, &p2p_config)) {
910 			PRINTM(MERROR, "woal_p2p_config fail\n");
911 			ret = -EFAULT;
912 			goto done;
913 		}
914 
915 		memset(&ps_mgmt, 0, sizeof(ps_mgmt));
916 		ps_mgmt.flags = PS_FLAG_PS_MODE;
917 		ps_mgmt.ps_mode = PS_MODE_INACTIVITY;
918 		if (MLAN_STATUS_SUCCESS !=
919 		    woal_set_get_uap_power_mode(priv, MLAN_ACT_SET, &ps_mgmt)) {
920 			PRINTM(MERROR, "woal_set_get_uap_power_mode fail\n");
921 			ret = -EFAULT;
922 			goto done;
923 		}
924 		PRINTM(MMSG, "Enable NOA: duration=%d, interval=%d\n",
925 		       priv->phandle->noa_duration,
926 		       priv->phandle->noa_interval);
927 	}
928 done:
929 	LEAVE();
930 	return ret;
931 }
932 
933 /**
934  * @brief reset bss role and wifi direct mode for wpa_supplicant
935  *
936  * @param priv			A pointer to moal private structure
937  *
938  * @return              0 -- success, otherwise fail
939  */
woal_cfg80211_deinit_p2p(moal_private * priv)940 int woal_cfg80211_deinit_p2p(moal_private *priv)
941 {
942 	int ret = MLAN_STATUS_SUCCESS;
943 	t_u16 wifi_direct_mode;
944 	t_u8 bss_role;
945 	t_u8 channel_status;
946 	moal_private *remain_priv = NULL;
947 	mlan_ds_ps_mgmt ps_mgmt;
948 
949 	ENTER();
950 
951 	/* bss type check */
952 	if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
953 		PRINTM(MERROR, "Unexpected bss type when deinit p2p\n");
954 		ret = -EFAULT;
955 		goto done;
956 	}
957 	/* unregister mgmt frame from FW */
958 	if (priv->mgmt_subtype_mask) {
959 		priv->mgmt_subtype_mask = 0;
960 		if (woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET,
961 					 &priv->mgmt_subtype_mask,
962 					 MOAL_IOCTL_WAIT)) {
963 			PRINTM(MERROR,
964 			       "deinit_p2p: fail to unregister mgmt frame\n");
965 			ret = -EFAULT;
966 			goto done;
967 		}
968 	}
969 
970 	/* cancel previous remain on channel */
971 	if (priv->phandle->remain_on_channel) {
972 		remain_priv =
973 			priv->phandle->priv[priv->phandle->remain_bss_index];
974 		if (!remain_priv) {
975 			PRINTM(MERROR,
976 			       "deinit_p2p: wrong remain_bss_index=%d\n",
977 			       priv->phandle->remain_bss_index);
978 			ret = -EFAULT;
979 			goto done;
980 		}
981 		if (woal_cfg80211_remain_on_channel_cfg(
982 			    remain_priv, MOAL_IOCTL_WAIT, MTRUE,
983 			    &channel_status, NULL, 0, 0)) {
984 			PRINTM(MERROR,
985 			       "deinit_p2p: Fail to cancel remain on channel\n");
986 			ret = -EFAULT;
987 			goto done;
988 		}
989 		if (priv->phandle->cookie) {
990 			cfg80211_remain_on_channel_expired(
991 #if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
992 				remain_priv->netdev,
993 #else
994 				remain_priv->wdev,
995 #endif
996 				priv->phandle->cookie, &priv->phandle->chan,
997 #if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
998 				priv->phandle->channel_type,
999 #endif
1000 				GFP_ATOMIC);
1001 			priv->phandle->cookie = 0;
1002 		}
1003 		priv->phandle->remain_on_channel = MFALSE;
1004 	}
1005 
1006 	/* get the bss role */
1007 	if (MLAN_STATUS_SUCCESS !=
1008 	    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
1009 		ret = -EFAULT;
1010 		goto done;
1011 	}
1012 
1013 	/* reset bss role */
1014 	if (bss_role != MLAN_BSS_ROLE_STA) {
1015 		memset(&ps_mgmt, 0, sizeof(ps_mgmt));
1016 		ps_mgmt.flags = PS_FLAG_PS_MODE;
1017 		ps_mgmt.ps_mode = PS_MODE_DISABLE;
1018 		if (MLAN_STATUS_SUCCESS !=
1019 		    woal_set_get_uap_power_mode(priv, MLAN_ACT_SET, &ps_mgmt)) {
1020 			PRINTM(MERROR, "woal_set_get_uap_power_mode fail\n");
1021 			ret = -EFAULT;
1022 			goto done;
1023 		}
1024 		bss_role = MLAN_BSS_ROLE_STA;
1025 		if (MLAN_STATUS_SUCCESS !=
1026 		    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
1027 			ret = -EFAULT;
1028 			goto done;
1029 		}
1030 	}
1031 
1032 	wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
1033 	if (MLAN_STATUS_SUCCESS !=
1034 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
1035 		ret = -EFAULT;
1036 		goto done;
1037 	}
1038 done:
1039 	LEAVE();
1040 	return ret;
1041 }
1042 #endif /* KERNEL_VERSION */
1043 #endif /* WIFI_DIRECT_SUPPORT */
1044 
1045 #ifdef UAP_SUPPORT
1046 /**
1047  * @brief Request to cancel CAC
1048  *
1049  * @param priv         A pointer to moal_private structure
1050  *
1051  * @return              N/A */
woal_cancel_cac(moal_private * priv)1052 void woal_cancel_cac(moal_private *priv)
1053 {
1054 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
1055 	if (priv->phandle->is_cac_timer_set &&
1056 	    priv->bss_index == priv->phandle->cac_bss_index) {
1057 		woal_cancel_timer(&priv->phandle->cac_timer);
1058 		priv->phandle->is_cac_timer_set = MFALSE;
1059 		/* Make sure Chan Report is cancelled */
1060 		if (woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT))
1061 			PRINTM(MERROR, "%s: cancel chan report failed \n",
1062 			       __func__);
1063 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1064 		cfg80211_cac_event(priv->netdev, &priv->phandle->dfs_channel,
1065 				   NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
1066 #else
1067 		cfg80211_cac_event(priv->netdev, NL80211_RADAR_CAC_ABORTED,
1068 				   GFP_KERNEL);
1069 #endif
1070 		memset(&priv->phandle->dfs_channel, 0,
1071 		       sizeof(struct cfg80211_chan_def));
1072 		priv->phandle->cac_bss_index = 0xff;
1073 	}
1074 #endif
1075 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1076 	if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
1077 		woal_cancel_cac_block(priv);
1078 #endif
1079 	return;
1080 }
1081 #endif
1082 
1083 /**
1084  * @brief Request the driver to change the interface type
1085  *
1086  * @param wiphy         A pointer to wiphy structure
1087  * @param dev           A pointer to net_device structure
1088  * @param type          Virtual interface types
1089  * @param flags         Flags
1090  * @param params        A pointer to vif_params structure
1091  *
1092  * @return              0 -- success, otherwise fail
1093  */
woal_cfg80211_change_virtual_intf(struct wiphy * wiphy,struct net_device * dev,enum nl80211_iftype type,u32 * flags,struct vif_params * params)1094 int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
1095 				      struct net_device *dev,
1096 				      enum nl80211_iftype type,
1097 #if KERNEL_VERSION(4, 12, 0) > CFG80211_VERSION_CODE
1098 				      u32 *flags,
1099 #endif
1100 				      struct vif_params *params)
1101 {
1102 	int ret = 0;
1103 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1104 	mlan_ds_bss *bss = NULL;
1105 	mlan_ioctl_req *req = NULL;
1106 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
1107 	t_u8 bss_role;
1108 #endif
1109 	mlan_status status = MLAN_STATUS_SUCCESS;
1110 
1111 	ENTER();
1112 
1113 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_MONITOR) {
1114 		ret = -EFAULT;
1115 		goto done;
1116 	}
1117 
1118 	if (priv->wdev->iftype == type) {
1119 		PRINTM(MINFO, "Already set to required type\n");
1120 		goto done;
1121 	}
1122 #ifdef UAP_SUPPORT
1123 	/* when AP mode switch to station mode, we use it to cancel pending CAC
1124 	 */
1125 	if (priv->wdev->iftype == NL80211_IFTYPE_AP &&
1126 	    type == NL80211_IFTYPE_STATION) {
1127 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
1128 		if (priv->phandle->is_cac_timer_set &&
1129 		    priv->bss_index == priv->phandle->cac_bss_index) {
1130 			woal_cancel_timer(&priv->phandle->cac_timer);
1131 			priv->phandle->is_cac_timer_set = MFALSE;
1132 			/* Make sure Chan Report is cancelled */
1133 			if (woal_11h_cancel_chan_report_ioctl(priv,
1134 							      MOAL_IOCTL_WAIT))
1135 				PRINTM(MERROR,
1136 				       "%s: cancel chan report failed \n",
1137 				       __func__);
1138 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1139 			cfg80211_cac_event(priv->netdev,
1140 					   &priv->phandle->dfs_channel,
1141 					   NL80211_RADAR_CAC_ABORTED,
1142 					   GFP_KERNEL);
1143 #else
1144 			cfg80211_cac_event(priv->netdev,
1145 					   NL80211_RADAR_CAC_ABORTED,
1146 					   GFP_KERNEL);
1147 #endif
1148 			memset(&priv->phandle->dfs_channel, 0,
1149 			       sizeof(struct cfg80211_chan_def));
1150 			priv->phandle->cac_bss_index = 0xff;
1151 		}
1152 #endif
1153 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1154 		if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD))
1155 			woal_cancel_cac_block(priv);
1156 #endif
1157 	}
1158 	if ((priv->bss_type == MLAN_BSS_TYPE_UAP) && (priv->bss_index > 0)) {
1159 		PRINTM(MMSG,
1160 		       "%s: Skip change virtual intf type on uap: from %d to %d\n",
1161 		       dev->name, priv->wdev->iftype, type);
1162 		priv->wdev->iftype = type;
1163 		goto done;
1164 	}
1165 #endif
1166 
1167 	PRINTM(MIOCTL, "%s: change virturl intf=%d\n", dev->name, type);
1168 #ifdef WIFI_DIRECT_SUPPORT
1169 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1170 	/** cancel previous remain on channel to avoid firmware hang */
1171 	if (priv->phandle->remain_on_channel) {
1172 		t_u8 channel_status;
1173 		moal_private *remain_priv = NULL;
1174 
1175 		remain_priv =
1176 			priv->phandle->priv[priv->phandle->remain_bss_index];
1177 		if (!remain_priv) {
1178 			PRINTM(MERROR,
1179 			       "change_virtual_intf:wrong remain_bss_index=%d\n",
1180 			       priv->phandle->remain_bss_index);
1181 			ret = -EFAULT;
1182 			goto done;
1183 		}
1184 		if (woal_cfg80211_remain_on_channel_cfg(
1185 			    remain_priv, MOAL_IOCTL_WAIT, MTRUE,
1186 			    &channel_status, NULL, 0, 0)) {
1187 			PRINTM(MERROR,
1188 			       "change_virtual_intf: Fail to cancel remain on channel\n");
1189 			ret = -EFAULT;
1190 			goto done;
1191 		}
1192 		if (priv->phandle->cookie) {
1193 			cfg80211_remain_on_channel_expired(
1194 #if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
1195 				remain_priv->netdev,
1196 #else
1197 				remain_priv->wdev,
1198 #endif
1199 				priv->phandle->cookie, &priv->phandle->chan,
1200 #if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
1201 				priv->phandle->channel_type,
1202 #endif
1203 				GFP_ATOMIC);
1204 			priv->phandle->cookie = 0;
1205 		}
1206 		priv->phandle->remain_on_channel = MFALSE;
1207 	}
1208 #endif
1209 #endif
1210 
1211 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
1212 	if (req == NULL) {
1213 		ret = -ENOMEM;
1214 		goto done;
1215 	}
1216 
1217 	bss = (mlan_ds_bss *)req->pbuf;
1218 	bss->sub_command = MLAN_OID_BSS_MODE;
1219 	req->req_id = MLAN_IOCTL_BSS;
1220 	req->action = MLAN_ACT_SET;
1221 
1222 	switch (type) {
1223 	case NL80211_IFTYPE_STATION:
1224 #ifdef WIFI_DIRECT_SUPPORT
1225 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1226 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
1227 		    (priv->wdev->iftype == NL80211_IFTYPE_AP ||
1228 		     priv->wdev->iftype == NL80211_IFTYPE_P2P_GO ||
1229 		     priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
1230 			if (priv->phandle->is_go_timer_set) {
1231 				woal_cancel_timer(&priv->phandle->go_timer);
1232 				priv->phandle->is_go_timer_set = MFALSE;
1233 			}
1234 			/* if we support wifi direct && priv->bss_type ==
1235 			 * wifi_direct, and currently the interface type is AP
1236 			 * or GO or client, that means wpa_supplicant deinit()
1237 			 * wifi direct interface, so we should deinit bss_role
1238 			 * and wifi direct mode, for other bss_type, we should
1239 			 * not update bss_role and wifi direct mode
1240 			 */
1241 
1242 			if (MLAN_STATUS_SUCCESS !=
1243 			    woal_cfg80211_deinit_p2p(priv)) {
1244 				ret = -EFAULT;
1245 				goto done;
1246 			}
1247 		}
1248 #endif /* KERNEL_VERSION */
1249 #endif /* WIFI_DIRECT_SUPPORT */
1250 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
1251 		if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
1252 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
1253 			woal_cfg80211_del_beacon(wiphy, dev, 0);
1254 #else
1255 			woal_cfg80211_del_beacon(wiphy, dev);
1256 #endif
1257 			bss_role = MLAN_BSS_ROLE_STA;
1258 			woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET,
1259 						   &bss_role);
1260 			PRINTM(MIOCTL, "set bss role for STA\n");
1261 		}
1262 #endif
1263 		bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
1264 		priv->wdev->iftype = NL80211_IFTYPE_STATION;
1265 		PRINTM(MINFO, "Setting interface type to managed\n");
1266 		break;
1267 #ifdef WIFI_DIRECT_SUPPORT
1268 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1269 	case NL80211_IFTYPE_P2P_CLIENT:
1270 		if (priv->phandle->is_go_timer_set) {
1271 			woal_cancel_timer(&priv->phandle->go_timer);
1272 			priv->phandle->is_go_timer_set = MFALSE;
1273 		}
1274 
1275 		if (MLAN_STATUS_SUCCESS !=
1276 		    woal_cfg80211_init_p2p_client(priv)) {
1277 			ret = -EFAULT;
1278 			goto done;
1279 		}
1280 
1281 		bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
1282 		priv->wdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
1283 		PRINTM(MINFO, "Setting interface type to P2P client\n");
1284 
1285 		break;
1286 #endif /* KERNEL_VERSION */
1287 #endif /* WIFI_DIRECT_SUPPORT */
1288 	case NL80211_IFTYPE_AP:
1289 #ifdef WIFI_DIRECT_SUPPORT
1290 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1291 	/* Fall Through */
1292 	case NL80211_IFTYPE_P2P_GO:
1293 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
1294 			if (MLAN_STATUS_SUCCESS !=
1295 			    woal_cfg80211_init_p2p_go(priv)) {
1296 				ret = -EFAULT;
1297 				goto done;
1298 			}
1299 			priv->phandle->is_go_timer_set = MTRUE;
1300 			woal_mod_timer(&priv->phandle->go_timer,
1301 				       MOAL_TIMER_10S);
1302 		}
1303 		if (type == NL80211_IFTYPE_P2P_GO)
1304 			priv->wdev->iftype = NL80211_IFTYPE_P2P_GO;
1305 #endif
1306 #endif
1307 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
1308 		if (priv->bss_type == MLAN_BSS_TYPE_STA) {
1309 #ifdef STA_CFG80211
1310 			/** cancel pending scan */
1311 			woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
1312 #endif
1313 			if (priv->probereq_index !=
1314 			    MLAN_CUSTOM_IE_AUTO_IDX_MASK)
1315 				if (woal_cfg80211_mgmt_frame_ie(
1316 					    priv, NULL, 0, NULL, 0, NULL, 0,
1317 					    NULL, 0, MGMT_MASK_PROBE_REQ,
1318 					    MOAL_IOCTL_WAIT))
1319 					PRINTM(MERROR,
1320 					       "%s: Clear probe req ie failed\n",
1321 					       __func__);
1322 			bss_role = MLAN_BSS_ROLE_UAP;
1323 			woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET,
1324 						   &bss_role);
1325 			PRINTM(MIOCTL, "set bss role for AP\n");
1326 		}
1327 #endif
1328 		if (type == NL80211_IFTYPE_AP)
1329 			priv->wdev->iftype = NL80211_IFTYPE_AP;
1330 		PRINTM(MINFO, "Setting interface type to P2P GO\n");
1331 
1332 		/* there is no need for P2P GO to set bss_mode */
1333 		goto done;
1334 
1335 		break;
1336 
1337 	case NL80211_IFTYPE_UNSPECIFIED:
1338 		bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
1339 		priv->wdev->iftype = NL80211_IFTYPE_STATION;
1340 		PRINTM(MINFO, "Setting interface type to auto\n");
1341 		break;
1342 	default:
1343 		ret = -EINVAL;
1344 		break;
1345 	}
1346 	if (ret)
1347 		goto done;
1348 
1349 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1350 	if (status != MLAN_STATUS_SUCCESS) {
1351 		ret = -EFAULT;
1352 		goto done;
1353 	}
1354 
1355 done:
1356 	if (status != MLAN_STATUS_PENDING)
1357 		kfree(req);
1358 	LEAVE();
1359 	return ret;
1360 }
1361 
1362 /**
1363  * @brief Request the driver to change the value of fragment
1364  * threshold or rts threshold or retry limit
1365  *
1366  * @param wiphy         A pointer to wiphy structure
1367  * @param changed       Change flags
1368  *
1369  * @return              0 -- success, otherwise fail
1370  */
woal_cfg80211_set_wiphy_params(struct wiphy * wiphy,u32 changed)1371 int woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1372 {
1373 	moal_private *priv = NULL;
1374 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
1375 #ifdef UAP_CFG80211
1376 #ifdef UAP_SUPPORT
1377 	pmlan_uap_bss_param sys_cfg = NULL;
1378 #endif
1379 #endif
1380 	int frag_thr = wiphy->frag_threshold;
1381 	int rts_thr = wiphy->rts_threshold;
1382 	int retry = wiphy->retry_long;
1383 
1384 	ENTER();
1385 
1386 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
1387 	if (!priv) {
1388 		LEAVE();
1389 		return -EFAULT;
1390 	}
1391 	if (rts_thr == (int)MLAN_FRAG_RTS_DISABLED)
1392 		rts_thr = MLAN_RTS_MAX_VALUE;
1393 	if (frag_thr == (int)MLAN_FRAG_RTS_DISABLED)
1394 		frag_thr = MLAN_FRAG_MAX_VALUE;
1395 
1396 #ifdef UAP_CFG80211
1397 #ifdef UAP_SUPPORT
1398 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
1399 		sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
1400 		if (!sys_cfg) {
1401 			PRINTM(MERROR,
1402 			       "Fail to alloc memory for mlan_uap_bss_param\n");
1403 			LEAVE();
1404 			return -EFAULT;
1405 		}
1406 		/* Initialize the invalid values so that the correct
1407 		 * values below are downloaded to firmware
1408 		 */
1409 		woal_set_sys_config_invalid_data(sys_cfg);
1410 		sys_cfg->frag_threshold = frag_thr;
1411 		sys_cfg->rts_threshold = rts_thr;
1412 		sys_cfg->retry_limit = retry;
1413 
1414 		if ((changed & WIPHY_PARAM_RTS_THRESHOLD) ||
1415 		    (changed & WIPHY_PARAM_FRAG_THRESHOLD) ||
1416 		    (changed &
1417 		     (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))) {
1418 			if (woal_set_get_sys_config(priv, MLAN_ACT_SET,
1419 						    MOAL_IOCTL_WAIT, sys_cfg)) {
1420 				kfree(sys_cfg);
1421 				goto fail;
1422 			}
1423 		}
1424 		kfree(sys_cfg);
1425 	}
1426 #endif
1427 #endif
1428 
1429 #ifdef STA_CFG80211
1430 #ifdef STA_SUPPORT
1431 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1432 		if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1433 			if (woal_set_get_rts(priv, MLAN_ACT_SET,
1434 					     MOAL_IOCTL_WAIT, &rts_thr))
1435 				goto fail;
1436 		}
1437 		if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
1438 			if (woal_set_get_frag(priv, MLAN_ACT_SET,
1439 					      MOAL_IOCTL_WAIT, &frag_thr))
1440 				goto fail;
1441 		}
1442 		if (changed &
1443 		    (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))
1444 			if (woal_set_get_retry(priv, MLAN_ACT_SET,
1445 					       MOAL_IOCTL_WAIT, &retry))
1446 				goto fail;
1447 	}
1448 #endif
1449 #endif
1450 	LEAVE();
1451 	return 0;
1452 
1453 fail:
1454 	PRINTM(MERROR, "Failed to change wiphy params %x\n", changed);
1455 	LEAVE();
1456 	return -EFAULT;
1457 }
1458 
1459 #if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
1460 /**
1461  * @brief Request the driver to add a key
1462  *
1463  * @param wiphy         A pointer to wiphy structure
1464  * @param netdev        A pointer to net_device structure
1465  * @param key_index     Key index
1466  * @param pairwise      Flag to indicate pairwise or group (for kernel > 2.6.36)
1467  * @param mac_addr      MAC address (NULL for group key)
1468  * @param params        A pointer to key_params structure
1469  *
1470  * @return              0 -- success, otherwise fail
1471  */
1472 #else
1473 /**
1474  * @brief Request the driver to add a key
1475  *
1476  * @param wiphy         A pointer to wiphy structure
1477  * @param netdev        A pointer to net_device structure
1478  * @param key_index     Key index
1479  * @param mac_addr      MAC address (NULL for group key)
1480  * @param params        A pointer to key_params structure
1481  *
1482  * @return              0 -- success, otherwise fail
1483  */
1484 #endif
woal_cfg80211_add_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,t_u8 key_index,bool pairwise,const t_u8 * mac_addr,struct key_params * params)1485 int woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
1486 #if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || IMX_ANDROID_13)
1487 			  int link_id,
1488 #endif
1489 			  t_u8 key_index,
1490 #if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
1491 			  bool pairwise,
1492 #endif
1493 			  const t_u8 *mac_addr, struct key_params *params)
1494 {
1495 	moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
1496 
1497 	ENTER();
1498 	if (priv->ft_pre_connect) {
1499 		PRINTM(MINFO, "Skip set keys during ft connecting\n");
1500 		return -EFAULT;
1501 	}
1502 
1503 	/** cancel pending scan */
1504 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
1505 
1506 	if (woal_cfg80211_set_key(priv, 0, params->cipher, params->key,
1507 				  params->key_len, params->seq, params->seq_len,
1508 				  key_index, mac_addr, 0, MOAL_IOCTL_WAIT)) {
1509 		PRINTM(MERROR, "Error adding the crypto keys\n");
1510 		LEAVE();
1511 		return -EFAULT;
1512 	}
1513 
1514 	PRINTM(MINFO, "Crypto keys added\n");
1515 
1516 	LEAVE();
1517 	return 0;
1518 }
1519 
1520 #if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
1521 /**
1522  * @brief Request the driver to delete a key
1523  *
1524  * @param wiphy         A pointer to wiphy structure
1525  * @param netdev        A pointer to net_device structure
1526  * @param key_index     Key index
1527  * @param pairwise      Flag to indicate pairwise or group (for kernel > 2.6.36)
1528  * @param mac_addr      MAC address (NULL for group key)
1529  *
1530  * @return              0 -- success, otherwise fail
1531  */
1532 #else
1533 /**
1534  * @brief Request the driver to delete a key
1535  *
1536  * @param wiphy         A pointer to wiphy structure
1537  * @param netdev        A pointer to net_device structure
1538  * @param key_index     Key index
1539  * @param mac_addr      MAC address (NULL for group key)
1540  *
1541  * @return              0 -- success, otherwise fail
1542  */
1543 #endif
woal_cfg80211_del_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,t_u8 key_index,bool pairwise,const t_u8 * mac_addr)1544 int woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
1545 #if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || IMX_ANDROID_13)
1546 			  int link_id,
1547 #endif
1548 			  t_u8 key_index,
1549 #if KERNEL_VERSION(2, 6, 36) < CFG80211_VERSION_CODE
1550 			  bool pairwise,
1551 #endif
1552 			  const t_u8 *mac_addr)
1553 {
1554 	moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
1555 
1556 	ENTER();
1557 	if (priv->phandle->driver_status) {
1558 		PRINTM(MERROR, "Block %s in abnormal driver state\n", __func__);
1559 		LEAVE();
1560 		return -EFAULT;
1561 	}
1562 	/* del_key will be trigger from cfg80211_rx_mlme_mgmt funtion
1563 	 * where we receive deauth/disassoicate packet in rx_work
1564 	 * use MOAL_NO_WAIT to avoid dead lock
1565 	 */
1566 	if (MLAN_STATUS_FAILURE ==
1567 	    woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, key_index,
1568 				  mac_addr, 1, MOAL_NO_WAIT)) {
1569 		PRINTM(MERROR, "Error deleting the crypto keys\n");
1570 		LEAVE();
1571 		return -EFAULT;
1572 	}
1573 
1574 	PRINTM(MINFO, "Crypto keys deleted\n");
1575 	LEAVE();
1576 	return 0;
1577 }
1578 
1579 #if KERNEL_VERSION(2, 6, 37) < CFG80211_VERSION_CODE
1580 /**
1581  * @brief Request to enable WEP key to driver
1582  *
1583  * @param wiphy         A pointer to wiphy structure
1584  * @param netdev        A pointer to net_device structure
1585  * @param key_index     Key index
1586  * @param ucast         Unicast flag (for kernel > 2.6.37)
1587  * @param mcast         Multicast flag (for kernel > 2.6.37)
1588  *
1589  * @return              0 -- success, otherwise fail
1590  */
1591 #else
1592 /**
1593  * @brief Request to enable WEP key to driver
1594  *
1595  * @param wiphy         A pointer to wiphy structure
1596  * @param netdev        A pointer to net_device structure
1597  * @param key_index     Key index
1598  *
1599  * @return              0 -- success, otherwise fail
1600  */
1601 #endif
woal_cfg80211_set_default_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,t_u8 key_index,bool ucast,bool mcast)1602 int woal_cfg80211_set_default_key(struct wiphy *wiphy,
1603 				  struct net_device *netdev,
1604 #if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || IMX_ANDROID_13)
1605 				  int link_id,
1606 #endif
1607 				  t_u8 key_index
1608 #if KERNEL_VERSION(2, 6, 37) < CFG80211_VERSION_CODE
1609 				  ,
1610 				  bool ucast, bool mcast
1611 #endif
1612 )
1613 {
1614 	int ret = 0;
1615 	moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
1616 	mlan_bss_info bss_info;
1617 
1618 	ENTER();
1619 	memset(&bss_info, 0, sizeof(mlan_bss_info));
1620 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1621 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
1622 		if (!bss_info.wep_status) {
1623 			LEAVE();
1624 			return ret;
1625 		}
1626 	}
1627 	if (MLAN_STATUS_SUCCESS !=
1628 	    woal_cfg80211_set_wep_keys(priv, NULL, 0, key_index,
1629 				       MOAL_IOCTL_WAIT)) {
1630 		ret = -EFAULT;
1631 	}
1632 	LEAVE();
1633 	return ret;
1634 }
1635 
1636 #if KERNEL_VERSION(2, 6, 30) <= CFG80211_VERSION_CODE
woal_cfg80211_set_default_mgmt_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,t_u8 key_index)1637 int woal_cfg80211_set_default_mgmt_key(struct wiphy *wiphy,
1638 				       struct net_device *netdev,
1639 #if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || IMX_ANDROID_13)
1640 				       int link_id,
1641 #endif
1642 				       t_u8 key_index)
1643 {
1644 	PRINTM(MINFO, "set default mgmt key, key index=%d\n", key_index);
1645 
1646 	return 0;
1647 }
1648 #endif
1649 
1650 #if KERNEL_VERSION(5, 10, 0) <= CFG80211_VERSION_CODE
woal_cfg80211_set_default_beacon_key(struct wiphy * wiphy,struct net_device * netdev,int link_id,t_u8 key_index)1651 int woal_cfg80211_set_default_beacon_key(struct wiphy *wiphy,
1652 					 struct net_device *netdev,
1653 #if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || IMX_ANDROID_13)
1654 					 int link_id,
1655 #endif
1656 					 t_u8 key_index)
1657 {
1658 	PRINTM(MINFO, "set default beacon key, key index=%d\n", key_index);
1659 
1660 	return 0;
1661 }
1662 #endif
1663 
1664 #if KERNEL_VERSION(3, 1, 0) <= CFG80211_VERSION_CODE
1665 /**
1666  *  @brief  Set GTK rekey data to driver
1667  *
1668  *  @param priv         A pointer to moal_private structure
1669  *  @param gtk_rekey     A pointer to mlan_ds_misc_gtk_rekey_data structure
1670  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
1671  *
1672  *  @return             0 --success, otherwise fail
1673  */
woal_set_rekey_data(moal_private * priv,mlan_ds_misc_gtk_rekey_data * gtk_rekey,t_u8 action,t_u8 wait_option)1674 mlan_status woal_set_rekey_data(moal_private *priv,
1675 				mlan_ds_misc_gtk_rekey_data *gtk_rekey,
1676 				t_u8 action, t_u8 wait_option)
1677 {
1678 	mlan_ioctl_req *req;
1679 	mlan_ds_misc_cfg *misc_cfg;
1680 	mlan_status status;
1681 
1682 	ENTER();
1683 
1684 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1685 
1686 	if (req == NULL) {
1687 		LEAVE();
1688 		return MLAN_STATUS_FAILURE;
1689 	} else {
1690 		misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
1691 		misc_cfg->sub_command = MLAN_OID_MISC_GTK_REKEY_OFFLOAD;
1692 		req->req_id = MLAN_IOCTL_MISC_CFG;
1693 
1694 		req->action = action;
1695 		if (action == MLAN_ACT_SET)
1696 			moal_memcpy_ext(priv->phandle,
1697 					&misc_cfg->param.gtk_rekey, gtk_rekey,
1698 					sizeof(mlan_ds_misc_gtk_rekey_data),
1699 					sizeof(mlan_ds_misc_gtk_rekey_data));
1700 
1701 		status = woal_request_ioctl(priv, req, wait_option);
1702 		if (status != MLAN_STATUS_PENDING)
1703 			kfree(req);
1704 	}
1705 
1706 	LEAVE();
1707 	return status;
1708 }
1709 
1710 /**
1711  * @brief Give the data necessary for GTK rekeying to the driver
1712  *
1713  * @param wiphy         A pointer to wiphy structure
1714  * @param dev           A pointer to net_device structure
1715  * @param data        A pointer to cfg80211_gtk_rekey_data structure
1716  *
1717  * @return              0 -- success, otherwise fail
1718  */
woal_cfg80211_set_rekey_data(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_gtk_rekey_data * data)1719 int woal_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
1720 				 struct cfg80211_gtk_rekey_data *data)
1721 {
1722 	int ret = 0;
1723 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1724 	mlan_ds_misc_gtk_rekey_data rekey;
1725 	mlan_fw_info fw_info;
1726 
1727 	ENTER();
1728 
1729 	if (priv->phandle->params.gtk_rekey_offload ==
1730 	    GTK_REKEY_OFFLOAD_DISABLE) {
1731 		PRINTM(MMSG, "%s return: gtk_rekey_offload is DISABLE\n",
1732 		       __func__);
1733 		LEAVE();
1734 		return ret;
1735 	}
1736 
1737 	memset(&fw_info, 0, sizeof(mlan_fw_info));
1738 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
1739 	if (!fw_info.fw_supplicant_support) {
1740 		LEAVE();
1741 		return -1;
1742 	}
1743 
1744 	moal_memcpy_ext(priv->phandle, rekey.kek, data->kek, MLAN_KEK_LEN,
1745 			MLAN_KEK_LEN);
1746 	moal_memcpy_ext(priv->phandle, rekey.kck, data->kck, MLAN_KCK_LEN,
1747 			MLAN_KCK_LEN);
1748 	moal_memcpy_ext(priv->phandle, rekey.replay_ctr, data->replay_ctr,
1749 			MLAN_REPLAY_CTR_LEN, MLAN_REPLAY_CTR_LEN);
1750 
1751 	moal_memcpy_ext(priv->phandle, &priv->gtk_rekey_data, &rekey,
1752 			sizeof(mlan_ds_misc_gtk_rekey_data),
1753 			sizeof(mlan_ds_misc_gtk_rekey_data));
1754 	if (priv->phandle->params.gtk_rekey_offload ==
1755 	    GTK_REKEY_OFFLOAD_SUSPEND) {
1756 		priv->gtk_data_ready = MTRUE;
1757 		LEAVE();
1758 		return ret;
1759 	}
1760 
1761 	if (MLAN_STATUS_SUCCESS !=
1762 	    woal_set_rekey_data(priv, &rekey, MLAN_ACT_SET, MOAL_IOCTL_WAIT)) {
1763 		ret = -EFAULT;
1764 	}
1765 
1766 	LEAVE();
1767 	return ret;
1768 }
1769 #endif
1770 
1771 #ifdef STA_SUPPORT
1772 /* Opportunistic Key Caching APIs functions support
1773  *
1774  * this function get pmksa entry list in private structure
1775  * @param priv         A pointer to moal_private structure
1776  * @param bssid        A pointer to bssid
1777  * @return             pointer to target entry or NULL
1778  */
woal_get_pmksa_entry(moal_private * priv,const u8 * bssid)1779 struct pmksa_entry *woal_get_pmksa_entry(moal_private *priv, const u8 *bssid)
1780 {
1781 	struct pmksa_entry *entry = NULL;
1782 	unsigned long flags;
1783 
1784 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1785 		PRINTM(MERROR, "Invalid interface structure\n");
1786 		return NULL;
1787 	}
1788 
1789 	spin_lock_irqsave(&priv->pmksa_list_lock, flags);
1790 	list_for_each_entry (entry, &priv->pmksa_cache_list, link) {
1791 		if (!memcmp(entry->bssid, bssid, ETH_ALEN)) {
1792 			spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1793 			return entry;
1794 		}
1795 	}
1796 	spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1797 
1798 	return NULL;
1799 }
1800 
1801 /**
1802  * This function flush pmksa entry list in private structure
1803  * @param priv         A pointer to moal_private structure
1804  * @return             success of failure
1805  */
woal_flush_pmksa_list(moal_private * priv)1806 int woal_flush_pmksa_list(moal_private *priv)
1807 {
1808 	struct pmksa_entry *entry, *tmp;
1809 	unsigned long flags;
1810 
1811 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1812 		PRINTM(MERROR, "Invalid interface structure\n");
1813 		return -EFAULT;
1814 	}
1815 
1816 	spin_lock_irqsave(&priv->pmksa_list_lock, flags);
1817 	list_for_each_entry_safe (entry, tmp, &priv->pmksa_cache_list, link) {
1818 		list_del(&entry->link);
1819 		kfree(entry);
1820 	}
1821 	INIT_LIST_HEAD(&priv->pmksa_cache_list);
1822 	spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1823 
1824 	return 0;
1825 }
1826 
1827 /**
1828  *  This function add new pmksa entry to list
1829  *  @param wiphy        A pointer to struct wiphy
1830  *  @param dev          A pointer to net_device structure
1831  *  @param pmksa        A pointer to cfg80211_pmksa structure
1832  *  @return             success of failure
1833  */
woal_cfg80211_set_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)1834 int woal_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
1835 			    struct cfg80211_pmksa *pmksa)
1836 {
1837 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1838 	struct pmksa_entry *entry = NULL;
1839 	unsigned long flags;
1840 	int ret = 0;
1841 
1842 	ENTER();
1843 
1844 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1845 		PRINTM(MERROR, "Invalid interface structure\n");
1846 		ret = -1;
1847 		goto done;
1848 	}
1849 
1850 	PRINTM(MIOCTL, "Set pmksa entry: bssid=" MACSTR "\n",
1851 	       MAC2STR(pmksa->bssid));
1852 	entry = woal_get_pmksa_entry(priv, pmksa->bssid);
1853 	if (!entry) {
1854 		entry = kzalloc(sizeof(struct pmksa_entry), GFP_ATOMIC);
1855 		if (!entry) {
1856 			PRINTM(MERROR, "Fail to allocate pmksa entry\n");
1857 			goto done;
1858 		}
1859 		INIT_LIST_HEAD(&entry->link);
1860 		moal_memcpy_ext(priv->phandle, entry->bssid, pmksa->bssid,
1861 				ETH_ALEN, ETH_ALEN);
1862 		moal_memcpy_ext(priv->phandle, entry->pmkid, pmksa->pmkid,
1863 				PMKID_LEN, PMKID_LEN);
1864 		spin_lock_irqsave(&priv->pmksa_list_lock, flags);
1865 		list_add_tail(&entry->link, &priv->pmksa_cache_list);
1866 		spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1867 	} else {
1868 		/** pmkid is differnt from previous value? */
1869 		memset(entry->pmkid, 0, PMKID_LEN);
1870 		moal_memcpy_ext(priv->phandle, entry->pmkid, pmksa->pmkid,
1871 				PMKID_LEN, PMKID_LEN);
1872 	}
1873 
1874 	/** Check if current roaming is going and received target pmkid */
1875 	if (priv->wait_target_ap_pmkid) {
1876 		struct cfg80211_connect_params *param = &priv->sme_current;
1877 
1878 		if (param && !memcmp(pmksa->bssid, param->bssid, ETH_ALEN)) {
1879 			PRINTM(MIOCTL,
1880 			       "Current roaming target bssid=" MACSTR "\n",
1881 			       MAC2STR(param->bssid));
1882 			priv->target_ap_pmksa = entry;
1883 			priv->wait_target_ap_pmkid = MFALSE;
1884 			wake_up_interruptible(&priv->okc_wait_q);
1885 		}
1886 	}
1887 
1888 done:
1889 	LEAVE();
1890 	return ret;
1891 }
1892 
1893 /**
1894  *  This function delete pmksa entry
1895  *  @param wiphy        A pointer to struct wiphy
1896  *  @param dev          A pointer to net_device structure
1897  *  @param pmksa        A pointer to cfg80211_pmksa structure
1898  *  @return             success of failure
1899  */
woal_cfg80211_del_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)1900 int woal_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
1901 			    struct cfg80211_pmksa *pmksa)
1902 {
1903 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1904 	struct pmksa_entry *entry, *tmp;
1905 	unsigned long flags;
1906 
1907 	ENTER();
1908 
1909 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1910 		PRINTM(MERROR, "Invalid interface structure\n");
1911 		LEAVE();
1912 		return -1;
1913 	}
1914 
1915 	PRINTM(MIOCTL, "Delete pmksa: bssid=" MACSTR "\n",
1916 	       MAC2STR(pmksa->bssid));
1917 	spin_lock_irqsave(&priv->pmksa_list_lock, flags);
1918 	list_for_each_entry_safe (entry, tmp, &priv->pmksa_cache_list, link) {
1919 		if (!memcmp(entry->bssid, pmksa->bssid, ETH_ALEN)) {
1920 			list_del(&entry->link);
1921 			kfree(entry);
1922 		}
1923 	}
1924 	spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1925 
1926 	LEAVE();
1927 	return 0;
1928 }
1929 
1930 /**
1931  *  This function flush pmksa entry list
1932  *  @param wiphy        A pointer to struct wiphy
1933  *  @param dev          A pointer to net_device structure
1934  *  @return             success of failure
1935  */
woal_cfg80211_flush_pmksa(struct wiphy * wiphy,struct net_device * dev)1936 int woal_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
1937 {
1938 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1939 
1940 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA)
1941 		return -1;
1942 
1943 	PRINTM(MIOCTL, "Flush pmksa list.\n");
1944 	return woal_flush_pmksa_list(priv);
1945 }
1946 #endif
1947 
1948 #if KERNEL_VERSION(3, 5, 0) > CFG80211_VERSION_CODE
1949 #if KERNEL_VERSION(2, 6, 34) < CFG80211_VERSION_CODE
1950 /**
1951  * @brief Request the driver to change the channel
1952  *
1953  * @param wiphy           A pointer to wiphy structure
1954  * @param dev             A pointer to net_device structure
1955  * @param chan            A pointer to ieee80211_channel structure
1956  * @param channel_type    Channel type of nl80211_channel_type
1957  *
1958  * @return                0 -- success, otherwise fail
1959  */
1960 #else
1961 /**
1962  * @brief Request the driver to change the channel
1963  *
1964  * @param wiphy           A pointer to wiphy structure
1965  * @param chan            A pointer to ieee80211_channel structure
1966  * @param channel_type    Channel type of nl80211_channel_type
1967  *
1968  * @return                0 -- success, otherwise fail
1969  */
1970 #endif
woal_cfg80211_set_channel(struct wiphy * wiphy,struct net_device * dev,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type)1971 int woal_cfg80211_set_channel(struct wiphy *wiphy,
1972 #if KERNEL_VERSION(2, 6, 34) < CFG80211_VERSION_CODE
1973 			      struct net_device *dev,
1974 #endif
1975 			      struct ieee80211_channel *chan,
1976 			      enum nl80211_channel_type channel_type)
1977 {
1978 	int ret = 0;
1979 	moal_private *priv = NULL;
1980 
1981 	ENTER();
1982 
1983 #if KERNEL_VERSION(3, 5, 0) > CFG80211_VERSION_CODE
1984 #if KERNEL_VERSION(2, 6, 34) < CFG80211_VERSION_CODE
1985 	if (dev)
1986 		priv = woal_get_netdev_priv(dev);
1987 #endif
1988 #endif
1989 	if (!priv) {
1990 		moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
1991 
1992 		if (handle)
1993 			priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
1994 	}
1995 	if (priv) {
1996 #ifdef STA_CFG80211
1997 #ifdef STA_SUPPORT
1998 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1999 			if (priv->media_connected == MTRUE) {
2000 				PRINTM(MERROR,
2001 				       "This configuration is valid only when station is not connected\n");
2002 				LEAVE();
2003 				return -EINVAL;
2004 			}
2005 			ret = woal_set_rf_channel(priv, chan, channel_type,
2006 						  MOAL_IOCTL_WAIT);
2007 		}
2008 #endif
2009 #endif
2010 		priv->channel =
2011 			ieee80211_frequency_to_channel(chan->center_freq);
2012 	}
2013 	/* set monitor channel support */
2014 
2015 	LEAVE();
2016 	return ret;
2017 }
2018 #endif
2019 
2020 #if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
woal_is_pattern_supported(struct cfg80211_pkt_pattern * pat,t_u8 * byte_seq,t_u8 max_byte_seq)2021 static bool woal_is_pattern_supported(struct cfg80211_pkt_pattern *pat,
2022 				      t_u8 *byte_seq, t_u8 max_byte_seq)
2023 {
2024 	int j, k, valid_byte_cnt = 0;
2025 	bool dont_care_byte = false;
2026 
2027 	for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) {
2028 		for (k = 0; k < 8; k++) {
2029 			if (pat->mask[j] & 1 << k) {
2030 				moal_memcpy_ext(NULL, byte_seq + valid_byte_cnt,
2031 						&pat->pattern[j * 8 + k], 1,
2032 						(t_u32)max_byte_seq -
2033 							(t_u32)valid_byte_cnt);
2034 				valid_byte_cnt++;
2035 				if (dont_care_byte)
2036 					return false;
2037 			} else {
2038 				if (valid_byte_cnt)
2039 					dont_care_byte = true;
2040 			}
2041 
2042 			if (valid_byte_cnt > max_byte_seq)
2043 				return false;
2044 		}
2045 	}
2046 
2047 	byte_seq[max_byte_seq] = valid_byte_cnt;
2048 
2049 	return true;
2050 }
2051 
woal_get_coalesce_pkt_type(t_u8 * byte_seq)2052 static int woal_get_coalesce_pkt_type(t_u8 *byte_seq)
2053 {
2054 	const t_u8 ipv4_mc_mac[] = {0x33, 0x33};
2055 	const t_u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
2056 	const t_u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff};
2057 
2058 	if ((byte_seq[0] & 0x01) && (byte_seq[COALESCE_MAX_BYTESEQ] == 1))
2059 		return PACKET_TYPE_UNICAST;
2060 	else if (!memcmp(byte_seq, bc_mac, 4))
2061 		return PACKET_TYPE_BROADCAST;
2062 	else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
2063 		  byte_seq[COALESCE_MAX_BYTESEQ] == 2) ||
2064 		 (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
2065 		  byte_seq[COALESCE_MAX_BYTESEQ] == 3))
2066 		return PACKET_TYPE_MULTICAST;
2067 
2068 	return 0;
2069 }
2070 
woal_fill_coalesce_rule_info(struct cfg80211_coalesce_rules * crule,struct coalesce_rule * mrule)2071 static int woal_fill_coalesce_rule_info(struct cfg80211_coalesce_rules *crule,
2072 					struct coalesce_rule *mrule)
2073 {
2074 	t_u8 byte_seq[COALESCE_MAX_BYTESEQ + 1];
2075 	struct filt_field_param *param;
2076 	int i;
2077 
2078 	mrule->max_coalescing_delay = crule->delay;
2079 
2080 	param = mrule->params;
2081 
2082 	for (i = 0; i < crule->n_patterns; i++) {
2083 		memset(byte_seq, 0, sizeof(byte_seq));
2084 		if (!woal_is_pattern_supported(&crule->patterns[i], byte_seq,
2085 					       COALESCE_MAX_BYTESEQ)) {
2086 			PRINTM(MERROR, "Pattern not supported\n");
2087 			return -EOPNOTSUPP;
2088 		}
2089 
2090 		if (!crule->patterns[i].pkt_offset) {
2091 			u8 pkt_type;
2092 
2093 			pkt_type = woal_get_coalesce_pkt_type(byte_seq);
2094 			if (pkt_type && mrule->pkt_type) {
2095 				PRINTM(MERROR,
2096 				       "Multiple packet types not allowed\n");
2097 				return -EOPNOTSUPP;
2098 			} else if (pkt_type) {
2099 				mrule->pkt_type = pkt_type;
2100 				continue;
2101 			}
2102 		}
2103 
2104 		if (crule->condition == NL80211_COALESCE_CONDITION_MATCH)
2105 			param->operation = RECV_FILTER_MATCH_TYPE_EQ;
2106 		else
2107 			param->operation = RECV_FILTER_MATCH_TYPE_NE;
2108 
2109 		param->operand_len = byte_seq[COALESCE_MAX_BYTESEQ];
2110 		moal_memcpy_ext(NULL, param->operand_byte_stream, byte_seq,
2111 				param->operand_len, COALESCE_MAX_BYTESEQ);
2112 		param->offset = crule->patterns[i].pkt_offset;
2113 		param++;
2114 
2115 		mrule->num_of_fields++;
2116 	}
2117 
2118 	if (!mrule->pkt_type) {
2119 		PRINTM(MERROR, "Packet type can not be determined\n");
2120 		return -EOPNOTSUPP;
2121 	}
2122 
2123 	return 0;
2124 }
2125 
2126 /**
2127  *  @brief Set coalesce parameter
2128  *
2129  *  @param priv             A pointer to moal_private structure
2130  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
2131  *  @param coalesce_cfg     A pointer to coalesce structure
2132  *
2133  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2134  */
woal_set_coalesce(moal_private * priv,t_u16 action,mlan_ds_coalesce_cfg * coalesce_cfg)2135 static mlan_status woal_set_coalesce(moal_private *priv, t_u16 action,
2136 				     mlan_ds_coalesce_cfg *coalesce_cfg)
2137 {
2138 	mlan_status ret = MLAN_STATUS_SUCCESS;
2139 	mlan_ds_misc_cfg *misc_cfg = NULL;
2140 	mlan_ioctl_req *req = NULL;
2141 
2142 	ENTER();
2143 
2144 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
2145 	if (req == NULL) {
2146 		ret = MLAN_STATUS_FAILURE;
2147 		goto done;
2148 	}
2149 
2150 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
2151 	misc_cfg->sub_command = MLAN_OID_MISC_COALESCE_CFG;
2152 	req->req_id = MLAN_IOCTL_MISC_CFG;
2153 	req->action = action;
2154 
2155 	moal_memcpy_ext(priv->phandle, &misc_cfg->param.coalesce_cfg,
2156 			coalesce_cfg, sizeof(mlan_ds_coalesce_cfg),
2157 			sizeof(mlan_ds_coalesce_cfg));
2158 
2159 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2160 	if (ret != MLAN_STATUS_SUCCESS)
2161 		goto done;
2162 
2163 done:
2164 	if (ret != MLAN_STATUS_PENDING)
2165 		kfree(req);
2166 	LEAVE();
2167 	return ret;
2168 }
2169 
2170 /**
2171  * @brief Request the driver to set the coalesce
2172  *
2173  * @param wiphy           A pointer to wiphy structure
2174  * @param coalesce        A pointer to cfg80211_coalesce structure
2175  *
2176  * @return                0 -- success, otherwise fail
2177  */
woal_cfg80211_set_coalesce(struct wiphy * wiphy,struct cfg80211_coalesce * coalesce)2178 int woal_cfg80211_set_coalesce(struct wiphy *wiphy,
2179 			       struct cfg80211_coalesce *coalesce)
2180 {
2181 	int ret = 0;
2182 	int i;
2183 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
2184 	moal_private *priv = NULL;
2185 	mlan_ds_coalesce_cfg coalesce_cfg;
2186 
2187 	ENTER();
2188 
2189 	if (!handle) {
2190 		PRINTM(MFATAL, "Unable to get handle\n");
2191 		ret = -EINVAL;
2192 		goto done;
2193 	}
2194 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
2195 	if (!priv) {
2196 		ret = -EINVAL;
2197 		goto done;
2198 	}
2199 
2200 	memset(&coalesce_cfg, 0, sizeof(coalesce_cfg));
2201 	if (!coalesce) {
2202 		PRINTM(MMSG, "Disable coalesce and reset all previous rules\n");
2203 	} else {
2204 		coalesce_cfg.num_of_rules = coalesce->n_rules;
2205 		for (i = 0; i < coalesce->n_rules; i++) {
2206 			ret = woal_fill_coalesce_rule_info(
2207 				&coalesce->rules[i], &coalesce_cfg.rule[i]);
2208 			if (ret) {
2209 				PRINTM(MERROR,
2210 				       "Recheck the patterns provided for rule %d\n",
2211 				       i + 1);
2212 				return ret;
2213 			}
2214 		}
2215 	}
2216 
2217 	if (MLAN_STATUS_SUCCESS !=
2218 	    woal_set_coalesce(priv, MLAN_ACT_SET, &coalesce_cfg)) {
2219 		PRINTM(MERROR, "wlan: Fail to set coalesce\n");
2220 		ret = -EFAULT;
2221 	}
2222 
2223 done:
2224 	LEAVE();
2225 	return ret;
2226 }
2227 #endif
2228 
2229 /**
2230  * @brief Request the driver to set the bitrate
2231  *
2232  * @param wiphy           A pointer to wiphy structure
2233  * @param dev             A pointer to net_device structure
2234  * @param peer            A pointer to peer address
2235  * @param mask            A pointer to cfg80211_bitrate_mask structure
2236  *
2237  * @return                0 -- success, otherwise fail
2238  */
woal_cfg80211_set_bitrate_mask(struct wiphy * wiphy,struct net_device * dev,unsigned int link_id,const u8 * peer,const struct cfg80211_bitrate_mask * mask)2239 int woal_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
2240 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
2241 				   unsigned int link_id,
2242 #endif
2243 				   const u8 *peer,
2244 				   const struct cfg80211_bitrate_mask *mask)
2245 {
2246 	int ret = 0;
2247 	mlan_status status = MLAN_STATUS_SUCCESS;
2248 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2249 	mlan_bss_info bss_info;
2250 	enum ieee80211_band band;
2251 	mlan_ioctl_req *req = NULL;
2252 	mlan_ds_rate *rate = NULL;
2253 	mlan_rate_cfg_t *rate_cfg = NULL;
2254 
2255 	ENTER();
2256 
2257 	if (priv->media_connected == MFALSE) {
2258 		PRINTM(MERROR, "Can not set data rate in disconnected state\n");
2259 		ret = -EINVAL;
2260 		goto done;
2261 	}
2262 
2263 	status = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
2264 	if (status)
2265 		goto done;
2266 	band = woal_band_cfg_to_ieee_band(bss_info.bss_band);
2267 
2268 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2269 	if (req == NULL) {
2270 		ret = -ENOMEM;
2271 		goto done;
2272 	}
2273 	rate = (mlan_ds_rate *)req->pbuf;
2274 	rate_cfg = &rate->param.rate_cfg;
2275 	rate->sub_command = MLAN_OID_RATE_CFG;
2276 	req->req_id = MLAN_IOCTL_RATE;
2277 	req->action = MLAN_ACT_SET;
2278 	rate_cfg->rate_type = MLAN_RATE_BITMAP;
2279 
2280 	/* Fill HR/DSSS rates. */
2281 	if (band == IEEE80211_BAND_2GHZ)
2282 		rate_cfg->bitmap_rates[0] = mask->control[band].legacy & 0x000f;
2283 
2284 	/* Fill OFDM rates */
2285 	if (band == IEEE80211_BAND_2GHZ)
2286 		rate_cfg->bitmap_rates[1] =
2287 			(mask->control[band].legacy & 0x0ff0) >> 4;
2288 	else
2289 		rate_cfg->bitmap_rates[1] = mask->control[band].legacy;
2290 
2291 #if KERNEL_VERSION(3, 4, 0) <= CFG80211_VERSION_CODE
2292 		/* Fill MCS rates */
2293 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
2294 	rate_cfg->bitmap_rates[2] = mask->control[band].ht_mcs[0];
2295 #else
2296 	rate_cfg->bitmap_rates[2] = mask->control[band].mcs[0];
2297 #endif
2298 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
2299 	rate_cfg->bitmap_rates[2] |= mask->control[band].ht_mcs[1] << 8;
2300 #else
2301 	rate_cfg->bitmap_rates[2] |= mask->control[band].mcs[1] << 8;
2302 #endif
2303 #endif
2304 
2305 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2306 	if (status != MLAN_STATUS_SUCCESS) {
2307 		ret = -EFAULT;
2308 		goto done;
2309 	}
2310 
2311 done:
2312 	if (status != MLAN_STATUS_PENDING)
2313 		kfree(req);
2314 	LEAVE();
2315 	return ret;
2316 }
2317 
2318 #if KERNEL_VERSION(2, 6, 38) <= CFG80211_VERSION_CODE
2319 /**
2320  * @brief Request the driver to get antenna configuration
2321  *
2322  * @param wiphy           A pointer to wiphy structure
2323  * @param tx_ant          Bitmaps of allowed antennas to use for TX
2324  * @param rx_ant          Bitmaps of allowed antennas to use for RX
2325  *
2326  * @return                0 -- success, otherwise fail
2327  */
woal_cfg80211_get_antenna(struct wiphy * wiphy,u32 * tx_ant,u32 * rx_ant)2328 int woal_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant)
2329 {
2330 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
2331 	moal_private *priv = NULL;
2332 	mlan_ds_radio_cfg *radio = NULL;
2333 	mlan_ioctl_req *req = NULL;
2334 	mlan_status status = MLAN_STATUS_SUCCESS;
2335 	int ret = 0;
2336 
2337 	ENTER();
2338 
2339 	if (!handle) {
2340 		PRINTM(MFATAL, "Unable to get handle\n");
2341 		ret = -EINVAL;
2342 		goto done;
2343 	}
2344 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
2345 	if (!priv) {
2346 		ret = -EINVAL;
2347 		goto done;
2348 	}
2349 
2350 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
2351 	if (req == NULL) {
2352 		ret = -ENOMEM;
2353 		goto done;
2354 	}
2355 
2356 	radio = (mlan_ds_radio_cfg *)req->pbuf;
2357 	radio->sub_command = MLAN_OID_ANT_CFG;
2358 	req->req_id = MLAN_IOCTL_RADIO_CFG;
2359 	req->action = MLAN_ACT_GET;
2360 
2361 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2362 	if (status != MLAN_STATUS_SUCCESS) {
2363 		ret = -EFAULT;
2364 		goto done;
2365 	}
2366 
2367 	if (handle->feature_control & FEATURE_CTRL_STREAM_2X2) {
2368 		*tx_ant = radio->param.ant_cfg.tx_antenna;
2369 		*rx_ant = radio->param.ant_cfg.rx_antenna;
2370 	} else {
2371 		*tx_ant = radio->param.ant_cfg_1x1.antenna;
2372 		*rx_ant = radio->param.ant_cfg_1x1.antenna;
2373 	}
2374 
2375 done:
2376 	if (status != MLAN_STATUS_PENDING)
2377 		kfree(req);
2378 	/* Driver must return -EINVAL to cfg80211 */
2379 	if (ret)
2380 		ret = -EINVAL;
2381 	LEAVE();
2382 	return ret;
2383 }
2384 
2385 /**
2386  * @brief Request the driver to set antenna configuration
2387  *
2388  * @param wiphy           A pointer to wiphy structure
2389  * @param tx_ant          Bitmaps of allowed antennas to use for TX
2390  * @param rx_ant          Bitmaps of allowed antennas to use for RX
2391  *
2392  * @return                0 -- success, otherwise fail
2393  */
woal_cfg80211_set_antenna(struct wiphy * wiphy,u32 tx_ant,u32 rx_ant)2394 int woal_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
2395 {
2396 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
2397 	moal_private *priv = NULL;
2398 	mlan_ds_radio_cfg *radio = NULL;
2399 	mlan_ioctl_req *req = NULL;
2400 	mlan_status status = MLAN_STATUS_SUCCESS;
2401 	int ret = 0;
2402 
2403 	ENTER();
2404 
2405 	if (!handle) {
2406 		PRINTM(MFATAL, "Unable to get handle\n");
2407 		ret = -EINVAL;
2408 		goto done;
2409 	}
2410 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
2411 	if (!priv) {
2412 		ret = -EINVAL;
2413 		goto done;
2414 	}
2415 
2416 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
2417 	if (req == NULL) {
2418 		ret = -ENOMEM;
2419 		goto done;
2420 	}
2421 	radio = (mlan_ds_radio_cfg *)req->pbuf;
2422 	radio->sub_command = MLAN_OID_ANT_CFG;
2423 	req->req_id = MLAN_IOCTL_RADIO_CFG;
2424 	req->action = MLAN_ACT_SET;
2425 	if (handle->feature_control & FEATURE_CTRL_STREAM_2X2) {
2426 		radio->param.ant_cfg.tx_antenna = tx_ant;
2427 		radio->param.ant_cfg.rx_antenna = rx_ant;
2428 	} else {
2429 		radio->param.ant_cfg_1x1.antenna = tx_ant;
2430 	}
2431 
2432 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2433 	if (status != MLAN_STATUS_SUCCESS) {
2434 		ret = -EFAULT;
2435 		goto done;
2436 	}
2437 
2438 done:
2439 	if (status != MLAN_STATUS_PENDING)
2440 		kfree(req);
2441 	/* Driver must return -EINVAL to cfg80211 */
2442 	if (ret)
2443 		ret = -EINVAL;
2444 	LEAVE();
2445 	return ret;
2446 }
2447 #endif
2448 /**
2449  * @brief register/unregister mgmt frame forwarding
2450  *
2451  * @param priv             A pointer to moal_private structure
2452  * @param frame_type      Bit mask for mgmt frame type
2453  * @param reg             Register or unregister
2454  *
2455  * @return                0 -- success, otherwise fail
2456  */
woal_mgmt_frame_register(moal_private * priv,u16 frame_type,bool reg)2457 void woal_mgmt_frame_register(moal_private *priv, u16 frame_type, bool reg)
2458 {
2459 	t_u32 mgmt_subtype_mask = 0x0;
2460 	t_u32 last_mgmt_subtype_mask = priv->mgmt_subtype_mask;
2461 
2462 	ENTER();
2463 
2464 #ifdef SDIO_SUSPEND_RESUME
2465 	if (priv->phandle->shutdown_hs_in_process) {
2466 		LEAVE();
2467 		return;
2468 	}
2469 #endif
2470 
2471 	if (reg == MTRUE) {
2472 		/* set mgmt_subtype_mask based on origin value */
2473 		mgmt_subtype_mask =
2474 			last_mgmt_subtype_mask | BIT(frame_type >> 4);
2475 	} else {
2476 		/* clear mgmt_subtype_mask */
2477 		mgmt_subtype_mask =
2478 			last_mgmt_subtype_mask & ~BIT(frame_type >> 4);
2479 	}
2480 	PRINTM(MIOCTL,
2481 	       "%s: frame_type=0x%x mgmt_subtype_mask=0x%x last_mgmt_subtype_mask=0x%x\n",
2482 	       priv->netdev->name, frame_type, mgmt_subtype_mask,
2483 	       last_mgmt_subtype_mask);
2484 	if (mgmt_subtype_mask != last_mgmt_subtype_mask) {
2485 		last_mgmt_subtype_mask = mgmt_subtype_mask;
2486 		/* Notify driver that a mgmt frame type was registered.
2487 		 * Note that this callback may not sleep, and cannot run
2488 		 * concurrently with itself.
2489 		 */
2490 		woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET, &mgmt_subtype_mask,
2491 				     MOAL_NO_WAIT);
2492 		priv->mgmt_subtype_mask = last_mgmt_subtype_mask;
2493 	}
2494 
2495 	LEAVE();
2496 }
2497 #if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
2498 /**
2499  * @brief register/unregister mgmt frame forwarding
2500  *
2501  * @param wiphy           A pointer to wiphy structure
2502  * @param dev             A pointer to net_device structure
2503  * @param frame_type      Bit mask for mgmt frame type
2504  * @param reg             Register or unregister
2505  *
2506  * @return                0 -- success, otherwise fail
2507  */
woal_cfg80211_mgmt_frame_register(struct wiphy * wiphy,struct net_device * dev,u16 frame_type,bool reg)2508 void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
2509 				       struct net_device *dev, u16 frame_type,
2510 				       bool reg)
2511 #else
2512 #if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE
2513 void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
2514 				       struct wireless_dev *wdev,
2515 				       struct mgmt_frame_regs *upd)
2516 #else
2517 /**
2518  * @brief register/unregister mgmt frame forwarding
2519  *
2520  * @param wiphy           A pointer to wiphy structure
2521  * @param wdev            A pointer to wireless_dev structure
2522  * @param frame_type      Bit mask for mgmt frame type
2523  * @param reg             Register or unregister
2524  *
2525  * @return                0 -- success, otherwise fail
2526  */
2527 void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
2528 				       struct wireless_dev *wdev,
2529 				       u16 frame_type, bool reg)
2530 #endif
2531 #endif
2532 {
2533 #if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
2534 	struct net_device *dev = wdev->netdev;
2535 #endif
2536 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2537 
2538 	ENTER();
2539 
2540 #if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE
2541 	if ((upd->interface_stypes & BIT(IEEE80211_STYPE_AUTH >> 4))
2542 	    /** Supplicant 2.8 always register auth, FW will handle auth when
2543 	     *  host_mlme=0
2544 	     */
2545 	    && !moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
2546 		upd->interface_stypes &= ~BIT(IEEE80211_STYPE_AUTH >> 4);
2547 
2548 	if (priv->mgmt_subtype_mask != upd->interface_stypes) {
2549 		priv->mgmt_subtype_mask = upd->interface_stypes;
2550 		woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET, &upd->interface_stypes,
2551 				     MOAL_NO_WAIT);
2552 	}
2553 #else
2554 	if (frame_type == IEEE80211_STYPE_AUTH
2555 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
2556 	    /** Supplicant 2.8 always register auth, FW will handle auth when
2557 	     *  host_mlme=0
2558 	     */
2559 	    && !moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
2560 #endif
2561 	) {
2562 		LEAVE();
2563 		return;
2564 	}
2565 	woal_mgmt_frame_register(priv, frame_type, reg);
2566 #endif
2567 	LEAVE();
2568 }
2569 
2570 #ifdef UAP_CFG80211
2571 #if KERNEL_VERSION(3, 12, 0) <= CFG80211_VERSION_CODE
2572 /*
2573  * @brief  prepare and send WOAL_EVENT_CANCEL_CHANRPT
2574  *
2575  * @param priv           A pointer moal_private structure
2576  *
2577  * @return          N/A
2578  */
woal_cancel_chanrpt_event(moal_private * priv)2579 void woal_cancel_chanrpt_event(moal_private *priv)
2580 {
2581 	struct woal_event *evt;
2582 	unsigned long flags;
2583 	moal_handle *handle = priv->phandle;
2584 
2585 	evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
2586 	if (!evt) {
2587 		PRINTM(MERROR, "Fail to alloc memory for deauth event\n");
2588 		LEAVE();
2589 		return;
2590 	}
2591 	evt->priv = priv;
2592 	evt->type = WOAL_EVENT_CANCEL_CHANRPT;
2593 	INIT_LIST_HEAD(&evt->link);
2594 	spin_lock_irqsave(&handle->evt_lock, flags);
2595 	list_add_tail(&evt->link, &handle->evt_queue);
2596 	spin_unlock_irqrestore(&handle->evt_lock, flags);
2597 	queue_work(handle->evt_workqueue, &handle->evt_work);
2598 }
2599 #endif
2600 #endif
2601 
2602 #if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
2603 #if KERNEL_VERSION(3, 3, 0) <= CFG80211_VERSION_CODE
2604 #if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
2605 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
2606 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
2607 /**
2608  * @brief tx mgmt frame
2609  *
2610  * @param wiphy                 A pointer to wiphy structure
2611  * @param wdev                  A pointer to wireless_dev structure
2612  * @param params                A pointer to cfg80211_mgmt_tx_params structure
2613  * @param cookie                A pointer to frame cookie
2614  *
2615  * @return                0 -- success, otherwise fail
2616  */
2617 #else
2618 /**
2619  * @brief tx mgmt frame
2620  *
2621  * @param wiphy                 A pointer to wiphy structure
2622  * @param wdev                  A pointer to wireless_dev structure
2623  * @param chan                  A pointer to ieee80211_channel structure
2624  * @param offchan               Off channel or not
2625  * @param wait                  Duration to wait
2626  * @param buf                   Frame buffer
2627  * @param len                   Frame length
2628  * @param no_cck                No CCK check
2629  * @param dont_wait_for_ack     Do not wait for ACK
2630  * @param cookie                A pointer to frame cookie
2631  *
2632  * @return                0 -- success, otherwise fail
2633  */
2634 #endif
2635 #else
2636 /**
2637  * @brief tx mgmt frame
2638  *
2639  * @param wiphy                 A pointer to wiphy structure
2640  * @param wdev                  A pointer to wireless_dev structure
2641  * @param chan                  A pointer to ieee80211_channel structure
2642  * @param offchan               Off channel or not
2643  * @param channel_type          Channel type
2644  * @param channel_type_valid    Is channel type valid or not
2645  * @param wait                  Duration to wait
2646  * @param buf                   Frame buffer
2647  * @param len                   Frame length
2648  * @param no_cck                No CCK check
2649  * @param dont_wait_for_ack     Do not wait for ACK
2650  * @param cookie                A pointer to frame cookie
2651  *
2652  * @return                0 -- success, otherwise fail
2653  */
2654 #endif
2655 #else
2656 /**
2657  * @brief tx mgmt frame
2658  *
2659  * @param wiphy                 A pointer to wiphy structure
2660  * @param dev                   A pointer to net_device structure
2661  * @param chan                  A pointer to ieee80211_channel structure
2662  * @param offchan               Off channel or not
2663  * @param channel_type          Channel type
2664  * @param channel_type_valid    Is channel type valid or not
2665  * @param wait                  Duration to wait
2666  * @param buf                   Frame buffer
2667  * @param len                   Frame length
2668  * @param no_cck                No CCK check
2669  * @param dont_wait_for_ack     Do not wait for ACK
2670  * @param cookie                A pointer to frame cookie
2671  *
2672  * @return                0 -- success, otherwise fail
2673  */
2674 #endif
2675 #else
2676 /**
2677  * @brief tx mgmt frame
2678  *
2679  * @param wiphy                 A pointer to wiphy structure
2680  * @param dev                   A pointer to net_device structure
2681  * @param chan                  A pointer to ieee80211_channel structure
2682  * @param offchan               Off channel or not
2683  * @param channel_type          Channel type
2684  * @param channel_type_valid    Is channel type valid or not
2685  * @param wait                  Duration to wait
2686  * @param buf                   Frame buffer
2687  * @param len                   Frame length
2688  * @param no_cck                No CCK check
2689  * @param cookie                A pointer to frame cookie
2690  *
2691  * @return                0 -- success, otherwise fail
2692  */
2693 #endif
2694 #else
2695 /**
2696  * @brief tx mgmt frame
2697  *
2698  * @param wiphy                 A pointer to wiphy structure
2699  * @param dev                   A pointer to net_device structure
2700  * @param chan                  A pointer to ieee80211_channel structure
2701  * @param offchan               Off channel or not
2702  * @param channel_type          Channel type
2703  * @param channel_type_valid    Is channel type valid or not
2704  * @param wait                  Duration to wait
2705  * @param buf                   Frame buffer
2706  * @param len                   Frame length
2707  * @param cookie                A pointer to frame cookie
2708  *
2709  * @return                0 -- success, otherwise fail
2710  */
2711 #endif
woal_cfg80211_mgmt_tx(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_mgmt_tx_params * params,u64 * cookie)2712 int woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
2713 #if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
2714 			  struct net_device *dev,
2715 #else
2716 			  struct wireless_dev *wdev,
2717 #endif
2718 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
2719 			  struct cfg80211_mgmt_tx_params *params,
2720 #else
2721 			  struct ieee80211_channel *chan, bool offchan,
2722 #if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
2723 			  enum nl80211_channel_type channel_type,
2724 			  bool channel_type_valid,
2725 #endif
2726 			  unsigned int wait, const u8 *buf, size_t len,
2727 #if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
2728 			  bool no_cck,
2729 #endif
2730 #if KERNEL_VERSION(3, 3, 0) <= CFG80211_VERSION_CODE
2731 			  bool dont_wait_for_ack,
2732 #endif
2733 #endif
2734 			  u64 *cookie)
2735 {
2736 #if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
2737 	struct net_device *dev = wdev->netdev;
2738 #endif
2739 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
2740 	struct ieee80211_channel *chan = params->chan;
2741 	unsigned int wait = params->wait;
2742 	const u8 *buf = params->buf;
2743 	size_t len = params->len;
2744 #endif
2745 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2746 	int ret = 0;
2747 	pmlan_buffer pmbuf = NULL;
2748 	mlan_status status = MLAN_STATUS_SUCCESS;
2749 	t_u16 packet_len = 0;
2750 	t_u8 addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
2751 	t_u32 pkt_type;
2752 	t_u32 tx_control;
2753 #if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
2754 	t_u8 channel_status;
2755 	t_u32 duration;
2756 	moal_private *remain_priv = NULL;
2757 #endif
2758 
2759 	unsigned long flags;
2760 	struct sk_buff *skb = NULL;
2761 	struct tx_status_info *tx_info = NULL;
2762 	t_u32 remain_len = 0;
2763 	t_u16 fc, type, stype;
2764 
2765 	ENTER();
2766 
2767 	if (buf == NULL || len == 0) {
2768 		PRINTM(MERROR, "%s: corrupt data\n", __func__);
2769 		LEAVE();
2770 		return -EFAULT;
2771 	}
2772 
2773 	/* If the packet is probe response, that means we are in listen phase,
2774 	 * so we should not call remain_on_channel_cfg because
2775 	 * remain_on_channl already handled it. If the packet if action, that
2776 	 * means we are in PD/GO negotiation, so we should call
2777 	 * remain_on_channel_cfg in order to receive action frame from peer
2778 	 * device
2779 	 */
2780 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
2781 		if (ieee80211_is_probe_resp(
2782 			    ((struct ieee80211_mgmt *)buf)->frame_control)) {
2783 			PRINTM(MIOCTL, "Skip send probe_resp in GO/UAP mode\n");
2784 			goto done;
2785 		}
2786 		fc = le16_to_cpu(((struct ieee80211_mgmt *)buf)->frame_control);
2787 		type = fc & IEEE80211_FCTL_FTYPE;
2788 		stype = fc & IEEE80211_FCTL_STYPE;
2789 		if (type == IEEE80211_FTYPE_MGMT) {
2790 			switch (stype) {
2791 			case IEEE80211_STYPE_AUTH:
2792 				PRINTM(MMSG, "wlan: HostMlme %s send Auth\n",
2793 				       priv->netdev->name);
2794 				break;
2795 			case IEEE80211_STYPE_DEAUTH:
2796 			case IEEE80211_STYPE_DISASSOC:
2797 #ifdef UAP_SUPPORT
2798 				if (!priv->bss_started) {
2799 					PRINTM(MCMND,
2800 					       "Drop deauth packet before AP started\n");
2801 					woal_cancel_cac(priv);
2802 					goto done;
2803 				}
2804 #endif
2805 				PRINTM(MMSG,
2806 				       "wlan: HostMlme %s send deauth/disassoc\n",
2807 				       priv->netdev->name);
2808 
2809 				break;
2810 			case IEEE80211_STYPE_ASSOC_RESP:
2811 			case IEEE80211_STYPE_REASSOC_RESP:
2812 				PRINTM(MMSG,
2813 				       "wlan: HostMlme %s send assoc/reassoc resp\n",
2814 				       priv->netdev->name);
2815 				break;
2816 			default:
2817 				break;
2818 			}
2819 		}
2820 	}
2821 
2822 #if KERNEL_VERSION(2, 6, 39) <= CFG80211_VERSION_CODE
2823 	if ((ieee80211_is_action(((struct ieee80211_mgmt *)buf)->frame_control))
2824 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
2825 	    || moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
2826 #endif
2827 	) {
2828 #ifdef WIFI_DIRECT_SUPPORT
2829 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
2830 			woal_cfg80211_display_p2p_actframe(buf, len, chan,
2831 							   MTRUE);
2832 		if (priv->phandle->is_go_timer_set) {
2833 			woal_cancel_timer(&priv->phandle->go_timer);
2834 			priv->phandle->is_go_timer_set = MFALSE;
2835 		}
2836 #endif
2837 		if (priv->phandle->is_remain_timer_set) {
2838 			woal_cancel_timer(&priv->phandle->remain_timer);
2839 			woal_remain_timer_func(priv->phandle);
2840 		}
2841 		/* With sd8777 We have difficulty to receive response packet in
2842 		 * 500ms
2843 		 */
2844 #define MGMT_TX_DEFAULT_WAIT_TIME 1500
2845 		if (priv->phandle->remain_on_channel)
2846 			remain_priv =
2847 				priv->phandle
2848 					->priv[priv->phandle->remain_bss_index];
2849 		/** cancel previous remain on channel */
2850 		if (priv->phandle->remain_on_channel && remain_priv) {
2851 			if (woal_cfg80211_remain_on_channel_cfg(
2852 				    remain_priv, MOAL_IOCTL_WAIT, MTRUE,
2853 				    &channel_status, NULL, 0, 0))
2854 				PRINTM(MERROR,
2855 				       "mgmt_tx:Fail to cancel remain on channel\n");
2856 			if (priv->phandle->cookie) {
2857 				cfg80211_remain_on_channel_expired(
2858 #if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
2859 					remain_priv->netdev,
2860 #else
2861 					remain_priv->wdev,
2862 #endif
2863 					priv->phandle->cookie,
2864 					&priv->phandle->chan,
2865 #if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
2866 					priv->phandle->channel_type,
2867 #endif
2868 					GFP_ATOMIC);
2869 				priv->phandle->cookie = 0;
2870 			}
2871 			priv->phandle->remain_on_channel = MFALSE;
2872 		}
2873 #ifdef STA_CFG80211
2874 		/** cancel pending scan */
2875 		woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
2876 #endif
2877 
2878 		if (chan && priv->bss_type != MLAN_BSS_ROLE_UAP) {
2879 			duration = (wait > MGMT_TX_DEFAULT_WAIT_TIME) ?
2880 					   wait :
2881 					   MGMT_TX_DEFAULT_WAIT_TIME;
2882 #if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
2883 			if (channel_type_valid)
2884 				ret = woal_cfg80211_remain_on_channel_cfg(
2885 					priv, MOAL_IOCTL_WAIT, MFALSE,
2886 					&channel_status, chan, channel_type,
2887 					duration);
2888 			else
2889 #endif
2890 				ret = woal_cfg80211_remain_on_channel_cfg(
2891 					priv, MOAL_IOCTL_WAIT, MFALSE,
2892 					&channel_status, chan, 0, duration);
2893 			if (ret) {
2894 				/* Return fail will cause p2p connection fail
2895 				 */
2896 				woal_sched_timeout(2);
2897 #if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
2898 				if (channel_type_valid)
2899 					ret = woal_cfg80211_remain_on_channel_cfg(
2900 						priv, MOAL_IOCTL_WAIT, MFALSE,
2901 						&channel_status, chan,
2902 						channel_type, duration);
2903 				else
2904 #endif
2905 					ret = woal_cfg80211_remain_on_channel_cfg(
2906 						priv, MOAL_IOCTL_WAIT, MFALSE,
2907 						&channel_status, chan, 0,
2908 						duration);
2909 				PRINTM(MERROR,
2910 				       "Try configure remain on channel again, ret=%d\n",
2911 				       ret);
2912 				ret = 0;
2913 			} else {
2914 				priv->phandle->remain_on_channel = MTRUE;
2915 				priv->phandle->remain_bss_index =
2916 					priv->bss_index;
2917 #if KERNEL_VERSION(3, 8, 0) > CFG80211_VERSION_CODE
2918 				priv->phandle->channel_type = channel_type;
2919 #endif
2920 				moal_memcpy_ext(
2921 					priv->phandle, &priv->phandle->chan,
2922 					chan, sizeof(struct ieee80211_channel),
2923 					sizeof(struct ieee80211_channel));
2924 				PRINTM(MIOCTL,
2925 				       "%s: Mgmt Tx: Set remain channel=%d duration=%d\n",
2926 				       dev->name,
2927 				       ieee80211_frequency_to_channel(
2928 					       chan->center_freq),
2929 				       duration);
2930 			}
2931 		}
2932 	}
2933 #endif
2934 
2935 	/* pkt_type + tx_control */
2936 #define HEADER_SIZE 8
2937 	packet_len = (t_u16)len + MLAN_MAC_ADDR_LENGTH;
2938 	pmbuf = woal_alloc_mlan_buffer(priv->phandle,
2939 				       MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
2940 					       packet_len + sizeof(packet_len));
2941 	if (!pmbuf) {
2942 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
2943 		ret = -ENOMEM;
2944 		goto done;
2945 	}
2946 #if KERNEL_VERSION(3, 8, 0) > LINUX_VERSION_CODE
2947 	*cookie = random32() | 1;
2948 #else
2949 #if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
2950 	*cookie = prandom_u32() | 1;
2951 #else
2952 	*cookie = get_random_u32() | 1;
2953 #endif
2954 #endif
2955 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
2956 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
2957 	tx_control = 0;
2958 	remain_len = HEADER_SIZE + packet_len + sizeof(packet_len);
2959 	/* Add pkt_type and tx_control */
2960 	moal_memcpy_ext(priv->phandle, pmbuf->pbuf + pmbuf->data_offset,
2961 			&pkt_type, sizeof(pkt_type), remain_len);
2962 	remain_len -= sizeof(pkt_type);
2963 	moal_memcpy_ext(priv->phandle,
2964 			pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
2965 			&tx_control, sizeof(tx_control), remain_len);
2966 	remain_len -= sizeof(tx_control);
2967 	/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
2968 #define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2)
2969 	moal_memcpy_ext(priv->phandle,
2970 			pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
2971 			&packet_len, sizeof(packet_len), remain_len);
2972 	remain_len -= sizeof(packet_len);
2973 	moal_memcpy_ext(priv->phandle,
2974 			pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
2975 				sizeof(packet_len),
2976 			buf, PACKET_ADDR4_POS, remain_len);
2977 	remain_len -= PACKET_ADDR4_POS;
2978 	moal_memcpy_ext(priv->phandle,
2979 			pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
2980 				sizeof(packet_len) + PACKET_ADDR4_POS,
2981 			addr, MLAN_MAC_ADDR_LENGTH, remain_len);
2982 	remain_len -= MLAN_MAC_ADDR_LENGTH;
2983 	moal_memcpy_ext(priv->phandle,
2984 			pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
2985 				sizeof(packet_len) + PACKET_ADDR4_POS +
2986 				MLAN_MAC_ADDR_LENGTH,
2987 			buf + PACKET_ADDR4_POS, len - PACKET_ADDR4_POS,
2988 			remain_len);
2989 
2990 	pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
2991 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
2992 	pmbuf->bss_index = priv->bss_index;
2993 	if ((ieee80211_is_action(((struct ieee80211_mgmt *)buf)->frame_control))
2994 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
2995 	    || moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
2996 #endif
2997 	) {
2998 		pmbuf->flags = MLAN_BUF_FLAG_TX_STATUS;
2999 		if (!priv->tx_seq_num)
3000 			priv->tx_seq_num++;
3001 		pmbuf->tx_seq_num = priv->tx_seq_num++;
3002 		tx_info = kzalloc(sizeof(struct tx_status_info), GFP_ATOMIC);
3003 		if (tx_info) {
3004 			skb = alloc_skb(len, GFP_ATOMIC);
3005 			if (skb) {
3006 				moal_memcpy_ext(priv->phandle, skb->data, buf,
3007 						len, len);
3008 				skb_put(skb, len);
3009 				spin_lock_irqsave(&priv->tx_stat_lock, flags);
3010 				tx_info->tx_cookie = *cookie;
3011 				tx_info->tx_skb = skb;
3012 				tx_info->tx_seq_num = pmbuf->tx_seq_num;
3013 				if ((priv->bss_role == MLAN_BSS_ROLE_UAP) &&
3014 				    (priv->phandle->remain_on_channel && !wait))
3015 					tx_info->cancel_remain_on_channel =
3016 						MTRUE;
3017 				INIT_LIST_HEAD(&tx_info->link);
3018 				list_add_tail(&tx_info->link,
3019 					      &priv->tx_stat_queue);
3020 				spin_unlock_irqrestore(&priv->tx_stat_lock,
3021 						       flags);
3022 			} else {
3023 				kfree(tx_info);
3024 				tx_info = NULL;
3025 			}
3026 		}
3027 	}
3028 
3029 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
3030 
3031 	switch (status) {
3032 	case MLAN_STATUS_PENDING:
3033 		atomic_inc(&priv->phandle->tx_pending);
3034 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
3035 
3036 		/* Delay 30ms to guarantee the packet has been already tx'ed,
3037 		 * because if we call cfg80211_mgmt_tx_status() immediately,
3038 		 * then wpa_supplicant will call cancel_remain_on_channel(),
3039 		 * which may affect the mgmt frame tx. Meanwhile it is only
3040 		 * necessary for P2P action handshake to wait 30ms.
3041 		 */
3042 		if ((ieee80211_is_action(
3043 			    ((struct ieee80211_mgmt *)buf)->frame_control))
3044 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
3045 		    || moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
3046 #endif
3047 		) {
3048 			if (tx_info)
3049 				break;
3050 			else
3051 				woal_sched_timeout(30);
3052 		}
3053 		/* Notify the mgmt tx status */
3054 #if KERNEL_VERSION(2, 6, 37) <= CFG80211_VERSION_CODE
3055 #if KERNEL_VERSION(3, 6, 0) > CFG80211_VERSION_CODE
3056 		cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true,
3057 					GFP_ATOMIC);
3058 #else
3059 		cfg80211_mgmt_tx_status(priv->wdev, *cookie, buf, len, true,
3060 					GFP_ATOMIC);
3061 #endif
3062 #endif
3063 		break;
3064 	case MLAN_STATUS_SUCCESS:
3065 		woal_free_mlan_buffer(priv->phandle, pmbuf);
3066 		break;
3067 	case MLAN_STATUS_FAILURE:
3068 	default:
3069 		woal_free_mlan_buffer(priv->phandle, pmbuf);
3070 		ret = -EFAULT;
3071 		break;
3072 	}
3073 
3074 done:
3075 
3076 	if (status != MLAN_STATUS_PENDING) {
3077 		if (tx_info)
3078 			woal_remove_tx_info(priv, tx_info->tx_seq_num);
3079 	}
3080 
3081 	LEAVE();
3082 	return ret;
3083 }
3084 
3085 /**
3086  * @brief Add custom ie to mgmt frames.
3087  *
3088  * @param priv                  A pointer to moal private structure
3089  * @param beacon_ies_data       Beacon ie
3090  * @param beacon_index          The index for beacon when auto index
3091  * @param proberesp_ies_data    Probe resp ie
3092  * @param proberesp_index       The index for probe resp when auto index
3093  * @param assocresp_ies_data    Assoc resp ie
3094  * @param assocresp_index       The index for assoc resp when auto index
3095  * @param probereq_ies_data     Probe req ie
3096  * @param probereq_index        The index for probe req when auto index
3097  * @param wait_option           wait option
3098  *
3099  * @return              0 -- success, otherwise fail
3100  */
3101 static mlan_status
woal_cfg80211_custom_ie(moal_private * priv,custom_ie * beacon_ies_data,t_u16 * beacon_index,custom_ie * proberesp_ies_data,t_u16 * proberesp_index,custom_ie * assocresp_ies_data,t_u16 * assocresp_index,custom_ie * probereq_ies_data,t_u16 * probereq_index,t_u8 wait_option)3102 woal_cfg80211_custom_ie(moal_private *priv, custom_ie *beacon_ies_data,
3103 			t_u16 *beacon_index, custom_ie *proberesp_ies_data,
3104 			t_u16 *proberesp_index, custom_ie *assocresp_ies_data,
3105 			t_u16 *assocresp_index, custom_ie *probereq_ies_data,
3106 			t_u16 *probereq_index, t_u8 wait_option)
3107 {
3108 	mlan_ioctl_req *ioctl_req = NULL;
3109 	mlan_ds_misc_cfg *misc = NULL;
3110 	mlan_ds_misc_custom_ie *pcustom_ie = NULL;
3111 	t_u8 *pos = NULL;
3112 	t_u16 len = 0;
3113 	mlan_status status = MLAN_STATUS_SUCCESS;
3114 	t_u32 remain_len = 0;
3115 
3116 	ENTER();
3117 
3118 	pcustom_ie = kzalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL);
3119 	if (!pcustom_ie) {
3120 		PRINTM(MERROR, "Fail to allocate custome_ie\n");
3121 		status = MLAN_STATUS_FAILURE;
3122 		goto done;
3123 	}
3124 
3125 	pcustom_ie->type = TLV_TYPE_MGMT_IE;
3126 
3127 	pos = (t_u8 *)pcustom_ie->ie_data_list;
3128 	remain_len = sizeof(pcustom_ie->ie_data_list);
3129 	if (beacon_ies_data) {
3130 		len = sizeof(*beacon_ies_data) - MAX_IE_SIZE +
3131 		      beacon_ies_data->ie_length;
3132 		moal_memcpy_ext(priv->phandle, pos, beacon_ies_data, len,
3133 				remain_len);
3134 		pos += len;
3135 		remain_len -= len;
3136 		pcustom_ie->len += len;
3137 	}
3138 
3139 	if (proberesp_ies_data) {
3140 		len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE +
3141 		      proberesp_ies_data->ie_length;
3142 		moal_memcpy_ext(priv->phandle, pos, proberesp_ies_data, len,
3143 				remain_len);
3144 		pos += len;
3145 		remain_len -= len;
3146 		pcustom_ie->len += len;
3147 	}
3148 
3149 	if (assocresp_ies_data) {
3150 		len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE +
3151 		      assocresp_ies_data->ie_length;
3152 		moal_memcpy_ext(priv->phandle, pos, assocresp_ies_data, len,
3153 				remain_len);
3154 		pos += len;
3155 		remain_len -= len;
3156 		pcustom_ie->len += len;
3157 	}
3158 
3159 	if (probereq_ies_data) {
3160 		len = sizeof(*probereq_ies_data) - MAX_IE_SIZE +
3161 		      probereq_ies_data->ie_length;
3162 		moal_memcpy_ext(priv->phandle, pos, probereq_ies_data, len,
3163 				remain_len);
3164 		pos += len;
3165 		remain_len -= len;
3166 		pcustom_ie->len += len;
3167 	}
3168 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3169 	if (ioctl_req == NULL) {
3170 		PRINTM(MERROR, "Fail to allocate ioctl_req\n");
3171 		status = MLAN_STATUS_FAILURE;
3172 		goto done;
3173 	}
3174 
3175 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
3176 	misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
3177 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
3178 	ioctl_req->action = MLAN_ACT_SET;
3179 
3180 	moal_memcpy_ext(priv->phandle, &misc->param.cust_ie, pcustom_ie,
3181 			sizeof(mlan_ds_misc_custom_ie),
3182 			sizeof(mlan_ds_misc_custom_ie));
3183 
3184 	status = woal_request_ioctl(priv, ioctl_req, wait_option);
3185 	if (status != MLAN_STATUS_SUCCESS)
3186 		goto done;
3187 
3188 	/* get the assigned index */
3189 	pos = (t_u8 *)(&misc->param.cust_ie.ie_data_list[0].ie_index);
3190 	if (beacon_ies_data && beacon_ies_data->ie_length &&
3191 	    beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
3192 		/* save beacon ie index after auto-indexing */
3193 		*beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index;
3194 		len = sizeof(*beacon_ies_data) - MAX_IE_SIZE +
3195 		      beacon_ies_data->ie_length;
3196 		pos += len;
3197 	}
3198 
3199 	if (proberesp_ies_data && proberesp_ies_data->ie_length &&
3200 	    proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
3201 		/* save probe resp ie index after auto-indexing */
3202 		*proberesp_index = *((t_u16 *)pos);
3203 		len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE +
3204 		      proberesp_ies_data->ie_length;
3205 		pos += len;
3206 	}
3207 
3208 	if (assocresp_ies_data && assocresp_ies_data->ie_length &&
3209 	    assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
3210 		/* save assoc resp ie index after auto-indexing */
3211 		*assocresp_index = *((t_u16 *)pos);
3212 		len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE +
3213 		      assocresp_ies_data->ie_length;
3214 		pos += len;
3215 	}
3216 	if (probereq_ies_data && probereq_ies_data->ie_length &&
3217 	    probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
3218 		/* save probe resp ie index after auto-indexing */
3219 		*probereq_index = *((t_u16 *)pos);
3220 		len = sizeof(*probereq_ies_data) - MAX_IE_SIZE +
3221 		      probereq_ies_data->ie_length;
3222 		pos += len;
3223 	}
3224 	// TODO why we check status_code at end
3225 	if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL)
3226 		status = MLAN_STATUS_FAILURE;
3227 
3228 done:
3229 	if (status != MLAN_STATUS_PENDING)
3230 		kfree(ioctl_req);
3231 	kfree(pcustom_ie);
3232 	LEAVE();
3233 	return status;
3234 }
3235 
3236 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
3237 /**
3238  * @brief set Qos map
3239  *
3240  * @param wiphy         A pointer to wiphy structure
3241  * @param dev           A pointer to net_device structure
3242  * @param qos_map       A pointer to cfg80211_qos_map structure
3243  *
3244  *
3245  * @return              0 -- success, otherwise fail
3246  */
woal_cfg80211_set_qos_map(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_qos_map * qos_map)3247 int woal_cfg80211_set_qos_map(struct wiphy *wiphy, struct net_device *dev,
3248 			      struct cfg80211_qos_map *qos_map)
3249 {
3250 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3251 	int i, j, ret = 0;
3252 
3253 	ENTER();
3254 	/**clear dscp map*/
3255 	if (!qos_map) {
3256 		memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
3257 		goto done;
3258 	}
3259 
3260 	/**update dscp map*/
3261 	for (i = 0; i < MAX_NUM_TID; i++) {
3262 		PRINTM(MINFO, "TID %d: dscp_low=%d, dscp_high=%d\n", i,
3263 		       qos_map->up[i].low, qos_map->up[i].high);
3264 		if (qos_map->up[i].low != 0xff && qos_map->up[i].high != 0xff &&
3265 		    qos_map->up[i].high <= 63) {
3266 			for (j = qos_map->up[i].low; j <= qos_map->up[i].high;
3267 			     j++)
3268 				priv->dscp_map[j] = i;
3269 		}
3270 	}
3271 
3272 	for (i = 0; i < qos_map->num_des; i++) {
3273 		if ((qos_map->dscp_exception[i].dscp <= 63) &&
3274 		    (qos_map->dscp_exception[i].up <= 7)) {
3275 			PRINTM(MINFO, "dscp excpt: value=%d priority=%d\n",
3276 			       qos_map->dscp_exception[i].dscp,
3277 			       qos_map->dscp_exception[i].up);
3278 			priv->dscp_map[qos_map->dscp_exception[i].dscp] =
3279 				qos_map->dscp_exception[i].up;
3280 		}
3281 	}
3282 
3283 	/**UAP update (re)associate response*/
3284 	if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
3285 		IEEEtypes_Generic_t qos_map_ie;
3286 		t_u16 qos_map_ies_len;
3287 
3288 		qos_map_ie.ieee_hdr.element_id = QOS_MAPPING;
3289 		qos_map_ie.ieee_hdr.len =
3290 			2 * qos_map->num_des + sizeof(qos_map->up);
3291 		qos_map_ies_len =
3292 			qos_map_ie.ieee_hdr.len + sizeof(qos_map_ie.ieee_hdr);
3293 
3294 		if (qos_map_ies_len > sizeof(qos_map_ie.data)) {
3295 			PRINTM(MERROR,
3296 			       "QoS MAP IE size exceeds the buffer len\n");
3297 			goto done;
3298 		}
3299 		moal_memcpy_ext(priv->phandle, qos_map_ie.data,
3300 				(t_u8 *)qos_map->dscp_exception,
3301 				2 * qos_map->num_des, sizeof(qos_map_ie.data));
3302 		moal_memcpy_ext(priv->phandle,
3303 				&qos_map_ie.data[2 * qos_map->num_des],
3304 				(t_u8 *)qos_map->up, sizeof(qos_map->up),
3305 				sizeof(qos_map_ie.data) - 2 * qos_map->num_des);
3306 
3307 		/* set the assoc response ies */
3308 		ret = woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0,
3309 						  (t_u8 *)&qos_map_ie,
3310 						  qos_map_ies_len, NULL, 0,
3311 						  MGMT_MASK_ASSOC_RESP_QOS_MAP,
3312 						  MOAL_IOCTL_WAIT);
3313 		if (ret) {
3314 			PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
3315 			goto done;
3316 		}
3317 	}
3318 
3319 done:
3320 	LEAVE();
3321 	return ret;
3322 }
3323 #endif
3324 
3325 /**
3326  * @brief get specific ie
3327  *
3328  * @param ie              Pointer to IEs
3329  * @param len             Total length of ie
3330  * @param ie_out          Pointer to out IE buf
3331  * @param ie_out_len    Total length of ie_out
3332  * @param mask            IE mask
3333  *
3334  * @return                out IE length
3335  */
woal_get_specific_ie(const t_u8 * ie,int len,t_u8 * ie_out,t_u32 ie_out_len,t_u16 mask)3336 static t_u16 woal_get_specific_ie(const t_u8 *ie, int len, t_u8 *ie_out,
3337 				  t_u32 ie_out_len, t_u16 mask)
3338 {
3339 	int left_len = len;
3340 	const t_u8 *pos = ie;
3341 	int length;
3342 	t_u8 id = 0;
3343 	t_u16 out_len = 0;
3344 	IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
3345 	const u8 wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
3346 	const u8 p2p_oui[4] = {0x50, 0x6f, 0x9a, 0x09};
3347 	const u8 wfd_oui[4] = {0x50, 0x6f, 0x9a, 0x0a};
3348 	const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
3349 
3350 	ENTER();
3351 	while (left_len >= 2) {
3352 		length = *(pos + 1);
3353 		id = *pos;
3354 		if ((length + 2) > left_len)
3355 			break;
3356 		if (id == VENDOR_SPECIFIC_221) {
3357 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
3358 			if (!memcmp(pvendor_ie->vend_hdr.oui, wmm_oui,
3359 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
3360 			    pvendor_ie->vend_hdr.oui_type == wmm_oui[3]) {
3361 				PRINTM(MIOCTL, "find WMM IE\n");
3362 			} else if (!memcmp(pvendor_ie->vend_hdr.oui, p2p_oui,
3363 					   sizeof(pvendor_ie->vend_hdr.oui)) &&
3364 				   pvendor_ie->vend_hdr.oui_type ==
3365 					   p2p_oui[3]) {
3366 				if (mask & IE_MASK_P2P) {
3367 					/** only get first p2p ie here */
3368 					moal_memcpy_ext(NULL, ie_out + out_len,
3369 							pos, length + 2,
3370 							ie_out_len - out_len);
3371 					out_len += length + 2;
3372 					break;
3373 				}
3374 			} else if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
3375 					   sizeof(pvendor_ie->vend_hdr.oui)) &&
3376 				   pvendor_ie->vend_hdr.oui_type ==
3377 					   wps_oui[3]) {
3378 				if (mask & IE_MASK_WPS) {
3379 					if ((out_len + length + 2) <
3380 					    (int)ie_out_len) {
3381 						moal_memcpy_ext(
3382 							NULL, ie_out + out_len,
3383 							pos, length + 2,
3384 							ie_out_len - out_len);
3385 						out_len += length + 2;
3386 					} else {
3387 						PRINTM(MERROR,
3388 						       "get_specific_ie: IE too big, fail copy WPS IE\n");
3389 						break;
3390 					}
3391 				}
3392 			} else if (!memcmp(pvendor_ie->vend_hdr.oui, wfd_oui,
3393 					   sizeof(pvendor_ie->vend_hdr.oui)) &&
3394 				   pvendor_ie->vend_hdr.oui_type ==
3395 					   wfd_oui[3]) {
3396 				if (mask & IE_MASK_WFD) {
3397 					if ((out_len + length + 2) <
3398 					    (int)ie_out_len) {
3399 						moal_memcpy_ext(
3400 							NULL, ie_out + out_len,
3401 							pos, length + 2,
3402 							ie_out_len - out_len);
3403 						out_len += length + 2;
3404 					} else {
3405 						PRINTM(MERROR,
3406 						       "get_specific_ie: IE too big, fail copy WFD IE\n");
3407 						break;
3408 					}
3409 				}
3410 			} else if (mask & IE_MASK_VENDOR) {
3411 				if ((out_len + length + 2) < (int)ie_out_len) {
3412 					moal_memcpy_ext(NULL, ie_out + out_len,
3413 							pos, length + 2,
3414 							ie_out_len - out_len);
3415 					out_len += length + 2;
3416 				} else {
3417 					PRINTM(MERROR,
3418 					       "get_specific_ie:IE too big, fail copy VENDOR IE\n");
3419 					break;
3420 				}
3421 			}
3422 		}
3423 		pos += (length + 2);
3424 		left_len -= (length + 2);
3425 	}
3426 	LEAVE();
3427 	return out_len;
3428 }
3429 
3430 /**
3431  * @brief Find specific IE from IE buffer
3432  *
3433  * @param ie              Pointer to IEs
3434  * @param len             Total length of ie
3435  * @param spec_ie         Pointer to specific IE buffer
3436  * @param spec_len        Total length of specific IE
3437  *
3438  * @return                out IE length
3439  */
woal_find_ie(const t_u8 * ie,int len,const t_u8 * spec_ie,int spec_len)3440 static t_u8 woal_find_ie(const t_u8 *ie, int len, const t_u8 *spec_ie,
3441 			 int spec_len)
3442 {
3443 	int left_len = len;
3444 	const t_u8 *pos = ie;
3445 	int length;
3446 
3447 	while (left_len >= 2) {
3448 		length = *(pos + 1);
3449 		if ((length + 2) > left_len)
3450 			break;
3451 		if ((length + 2) == spec_len) {
3452 			if (!memcmp(pos, spec_ie, spec_len))
3453 				return MTRUE;
3454 		}
3455 		pos += (length + 2);
3456 		left_len -= (length + 2);
3457 	}
3458 	return MFALSE;
3459 }
3460 
3461 /**
3462  * @brief Filter specific IE in ie buf
3463  *
3464  * @param priv            pointer to moal private structure
3465  * @param ie              Pointer to IEs
3466  * @param len             Total length of ie
3467  * @param ie_out		  Pointer to out IE buf
3468  * @param ie_out_len      Total length of ie_out
3469  * @param wps_flag	      flag for wps/p2p
3470  * @param dup_ie          Pointer to duplicate ie
3471  * @param dup_ie_len	  duplicate IE len
3472  *
3473  * @return                out IE length
3474  */
woal_filter_beacon_ies(moal_private * priv,const t_u8 * ie,int len,t_u8 * ie_out,t_u32 ie_out_len,t_u16 wps_flag,const t_u8 * dup_ie,int dup_ie_len)3475 static t_u16 woal_filter_beacon_ies(moal_private *priv, const t_u8 *ie, int len,
3476 				    t_u8 *ie_out, t_u32 ie_out_len,
3477 				    t_u16 wps_flag, const t_u8 *dup_ie,
3478 				    int dup_ie_len)
3479 {
3480 	int left_len = len;
3481 	const t_u8 *pos = ie;
3482 	int length;
3483 	t_u8 id = 0;
3484 	t_u16 out_len = 0;
3485 	IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
3486 	const u8 wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
3487 	const u8 p2p_oui[4] = {0x50, 0x6f, 0x9a, 0x09};
3488 	const u8 wfd_oui[4] = {0x50, 0x6f, 0x9a, 0x0a};
3489 	const t_u8 wmm_oui[4] = {0x00, 0x50, 0xf2, 0x02};
3490 	t_u8 find_p2p_ie = MFALSE;
3491 	t_u8 enable_11d = MFALSE;
3492 	t_u8 ext_id = 0;
3493 	int ie_len;
3494 
3495 	/* ERP_INFO/EXTENDED_SUPPORT_RATES/HT_CAPABILITY/HT_OPERATION/WMM
3496 	 * and WPS/P2P/WFD IE will be fileter out
3497 	 */
3498 	while (left_len >= 2) {
3499 		length = *(pos + 1);
3500 		id = *pos;
3501 		if ((length + 2) > left_len)
3502 			break;
3503 		if (dup_ie && dup_ie_len &&
3504 		    woal_find_ie(dup_ie, dup_ie_len, pos, length + 2)) {
3505 			PRINTM(MIOCTL, "skip duplicate IE\n");
3506 			pos += (length + 2);
3507 			left_len -= (length + 2);
3508 			continue;
3509 		}
3510 		switch (id) {
3511 		case COUNTRY_INFO:
3512 			enable_11d = MTRUE;
3513 			if ((out_len + length + 2) < (int)ie_out_len) {
3514 				moal_memcpy_ext(priv->phandle, ie_out + out_len,
3515 						pos, length + 2,
3516 						ie_out_len - out_len);
3517 				out_len += length + 2;
3518 			} else {
3519 				PRINTM(MERROR,
3520 				       "IE too big, fail copy COUNTRY INFO IE\n");
3521 			}
3522 			break;
3523 		case HT_CAPABILITY:
3524 		case HT_OPERATION:
3525 		case VHT_CAPABILITY:
3526 		case VHT_OPERATION:
3527 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
3528 			if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
3529 				if ((out_len + length + 2) < (int)ie_out_len) {
3530 					moal_memcpy_ext(priv->phandle,
3531 							ie_out + out_len, pos,
3532 							length + 2,
3533 							ie_out_len - out_len);
3534 					out_len += length + 2;
3535 				} else {
3536 					PRINTM(MERROR,
3537 					       "IE too big, fail copy COUNTRY INFO IE\n");
3538 				}
3539 			}
3540 #endif
3541 			break;
3542 		case EXTENDED_SUPPORTED_RATES:
3543 		case WLAN_EID_ERP_INFO:
3544 		/* Fall Through */
3545 		case REGULATORY_CLASS:
3546 		/* Fall Through */
3547 		case OVERLAPBSSSCANPARAM:
3548 		/* Fall Through */
3549 		case WAPI_IE:
3550 			break;
3551 		case EXTENSION:
3552 			ext_id = *(pos + 2);
3553 			if ((ext_id == HE_CAPABILITY || ext_id == HE_OPERATION)
3554 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
3555 			    && !moal_extflg_isset(priv->phandle, EXT_HOST_MLME)
3556 #endif
3557 			)
3558 				break;
3559 			else {
3560 #ifdef UAP_SUPPORT
3561 #if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 20, 0)
3562 				if (ext_id == HE_CAPABILITY) {
3563 					mlan_ds_11ax_he_cfg he_cfg;
3564 					IEEEtypes_HECap_t *hecap_ie;
3565 
3566 					if (priv->channel <= 14)
3567 						he_cfg.band = MBIT(0);
3568 					else
3569 						he_cfg.band = MBIT(1);
3570 
3571 					PRINTM(MCMND,
3572 					       "Retrieve 11ax cfg by channel=%d band=%d\n",
3573 					       priv->channel, he_cfg.band);
3574 
3575 					if (0 == woal_11ax_cfg(priv,
3576 							       MLAN_ACT_GET,
3577 							       &he_cfg)) {
3578 						hecap_ie = (IEEEtypes_HECap_t
3579 								    *)&he_cfg
3580 								   .he_cap.len;
3581 
3582 						hecap_ie->ieee_hdr.len =
3583 							he_cfg.he_cap.len;
3584 						hecap_ie->ieee_hdr.element_id =
3585 							he_cfg.he_cap.id;
3586 
3587 						moal_memcpy_ext(
3588 							priv->phandle,
3589 							ie_out + out_len,
3590 							hecap_ie,
3591 							hecap_ie->ieee_hdr.len +
3592 								2,
3593 							ie_out_len - out_len);
3594 
3595 						out_len +=
3596 							hecap_ie->ieee_hdr.len +
3597 							2;
3598 					} else {
3599 						PRINTM(MERROR,
3600 						       "Fail to get 11ax he_cap parameters\n");
3601 					}
3602 				} else
3603 #endif
3604 #endif
3605 				{
3606 					if ((out_len + length + 2) <
3607 					    (int)ie_out_len) {
3608 						moal_memcpy_ext(
3609 							priv->phandle,
3610 							ie_out + out_len, pos,
3611 							length + 2,
3612 							ie_out_len - out_len);
3613 						out_len += length + 2;
3614 					} else {
3615 						PRINTM(MERROR,
3616 						       "IE too big, fail copy EXTENSION IE\n");
3617 					}
3618 				}
3619 				break;
3620 			}
3621 		case EXT_CAPABILITY:
3622 			/* filter out EXTCAP */
3623 			if (wps_flag & IE_MASK_EXTCAP) {
3624 				ie_len = length + 2;
3625 				if (MLAN_STATUS_SUCCESS !=
3626 				    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
3627 							(t_u8 *)pos, &ie_len,
3628 							MOAL_IOCTL_WAIT))
3629 					PRINTM(MERROR,
3630 					       "Fail to set EXTCAP IE\n");
3631 				break;
3632 			}
3633 			if ((out_len + length + 2) < (int)ie_out_len) {
3634 				moal_memcpy_ext(priv->phandle, ie_out + out_len,
3635 						pos, length + 2,
3636 						ie_out_len - out_len);
3637 				out_len += length + 2;
3638 			} else {
3639 				PRINTM(MERROR,
3640 				       "IE too big, fail copy EXTCAP IE\n");
3641 			}
3642 			break;
3643 		case VENDOR_SPECIFIC_221:
3644 			/* filter out wmm ie */
3645 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
3646 			if (!memcmp(pvendor_ie->vend_hdr.oui, wmm_oui,
3647 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
3648 			    pvendor_ie->vend_hdr.oui_type == wmm_oui[3]) {
3649 				break;
3650 			}
3651 			/* filter out wps ie */
3652 			else if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
3653 					 sizeof(pvendor_ie->vend_hdr.oui)) &&
3654 				 pvendor_ie->vend_hdr.oui_type == wps_oui[3]) {
3655 				if (wps_flag & IE_MASK_WPS)
3656 					break;
3657 			}
3658 			/* filter out first p2p ie */
3659 			else if (!memcmp(pvendor_ie->vend_hdr.oui, p2p_oui,
3660 					 sizeof(pvendor_ie->vend_hdr.oui)) &&
3661 				 pvendor_ie->vend_hdr.oui_type == p2p_oui[3]) {
3662 				if (!find_p2p_ie && (wps_flag & IE_MASK_P2P)) {
3663 					find_p2p_ie = MTRUE;
3664 					break;
3665 				}
3666 			}
3667 			/* filter out wfd ie */
3668 			else if (!memcmp(pvendor_ie->vend_hdr.oui, wfd_oui,
3669 					 sizeof(pvendor_ie->vend_hdr.oui)) &&
3670 				 pvendor_ie->vend_hdr.oui_type == wfd_oui[3]) {
3671 				if (wps_flag & IE_MASK_WFD)
3672 					break;
3673 			} else if (wps_flag & IE_MASK_VENDOR) {
3674 				// filter out vendor IE
3675 				break;
3676 			}
3677 			if ((out_len + length + 2) < (int)ie_out_len) {
3678 				moal_memcpy_ext(priv->phandle, ie_out + out_len,
3679 						pos, length + 2,
3680 						ie_out_len - out_len);
3681 				out_len += length + 2;
3682 			} else {
3683 				PRINTM(MERROR,
3684 				       "IE too big, fail copy VENDOR_SPECIFIC_221 IE\n");
3685 			}
3686 			break;
3687 		default:
3688 			if ((out_len + length + 2) < (int)ie_out_len) {
3689 				moal_memcpy_ext(priv->phandle, ie_out + out_len,
3690 						pos, length + 2,
3691 						ie_out_len - out_len);
3692 				out_len += length + 2;
3693 			} else {
3694 				PRINTM(MERROR, "IE too big, fail copy %d IE\n",
3695 				       id);
3696 			}
3697 			break;
3698 		}
3699 		pos += (length + 2);
3700 		left_len -= (length + 2);
3701 	}
3702 
3703 #ifdef UAP_SUPPORT
3704 	if (enable_11d && !priv->bss_started) {
3705 		if (MLAN_STATUS_SUCCESS !=
3706 		    woal_set_11d(priv, MOAL_IOCTL_WAIT, MTRUE)) {
3707 			PRINTM(MERROR, "woal_set_11d fail\n");
3708 		}
3709 	}
3710 #endif
3711 	return out_len;
3712 }
3713 
3714 #ifdef WIFI_DIRECT_SUPPORT
3715 /**
3716  * @brief Check if selected_registrar_on in wps_ie
3717  *
3718  * @param ie              Pointer to IEs
3719  * @param len             Total length of ie
3720  *
3721  * @return                MTRUE/MFALSE
3722  */
is_selected_registrar_on(const t_u8 * ie,int len)3723 static t_u8 is_selected_registrar_on(const t_u8 *ie, int len)
3724 {
3725 #define WPS_IE_FIX_LEN 6
3726 #define TLV_ID_SELECTED_REGISTRAR 0x1041
3727 	int left_len = len - WPS_IE_FIX_LEN;
3728 
3729 	TLV_Generic_t *tlv = (TLV_Generic_t *)(ie + WPS_IE_FIX_LEN);
3730 	u16 tlv_type, tlv_len;
3731 	u8 *pos = NULL;
3732 
3733 	while (left_len > (int)sizeof(TLV_Generic_t)) {
3734 		tlv_type = ntohs((__force __be16)tlv->type);
3735 		tlv_len = ntohs((__force __be16)tlv->len);
3736 		if (tlv_type == TLV_ID_SELECTED_REGISTRAR) {
3737 			PRINTM(MIOCTL, "Selected Registrar found !");
3738 			pos = (u8 *)tlv + sizeof(TLV_Generic_t);
3739 			if (*pos == 1)
3740 				return MTRUE;
3741 			else
3742 				return MFALSE;
3743 		}
3744 		tlv = (TLV_Generic_t *)((u8 *)tlv + tlv_len +
3745 					sizeof(TLV_Generic_t));
3746 		left_len -= tlv_len + sizeof(TLV_Generic_t);
3747 	}
3748 	return MFALSE;
3749 }
3750 
3751 /**
3752  * @brief Check if selected_registrar_on in ies
3753  *
3754  * @param ie              Pointer to IEs
3755  * @param len             Total length of ie
3756  *
3757  *
3758  * @return                MTRUE/MFALSE
3759  */
woal_is_selected_registrar_on(const t_u8 * ie,int len)3760 static t_u16 woal_is_selected_registrar_on(const t_u8 *ie, int len)
3761 {
3762 	int left_len = len;
3763 	const t_u8 *pos = ie;
3764 	int length;
3765 	t_u8 id = 0;
3766 	IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
3767 	const u8 wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
3768 
3769 	while (left_len >= 2) {
3770 		length = *(pos + 1);
3771 		id = *pos;
3772 		if ((length + 2) > left_len)
3773 			break;
3774 		switch (id) {
3775 		case VENDOR_SPECIFIC_221:
3776 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
3777 			if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
3778 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
3779 			    pvendor_ie->vend_hdr.oui_type == wps_oui[3]) {
3780 				PRINTM(MIOCTL, "Find WPS ie\n");
3781 				return is_selected_registrar_on(pos,
3782 								length + 2);
3783 			}
3784 			break;
3785 		default:
3786 			break;
3787 		}
3788 		pos += (length + 2);
3789 		left_len -= (length + 2);
3790 	}
3791 	return MFALSE;
3792 }
3793 #endif
3794 
3795 /**
3796  * @brief config AP or GO for mgmt frame ies.
3797  *
3798  * @param priv                  A pointer to moal private structure
3799  * @param beacon_ies            A pointer to beacon ies
3800  * @param beacon_ies_len        Beacon ies length
3801  * @param proberesp_ies         A pointer to probe resp ies
3802  * @param proberesp_ies_len     Probe resp ies length
3803  * @param assocresp_ies         A pointer to probe resp ies
3804  * @param assocresp_ies_len     Assoc resp ies length
3805  * @param probereq_ies          A pointer to probe req ies
3806  * @param probereq_ies_len      Probe req ies length *
3807  * @param mask					Mgmt frame mask
3808  * @param wait_option           wait_option
3809  *
3810  * @return                      0 -- success, otherwise fail
3811  */
woal_cfg80211_mgmt_frame_ie(moal_private * priv,const t_u8 * beacon_ies,size_t beacon_ies_len,const t_u8 * proberesp_ies,size_t proberesp_ies_len,const t_u8 * assocresp_ies,size_t assocresp_ies_len,const t_u8 * probereq_ies,size_t probereq_ies_len,t_u16 mask,t_u8 wait_option)3812 int woal_cfg80211_mgmt_frame_ie(
3813 	moal_private *priv, const t_u8 *beacon_ies, size_t beacon_ies_len,
3814 	const t_u8 *proberesp_ies, size_t proberesp_ies_len,
3815 	const t_u8 *assocresp_ies, size_t assocresp_ies_len,
3816 	const t_u8 *probereq_ies, size_t probereq_ies_len, t_u16 mask,
3817 	t_u8 wait_option)
3818 {
3819 	int ret = 0;
3820 	t_u8 *pos = NULL;
3821 	custom_ie *beacon_ies_data = NULL;
3822 	custom_ie *proberesp_ies_data = NULL;
3823 	custom_ie *assocresp_ies_data = NULL;
3824 	custom_ie *probereq_ies_data = NULL;
3825 
3826 	/* static variables for mgmt frame ie auto-indexing */
3827 	t_u16 beacon_index = priv->beacon_index;
3828 	t_u16 proberesp_index = priv->proberesp_index;
3829 	t_u16 assocresp_index = priv->assocresp_index;
3830 	t_u16 probereq_index = priv->probereq_index;
3831 	t_u16 beacon_wps_index = priv->beacon_wps_index;
3832 	t_u16 proberesp_p2p_index = priv->proberesp_p2p_index;
3833 	t_u16 assocrep_qos_map_index = priv->assocresp_qos_map_index;
3834 	t_u16 beacon_vendor_index = priv->beacon_vendor_index;
3835 
3836 	ENTER();
3837 
3838 	/* we need remove vendor IE from beacon extra IE, vendor IE will be
3839 	 * configure through proberesp_vendor_index
3840 	 */
3841 	if (mask & MGMT_MASK_BEACON_WPS_P2P) {
3842 		beacon_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
3843 		if (!beacon_ies_data) {
3844 			ret = -ENOMEM;
3845 			goto done;
3846 		}
3847 		if (beacon_ies && beacon_ies_len) {
3848 #ifdef WIFI_DIRECT_SUPPORT
3849 			if (woal_is_selected_registrar_on(beacon_ies,
3850 							  beacon_ies_len)) {
3851 				PRINTM(MIOCTL, "selected_registrar is on\n");
3852 				priv->phandle->is_go_timer_set = MTRUE;
3853 				woal_mod_timer(&priv->phandle->go_timer,
3854 					       MOAL_TIMER_10S);
3855 			} else
3856 				PRINTM(MIOCTL, "selected_registrar is off\n");
3857 #endif
3858 			beacon_ies_data->ie_index = beacon_wps_index;
3859 			beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON;
3860 			beacon_ies_data->ie_length = woal_filter_beacon_ies(
3861 				priv, beacon_ies, beacon_ies_len,
3862 				beacon_ies_data->ie_buffer, MAX_IE_SIZE,
3863 				IE_MASK_VENDOR, NULL, 0);
3864 			DBG_HEXDUMP(MCMD_D, "beacon extra ie",
3865 				    beacon_ies_data->ie_buffer,
3866 				    beacon_ies_data->ie_length);
3867 		} else {
3868 			/* clear the beacon wps ies */
3869 			if (beacon_wps_index > MAX_MGMT_IE_INDEX) {
3870 				PRINTM(MERROR,
3871 				       "Invalid beacon wps index for mgmt frame ie.\n");
3872 				ret = -EFAULT;
3873 				goto done;
3874 			}
3875 
3876 			beacon_ies_data->ie_index = beacon_wps_index;
3877 			beacon_ies_data->mgmt_subtype_mask =
3878 				MLAN_CUSTOM_IE_DELETE_MASK;
3879 			beacon_ies_data->ie_length = 0;
3880 			beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3881 		}
3882 		if ((beacon_ies && beacon_ies_len &&
3883 		     beacon_ies_data->ie_length) ||
3884 		    (beacon_ies_data->mgmt_subtype_mask ==
3885 		     MLAN_CUSTOM_IE_DELETE_MASK)) {
3886 			if (MLAN_STATUS_FAILURE ==
3887 			    woal_cfg80211_custom_ie(
3888 				    priv, beacon_ies_data, &beacon_wps_index,
3889 				    proberesp_ies_data, &proberesp_index,
3890 				    assocresp_ies_data, &assocresp_index,
3891 				    probereq_ies_data, &probereq_index,
3892 				    wait_option)) {
3893 				PRINTM(MERROR, "Fail to set beacon wps IE\n");
3894 				ret = -EFAULT;
3895 			}
3896 			priv->beacon_wps_index = beacon_wps_index;
3897 			PRINTM(MCMND, "beacon_wps_index=0x%x len=%d\n",
3898 			       beacon_wps_index, beacon_ies_data->ie_length);
3899 			goto done;
3900 		}
3901 		kfree(beacon_ies_data); // Further allocation of beacon_ies_data
3902 					// is happening, so need to free here.
3903 		beacon_ies_data = NULL;
3904 	}
3905 
3906 	if (mask & MGMT_MASK_ASSOC_RESP_QOS_MAP) {
3907 		assocresp_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
3908 		if (!assocresp_ies_data) {
3909 			ret = -ENOMEM;
3910 			goto done;
3911 		}
3912 		if (assocresp_ies && assocresp_ies_len) {
3913 			/* set the assoc response qos map ies */
3914 			assocresp_ies_data->ie_index = assocrep_qos_map_index;
3915 			assocresp_ies_data->mgmt_subtype_mask =
3916 				MGMT_MASK_ASSOC_RESP;
3917 			if (MLAN_CUSTOM_IE_AUTO_IDX_MASK ==
3918 			    assocrep_qos_map_index)
3919 				assocresp_ies_data->mgmt_subtype_mask |=
3920 					MLAN_CUSTOM_IE_NEW_MASK;
3921 			if (assocresp_ies_len > MAX_IE_SIZE) {
3922 				PRINTM(MERROR,
3923 				       "IE too big: assocresp_ies_len=%d\n",
3924 				       (int)assocresp_ies_len);
3925 				ret = -EFAULT;
3926 				goto done;
3927 			}
3928 			assocresp_ies_data->ie_length = assocresp_ies_len;
3929 			pos = assocresp_ies_data->ie_buffer;
3930 			moal_memcpy_ext(priv->phandle, pos, assocresp_ies,
3931 					assocresp_ies_len, MAX_IE_SIZE);
3932 			DBG_HEXDUMP(MCMD_D, "Qos Map",
3933 				    assocresp_ies_data->ie_buffer,
3934 				    assocresp_ies_data->ie_length);
3935 		} else {
3936 			/* clear the assoc response qos map ie */
3937 			if (assocrep_qos_map_index > MAX_MGMT_IE_INDEX) {
3938 				PRINTM(MERROR,
3939 				       "Invalid Qos map index for mgmt frame ie.\n");
3940 				ret = -EFAULT;
3941 				goto done;
3942 			}
3943 
3944 			assocresp_ies_data->ie_index = assocrep_qos_map_index;
3945 			assocresp_ies_data->mgmt_subtype_mask =
3946 				MLAN_CUSTOM_IE_DELETE_MASK;
3947 			assocresp_ies_data->ie_length = 0;
3948 			assocrep_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3949 		}
3950 		if (MLAN_STATUS_FAILURE ==
3951 		    woal_cfg80211_custom_ie(priv, NULL, &beacon_wps_index, NULL,
3952 					    &proberesp_index,
3953 					    assocresp_ies_data,
3954 					    &assocrep_qos_map_index, NULL,
3955 					    &probereq_index, wait_option)) {
3956 			PRINTM(MERROR, "Fail to set Qos map IE\n");
3957 			ret = -EFAULT;
3958 		}
3959 		priv->assocresp_qos_map_index = assocrep_qos_map_index;
3960 		PRINTM(MCMND, "qos map ie index=0x%x len=%d\n",
3961 		       assocrep_qos_map_index, assocresp_ies_data->ie_length);
3962 		goto done;
3963 	}
3964 
3965 	if (mask & MGMT_MASK_BEACON) {
3966 		beacon_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
3967 		if (!beacon_ies_data) {
3968 			ret = -ENOMEM;
3969 			goto done;
3970 		}
3971 	}
3972 
3973 	if (mask & MGMT_MASK_PROBE_RESP) {
3974 		/** set or clear proberesp ie */
3975 		if (proberesp_ies_len ||
3976 		    (!proberesp_ies_len && !beacon_ies_len)) {
3977 			proberesp_ies_data =
3978 				kzalloc(sizeof(custom_ie), GFP_KERNEL);
3979 			if (!proberesp_ies_data) {
3980 				ret = -ENOMEM;
3981 				goto done;
3982 			}
3983 		}
3984 	}
3985 
3986 	if (mask & MGMT_MASK_ASSOC_RESP) {
3987 		/** set or clear assocresp ie */
3988 		if (assocresp_ies_len ||
3989 		    (!assocresp_ies_len && !beacon_ies_len)) {
3990 			assocresp_ies_data =
3991 				kzalloc(sizeof(custom_ie), GFP_KERNEL);
3992 			if (!assocresp_ies_data) {
3993 				ret = -ENOMEM;
3994 				goto done;
3995 			}
3996 		}
3997 	}
3998 	if (mask & MGMT_MASK_PROBE_REQ) {
3999 		probereq_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
4000 		if (!probereq_ies_data) {
4001 			ret = -ENOMEM;
4002 			goto done;
4003 		}
4004 	}
4005 
4006 	if (beacon_ies_data) {
4007 		if (beacon_ies && beacon_ies_len) {
4008 			/* set the probe response/beacon vendor ies which
4009 			 * includes wpa IE
4010 			 */
4011 			beacon_ies_data->ie_index = beacon_vendor_index;
4012 			beacon_ies_data->mgmt_subtype_mask =
4013 				MGMT_MASK_PROBE_RESP | MGMT_MASK_BEACON;
4014 			if (beacon_vendor_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK)
4015 				beacon_ies_data->mgmt_subtype_mask |=
4016 					MLAN_CUSTOM_IE_NEW_MASK;
4017 			beacon_ies_data->ie_length =
4018 				woal_get_specific_ie(beacon_ies, beacon_ies_len,
4019 						     beacon_ies_data->ie_buffer,
4020 						     MAX_IE_SIZE,
4021 						     IE_MASK_VENDOR);
4022 			DBG_HEXDUMP(MCMD_D, "beacon vendor IE",
4023 				    beacon_ies_data->ie_buffer,
4024 				    beacon_ies_data->ie_length);
4025 		}
4026 		if (beacon_vendor_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK &&
4027 		    !beacon_ies_data->ie_length) {
4028 			/* clear the beacon vendor ies */
4029 			if (beacon_vendor_index > MAX_MGMT_IE_INDEX) {
4030 				PRINTM(MERROR,
4031 				       "Invalid beacon_vendor_index for mgmt frame ie.\n");
4032 				ret = -EFAULT;
4033 				goto done;
4034 			}
4035 			beacon_ies_data->ie_index = beacon_vendor_index;
4036 			beacon_ies_data->mgmt_subtype_mask =
4037 				MLAN_CUSTOM_IE_DELETE_MASK;
4038 			beacon_ies_data->ie_length = 0;
4039 			beacon_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
4040 		}
4041 		if ((beacon_ies && beacon_ies_len &&
4042 		     beacon_ies_data->ie_length) ||
4043 		    (beacon_ies_data->mgmt_subtype_mask ==
4044 		     MLAN_CUSTOM_IE_DELETE_MASK)) {
4045 			if (MLAN_STATUS_FAILURE ==
4046 			    woal_cfg80211_custom_ie(
4047 				    priv, beacon_ies_data, &beacon_vendor_index,
4048 				    NULL, &proberesp_index, NULL,
4049 				    &assocresp_index, NULL, &probereq_index,
4050 				    wait_option)) {
4051 				PRINTM(MERROR,
4052 				       "Fail to set beacon vendor IE\n");
4053 				ret = -EFAULT;
4054 				goto done;
4055 			}
4056 			priv->beacon_vendor_index = beacon_vendor_index;
4057 			PRINTM(MCMND, "beacon_vendor=0x%x len=%d\n",
4058 			       beacon_vendor_index, beacon_ies_data->ie_length);
4059 		}
4060 		memset(beacon_ies_data, 0x00, sizeof(custom_ie));
4061 		if (beacon_ies && beacon_ies_len) {
4062 			/* set the beacon ies */
4063 			/* we need remove vendor IE from beacon tail, vendor/wpa
4064 			 * IE will be configure through beacon_vendor_index
4065 			 */
4066 			beacon_ies_data->ie_index = beacon_index;
4067 			beacon_ies_data->mgmt_subtype_mask =
4068 				MGMT_MASK_BEACON | MGMT_MASK_ASSOC_RESP |
4069 				MGMT_MASK_PROBE_RESP;
4070 			beacon_ies_data->ie_length = woal_filter_beacon_ies(
4071 				priv, beacon_ies, beacon_ies_len,
4072 				beacon_ies_data->ie_buffer, MAX_IE_SIZE,
4073 				IE_MASK_WPS | IE_MASK_WFD | IE_MASK_P2P |
4074 					IE_MASK_VENDOR,
4075 				proberesp_ies, proberesp_ies_len);
4076 			if (beacon_ies_data->ie_length)
4077 				DBG_HEXDUMP(MCMD_D, "beacon ie",
4078 					    beacon_ies_data->ie_buffer,
4079 					    beacon_ies_data->ie_length);
4080 			else {
4081 				kfree(beacon_ies_data);
4082 				beacon_ies_data = NULL;
4083 			}
4084 		} else {
4085 			/* clear the beacon ies */
4086 			if (beacon_index > MAX_MGMT_IE_INDEX) {
4087 				PRINTM(MINFO,
4088 				       "Invalid beacon index for mgmt frame ie.\n");
4089 				ret = -EFAULT;
4090 				goto done;
4091 			}
4092 
4093 			beacon_ies_data->ie_index = beacon_index;
4094 			beacon_ies_data->mgmt_subtype_mask =
4095 				MLAN_CUSTOM_IE_DELETE_MASK;
4096 			beacon_ies_data->ie_length = 0;
4097 			beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
4098 		}
4099 	}
4100 
4101 	if (proberesp_ies_data) {
4102 		proberesp_ies_data->mgmt_subtype_mask = 0xff;
4103 		if (proberesp_ies && proberesp_ies_len) {
4104 			/* set the probe response p2p ies */
4105 			proberesp_ies_data->ie_index = proberesp_p2p_index;
4106 			proberesp_ies_data->mgmt_subtype_mask =
4107 				MGMT_MASK_PROBE_RESP;
4108 			proberesp_ies_data->ie_length = woal_get_specific_ie(
4109 				proberesp_ies, proberesp_ies_len,
4110 				proberesp_ies_data->ie_buffer, MAX_IE_SIZE,
4111 				IE_MASK_P2P);
4112 			DBG_HEXDUMP(MCMD_D, "proberesp p2p ie",
4113 				    proberesp_ies_data->ie_buffer,
4114 				    proberesp_ies_data->ie_length);
4115 		} else if (proberesp_p2p_index !=
4116 			   MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
4117 			/* clear the probe response p2p ies */
4118 			if (proberesp_p2p_index > MAX_MGMT_IE_INDEX) {
4119 				PRINTM(MERROR,
4120 				       "Invalid proberesp_p2p_index for mgmt frame ie.\n");
4121 				ret = -EFAULT;
4122 				goto done;
4123 			}
4124 			proberesp_ies_data->ie_index = proberesp_p2p_index;
4125 			proberesp_ies_data->mgmt_subtype_mask =
4126 				MLAN_CUSTOM_IE_DELETE_MASK;
4127 			proberesp_ies_data->ie_length = 0;
4128 			proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
4129 		}
4130 		if ((proberesp_ies && proberesp_ies_len &&
4131 		     proberesp_ies_data->ie_length) ||
4132 		    (proberesp_ies_data->mgmt_subtype_mask ==
4133 		     MLAN_CUSTOM_IE_DELETE_MASK)) {
4134 			if (MLAN_STATUS_FAILURE ==
4135 			    woal_cfg80211_custom_ie(
4136 				    priv, NULL, &beacon_index,
4137 				    proberesp_ies_data, &proberesp_p2p_index,
4138 				    NULL, &assocresp_index, NULL,
4139 				    &probereq_index, wait_option)) {
4140 				PRINTM(MERROR,
4141 				       "Fail to set proberesp p2p IE\n");
4142 				ret = -EFAULT;
4143 				goto done;
4144 			}
4145 			priv->proberesp_p2p_index = proberesp_p2p_index;
4146 			PRINTM(MCMND, "proberesp_p2p=0x%x len=%d\n",
4147 			       proberesp_p2p_index,
4148 			       proberesp_ies_data->ie_length);
4149 		}
4150 		memset(proberesp_ies_data, 0x00, sizeof(custom_ie));
4151 		if (proberesp_ies && proberesp_ies_len) {
4152 			/* set the probe response ies */
4153 			proberesp_ies_data->ie_index = proberesp_index;
4154 			proberesp_ies_data->mgmt_subtype_mask =
4155 				MGMT_MASK_PROBE_RESP;
4156 			if (proberesp_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK)
4157 				proberesp_ies_data->mgmt_subtype_mask |=
4158 					MLAN_CUSTOM_IE_NEW_MASK;
4159 			proberesp_ies_data->ie_length = woal_filter_beacon_ies(
4160 				priv, proberesp_ies, proberesp_ies_len,
4161 				proberesp_ies_data->ie_buffer, MAX_IE_SIZE,
4162 				IE_MASK_P2P | IE_MASK_VENDOR, NULL, 0);
4163 			if (proberesp_ies_data->ie_length) {
4164 				DBG_HEXDUMP(MCMD_D, "proberesp ie",
4165 					    proberesp_ies_data->ie_buffer,
4166 					    proberesp_ies_data->ie_length);
4167 			} else {
4168 				kfree(proberesp_ies_data);
4169 				proberesp_ies_data = NULL;
4170 			}
4171 		} else {
4172 			/* clear the probe response ies */
4173 			if (proberesp_index > MAX_MGMT_IE_INDEX) {
4174 				PRINTM(MERROR,
4175 				       "Invalid probe resp index for mgmt frame ie.\n");
4176 				ret = -EFAULT;
4177 				goto done;
4178 			}
4179 			proberesp_ies_data->ie_index = proberesp_index;
4180 			proberesp_ies_data->mgmt_subtype_mask =
4181 				MLAN_CUSTOM_IE_DELETE_MASK;
4182 			proberesp_ies_data->ie_length = 0;
4183 			proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
4184 		}
4185 	}
4186 	if (assocresp_ies_data) {
4187 		if (assocresp_ies && assocresp_ies_len) {
4188 			/* set the assoc response ies */
4189 			assocresp_ies_data->ie_index = assocresp_index;
4190 			assocresp_ies_data->mgmt_subtype_mask =
4191 				MGMT_MASK_ASSOC_RESP;
4192 			if (assocresp_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK)
4193 				assocresp_ies_data->mgmt_subtype_mask |=
4194 					MLAN_CUSTOM_IE_NEW_MASK;
4195 			if (assocresp_ies_len > MAX_IE_SIZE) {
4196 				PRINTM(MERROR,
4197 				       "IE too big, assocresp_ies_len=%d\n",
4198 				       (int)assocresp_ies_len);
4199 				ret = -EFAULT;
4200 				goto done;
4201 			}
4202 			assocresp_ies_data->ie_length = assocresp_ies_len;
4203 			pos = assocresp_ies_data->ie_buffer;
4204 			moal_memcpy_ext(priv->phandle, pos, assocresp_ies,
4205 					assocresp_ies_len, MAX_IE_SIZE);
4206 			DBG_HEXDUMP(MCMD_D, "assocresp ie",
4207 				    assocresp_ies_data->ie_buffer,
4208 				    assocresp_ies_data->ie_length);
4209 		} else {
4210 			/* clear the assoc response ies */
4211 			if (assocresp_index > MAX_MGMT_IE_INDEX) {
4212 				PRINTM(MERROR,
4213 				       "Invalid assoc resp index for mgmt frame ie.\n");
4214 				ret = -EFAULT;
4215 				goto done;
4216 			}
4217 
4218 			assocresp_ies_data->ie_index = assocresp_index;
4219 			assocresp_ies_data->mgmt_subtype_mask =
4220 				MLAN_CUSTOM_IE_DELETE_MASK;
4221 			assocresp_ies_data->ie_length = 0;
4222 			assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
4223 		}
4224 	}
4225 
4226 	if (probereq_ies_data) {
4227 		if (probereq_ies && probereq_ies_len) {
4228 			/* set the probe req ies */
4229 			probereq_ies_data->ie_index = probereq_index;
4230 			probereq_ies_data->mgmt_subtype_mask =
4231 				MGMT_MASK_PROBE_REQ;
4232 #ifdef WIFI_DIRECT_SUPPORT
4233 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
4234 			if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
4235 				/* filter out P2P/WFD ie/EXT_CAP ie */
4236 				probereq_ies_data->ie_length =
4237 					woal_filter_beacon_ies(
4238 						priv, probereq_ies,
4239 						probereq_ies_len,
4240 						probereq_ies_data->ie_buffer,
4241 						MAX_IE_SIZE,
4242 						IE_MASK_P2P | IE_MASK_WFD |
4243 							IE_MASK_EXTCAP,
4244 						NULL, 0);
4245 			} else {
4246 #endif /* KERNEL_VERSION */
4247 #endif /* WIFI_DIRECT_SUPPORT */
4248 				if (probereq_ies_len > MAX_IE_SIZE) {
4249 					PRINTM(MERROR,
4250 					       "IE too big, probereq_ies_len=%d\n",
4251 					       (int)probereq_ies_len);
4252 					ret = -EFAULT;
4253 					goto done;
4254 				}
4255 				probereq_ies_data->ie_length = probereq_ies_len;
4256 				pos = probereq_ies_data->ie_buffer;
4257 				moal_memcpy_ext(priv->phandle, pos,
4258 						probereq_ies, probereq_ies_len,
4259 						MAX_IE_SIZE);
4260 #ifdef WIFI_DIRECT_SUPPORT
4261 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
4262 			}
4263 #endif /* KERNEL_VERSION */
4264 #endif /* WIFI_DIRECT_SUPPORT */
4265 			if (probereq_ies_data->ie_length)
4266 				DBG_HEXDUMP(MCMD_D, "probereq ie",
4267 					    probereq_ies_data->ie_buffer,
4268 					    probereq_ies_data->ie_length);
4269 			else {
4270 				kfree(probereq_ies_data);
4271 				probereq_ies_data = NULL;
4272 			}
4273 		} else {
4274 			/* clear the probe req ies */
4275 			if (probereq_index > MAX_MGMT_IE_INDEX) {
4276 				PRINTM(MERROR,
4277 				       "Invalid probe req index for mgmt frame ie.\n");
4278 				ret = -EFAULT;
4279 				goto done;
4280 			}
4281 			probereq_ies_data->ie_index = probereq_index;
4282 			probereq_ies_data->mgmt_subtype_mask =
4283 				MLAN_CUSTOM_IE_DELETE_MASK;
4284 			probereq_ies_data->ie_length = 0;
4285 			probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
4286 		}
4287 	}
4288 
4289 	if (beacon_ies_data || proberesp_ies_data || assocresp_ies_data ||
4290 	    probereq_ies_data) {
4291 		if (MLAN_STATUS_FAILURE ==
4292 		    woal_cfg80211_custom_ie(
4293 			    priv, beacon_ies_data, &beacon_index,
4294 			    proberesp_ies_data, &proberesp_index,
4295 			    assocresp_ies_data, &assocresp_index,
4296 			    probereq_ies_data, &probereq_index, wait_option)) {
4297 			PRINTM(MERROR,
4298 			       "Fail to set beacon proberesp assoc probereq IES\n");
4299 			ret = -EFAULT;
4300 			goto done;
4301 		}
4302 	}
4303 	if (beacon_ies_data) {
4304 		priv->beacon_index = beacon_index;
4305 		PRINTM(MCMND, "beacon ie length = %d\n",
4306 		       beacon_ies_data->ie_length);
4307 	}
4308 	if (assocresp_ies_data) {
4309 		priv->assocresp_index = assocresp_index;
4310 		PRINTM(MCMND, "assocresp ie length = %d\n",
4311 		       assocresp_ies_data->ie_length);
4312 	}
4313 	if (proberesp_ies_data) {
4314 		priv->proberesp_index = proberesp_index;
4315 		PRINTM(MCMND, "proberesp ie length = %d\n",
4316 		       proberesp_ies_data->ie_length);
4317 	}
4318 	if (probereq_ies_data) {
4319 		priv->probereq_index = probereq_index;
4320 		PRINTM(MCMND, "probereq ie length = %d\n",
4321 		       probereq_ies_data->ie_length);
4322 	}
4323 	PRINTM(MCMND, "beacon=%x assocresp=%x proberesp=%x probereq=%x\n",
4324 	       beacon_index, assocresp_index, proberesp_index, probereq_index);
4325 done:
4326 	kfree(beacon_ies_data);
4327 	kfree(proberesp_ies_data);
4328 	kfree(assocresp_ies_data);
4329 	kfree(probereq_ies_data);
4330 
4331 	LEAVE();
4332 
4333 	return ret;
4334 }
4335 
4336 /**
4337  *  @brief Sets up the ieee80211_supported band
4338  *  *
4339  *  @param ht_info      A pointer to ieee80211_sta_ht_cap structure
4340  *  @param dev_cap      Device capability information
4341  *  @param mcs_set      Device MCS sets
4342  *
4343  *  @return             N/A
4344  */
woal_setup_wiphy_bands(t_u8 ieee_band)4345 struct ieee80211_supported_band *woal_setup_wiphy_bands(t_u8 ieee_band)
4346 {
4347 	struct ieee80211_supported_band *band = NULL;
4348 	switch (ieee_band) {
4349 	case IEEE80211_BAND_5GHZ:
4350 		band = kmemdup(&cfg80211_band_5ghz,
4351 			       sizeof(struct ieee80211_supported_band),
4352 			       GFP_KERNEL);
4353 		if (!band) {
4354 			PRINTM(MERROR, "No memory for 5g band\n");
4355 			break;
4356 		}
4357 		band->channels =
4358 			kmemdup(&cfg80211_channels_5ghz,
4359 				sizeof(cfg80211_channels_5ghz), GFP_KERNEL);
4360 		if (!band->channels) {
4361 			PRINTM(MERROR, "No memory for 5g band->channel\n");
4362 			kfree(band);
4363 			band = NULL;
4364 			break;
4365 		}
4366 		band->n_channels = ARRAY_SIZE(cfg80211_channels_5ghz);
4367 		break;
4368 	case IEEE80211_BAND_2GHZ:
4369 	default:
4370 		band = kmemdup(&cfg80211_band_2ghz,
4371 			       sizeof(struct ieee80211_supported_band),
4372 			       GFP_KERNEL);
4373 		if (!band) {
4374 			PRINTM(MERROR, "No memory for 2g band\n");
4375 			break;
4376 		}
4377 		band->channels =
4378 			kmemdup(&cfg80211_channels_2ghz,
4379 				sizeof(cfg80211_channels_2ghz), GFP_KERNEL);
4380 		if (!band->channels) {
4381 			PRINTM(MERROR, "No memory for 2g band->channel\n");
4382 			kfree(band);
4383 			band = NULL;
4384 			break;
4385 		}
4386 		band->n_channels = ARRAY_SIZE(cfg80211_channels_2ghz);
4387 		break;
4388 	}
4389 	return band;
4390 }
4391 
4392 /**
4393  *  @brief Sets up the CFG802.11 specific HT capability fields
4394  *  with default values
4395  *
4396  *  @param ht_info      A pointer to ieee80211_sta_ht_cap structure
4397  *  @param dev_cap      Device capability information
4398  *  @param mcs_set      Device MCS sets
4399  *
4400  *  @return             N/A
4401  */
woal_cfg80211_setup_ht_cap(struct ieee80211_sta_ht_cap * ht_info,t_u32 dev_cap,t_u8 * mcs_set)4402 void woal_cfg80211_setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
4403 				t_u32 dev_cap, t_u8 *mcs_set)
4404 {
4405 	ENTER();
4406 
4407 	ht_info->ht_supported = true;
4408 	ht_info->ampdu_factor = 0x3;
4409 	ht_info->ampdu_density = 0;
4410 
4411 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
4412 	ht_info->cap = 0;
4413 	if (mcs_set)
4414 		moal_memcpy_ext(NULL, ht_info->mcs.rx_mask, mcs_set,
4415 				sizeof(ht_info->mcs.rx_mask),
4416 				sizeof(ht_info->mcs.rx_mask));
4417 	if (dev_cap & MBIT(8)) /* 40Mhz intolarance enabled */
4418 		ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT;
4419 	if (dev_cap & MBIT(17)) /* Channel width 20/40Mhz support */
4420 		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
4421 	if ((dev_cap >> 20) & 0x03) /* Delayed ACK supported */
4422 		ht_info->cap |= IEEE80211_HT_CAP_DELAY_BA;
4423 	if (dev_cap & MBIT(22)) /* Rx LDPC supported */
4424 		ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
4425 	if (dev_cap & MBIT(23)) /* Short GI @ 20Mhz supported */
4426 		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
4427 	if (dev_cap & MBIT(24)) /* Short GI @ 40Mhz supported */
4428 		ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
4429 	if (dev_cap & MBIT(25)) /* Tx STBC supported */
4430 		ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
4431 	if (dev_cap & MBIT(26)) /* Rx STBC supported */
4432 		ht_info->cap |= IEEE80211_HT_CAP_RX_STBC;
4433 	if (dev_cap & MBIT(27)) /* MIMO PS supported */
4434 		ht_info->cap |= 0; /* WLAN_HT_CAP_SM_PS_STATIC */
4435 	else /* Disable HT SM PS */
4436 		ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
4437 	if (dev_cap & MBIT(29)) /* Green field supported */
4438 		ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
4439 	if (dev_cap & MBIT(31)) /* MAX AMSDU supported */
4440 		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
4441 	/* DSSS/CCK in 40Mhz supported*/
4442 	ht_info->cap |= IEEE80211_HT_CAP_DSSSCCK40;
4443 	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
4444 
4445 	LEAVE();
4446 }
4447 
4448 #if KERNEL_VERSION(3, 6, 0) <= CFG80211_VERSION_CODE
4449 /**
4450  *  @brief Sets up the CFG802.11 specific VHT capability fields
4451  *  with default values
4452  *
4453  * @param priv         A pointer to moal private structure
4454  *  @param vht_cap      A pointer to ieee80211_sta_vht_cap structure
4455  *
4456  *  @return             N/A
4457  */
woal_cfg80211_setup_vht_cap(moal_private * priv,struct ieee80211_sta_vht_cap * vht_cap)4458 void woal_cfg80211_setup_vht_cap(moal_private *priv,
4459 				 struct ieee80211_sta_vht_cap *vht_cap)
4460 {
4461 	mlan_ioctl_req *req = NULL;
4462 	mlan_ds_11ac_cfg *cfg_11ac = NULL;
4463 	mlan_status status;
4464 
4465 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg));
4466 	if (req == NULL) {
4467 		status = MLAN_STATUS_FAILURE;
4468 		PRINTM(MERROR, "Fail to allocate buf for setup vht_cap\n");
4469 		goto done;
4470 	}
4471 	cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf;
4472 	cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG;
4473 	req->req_id = MLAN_IOCTL_11AC_CFG;
4474 	req->action = MLAN_ACT_GET;
4475 	cfg_11ac->param.vht_cfg.band = BAND_SELECT_A;
4476 	cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX;
4477 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4478 	if (status != MLAN_STATUS_SUCCESS) {
4479 		PRINTM(MERROR, "Fail to get vht_cfg\n");
4480 		goto done;
4481 	}
4482 	vht_cap->vht_supported = true;
4483 	vht_cap->cap = cfg_11ac->param.vht_cfg.vht_cap_info;
4484 	vht_cap->vht_mcs.rx_mcs_map =
4485 		(__force __le16)cfg_11ac->param.vht_cfg.vht_rx_mcs;
4486 	vht_cap->vht_mcs.rx_highest =
4487 		(__force __le16)cfg_11ac->param.vht_cfg.vht_rx_max_rate;
4488 	vht_cap->vht_mcs.tx_mcs_map =
4489 		(__force __le16)cfg_11ac->param.vht_cfg.vht_tx_mcs;
4490 	vht_cap->vht_mcs.tx_highest =
4491 		(__force __le16)cfg_11ac->param.vht_cfg.vht_tx_max_rate;
4492 	PRINTM(MCMND,
4493 	       "vht_cap=0x%x rx_mcs_map=0x%x rx_max=0x%x tx_mcs_map=0x%x tx_max=0x%x\n",
4494 	       vht_cap->cap, vht_cap->vht_mcs.rx_mcs_map,
4495 	       vht_cap->vht_mcs.rx_highest, vht_cap->vht_mcs.tx_mcs_map,
4496 	       vht_cap->vht_mcs.tx_highest);
4497 done:
4498 	if (status != MLAN_STATUS_PENDING)
4499 		kfree(req);
4500 	LEAVE();
4501 }
4502 #endif
4503 
4504 #if KERNEL_VERSION(4, 20, 0) <= CFG80211_VERSION_CODE
4505 /*
4506 ===============
4507 11AX CAP for uAP
4508 ===============
4509 Note: bits not mentioned below are set to 0.
4510 
4511 5G
4512 ===
4513 HE MAC Cap:
4514 Bit0:  1  (+HTC HE Support)
4515 Bit25: 1  (OM Control Support. But uAP does not support
4516 	   Tx OM received from the STA, as it does not support UL OFDMA)
4517 
4518 HE PHY Cap:
4519 Bit1-7: 0x2 (Supported Channel Width Set.
4520 	     Note it would be changed after 80+80 MHz is supported)
4521 Bit8-11: 0x3 (Punctured Preamble Rx.
4522 	      Note: it would be changed after 80+80 MHz is supported)
4523 Bit12: 0x0 (Device Class)
4524 Bit13: 0x1 (LDPC coding in Payload)
4525 Bit17: 0x1 (NDP with 4xHE-LTF+3.2usGI)
4526 Bit18: 0x1 (STBC Tx <= 80 MHz)
4527 Bit19: 0x1 (STBC Rx <= 80 MHz)
4528 Bit20: 0x1 (Doppler Tx)
4529 Bit21: 0x1 (Doppler Rx)
4530 Bit27-28: 0x1 (DCM Max Constellation Rx)
4531 Bit31: 0x1 (SU Beamformer)
4532 Bit32: 0x1 (SU BeamFormee)
4533 Bit34-36: 0x7 (Beamformee STS <= 80 MHz)
4534 Bit40-42: 0x1 (Number of Sounding Dimentions <= 80 MHz)
4535 Bit53: 0x1 (Partial Bandwidth Extended Range)
4536 Bit55: 0x1 (PPE Threshold Present.
4537 	    Note: PPE threshold may have some changes later)
4538 Bit58: 0x1 (HE SU PPDU and HE MU PPDU with 4xHE-LTF+0.8usGI)
4539 Bit59-61: 0x1 (Max Nc)
4540 Bit75: 0x1 (Rx 1024-QAM Support < 242-tone RU)
4541 */
4542 
4543 #define UAP_HE_MAC_CAP0_MASK 0x00
4544 #define UAP_HE_MAC_CAP1_MASK 0x00
4545 #define UAP_HE_MAC_CAP2_MASK 0x00
4546 #define UAP_HE_MAC_CAP3_MASK 0x02
4547 #define UAP_HE_MAC_CAP4_MASK 0x00
4548 #define UAP_HE_MAC_CAP5_MASK 0x00
4549 #define UAP_HE_PHY_CAP0_MASK 0x04
4550 #define UAP_HE_PHY_CAP1_MASK 0x23
4551 #define UAP_HE_PHY_CAP2_MASK 0x3E
4552 #define UAP_HE_PHY_CAP3_MASK 0x88
4553 #define UAP_HE_PHY_CAP4_MASK 0x1D
4554 #define UAP_HE_PHY_CAP5_MASK 0x01
4555 #define UAP_HE_PHY_CAP6_MASK 0xA0
4556 #define UAP_HE_PHY_CAP7_MASK 0x0C
4557 #define UAP_HE_PHY_CAP8_MASK 0x00
4558 #define UAP_HE_PHY_CAP9_MASK 0x08
4559 #define UAP_HE_PHY_CAP10_MASK 0x00
4560 
4561 /*
4562 2G
4563 ===
4564 HE MAC Cap:
4565 Bit0:   1  (+HTC HE Support)
4566 Bit25: 1  (OM Control Support. Note: uAP does not support
4567 	Tx OM received from the STA, as it does not support UL OFDMA)
4568 
4569 HE PHY Cap:
4570 Bit1-7: 0x1 (Supported Channel Width Set)
4571 Bit8-11: 0x0 (Punctured Preamble Rx)
4572 Bit12: 0x0 (Device Class)
4573 Bit13: 0x1 (LDPC coding in Payload)
4574 Bit17: 0x1 (NDP with 4xLTF+3.2usGI)
4575 Bit18: 0x1 (STBC Tx <= 80 MHz)
4576 Bit19: 0x1 (STBC Rx <= 80 MHz)
4577 Bit20: 0x1 (Doppler Tx)
4578 Bit21: 0x1 (Doppler Rx)
4579 Bit27-28: 0x1 (DCM Max Constellation Rx)
4580 Bit31: 0x1 (SU Beamformer)
4581 Bit32: 0x1 (SU BeamFormee)
4582 Bit34-36: 0x7 (Beamformee STS <= 80 MHz)
4583 Bit40-42: 0x1 (Number of Sounding Dimentions <= 80 MHz)
4584 Bit53: 0x1 (Partial Bandwidth Extended Range)
4585 Bit55: 0x1 (PPE Threshold Present.
4586 	    Note: PPE threshold may have some changes later)
4587 Bit58: 0x1 (HE SU PPDU and HE MU PPDU with 4xHE-LTF+0.8usGI)
4588 Bit59-61: 0x1 (Max Nc)
4589 Bit75: 0x1 (Rx 1024-QAM Support < 242-tone RU)
4590 */
4591 #define UAP_HE_2G_MAC_CAP0_MASK 0x00
4592 #define UAP_HE_2G_MAC_CAP1_MASK 0x00
4593 #define UAP_HE_2G_MAC_CAP2_MASK 0x00
4594 #define UAP_HE_2G_MAC_CAP3_MASK 0x02
4595 #define UAP_HE_2G_MAC_CAP4_MASK 0x00
4596 #define UAP_HE_2G_MAC_CAP5_MASK 0x00
4597 #define UAP_HE_2G_PHY_CAP0_MASK 0x02
4598 #define UAP_HE_2G_PHY_CAP1_MASK 0x20
4599 #define UAP_HE_2G_PHY_CAP2_MASK 0x3E
4600 #define UAP_HE_2G_PHY_CAP3_MASK 0x88
4601 #define UAP_HE_2G_PHY_CAP4_MASK 0x1D
4602 #define UAP_HE_2G_PHY_CAP5_MASK 0x01
4603 #define UAP_HE_2G_PHY_CAP6_MASK 0xA0
4604 #define UAP_HE_2G_PHY_CAP7_MASK 0x0C
4605 #define UAP_HE_2G_PHY_CAP8_MASK 0x00
4606 #define UAP_HE_2G_PHY_CAP9_MASK 0x08
4607 #define UAP_HE_2G_PHY_CAP10_MASK 0x00
4608 
4609 /**
4610  *  @brief update 11ax ie for AP mode *
4611  *  @param band     channel band
4612  *  @hecap_ie       a pointer to mlan_ds_11ax_he_capa
4613  *
4614  *  @return         0--success, otherwise failure
4615  */
woal_uap_update_11ax_ie(t_u8 band,mlan_ds_11ax_he_capa * hecap_ie)4616 static void woal_uap_update_11ax_ie(t_u8 band, mlan_ds_11ax_he_capa *hecap_ie)
4617 {
4618 	if (band == BAND_5GHZ) {
4619 		hecap_ie->he_mac_cap[0] &= UAP_HE_MAC_CAP0_MASK;
4620 		hecap_ie->he_mac_cap[1] &= UAP_HE_MAC_CAP1_MASK;
4621 		hecap_ie->he_mac_cap[2] &= UAP_HE_MAC_CAP2_MASK;
4622 		hecap_ie->he_mac_cap[3] &= UAP_HE_MAC_CAP3_MASK;
4623 		hecap_ie->he_mac_cap[4] &= UAP_HE_MAC_CAP4_MASK;
4624 		hecap_ie->he_mac_cap[5] &= UAP_HE_MAC_CAP5_MASK;
4625 		hecap_ie->he_phy_cap[0] &= UAP_HE_PHY_CAP0_MASK;
4626 		hecap_ie->he_phy_cap[1] &= UAP_HE_PHY_CAP1_MASK;
4627 		hecap_ie->he_phy_cap[2] &= UAP_HE_PHY_CAP2_MASK;
4628 		hecap_ie->he_phy_cap[3] &= UAP_HE_PHY_CAP3_MASK;
4629 		hecap_ie->he_phy_cap[4] &= UAP_HE_PHY_CAP4_MASK;
4630 		hecap_ie->he_phy_cap[5] &= UAP_HE_PHY_CAP5_MASK;
4631 		hecap_ie->he_phy_cap[6] &= UAP_HE_PHY_CAP6_MASK;
4632 		hecap_ie->he_phy_cap[7] &= UAP_HE_PHY_CAP7_MASK;
4633 		hecap_ie->he_phy_cap[8] &= UAP_HE_PHY_CAP8_MASK;
4634 		hecap_ie->he_phy_cap[9] &= UAP_HE_PHY_CAP9_MASK;
4635 		hecap_ie->he_phy_cap[10] &= UAP_HE_PHY_CAP10_MASK;
4636 	} else {
4637 		hecap_ie->he_mac_cap[0] &= UAP_HE_2G_MAC_CAP0_MASK;
4638 		hecap_ie->he_mac_cap[1] &= UAP_HE_2G_MAC_CAP1_MASK;
4639 		hecap_ie->he_mac_cap[2] &= UAP_HE_2G_MAC_CAP2_MASK;
4640 		hecap_ie->he_mac_cap[3] &= UAP_HE_2G_MAC_CAP3_MASK;
4641 		hecap_ie->he_mac_cap[4] &= UAP_HE_2G_MAC_CAP4_MASK;
4642 		hecap_ie->he_mac_cap[5] &= UAP_HE_2G_MAC_CAP5_MASK;
4643 		hecap_ie->he_phy_cap[0] &= UAP_HE_2G_PHY_CAP0_MASK;
4644 		hecap_ie->he_phy_cap[1] &= UAP_HE_2G_PHY_CAP1_MASK;
4645 		hecap_ie->he_phy_cap[2] &= UAP_HE_2G_PHY_CAP2_MASK;
4646 		hecap_ie->he_phy_cap[3] &= UAP_HE_2G_PHY_CAP3_MASK;
4647 		hecap_ie->he_phy_cap[4] &= UAP_HE_2G_PHY_CAP4_MASK;
4648 		hecap_ie->he_phy_cap[5] &= UAP_HE_2G_PHY_CAP5_MASK;
4649 		hecap_ie->he_phy_cap[6] &= UAP_HE_2G_PHY_CAP6_MASK;
4650 		hecap_ie->he_phy_cap[7] &= UAP_HE_2G_PHY_CAP7_MASK;
4651 		hecap_ie->he_phy_cap[8] &= UAP_HE_2G_PHY_CAP8_MASK;
4652 		hecap_ie->he_phy_cap[9] &= UAP_HE_2G_PHY_CAP9_MASK;
4653 		hecap_ie->he_phy_cap[10] &= UAP_HE_2G_PHY_CAP10_MASK;
4654 	}
4655 	return;
4656 }
4657 
4658 /**
4659  *  @brief Sets up the CFG802.11 specific HE capability fields *  with default
4660  * values
4661  *
4662  *  @param priv         A pointer to moal private structure
4663  *  @param iftype_data  A pointer to ieee80211_sband_iftype_data structure
4664  *
4665  *  @return             N/A
4666  */
woal_cfg80211_setup_he_cap(moal_private * priv,struct ieee80211_supported_band * band)4667 void woal_cfg80211_setup_he_cap(moal_private *priv,
4668 				struct ieee80211_supported_band *band)
4669 {
4670 	mlan_fw_info fw_info;
4671 	struct ieee80211_sband_iftype_data *iftype_data = NULL;
4672 	t_u8 extra_mcs_size = 0;
4673 	int ppe_threshold_len = 0;
4674 	mlan_ds_11ax_he_capa *phe_cap = NULL;
4675 	t_u8 hw_hecap_len;
4676 
4677 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
4678 	if (band->band == NL80211_BAND_5GHZ) {
4679 		phe_cap = (mlan_ds_11ax_he_capa *)fw_info.hw_he_cap;
4680 		hw_hecap_len = fw_info.hw_hecap_len;
4681 		woal_uap_update_11ax_ie(BAND_5GHZ, phe_cap);
4682 	} else {
4683 		phe_cap = (mlan_ds_11ax_he_capa *)fw_info.hw_2g_he_cap;
4684 		hw_hecap_len = fw_info.hw_2g_hecap_len;
4685 		woal_uap_update_11ax_ie(BAND_2GHZ, phe_cap);
4686 	}
4687 
4688 	if (!hw_hecap_len)
4689 		return;
4690 	DBG_HEXDUMP(MCMD_D, "Setup HECAP", (u8 *)phe_cap, hw_hecap_len);
4691 	iftype_data =
4692 		kmalloc(sizeof(struct ieee80211_sband_iftype_data), GFP_KERNEL);
4693 	if (!iftype_data) {
4694 		PRINTM(MERROR, "Fail to allocate iftype data\n");
4695 		goto done;
4696 	}
4697 	memset(iftype_data, 0, sizeof(struct ieee80211_sband_iftype_data));
4698 	iftype_data->types_mask =
4699 		MBIT(NL80211_IFTYPE_STATION) | MBIT(NL80211_IFTYPE_AP) |
4700 		MBIT(NL80211_IFTYPE_P2P_CLIENT) | MBIT(NL80211_IFTYPE_P2P_GO);
4701 	iftype_data->he_cap.has_he = true;
4702 	moal_memcpy_ext(priv->phandle,
4703 			iftype_data->he_cap.he_cap_elem.mac_cap_info,
4704 			phe_cap->he_mac_cap, sizeof(phe_cap->he_mac_cap),
4705 			sizeof(iftype_data->he_cap.he_cap_elem.mac_cap_info));
4706 	moal_memcpy_ext(priv->phandle,
4707 			iftype_data->he_cap.he_cap_elem.phy_cap_info,
4708 			phe_cap->he_phy_cap, sizeof(phe_cap->he_phy_cap),
4709 			sizeof(iftype_data->he_cap.he_cap_elem.phy_cap_info));
4710 	memset(&iftype_data->he_cap.he_mcs_nss_supp, 0xff,
4711 	       sizeof(struct ieee80211_he_mcs_nss_supp));
4712 	moal_memcpy_ext(priv->phandle, &iftype_data->he_cap.he_mcs_nss_supp,
4713 			phe_cap->he_txrx_mcs_support,
4714 			sizeof(phe_cap->he_txrx_mcs_support),
4715 			sizeof(struct ieee80211_he_mcs_nss_supp));
4716 	// Support 160Mhz
4717 	if (phe_cap->he_phy_cap[0] & MBIT(3))
4718 		extra_mcs_size += 4;
4719 
4720 	// Support 80+80
4721 	if (phe_cap->he_phy_cap[0] & MBIT(4))
4722 		extra_mcs_size += 4;
4723 	if (extra_mcs_size)
4724 		moal_memcpy_ext(
4725 			priv->phandle,
4726 			(t_u8 *)&iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_160,
4727 			phe_cap->val, extra_mcs_size,
4728 			sizeof(struct ieee80211_he_mcs_nss_supp) - 4);
4729 
4730 #define HE_CAP_FIX_SIZE 22
4731 	// Support PPE threshold
4732 	ppe_threshold_len = phe_cap->len - HE_CAP_FIX_SIZE - extra_mcs_size;
4733 	if (phe_cap->he_phy_cap[6] & MBIT(7) && ppe_threshold_len) {
4734 		moal_memcpy_ext(priv->phandle, iftype_data->he_cap.ppe_thres,
4735 				&phe_cap->val[extra_mcs_size],
4736 				ppe_threshold_len,
4737 				sizeof(iftype_data->he_cap.ppe_thres));
4738 	} else {
4739 		iftype_data->he_cap.he_cap_elem.phy_cap_info[6] &= ~MBIT(7);
4740 		PRINTM(MCMND, "Clear PPE threshold 0x%x\n",
4741 		       iftype_data->he_cap.he_cap_elem.phy_cap_info[7]);
4742 	}
4743 	band->n_iftype_data = 1;
4744 	band->iftype_data = iftype_data;
4745 done:
4746 	LEAVE();
4747 }
4748 
4749 #endif
4750 
4751 /**
4752  *  @brief free iftype_data
4753  *
4754  *  @param wiphy        A pointer to struct wiphy
4755  *
4756  *
4757  *  @return             N/A
4758  */
woal_cfg80211_free_bands(struct wiphy * wiphy)4759 void woal_cfg80211_free_bands(struct wiphy *wiphy)
4760 {
4761 	t_u8 band;
4762 
4763 	for (band = NL80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; ++band) {
4764 		if (!wiphy->bands[band])
4765 			continue;
4766 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
4767 		if (wiphy->bands[band]->iftype_data) {
4768 			kfree(wiphy->bands[band]->iftype_data);
4769 			wiphy->bands[band]->n_iftype_data = 0;
4770 		}
4771 #endif
4772 		kfree(wiphy->bands[band]->channels);
4773 		kfree(wiphy->bands[band]);
4774 		wiphy->bands[band] = NULL;
4775 	}
4776 }
4777 
4778 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
4779 /*
4780  * @brief  prepare and send fake deauth packet to cfg80211 to
4781  *         notify wpa_supplicant about disconnection
4782  *	       <host_mlme, wiphy suspend case>
4783  *
4784  * @param priv           A pointer moal_private structure
4785  * @param reason_code    disconnect reason code
4786  *
4787  * @return          N/A
4788  */
woal_deauth_event(moal_private * priv,int reason_code)4789 void woal_deauth_event(moal_private *priv, int reason_code)
4790 {
4791 	struct woal_event *evt;
4792 	unsigned long flags;
4793 	moal_handle *handle = priv->phandle;
4794 
4795 	evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
4796 	if (!evt) {
4797 		PRINTM(MERROR, "Fail to alloc memory for deauth event\n");
4798 		LEAVE();
4799 		return;
4800 	}
4801 	evt->priv = priv;
4802 	evt->type = WOAL_EVENT_DEAUTH;
4803 	evt->reason_code = reason_code;
4804 	INIT_LIST_HEAD(&evt->link);
4805 	spin_lock_irqsave(&handle->evt_lock, flags);
4806 	list_add_tail(&evt->link, &handle->evt_queue);
4807 	spin_unlock_irqrestore(&handle->evt_lock, flags);
4808 	queue_work(handle->evt_workqueue, &handle->evt_work);
4809 }
4810 #endif
4811 
4812 #ifdef STA_CFG80211
4813 #if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
4814 /**
4815  * @brief   prepare woal_bgscan_stop event
4816  *
4817  * @param priv          A pointer moal_private structure
4818  * @param pchan_info    A pointer to chan_band structure
4819  *
4820  * @return          N/A
4821  */
woal_bgscan_stop_event(moal_private * priv)4822 void woal_bgscan_stop_event(moal_private *priv)
4823 {
4824 	struct woal_event *evt;
4825 	unsigned long flags;
4826 	moal_handle *handle = priv->phandle;
4827 
4828 	evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
4829 	if (evt) {
4830 		evt->priv = priv;
4831 		evt->type = WOAL_EVENT_BGSCAN_STOP;
4832 		INIT_LIST_HEAD(&evt->link);
4833 		spin_lock_irqsave(&handle->evt_lock, flags);
4834 		list_add_tail(&evt->link, &handle->evt_queue);
4835 		spin_unlock_irqrestore(&handle->evt_lock, flags);
4836 		queue_work(handle->evt_workqueue, &handle->evt_work);
4837 	}
4838 }
4839 
4840 /**
4841  * @brief Notify cfg80211 schedule scan stopped
4842  *
4843  * @param priv          A pointer moal_private structure
4844  *
4845  * @return          N/A
4846  */
woal_cfg80211_notify_sched_scan_stop(moal_private * priv)4847 void woal_cfg80211_notify_sched_scan_stop(moal_private *priv)
4848 {
4849 	cfg80211_sched_scan_stopped(priv->wdev->wiphy
4850 #if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE
4851 				    ,
4852 				    0
4853 #endif
4854 	);
4855 	priv->sched_scanning = MFALSE;
4856 	PRINTM(MEVENT, "Notify sched scan stopped\n");
4857 }
4858 
4859 /**
4860  * @brief report sched_scan result to kernel
4861  *
4862  * @param priv          A pointer moal_private structure
4863  *
4864  * @return          N/A
4865  */
woal_report_sched_scan_result(moal_private * priv)4866 void woal_report_sched_scan_result(moal_private *priv)
4867 {
4868 	cfg80211_sched_scan_results(priv->wdev->wiphy
4869 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
4870 				    ,
4871 				    priv->bg_scan_reqid
4872 #endif
4873 	);
4874 }
4875 #endif
4876 #endif
4877 
4878 #if KERNEL_VERSION(3, 5, 0) <= CFG80211_VERSION_CODE
4879 /**
4880  * @brief   Handle woal_channel_switch event
4881  *
4882  * @param priv          A pointer moal_private structure
4883  * @param pchan_info    A pointer to chan_band structure
4884  *
4885  * @return          N/A
4886  */
woal_channel_switch_event(moal_private * priv,chan_band_info * pchan_info)4887 void woal_channel_switch_event(moal_private *priv, chan_band_info *pchan_info)
4888 {
4889 	struct woal_event *evt;
4890 	unsigned long flags;
4891 	moal_handle *handle = priv->phandle;
4892 
4893 	evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
4894 	if (evt) {
4895 		evt->priv = priv;
4896 		evt->type = WOAL_EVENT_CHAN_SWITCH;
4897 		moal_memcpy_ext(priv->phandle, &evt->chan_info, pchan_info,
4898 				sizeof(chan_band_info), sizeof(chan_band_info));
4899 		INIT_LIST_HEAD(&evt->link);
4900 		spin_lock_irqsave(&handle->evt_lock, flags);
4901 		list_add_tail(&evt->link, &handle->evt_queue);
4902 		spin_unlock_irqrestore(&handle->evt_lock, flags);
4903 		queue_work(handle->evt_workqueue, &handle->evt_work);
4904 	}
4905 }
4906 
4907 /**
4908  * @brief Notify cfg80211 supplicant channel changed
4909  *
4910  * @param priv          A pointer moal_private structure
4911  * @param pchan_info    A pointer to chan_band structure
4912  *
4913  * @return          N/A
4914  */
woal_cfg80211_notify_channel(moal_private * priv,chan_band_info * pchan_info)4915 void woal_cfg80211_notify_channel(moal_private *priv,
4916 				  chan_band_info *pchan_info)
4917 {
4918 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
4919 	struct cfg80211_chan_def chandef;
4920 #else
4921 #if KERNEL_VERSION(3, 5, 0) <= CFG80211_VERSION_CODE
4922 	enum nl80211_channel_type type;
4923 	enum ieee80211_band band;
4924 	int freq = 0;
4925 #endif
4926 #endif
4927 	ENTER();
4928 
4929 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
4930 	if (MLAN_STATUS_SUCCESS ==
4931 	    woal_chandef_create(priv, &chandef, pchan_info)) {
4932 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
4933 		mutex_lock(&priv->wdev->mtx);
4934 #endif
4935 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
4936 		cfg80211_ch_switch_notify(priv->netdev, &chandef, 0);
4937 #else
4938 		cfg80211_ch_switch_notify(priv->netdev, &chandef);
4939 #endif
4940 #if KERNEL_VERSION(3, 14, 0) <= CFG80211_VERSION_CODE
4941 		mutex_unlock(&priv->wdev->mtx);
4942 #endif
4943 		priv->channel = pchan_info->channel;
4944 #ifdef UAP_CFG80211
4945 		moal_memcpy_ext(priv->phandle, &priv->chan, &chandef,
4946 				sizeof(struct cfg80211_chan_def),
4947 				sizeof(struct cfg80211_chan_def));
4948 #endif
4949 	}
4950 #else
4951 #if KERNEL_VERSION(3, 5, 0) <= CFG80211_VERSION_CODE
4952 	if (pchan_info->bandcfg.chanBand == BAND_2GHZ)
4953 		band = IEEE80211_BAND_2GHZ;
4954 	else if (pchan_info->bandcfg.chanBand == BAND_5GHZ)
4955 		band = IEEE80211_BAND_5GHZ;
4956 	else {
4957 		LEAVE();
4958 		return;
4959 	}
4960 	priv->channel = pchan_info->channel;
4961 	freq = ieee80211_channel_to_frequency(pchan_info->channel, band);
4962 	switch (pchan_info->bandcfg.chanWidth) {
4963 	case CHAN_BW_20MHZ:
4964 		if (pchan_info->is_11n_enabled)
4965 			type = NL80211_CHAN_HT20;
4966 		else
4967 			type = NL80211_CHAN_NO_HT;
4968 		break;
4969 	default:
4970 		if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_ABOVE)
4971 			type = NL80211_CHAN_HT40PLUS;
4972 		else if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_BELOW)
4973 			type = NL80211_CHAN_HT40MINUS;
4974 		else
4975 			type = NL80211_CHAN_HT20;
4976 		break;
4977 	}
4978 	cfg80211_ch_switch_notify(priv->netdev, freq, type);
4979 #endif
4980 #endif
4981 	LEAVE();
4982 }
4983 #endif
4984 
4985 #if defined(UAP_CFG80211) || defined(STA_CFG80211)
4986 /**
4987  * @brief Notify cfg80211 supplicant ant cfg changed
4988  *
4989  * @param priv          A pointer moal_private structure
4990  * @param wiphy         A pointer structure wiphy
4991  * @param radio         A pointer to radio cfg structure
4992  *
4993  * @return              N/A
4994  */
woal_cfg80211_notify_antcfg(moal_private * priv,struct wiphy * wiphy,mlan_ds_radio_cfg * radio)4995 void woal_cfg80211_notify_antcfg(moal_private *priv, struct wiphy *wiphy,
4996 				 mlan_ds_radio_cfg *radio)
4997 {
4998 	if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext) &&
4999 	    wiphy) {
5000 		if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
5001 			struct ieee80211_supported_band *bands =
5002 				wiphy->bands[IEEE80211_BAND_2GHZ];
5003 
5004 			if (((radio->param.ant_cfg.tx_antenna & 0xFF) != 3 &&
5005 			     (radio->param.ant_cfg.tx_antenna & 0xFF) != 0) ||
5006 			    ((radio->param.ant_cfg.rx_antenna & 0xFF) != 3 &&
5007 			     (radio->param.ant_cfg.rx_antenna & 0xFF) != 0)) {
5008 				bands->ht_cap.mcs.rx_mask[1] = 0;
5009 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
5010 				if (bands->n_iftype_data &&
5011 				    bands->iftype_data &&
5012 				    bands->iftype_data->he_cap.has_he) {
5013 					t_u16 mcs_nss[2];
5014 
5015 					mcs_nss[0] = bands->iftype_data->he_cap
5016 							     .he_mcs_nss_supp
5017 							     .rx_mcs_80;
5018 					mcs_nss[1] = mcs_nss[0] |= 0x0c;
5019 					moal_memcpy_ext(
5020 						priv->phandle,
5021 						(t_void *)&bands->iftype_data
5022 							->he_cap.he_mcs_nss_supp
5023 							.rx_mcs_80,
5024 						(t_void *)&mcs_nss,
5025 						sizeof(mcs_nss),
5026 						sizeof(bands->iftype_data->he_cap
5027 							       .he_mcs_nss_supp));
5028 				}
5029 #endif
5030 			} else if ((radio->param.ant_cfg.tx_antenna & 0xFF) ==
5031 					   3 ||
5032 				   (radio->param.ant_cfg.rx_antenna & 0xFF) ==
5033 					   3) {
5034 				bands->ht_cap.mcs.rx_mask[1] = 0xff;
5035 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
5036 				if (bands->n_iftype_data &&
5037 				    bands->iftype_data &&
5038 				    bands->iftype_data->he_cap.has_he) {
5039 					t_u16 mcs_nss[2];
5040 
5041 					mcs_nss[0] = bands->iftype_data->he_cap
5042 							     .he_mcs_nss_supp
5043 							     .rx_mcs_80;
5044 					mcs_nss[1] = mcs_nss[0] =
5045 						(mcs_nss[0] & ~0x0c) |
5046 						((mcs_nss[0] & 0x3) << 2);
5047 
5048 					moal_memcpy_ext(
5049 						priv->phandle,
5050 						(t_void *)&bands->iftype_data
5051 							->he_cap.he_mcs_nss_supp
5052 							.rx_mcs_80,
5053 						(t_void *)&mcs_nss,
5054 						sizeof(mcs_nss),
5055 						sizeof(bands->iftype_data->he_cap
5056 							       .he_mcs_nss_supp));
5057 				}
5058 #endif
5059 			}
5060 		}
5061 
5062 		if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
5063 			struct ieee80211_supported_band *bands =
5064 				wiphy->bands[IEEE80211_BAND_5GHZ];
5065 
5066 			if (((radio->param.ant_cfg.tx_antenna & 0xFF00) !=
5067 				     0x300 &&
5068 			     (radio->param.ant_cfg.tx_antenna & 0xFF00) != 0) ||
5069 			    ((radio->param.ant_cfg.rx_antenna & 0xFF00) !=
5070 				     0x300 &&
5071 			     (radio->param.ant_cfg.rx_antenna & 0xFF00) != 0)) {
5072 				bands->ht_cap.mcs.rx_mask[1] = 0;
5073 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
5074 				bands->vht_cap.vht_mcs.rx_mcs_map =
5075 					(__force __le16)0xfffe;
5076 				bands->vht_cap.vht_mcs.tx_mcs_map =
5077 					(__force __le16)0xfffe;
5078 				bands->vht_cap.vht_mcs.rx_highest =
5079 					(__force __le16)0x186;
5080 				bands->vht_cap.vht_mcs.tx_highest =
5081 					(__force __le16)0x186;
5082 #endif
5083 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
5084 				if (bands->n_iftype_data &&
5085 				    bands->iftype_data &&
5086 				    bands->iftype_data->he_cap.has_he) {
5087 					t_u16 mcs_nss[2];
5088 
5089 					mcs_nss[0] = bands->iftype_data->he_cap
5090 							     .he_mcs_nss_supp
5091 							     .rx_mcs_80;
5092 					mcs_nss[1] = mcs_nss[0] |= 0x0c;
5093 					moal_memcpy_ext(
5094 						priv->phandle,
5095 						(t_void *)&bands->iftype_data
5096 							->he_cap.he_mcs_nss_supp
5097 							.rx_mcs_80,
5098 						(t_void *)&mcs_nss,
5099 						sizeof(mcs_nss),
5100 						sizeof(bands->iftype_data->he_cap
5101 							       .he_mcs_nss_supp));
5102 				}
5103 #endif
5104 			} else if ((radio->param.ant_cfg.tx_antenna & 0xFF00) ==
5105 					   0x300 ||
5106 				   (radio->param.ant_cfg.rx_antenna & 0xFF00) ==
5107 					   0x300) {
5108 				bands->ht_cap.mcs.rx_mask[1] = 0xff;
5109 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
5110 				bands->vht_cap.vht_mcs.rx_mcs_map =
5111 					(__force __le16)0xfffa;
5112 				bands->vht_cap.vht_mcs.tx_mcs_map =
5113 					(__force __le16)0xfffa;
5114 				bands->vht_cap.vht_mcs.rx_highest =
5115 					(__force __le16)0x30c;
5116 				bands->vht_cap.vht_mcs.tx_highest =
5117 					(__force __le16)0x30c;
5118 #endif
5119 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
5120 				if (bands->n_iftype_data &&
5121 				    bands->iftype_data &&
5122 				    bands->iftype_data->he_cap.has_he) {
5123 					t_u16 mcs_nss[2];
5124 
5125 					mcs_nss[0] = bands->iftype_data->he_cap
5126 							     .he_mcs_nss_supp
5127 							     .rx_mcs_80;
5128 					mcs_nss[1] = mcs_nss[0] =
5129 						(mcs_nss[0] & ~0x0c) |
5130 						((mcs_nss[0] & 0x3) << 2);
5131 
5132 					moal_memcpy_ext(
5133 						priv->phandle,
5134 						(t_void *)&bands->iftype_data
5135 							->he_cap.he_mcs_nss_supp
5136 							.rx_mcs_80,
5137 						(t_void *)&mcs_nss,
5138 						sizeof(mcs_nss),
5139 						sizeof(bands->iftype_data->he_cap
5140 							       .he_mcs_nss_supp));
5141 				}
5142 #endif
5143 			}
5144 		}
5145 	}
5146 }
5147 #endif
5148 
5149 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
5150 /**
5151  * @brief create cfg80211_chan_def structure based on chan_band info
5152  *
5153  * @param priv          A pointer moal_private structure
5154  * @param chandef       A pointer to cfg80211_chan_def structure
5155  * @param pchan_info    A pointer to chan_band_info structure
5156  *
5157  * @return              MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE
5158  */
woal_chandef_create(moal_private * priv,struct cfg80211_chan_def * chandef,chan_band_info * pchan_info)5159 mlan_status woal_chandef_create(moal_private *priv,
5160 				struct cfg80211_chan_def *chandef,
5161 				chan_band_info *pchan_info)
5162 {
5163 	enum ieee80211_band band = IEEE80211_BAND_2GHZ;
5164 	mlan_status status = MLAN_STATUS_SUCCESS;
5165 
5166 	ENTER();
5167 	memset(chandef, 0, sizeof(struct cfg80211_chan_def));
5168 	chandef->center_freq2 = 0;
5169 	if (pchan_info->bandcfg.chanBand == BAND_2GHZ)
5170 		band = IEEE80211_BAND_2GHZ;
5171 	else if (pchan_info->bandcfg.chanBand == BAND_5GHZ)
5172 		band = IEEE80211_BAND_5GHZ;
5173 	chandef->chan = ieee80211_get_channel(
5174 		priv->wdev->wiphy,
5175 		ieee80211_channel_to_frequency(pchan_info->channel, band));
5176 	if (chandef->chan == NULL) {
5177 		PRINTM(MERROR,
5178 		       "Fail on ieee80211_get_channel, channel=%d, band=%d\n",
5179 		       pchan_info->channel, band);
5180 		status = MLAN_STATUS_FAILURE;
5181 		goto done;
5182 	}
5183 	switch (pchan_info->bandcfg.chanWidth) {
5184 	case CHAN_BW_20MHZ:
5185 		if (pchan_info->is_11n_enabled)
5186 			chandef->width = NL80211_CHAN_WIDTH_20;
5187 		else
5188 			chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
5189 		chandef->center_freq1 = chandef->chan->center_freq;
5190 		break;
5191 	case CHAN_BW_40MHZ:
5192 		chandef->width = NL80211_CHAN_WIDTH_40;
5193 		if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_ABOVE)
5194 			chandef->center_freq1 = chandef->chan->center_freq + 10;
5195 		else if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_BELOW)
5196 			chandef->center_freq1 = chandef->chan->center_freq - 10;
5197 		break;
5198 	case CHAN_BW_80MHZ:
5199 		chandef->width = NL80211_CHAN_WIDTH_80;
5200 		chandef->center_freq1 = ieee80211_channel_to_frequency(
5201 			pchan_info->center_chan, band);
5202 		break;
5203 	default:
5204 		break;
5205 	}
5206 done:
5207 	LEAVE();
5208 	return status;
5209 }
5210 #endif
5211 
5212 /**
5213  * @brief Set given radar channel dfs_state to AVAILABLE
5214  *
5215  * @param wiphy           A pointer to struct wiphy
5216  *
5217  * @return                N/A
5218  */
woal_clear_wiphy_dfs_state(struct wiphy * wiphy)5219 void woal_clear_wiphy_dfs_state(struct wiphy *wiphy)
5220 {
5221 	struct ieee80211_supported_band *sband;
5222 	int i;
5223 
5224 	ENTER();
5225 	if (!wiphy) {
5226 		LEAVE();
5227 		return;
5228 	}
5229 	sband = wiphy->bands[NL80211_BAND_5GHZ];
5230 
5231 	if (!sband) {
5232 		LEAVE();
5233 		return;
5234 	}
5235 
5236 	for (i = 0; i < sband->n_channels; i++) {
5237 		if (sband->channels[i].flags & IEEE80211_CHAN_RADAR) {
5238 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
5239 			if (sband->channels[i].dfs_state ==
5240 			    NL80211_DFS_UNAVAILABLE) {
5241 				sband->channels[i].dfs_state =
5242 					NL80211_DFS_USABLE;
5243 				sband->channels[i].dfs_state_entered = jiffies;
5244 			}
5245 #endif
5246 		}
5247 	}
5248 	LEAVE();
5249 }
5250 
5251 /**
5252  * @brief Set given radar channel dfs_state to AVAILABLE
5253  *
5254  * @param wiphy           A pointer to struct wiphy
5255  * @param ch_dfs_state    A pointer to struct mlan_ds_11h_chan_dfs_state
5256  *
5257  * @return                N/A
5258  */
woal_get_wiphy_chan_dfs_state(struct wiphy * wiphy,mlan_ds_11h_chan_dfs_state * ch_dfs_state)5259 int woal_get_wiphy_chan_dfs_state(struct wiphy *wiphy,
5260 				  mlan_ds_11h_chan_dfs_state *ch_dfs_state)
5261 {
5262 	struct ieee80211_supported_band *sband;
5263 	int i;
5264 	int ret = -1;
5265 	t_u8 channel = ch_dfs_state->channel;
5266 
5267 	ENTER();
5268 	if (!wiphy) {
5269 		LEAVE();
5270 		return ret;
5271 	}
5272 	sband = wiphy->bands[NL80211_BAND_5GHZ];
5273 
5274 	if (!sband) {
5275 		LEAVE();
5276 		return ret;
5277 	}
5278 	ch_dfs_state->dfs_required = MFALSE;
5279 	for (i = 0; i < sband->n_channels; i++) {
5280 		if (sband->channels[i].hw_value == channel) {
5281 			if (sband->channels[i].flags & IEEE80211_CHAN_RADAR) {
5282 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
5283 				ch_dfs_state->dfs_state =
5284 					(dfs_state_t)sband->channels[i]
5285 						.dfs_state;
5286 				ch_dfs_state->dfs_required = MTRUE;
5287 #endif
5288 			}
5289 			ret = 0;
5290 			break;
5291 		}
5292 	}
5293 	LEAVE();
5294 	return ret;
5295 }
5296 
5297 /**
5298  * @brief Set given radar channel dfs_state to AVAILABLE
5299  *
5300  * @param wiphy           A pointer to struct wiphy
5301  * @param channel         given radar channel
5302  * @param dfs_state       dfs_state
5303  *
5304  * @return                N/A
5305  */
woal_update_wiphy_chan_dfs_state(struct wiphy * wiphy,t_u8 channel,t_u8 dfs_state)5306 static void woal_update_wiphy_chan_dfs_state(struct wiphy *wiphy, t_u8 channel,
5307 					     t_u8 dfs_state)
5308 {
5309 	struct ieee80211_supported_band *sband;
5310 	int i;
5311 
5312 	ENTER();
5313 	if (!wiphy) {
5314 		LEAVE();
5315 		return;
5316 	}
5317 	sband = wiphy->bands[NL80211_BAND_5GHZ];
5318 
5319 	if (!sband) {
5320 		LEAVE();
5321 		return;
5322 	}
5323 
5324 	for (i = 0; i < sband->n_channels; i++) {
5325 		if (sband->channels[i].flags & IEEE80211_CHAN_RADAR) {
5326 			if (sband->channels[i].hw_value == channel) {
5327 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
5328 				sband->channels[i].dfs_state = dfs_state;
5329 				sband->channels[i].dfs_state_entered = jiffies;
5330 #endif
5331 				break;
5332 			}
5333 		}
5334 	}
5335 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 8, 13)
5336 	if (i < sband->n_channels)
5337 		PRINTM(MCMD_D, "DFS: Set channel %d dfs_state: %d\n", channel,
5338 		       sband->channels[i].dfs_state);
5339 #endif
5340 	LEAVE();
5341 }
5342 /**
5343  * @brief Set given radar channel dfs_state
5344  *
5345  * @param wiphy           A pointer to wiphy structure
5346  * @param channel         given radar channel
5347  * @param dfs_state       dfs_state
5348  *
5349  * @return                N/A
5350  */
woal_update_wiphy_channel_dfs_state(struct wiphy * wiphy,t_u8 channel,t_u8 dfs_state)5351 static void woal_update_wiphy_channel_dfs_state(struct wiphy *wiphy,
5352 						t_u8 channel, t_u8 dfs_state)
5353 {
5354 	if (!wiphy) {
5355 		LEAVE();
5356 		return;
5357 	}
5358 	woal_update_wiphy_chan_dfs_state(wiphy, channel, dfs_state);
5359 }
5360 
5361 /**
5362  * @brief update channel dfs state to all wiphy
5363  *
5364  * @param channel         given radar channel
5365  * @param dfs_state       dfs_state
5366  *
5367  * @return                N/A
5368  */
woal_update_channel_dfs_state(t_u8 channel,t_u8 dfs_state)5369 void woal_update_channel_dfs_state(t_u8 channel, t_u8 dfs_state)
5370 {
5371 	int index;
5372 	for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
5373 		if (m_handle[index] && m_handle[index]->wiphy)
5374 			woal_update_wiphy_channel_dfs_state(
5375 				m_handle[index]->wiphy, channel, dfs_state);
5376 	}
5377 }
5378