xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlinux/moal_cfg80211.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file moal_cfg80211.c
2   *
3   * @brief This file contains the functions for CFG80211.
4   *
5   * Copyright (C) 2011-2017, Marvell International Ltd.
6   *
7   * This software file (the "File") is distributed by Marvell International
8   * Ltd. under the terms of the GNU General Public License Version 2, June 1991
9   * (the "License").  You may use, redistribute and/or modify this File in
10   * accordance with the terms and conditions of the License, a copy of which
11   * is available by writing to the Free Software Foundation, Inc.,
12   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
13   * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14   *
15   * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16   * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17   * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
18   * this warranty disclaimer.
19   *
20   */
21 
22 #include    "moal_cfg80211.h"
23 #ifdef UAP_CFG80211
24 #ifdef UAP_SUPPORT
25 #include    "moal_uap.h"
26 #endif
27 #endif
28 
29 /********************************************************
30 				Local Variables
31 ********************************************************/
32 /** Supported rates to be advertised to the cfg80211 */
33 static struct ieee80211_rate cfg80211_rates[] = {
34 	{.bitrate = 10,.hw_value = 2,},
35 	{.bitrate = 20,.hw_value = 4,},
36 	{.bitrate = 55,.hw_value = 11},
37 	{.bitrate = 110,.hw_value = 22,},
38 	{.bitrate = 220,.hw_value = 44,},
39 	{.bitrate = 60,.hw_value = 12,},
40 	{.bitrate = 90,.hw_value = 18,},
41 	{.bitrate = 120,.hw_value = 24,},
42 	{.bitrate = 180,.hw_value = 36,},
43 	{.bitrate = 240,.hw_value = 48,},
44 	{.bitrate = 360,.hw_value = 72,},
45 	{.bitrate = 480,.hw_value = 96,},
46 	{.bitrate = 540,.hw_value = 108,},
47 	{.bitrate = 720,.hw_value = 144,},
48 };
49 
50 /** Channel definitions for 2 GHz to be advertised to cfg80211 */
51 static struct ieee80211_channel cfg80211_channels_2ghz[] = {
52 	{.center_freq = 2412,.hw_value = 1,.max_power = 20},
53 	{.center_freq = 2417,.hw_value = 2,.max_power = 20},
54 	{.center_freq = 2422,.hw_value = 3,.max_power = 20},
55 	{.center_freq = 2427,.hw_value = 4,.max_power = 20},
56 	{.center_freq = 2432,.hw_value = 5,.max_power = 20},
57 	{.center_freq = 2437,.hw_value = 6,.max_power = 20},
58 	{.center_freq = 2442,.hw_value = 7,.max_power = 20},
59 	{.center_freq = 2447,.hw_value = 8,.max_power = 20},
60 	{.center_freq = 2452,.hw_value = 9,.max_power = 20},
61 	{.center_freq = 2457,.hw_value = 10,.max_power = 20},
62 	{.center_freq = 2462,.hw_value = 11,.max_power = 20},
63 	{.center_freq = 2467,.hw_value = 12,.max_power = 20},
64 	{.center_freq = 2472,.hw_value = 13,.max_power = 20},
65 	{.center_freq = 2484,.hw_value = 14,.max_power = 20},
66 };
67 
68 /** Channel definitions for 5 GHz to be advertised to cfg80211 */
69 static struct ieee80211_channel cfg80211_channels_5ghz[] = {
70 	{.center_freq = 5180,.hw_value = 36,.max_power = 20},
71 	{.center_freq = 5200,.hw_value = 40,.max_power = 20},
72 	{.center_freq = 5220,.hw_value = 44,.max_power = 20},
73 	{.center_freq = 5240,.hw_value = 48,.max_power = 20},
74 	{.center_freq = 5260,.hw_value = 52,.max_power = 20},
75 	{.center_freq = 5280,.hw_value = 56,.max_power = 20},
76 	{.center_freq = 5300,.hw_value = 60,.max_power = 20},
77 	{.center_freq = 5320,.hw_value = 64,.max_power = 20},
78 	{.center_freq = 5500,.hw_value = 100,.max_power = 20},
79 	{.center_freq = 5520,.hw_value = 104,.max_power = 20},
80 	{.center_freq = 5540,.hw_value = 108,.max_power = 20},
81 	{.center_freq = 5560,.hw_value = 112,.max_power = 20},
82 	{.center_freq = 5580,.hw_value = 116,.max_power = 20},
83 	{.center_freq = 5600,.hw_value = 120,.max_power = 20},
84 	{.center_freq = 5620,.hw_value = 124,.max_power = 20},
85 	{.center_freq = 5640,.hw_value = 128,.max_power = 20},
86 	{.center_freq = 5660,.hw_value = 132,.max_power = 20},
87 	{.center_freq = 5680,.hw_value = 136,.max_power = 20},
88 	{.center_freq = 5700,.hw_value = 140,.max_power = 20},
89 	{.center_freq = 5745,.hw_value = 149,.max_power = 20},
90 	{.center_freq = 5765,.hw_value = 153,.max_power = 20},
91 	{.center_freq = 5785,.hw_value = 157,.max_power = 20},
92 	{.center_freq = 5805,.hw_value = 161,.max_power = 20},
93 	{.center_freq = 5825,.hw_value = 165,.max_power = 20},
94 };
95 
96 /********************************************************
97 				Global Variables
98 ********************************************************/
99 extern int cfg80211_wext;
100 
101 struct ieee80211_supported_band cfg80211_band_2ghz = {
102 	.channels = cfg80211_channels_2ghz,
103 	.n_channels = ARRAY_SIZE(cfg80211_channels_2ghz),
104 	.bitrates = cfg80211_rates,
105 	.n_bitrates = ARRAY_SIZE(cfg80211_rates),
106 };
107 
108 struct ieee80211_supported_band cfg80211_band_5ghz = {
109 	.channels = cfg80211_channels_5ghz,
110 	.n_channels = ARRAY_SIZE(cfg80211_channels_5ghz),
111 	.bitrates = cfg80211_rates + 5,
112 	.n_bitrates = ARRAY_SIZE(cfg80211_rates) - 5,
113 };
114 
115 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
116 #ifdef UAP_SUPPORT
117 /** Network device handlers for uAP */
118 extern const struct net_device_ops woal_uap_netdev_ops;
119 #endif
120 #ifdef STA_SUPPORT
121 /** Network device handlers for STA */
122 extern const struct net_device_ops woal_netdev_ops;
123 #endif
124 #endif
125 
126 /** gtk rekey offload mode */
127 extern int gtk_rekey_offload;
128 /********************************************************
129 				Local Functions
130 ********************************************************/
131 
132 /********************************************************
133 				Global Functions
134 ********************************************************/
135 
136 /**
137  * @brief Get the private structure from wiphy
138  *
139  * @param wiphy     A pointer to wiphy structure
140  *
141  * @return          Pointer to moal_private
142  */
143 void *
woal_get_wiphy_priv(struct wiphy * wiphy)144 woal_get_wiphy_priv(struct wiphy *wiphy)
145 {
146 	return (void *)(*(unsigned long *)wiphy_priv(wiphy));
147 }
148 
149 /**
150  * @brief Get the private structure from net device
151  *
152  * @param dev       A pointer to net_device structure
153  *
154  * @return          Pointer to moal_private
155  */
156 void *
woal_get_netdev_priv(struct net_device * dev)157 woal_get_netdev_priv(struct net_device *dev)
158 {
159 	return (void *)netdev_priv(dev);
160 }
161 
162 /**
163  *  @brief Get current frequency of active interface
164  *
165  *  @param priv        A pointer to moal_private
166  *
167  *  @return              channel frequency
168  */
169 int
woal_get_active_intf_freq(moal_private * priv)170 woal_get_active_intf_freq(moal_private *priv)
171 {
172 	moal_handle *handle = priv->phandle;
173 	int i;
174 	for (i = 0; i < handle->priv_num; i++) {
175 #ifdef STA_SUPPORT
176 		if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) {
177 			if ((handle->priv[i]->media_connected == MTRUE) &&
178 			    (handle->priv[i]->bss_type == priv->bss_type))
179 				return ieee80211_channel_to_frequency(handle->
180 								      priv[i]->
181 								      channel
182 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
183 								      ,
184 								      (handle->
185 								       priv[i]->
186 								       channel
187 								       <=
188 								       14 ?
189 								       IEEE80211_BAND_2GHZ
190 								       :
191 								       IEEE80211_BAND_5GHZ)
192 #endif
193 					);
194 
195 		}
196 #endif
197 #ifdef UAP_SUPPORT
198 		if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) {
199 			if ((handle->priv[i]->bss_started == MTRUE) &&
200 			    (handle->priv[i]->bss_type == priv->bss_type))
201 				return ieee80211_channel_to_frequency(handle->
202 								      priv[i]->
203 								      channel
204 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
205 								      ,
206 								      (handle->
207 								       priv[i]->
208 								       channel
209 								       <=
210 								       14 ?
211 								       IEEE80211_BAND_2GHZ
212 								       :
213 								       IEEE80211_BAND_5GHZ)
214 #endif
215 					);
216 		}
217 #endif
218 	}
219 	return 0;
220 }
221 
222 /**
223  *  @brief Convert driver band configuration to IEEE band type
224  *
225  *  @param band     Driver band configuration
226  *
227  *  @return         IEEE band type
228  */
229 t_u8
woal_band_cfg_to_ieee_band(t_u32 band)230 woal_band_cfg_to_ieee_band(t_u32 band)
231 {
232 	t_u8 ret_radio_type;
233 
234 	ENTER();
235 
236 	switch (band) {
237 	case BAND_A:
238 	case BAND_AN:
239 	case BAND_A | BAND_AN:
240 		ret_radio_type = IEEE80211_BAND_5GHZ;
241 		break;
242 	case BAND_B:
243 	case BAND_G:
244 	case BAND_B | BAND_G:
245 	case BAND_GN:
246 	case BAND_B | BAND_GN:
247 	default:
248 		ret_radio_type = IEEE80211_BAND_2GHZ;
249 		break;
250 	}
251 
252 	LEAVE();
253 	return ret_radio_type;
254 }
255 
256 /**
257  *  @brief Set/Enable encryption key
258  *
259  *  @param priv             A pointer to moal_private structure
260  *  @param is_enable_wep    Enable WEP default key
261  *  @param cipher           Cipher suite selector
262  *  @param key              A pointer to key
263  *  @param key_len          Key length
264  *  @param seq              A pointer to sequence
265  *  @param seq_len          Sequence length
266  *  @param key_index        Key index
267  *  @param addr             Mac for which key is to be set
268  *  @param disable          Key disabled or not
269  *  @param wait_option      wait option
270  *
271  *  @return                 MLAN_STATUS_SUCCESS -- success, otherwise fail
272  */
273 mlan_status
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)274 woal_cfg80211_set_key(moal_private *priv, t_u8 is_enable_wep,
275 		      t_u32 cipher, const t_u8 *key, int key_len,
276 		      const t_u8 *seq, int seq_len, t_u8 key_index,
277 		      const t_u8 *addr, int disable, t_u8 wait_option)
278 {
279 	mlan_ioctl_req *req = NULL;
280 	mlan_ds_sec_cfg *sec = NULL;
281 	mlan_status ret = MLAN_STATUS_SUCCESS;
282 	t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
283 
284 	ENTER();
285 
286 #ifdef UAP_CFG80211
287 #ifdef UAP_SUPPORT
288 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
289 		if (is_enable_wep) {
290 			PRINTM(MIOCTL, "Enable UAP default key=%d\n",
291 			       key_index);
292 			priv->uap_wep_key[key_index].is_default = MTRUE;
293 			goto done;
294 		}
295 		if (key && key_len &&
296 		    ((cipher == WLAN_CIPHER_SUITE_WEP40) ||
297 		     (cipher == WLAN_CIPHER_SUITE_WEP104))) {
298 			priv->uap_wep_key[key_index].length = key_len;
299 			memcpy(priv->uap_wep_key[key_index].key, key, key_len);
300 			priv->cipher = cipher;
301 			priv->uap_wep_key[key_index].key_index = key_index;
302 			priv->uap_wep_key[key_index].is_default = MFALSE;
303 			PRINTM(MIOCTL, "Set UAP WEP key: key_index=%d len=%d\n",
304 			       key_index, key_len);
305 			goto done;
306 		}
307 	}
308 #endif
309 #endif
310 
311 	/* Allocate an IOCTL request buffer */
312 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
313 	if (req == NULL) {
314 		ret = MLAN_STATUS_FAILURE;
315 		goto done;
316 	}
317 
318 	/* Fill request buffer */
319 	sec = (mlan_ds_sec_cfg *)req->pbuf;
320 	sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
321 	req->req_id = MLAN_IOCTL_SEC_CFG;
322 	req->action = MLAN_ACT_SET;
323 
324 	if (is_enable_wep) {
325 		sec->param.encrypt_key.key_index = key_index;
326 		sec->param.encrypt_key.is_current_wep_key = MTRUE;
327 	} else if (!disable) {
328 		if (cipher != WLAN_CIPHER_SUITE_WEP40 &&
329 		    cipher != WLAN_CIPHER_SUITE_WEP104 &&
330 		    cipher != WLAN_CIPHER_SUITE_TKIP &&
331 		    cipher != WLAN_CIPHER_SUITE_SMS4 &&
332 		    cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
333 		    cipher != WLAN_CIPHER_SUITE_CCMP) {
334 			PRINTM(MERROR, "Invalid cipher suite specified\n");
335 			ret = MLAN_STATUS_FAILURE;
336 			goto done;
337 		}
338 		sec->param.encrypt_key.key_index = key_index;
339 		if (key && key_len) {
340 			memcpy(sec->param.encrypt_key.key_material, key,
341 			       key_len);
342 			sec->param.encrypt_key.key_len = key_len;
343 		}
344 		/* Set WAPI key */
345 		if (cipher == WLAN_CIPHER_SUITE_SMS4) {
346 			sec->param.encrypt_key.is_wapi_key = MTRUE;
347 			if (seq_len) {
348 				memcpy(sec->param.encrypt_key.pn, seq, PN_SIZE);
349 				DBG_HEXDUMP(MCMD_D, "WAPI PN",
350 					    sec->param.encrypt_key.pn, seq_len);
351 			}
352 		}
353 		if (addr) {
354 			memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN);
355 			if (0 ==
356 			    memcmp(sec->param.encrypt_key.mac_addr, bcast_addr,
357 				   ETH_ALEN))
358 				 sec->param.encrypt_key.key_flags =
359 					KEY_FLAG_GROUP_KEY;
360 			else
361 				sec->param.encrypt_key.key_flags =
362 					KEY_FLAG_SET_TX_KEY;
363 		} else {
364 			memcpy(sec->param.encrypt_key.mac_addr, bcast_addr,
365 			       ETH_ALEN);
366 			sec->param.encrypt_key.key_flags =
367 				KEY_FLAG_GROUP_KEY | KEY_FLAG_SET_TX_KEY;
368 		}
369 		if (seq && seq_len) {
370 			memcpy(sec->param.encrypt_key.pn, seq, seq_len);
371 			sec->param.encrypt_key.key_flags |=
372 				KEY_FLAG_RX_SEQ_VALID;
373 		}
374 
375 		if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
376 			sec->param.encrypt_key.key_flags |=
377 				KEY_FLAG_AES_MCAST_IGTK;
378 		}
379 	} else {
380 		if (key_index == KEY_INDEX_CLEAR_ALL)
381 			sec->param.encrypt_key.key_disable = MTRUE;
382 		else {
383 			sec->param.encrypt_key.key_remove = MTRUE;
384 			sec->param.encrypt_key.key_index = key_index;
385 		}
386 		sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY;
387 		if (addr)
388 			memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN);
389 	}
390 
391 	/* Send IOCTL request to MLAN */
392 	ret = woal_request_ioctl(priv, req, wait_option);
393 
394 done:
395 	if (ret != MLAN_STATUS_PENDING)
396 		kfree(req);
397 	LEAVE();
398 	return ret;
399 }
400 
401 /**
402  * @brief Set/Enable the WEP key to driver
403  *
404  * @param priv      A pointer to moal_private structure
405  * @param key       A pointer to key data
406  * @param key_len   Length of the key data
407  * @param index     Key index
408  * @param wait_option wait_option
409  *
410  * @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
411  */
412 mlan_status
woal_cfg80211_set_wep_keys(moal_private * priv,const t_u8 * key,int key_len,t_u8 index,t_u8 wait_option)413 woal_cfg80211_set_wep_keys(moal_private *priv, const t_u8 *key, int key_len,
414 			   t_u8 index, t_u8 wait_option)
415 {
416 	mlan_status ret = MLAN_STATUS_SUCCESS;
417 	t_u32 cipher = 0;
418 
419 	ENTER();
420 
421 	if (key_len) {
422 		if (key_len == 5)
423 			cipher = WLAN_CIPHER_SUITE_WEP40;
424 		else
425 			cipher = WLAN_CIPHER_SUITE_WEP104;
426 		ret = woal_cfg80211_set_key(priv, 0, cipher, key, key_len, NULL,
427 					    0, index, NULL, 0, wait_option);
428 	} else {
429 		/* No key provided so it is enable key. We
430 		 * want to just set the transmit key index */
431 		woal_cfg80211_set_key(priv, 1, cipher, key, key_len, NULL, 0,
432 				      index, NULL, 0, wait_option);
433 	}
434 
435 	LEAVE();
436 	return ret;
437 }
438 
439 /**
440  * @brief clear all mgmt ies
441  *
442  * @param priv              A pointer to moal private structure
443  * @param wait_option       wait_option
444  * @return                  N/A
445  */
446 void
woal_clear_all_mgmt_ies(moal_private * priv,t_u8 wait_option)447 woal_clear_all_mgmt_ies(moal_private *priv, t_u8 wait_option)
448 {
449 	t_u16 mask = 0;
450 	/* clear BEACON WPS/P2P IE */
451 	if (priv->beacon_wps_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
452 		PRINTM(MCMND, "Clear BEACON WPS ie\n");
453 		woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0,
454 					    NULL, 0, MGMT_MASK_BEACON_WPS_P2P,
455 					    wait_option);
456 		priv->beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
457 	}
458 	if (priv->assocresp_qos_map_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
459 		PRINTM(MCMND, "Clear associate response QOS map ie\n");
460 		woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0,
461 					    NULL, 0,
462 					    MGMT_MASK_ASSOC_RESP_QOS_MAP,
463 					    wait_option);
464 		priv->assocresp_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
465 	}
466 	/* clear mgmt frame ies */
467 	if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
468 		mask |= MGMT_MASK_PROBE_REQ;
469 	if (priv->beacon_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
470 		mask |= MGMT_MASK_BEACON;
471 	if (priv->proberesp_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
472 		mask |= MGMT_MASK_PROBE_RESP;
473 	if (priv->assocresp_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
474 		mask |= MGMT_MASK_ASSOC_RESP;
475 	if (priv->proberesp_p2p_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
476 		mask |= MGMT_MASK_PROBE_RESP;
477 	if (priv->proberesp_vendor_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
478 		mask |= MGMT_MASK_PROBE_RESP;
479 	if (mask) {
480 		PRINTM(MCMND, "Clear IES: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
481 		       priv->beacon_index, priv->probereq_index,
482 		       priv->proberesp_index, priv->assocresp_index,
483 		       priv->proberesp_p2p_index, priv->proberesp_vendor_index);
484 		woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0,
485 					    NULL, 0, mask, wait_option);
486 	}
487 	priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
488 	priv->beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
489 	priv->proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
490 	priv->assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
491 	priv->proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
492 	priv->proberesp_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
493 }
494 
495 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
496 /**
497  * @brief set bss role
498  *
499  * @param priv              A pointer to moal private structure
500  * @param action            Action: set or get
501  * @param role              A pointer to bss role
502  *
503  * @return                  0 -- success, otherwise fail
504  */
505 int
woal_cfg80211_bss_role_cfg(moal_private * priv,t_u16 action,t_u8 * bss_role)506 woal_cfg80211_bss_role_cfg(moal_private *priv, t_u16 action, t_u8 *bss_role)
507 {
508 	int ret = 0;
509 
510 	ENTER();
511 
512 	if (action == MLAN_ACT_SET) {
513 		/* Reset interface */
514 		woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE);
515 	}
516 
517 	if (MLAN_STATUS_SUCCESS !=
518 	    woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, bss_role)) {
519 		ret = -EFAULT;
520 		goto done;
521 	}
522 
523 	if (action == MLAN_ACT_SET) {
524 		/* set back the mac address */
525 		woal_request_set_mac_address(priv);
526 		/* clear the mgmt ies */
527 		woal_clear_all_mgmt_ies(priv, MOAL_IOCTL_WAIT);
528 		/* Initialize private structures */
529 		woal_init_priv(priv, MOAL_IOCTL_WAIT);
530 
531 		/* Enable interfaces */
532 		netif_device_attach(priv->netdev);
533 		woal_start_queue(priv->netdev);
534 	}
535 
536 done:
537 	LEAVE();
538 	return ret;
539 }
540 #endif
541 
542 #if defined(WIFI_DIRECT_SUPPORT)
543 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
544 /**
545  *  @brief This function display P2P public action frame type
546  *
547  *  @param  buf      A buffer to a management frame
548  *  @param  len      buffer len
549  *  @param chan      the channel
550  *  @param flag      Tx/Rx flag. Tx:flag = 1;Rx:flag = 0;
551  *
552  *  @return          N/A
553  */
554 void
woal_cfg80211_display_p2p_actframe(const t_u8 * buf,int len,struct ieee80211_channel * chan,const t_u8 flag)555 woal_cfg80211_display_p2p_actframe(const t_u8 *buf, int len,
556 				   struct ieee80211_channel *chan,
557 				   const t_u8 flag)
558 {
559 	const t_u8 p2p_oui[] = { 0x50, 0x6f, 0x9a, 0x09 };
560 	t_u8 subtype;
561 
562 	ENTER();
563 
564 	if (!buf || len < (P2P_ACT_FRAME_OUI_SUBTYPE_OFFSET + 1)) {
565 		LEAVE();
566 		return;
567 	}
568 
569 	if (((struct ieee80211_mgmt *)buf)->u.action.category ==
570 	    P2P_ACT_FRAME_CATEGORY &&
571 	    !memcmp(buf + P2P_ACT_FRAME_OUI_OFFSET, p2p_oui, sizeof(p2p_oui))) {
572 		subtype = *(buf + P2P_ACT_FRAME_OUI_SUBTYPE_OFFSET);
573 		switch (subtype) {
574 		case P2P_GO_NEG_REQ:
575 			PRINTM(MMSG,
576 			       "wlan: %s P2P Group Owner Negotiation Req Frame, channel=%d\n",
577 			       (flag) ? "TX" : "RX",
578 			       (chan) ? chan->hw_value : 0);
579 			break;
580 		case P2P_GO_NEG_RSP:
581 			PRINTM(MMSG,
582 			       "wlan: %s P2P Group Owner Negotiation Rsp Frame, channel=%d\n",
583 			       (flag) ? "TX" : "RX",
584 			       (chan) ? chan->hw_value : 0);
585 			break;
586 		case P2P_GO_NEG_CONF:
587 			PRINTM(MMSG,
588 			       "wlan: %s P2P Group Owner Negotiation Confirm Frame, channel=%d\n",
589 			       (flag) ? "TX" : "RX",
590 			       (chan) ? chan->hw_value : 0);
591 			break;
592 		case P2P_INVITE_REQ:
593 			PRINTM(MMSG,
594 			       "wlan: %s P2P Invitation Request, channel=%d\n",
595 			       (flag) ? "TX" : "RX",
596 			       (chan) ? chan->hw_value : 0);
597 			break;
598 		case P2P_INVITE_RSP:
599 			PRINTM(MMSG,
600 			       "wlan: %s P2P Invitation Response, channel=%d\n",
601 			       (flag) ? "TX" : "RX",
602 			       (chan) ? chan->hw_value : 0);
603 			break;
604 		case P2P_DEVDIS_REQ:
605 			PRINTM(MMSG,
606 			       "wlan: %s P2P Device Discoverability Request, channel=%d\n",
607 			       (flag) ? "TX" : "RX",
608 			       (chan) ? chan->hw_value : 0);
609 			break;
610 		case P2P_DEVDIS_RSP:
611 			PRINTM(MIOCTL,
612 			       "wlan: %s P2P Device Discoverability Response, channel=%d\n",
613 			       (flag) ? "TX" : "RX",
614 			       (chan) ? chan->hw_value : 0);
615 			break;
616 		case P2P_PROVDIS_REQ:
617 			PRINTM(MMSG,
618 			       "wlan: %s P2P Provision Discovery Request, channel=%d\n",
619 			       (flag) ? "TX" : "RX",
620 			       (chan) ? chan->hw_value : 0);
621 			break;
622 		case P2P_PROVDIS_RSP:
623 			PRINTM(MMSG,
624 			       "wlan: %s P2P Provision Discovery Response, channnel=%d\n",
625 			       (flag) ? "TX" : "RX",
626 			       (chan) ? chan->hw_value : 0);
627 			break;
628 		default:
629 			PRINTM(MMSG,
630 			       "wlan: %s Unknow P2P Action Frame, channel=%d, subtype=%d\n",
631 			       (flag) ? "TX" : "RX",
632 			       (chan) ? chan->hw_value : 0, subtype);
633 			break;
634 		}
635 	}
636 
637 	LEAVE();
638 	return;
639 }
640 
641 /**
642  * @brief initialize p2p client for wpa_supplicant
643  *
644  * @param priv			A pointer to moal private structure
645  *
646  * @return              0 -- success, otherwise fail
647  */
648 int
woal_cfg80211_init_p2p_client(moal_private * priv)649 woal_cfg80211_init_p2p_client(moal_private *priv)
650 {
651 	int ret = MLAN_STATUS_SUCCESS;
652 	t_u16 wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
653 	t_u8 bss_role;
654 
655 	ENTER();
656 
657 	/* bss type check */
658 	if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
659 		PRINTM(MERROR, "Unexpected bss type when init p2p client\n");
660 		ret = -EFAULT;
661 		goto done;
662 	}
663 
664 	/* get the bss role */
665 	if (MLAN_STATUS_SUCCESS !=
666 	    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
667 		ret = -EFAULT;
668 		goto done;
669 	}
670 
671 	if (bss_role != MLAN_BSS_ROLE_STA) {
672 		bss_role = MLAN_BSS_ROLE_STA;
673 		if (MLAN_STATUS_SUCCESS !=
674 		    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
675 			ret = -EFAULT;
676 			goto done;
677 		}
678 	}
679 
680 	wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
681 	if (MLAN_STATUS_SUCCESS !=
682 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
683 		ret = -EFAULT;
684 		goto done;
685 	}
686 
687 	/* first, init wifi direct to listen mode */
688 	wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
689 	if (MLAN_STATUS_SUCCESS !=
690 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
691 		ret = -EFAULT;
692 		goto done;
693 	}
694 
695 	/* second, init wifi direct client  */
696 	wifi_direct_mode = WIFI_DIRECT_MODE_CLIENT;
697 	if (MLAN_STATUS_SUCCESS !=
698 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
699 		ret = -EFAULT;
700 		goto done;
701 	}
702 done:
703 	LEAVE();
704 	return ret;
705 }
706 
707 /**
708  * @brief initialize p2p GO for wpa_supplicant
709  *
710  * @param priv			A pointer to moal private structure
711  *
712  * @return              0 -- success, otherwise fail
713  */
714 int
woal_cfg80211_init_p2p_go(moal_private * priv)715 woal_cfg80211_init_p2p_go(moal_private *priv)
716 {
717 	int ret = MLAN_STATUS_SUCCESS;
718 	t_u16 wifi_direct_mode;
719 	t_u8 bss_role;
720 	mlan_ds_wifi_direct_config p2p_config;
721 	mlan_ds_ps_mgmt ps_mgmt;
722 
723 	ENTER();
724 
725 	/* bss type check */
726 	if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
727 		PRINTM(MERROR, "Unexpected bss type when init p2p GO\n");
728 		ret = -EFAULT;
729 		goto done;
730 	}
731 
732 	wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
733 	if (MLAN_STATUS_SUCCESS !=
734 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
735 		ret = -EFAULT;
736 		goto done;
737 	}
738 
739 	/* first, init wifi direct to listen mode */
740 	wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN;
741 	if (MLAN_STATUS_SUCCESS !=
742 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
743 		ret = -EFAULT;
744 		goto done;
745 	}
746 
747 	/* second, init wifi direct to GO mode  */
748 	wifi_direct_mode = WIFI_DIRECT_MODE_GO;
749 	if (MLAN_STATUS_SUCCESS !=
750 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
751 		ret = -EFAULT;
752 		goto done;
753 	}
754 
755 	/* get the bss role, and set it to uAP */
756 	if (MLAN_STATUS_SUCCESS !=
757 	    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) {
758 		ret = -EFAULT;
759 		goto done;
760 	}
761 
762 	if (bss_role != MLAN_BSS_ROLE_UAP) {
763 		bss_role = MLAN_BSS_ROLE_UAP;
764 		if (MLAN_STATUS_SUCCESS !=
765 		    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
766 			ret = -EFAULT;
767 			goto done;
768 		}
769 	}
770 /* NoA:-- Interval = 100TUs and Duration= 50TUs, count=255*/
771 #define DEF_NOA_COUNT       255
772 	if (priv->phandle->noa_duration) {
773 		memset(&p2p_config, 0, sizeof(p2p_config));
774 		p2p_config.noa_enable = MTRUE;
775 		p2p_config.index = 0;
776 		p2p_config.noa_count = DEF_NOA_COUNT;
777 		p2p_config.noa_duration = priv->phandle->noa_duration;
778 		p2p_config.noa_interval = priv->phandle->noa_interval;
779 		p2p_config.flags = WIFI_DIRECT_NOA;
780 		woal_p2p_config(priv, MLAN_ACT_SET, &p2p_config);
781 		memset(&ps_mgmt, 0, sizeof(ps_mgmt));
782 		ps_mgmt.flags = PS_FLAG_PS_MODE;
783 		ps_mgmt.ps_mode = PS_MODE_INACTIVITY;
784 		woal_set_get_uap_power_mode(priv, MLAN_ACT_SET, &ps_mgmt);
785 		PRINTM(MMSG, "Enable NOA: duration=%d, interval=%d\n",
786 		       priv->phandle->noa_duration,
787 		       priv->phandle->noa_interval);
788 	}
789 done:
790 	LEAVE();
791 	return ret;
792 }
793 
794 /**
795  * @brief reset bss role and wifi direct mode for wpa_supplicant
796  *
797  * @param priv			A pointer to moal private structure
798  *
799  * @return              0 -- success, otherwise fail
800  */
801 int
woal_cfg80211_deinit_p2p(moal_private * priv)802 woal_cfg80211_deinit_p2p(moal_private *priv)
803 {
804 	int ret = MLAN_STATUS_SUCCESS;
805 	t_u16 wifi_direct_mode;
806 	t_u8 bss_role;
807 	t_u8 channel_status;
808 	moal_private *remain_priv = NULL;
809 	mlan_ds_ps_mgmt ps_mgmt;
810 
811 	ENTER();
812 
813 	/* bss type check */
814 	if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
815 		PRINTM(MERROR, "Unexpected bss type when deinit p2p\n");
816 		ret = -EFAULT;
817 		goto done;
818 	}
819 	/* unregister mgmt frame from FW */
820 	if (priv->mgmt_subtype_mask) {
821 		priv->mgmt_subtype_mask = 0;
822 		if (woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET,
823 					 &priv->mgmt_subtype_mask,
824 					 MOAL_IOCTL_WAIT)) {
825 			PRINTM(MERROR,
826 			       "deinit_p2p: fail to unregister mgmt frame\n");
827 			ret = -EFAULT;
828 			goto done;
829 		}
830 	}
831 	/* cancel previous remain on channel */
832 	if (priv->phandle->remain_on_channel) {
833 		remain_priv =
834 			priv->phandle->priv[priv->phandle->remain_bss_index];
835 		if (!remain_priv) {
836 			PRINTM(MERROR,
837 			       "deinit_p2p: wrong remain_bss_index=%d\n",
838 			       priv->phandle->remain_bss_index);
839 			ret = -EFAULT;
840 			goto done;
841 		}
842 		if (woal_cfg80211_remain_on_channel_cfg
843 		    (remain_priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL,
844 		     0, 0)) {
845 			PRINTM(MERROR,
846 			       "deinit_p2p: Fail to cancel remain on channel\n");
847 			ret = -EFAULT;
848 			goto done;
849 		}
850 		if (priv->phandle->cookie) {
851 			cfg80211_remain_on_channel_expired(
852 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
853 								  remain_priv->
854 								  netdev,
855 #else
856 								  remain_priv->
857 								  wdev,
858 #endif
859 								  priv->
860 								  phandle->
861 								  cookie,
862 								  &priv->
863 								  phandle->chan,
864 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
865 								  priv->
866 								  phandle->
867 								  channel_type,
868 #endif
869 								  GFP_ATOMIC);
870 			priv->phandle->cookie = 0;
871 		}
872 		priv->phandle->remain_on_channel = MFALSE;
873 	}
874 
875 	/* get the bss role */
876 	if (MLAN_STATUS_SUCCESS != woal_cfg80211_bss_role_cfg(priv,
877 							      MLAN_ACT_GET,
878 							      &bss_role)) {
879 		ret = -EFAULT;
880 		goto done;
881 	}
882 
883 	/* reset bss role */
884 	if (bss_role != MLAN_BSS_ROLE_STA) {
885 		memset(&ps_mgmt, 0, sizeof(ps_mgmt));
886 		ps_mgmt.flags = PS_FLAG_PS_MODE;
887 		ps_mgmt.ps_mode = PS_MODE_DISABLE;
888 		woal_set_get_uap_power_mode(priv, MLAN_ACT_SET, &ps_mgmt);
889 		bss_role = MLAN_BSS_ROLE_STA;
890 		if (MLAN_STATUS_SUCCESS !=
891 		    woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) {
892 			ret = -EFAULT;
893 			goto done;
894 		}
895 	}
896 
897 	wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE;
898 	if (MLAN_STATUS_SUCCESS !=
899 	    woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) {
900 		ret = -EFAULT;
901 		goto done;
902 	}
903 done:
904 	LEAVE();
905 	return ret;
906 }
907 #endif /* KERNEL_VERSION */
908 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
909 
910 /**
911  * @brief Request the driver to change the interface type
912  *
913  * @param wiphy         A pointer to wiphy structure
914  * @param dev           A pointer to net_device structure
915  * @param type          Virtual interface types
916  * @param flags         Flags
917  * @param params        A pointer to vif_params structure
918  *
919  * @return              0 -- success, otherwise fail
920  */
921 int
woal_cfg80211_change_virtual_intf(struct wiphy * wiphy,struct net_device * dev,enum nl80211_iftype type,u32 * flags,struct vif_params * params)922 woal_cfg80211_change_virtual_intf(struct wiphy *wiphy,
923 				  struct net_device *dev,
924 				  enum nl80211_iftype type,
925 #if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
926 				  u32 *flags,
927 #endif
928 				  struct vif_params *params)
929 {
930 	int ret = 0;
931 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
932 	mlan_ds_bss *bss = NULL;
933 	mlan_ioctl_req *req = NULL;
934 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
935 	t_u8 bss_role;
936 #endif
937 	mlan_status status = MLAN_STATUS_SUCCESS;
938 
939 	ENTER();
940 
941 	if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_MONITOR) {
942 		ret = -EFAULT;
943 		goto done;
944 	}
945 
946 	if (priv->wdev->iftype == type) {
947 		PRINTM(MINFO, "Already set to required type\n");
948 		goto done;
949 	}
950 #ifdef UAP_SUPPORT
951 	if ((priv->bss_type == MLAN_BSS_TYPE_UAP) && (priv->bss_index > 0)) {
952 		priv->wdev->iftype = type;
953 		PRINTM(MMSG, "%s: Skip change virtual intf on uap: type=%d\n",
954 		       dev->name, type);
955 		goto done;
956 	}
957 #endif
958 
959 	PRINTM(MIOCTL, "%s: change virturl intf=%d\n", dev->name, type);
960 
961 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
962 	/** cancel previous remain on channel to avoid firmware hang */
963 	if (priv->phandle->remain_on_channel) {
964 		t_u8 channel_status;
965 		moal_private *remain_priv = NULL;
966 		remain_priv =
967 			priv->phandle->priv[priv->phandle->remain_bss_index];
968 		if (!remain_priv) {
969 			PRINTM(MERROR,
970 			       "change_virtual_intf:wrong remain_bss_index=%d\n",
971 			       priv->phandle->remain_bss_index);
972 			ret = -EFAULT;
973 			goto done;
974 		}
975 		if (woal_cfg80211_remain_on_channel_cfg
976 		    (remain_priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL,
977 		     0, 0)) {
978 			PRINTM(MERROR,
979 			       "change_virtual_intf: Fail to cancel remain on channel\n");
980 			ret = -EFAULT;
981 			goto done;
982 		}
983 		if (priv->phandle->cookie) {
984 			cfg80211_remain_on_channel_expired(
985 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
986 								  remain_priv->
987 								  netdev,
988 #else
989 								  remain_priv->
990 								  wdev,
991 #endif
992 								  priv->
993 								  phandle->
994 								  cookie,
995 								  &priv->
996 								  phandle->chan,
997 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
998 								  priv->
999 								  phandle->
1000 								  channel_type,
1001 #endif
1002 								  GFP_ATOMIC);
1003 			priv->phandle->cookie = 0;
1004 		}
1005 		priv->phandle->remain_on_channel = MFALSE;
1006 	}
1007 #endif
1008 
1009 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
1010 	if (req == NULL) {
1011 		ret = -ENOMEM;
1012 		goto done;
1013 	}
1014 
1015 	bss = (mlan_ds_bss *)req->pbuf;
1016 	bss->sub_command = MLAN_OID_BSS_MODE;
1017 	req->req_id = MLAN_IOCTL_BSS;
1018 	req->action = MLAN_ACT_SET;
1019 
1020 	switch (type) {
1021 	case NL80211_IFTYPE_ADHOC:
1022 		bss->param.bss_mode = MLAN_BSS_MODE_IBSS;
1023 		priv->wdev->iftype = NL80211_IFTYPE_ADHOC;
1024 		PRINTM(MINFO, "Setting interface type to adhoc\n");
1025 		break;
1026 	case NL80211_IFTYPE_STATION:
1027 #if defined(WIFI_DIRECT_SUPPORT)
1028 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1029 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
1030 		    && (priv->wdev->iftype == NL80211_IFTYPE_AP
1031 			|| priv->wdev->iftype == NL80211_IFTYPE_P2P_GO
1032 			|| priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
1033 			if (priv->phandle->is_go_timer_set) {
1034 				woal_cancel_timer(&priv->phandle->go_timer);
1035 				priv->phandle->is_go_timer_set = MFALSE;
1036 			}
1037 			/* if we support wifi direct && priv->bss_type == wifi_direct,
1038 			 * and currently the interface type is AP or GO or client,
1039 			 * that means wpa_supplicant deinit() wifi direct interface,
1040 			 * so we should deinit bss_role and wifi direct mode,
1041 			 * for other bss_type, we should not update bss_role
1042 			 * and wifi direct mode */
1043 
1044 			if (MLAN_STATUS_SUCCESS !=
1045 			    woal_cfg80211_deinit_p2p(priv)) {
1046 				ret = -EFAULT;
1047 				goto done;
1048 			}
1049 		}
1050 #endif /* KERNEL_VERSION */
1051 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
1052 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
1053 		if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
1054 			woal_cfg80211_del_beacon(wiphy, dev);
1055 			bss_role = MLAN_BSS_ROLE_STA;
1056 			woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET,
1057 						   &bss_role);
1058 			PRINTM(MIOCTL, "set bss role for STA\n");
1059 		}
1060 #endif
1061 		bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
1062 		priv->wdev->iftype = NL80211_IFTYPE_STATION;
1063 		PRINTM(MINFO, "Setting interface type to managed\n");
1064 		break;
1065 #if defined(WIFI_DIRECT_SUPPORT)
1066 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1067 	case NL80211_IFTYPE_P2P_CLIENT:
1068 		if (priv->phandle->is_go_timer_set) {
1069 			woal_cancel_timer(&priv->phandle->go_timer);
1070 			priv->phandle->is_go_timer_set = MFALSE;
1071 		}
1072 
1073 		if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_client(priv)) {
1074 			ret = -EFAULT;
1075 			goto done;
1076 		}
1077 
1078 		bss->param.bss_mode = MLAN_BSS_MODE_INFRA;
1079 		priv->wdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
1080 		PRINTM(MINFO, "Setting interface type to P2P client\n");
1081 
1082 		break;
1083 #endif /* KERNEL_VERSION */
1084 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
1085 	case NL80211_IFTYPE_AP:
1086 #if defined(WIFI_DIRECT_SUPPORT)
1087 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1088 	case NL80211_IFTYPE_P2P_GO:
1089 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
1090 			if (MLAN_STATUS_SUCCESS !=
1091 			    woal_cfg80211_init_p2p_go(priv)) {
1092 				ret = -EFAULT;
1093 				goto done;
1094 			}
1095 			priv->phandle->is_go_timer_set = MTRUE;
1096 			woal_mod_timer(&priv->phandle->go_timer,
1097 				       MOAL_TIMER_10S);
1098 		}
1099 		if (type == NL80211_IFTYPE_P2P_GO)
1100 			priv->wdev->iftype = NL80211_IFTYPE_P2P_GO;
1101 #endif
1102 #endif
1103 #if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
1104 		if (priv->bss_type == MLAN_BSS_TYPE_STA) {
1105 #ifdef STA_CFG80211
1106 	    /** cancel pending scan */
1107 			woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
1108 
1109 #endif
1110 			if (priv->probereq_index !=
1111 			    MLAN_CUSTOM_IE_AUTO_IDX_MASK)
1112 				woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL,
1113 							    0, NULL, 0, NULL, 0,
1114 							    MGMT_MASK_PROBE_REQ,
1115 							    MOAL_IOCTL_WAIT);
1116 
1117 			bss_role = MLAN_BSS_ROLE_UAP;
1118 			woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET,
1119 						   &bss_role);
1120 			PRINTM(MIOCTL, "set bss role for AP\n");
1121 		}
1122 #endif
1123 		if (type == NL80211_IFTYPE_AP)
1124 			priv->wdev->iftype = NL80211_IFTYPE_AP;
1125 		PRINTM(MINFO, "Setting interface type to P2P GO\n");
1126 
1127 		/* there is no need for P2P GO to set bss_mode */
1128 		goto done;
1129 
1130 		break;
1131 
1132 	case NL80211_IFTYPE_UNSPECIFIED:
1133 		bss->param.bss_mode = MLAN_BSS_MODE_AUTO;
1134 		priv->wdev->iftype = NL80211_IFTYPE_STATION;
1135 		PRINTM(MINFO, "Setting interface type to auto\n");
1136 		break;
1137 	default:
1138 		ret = -EINVAL;
1139 		break;
1140 	}
1141 	if (ret)
1142 		goto done;
1143 
1144 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1145 	if (MLAN_STATUS_SUCCESS != status) {
1146 		ret = -EFAULT;
1147 		goto done;
1148 	}
1149 
1150 done:
1151 	if (status != MLAN_STATUS_PENDING)
1152 		kfree(req);
1153 	LEAVE();
1154 	return ret;
1155 }
1156 
1157 /**
1158  * @brief Request the driver to change the value of fragment
1159  * threshold or rts threshold or retry limit
1160  *
1161  * @param wiphy         A pointer to wiphy structure
1162  * @param changed       Change flags
1163  *
1164  * @return              0 -- success, otherwise fail
1165  */
1166 int
woal_cfg80211_set_wiphy_params(struct wiphy * wiphy,u32 changed)1167 woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1168 {
1169 	moal_private *priv = NULL;
1170 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
1171 #ifdef UAP_CFG80211
1172 #ifdef UAP_SUPPORT
1173 	mlan_uap_bss_param *sys_cfg = NULL;
1174 #endif
1175 #endif
1176 	int frag_thr = wiphy->frag_threshold;
1177 	int rts_thr = wiphy->rts_threshold;
1178 	int retry = wiphy->retry_long;
1179 
1180 	ENTER();
1181 
1182 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
1183 	if (!priv) {
1184 		LEAVE();
1185 		return -EFAULT;
1186 	}
1187 	if (rts_thr == MLAN_FRAG_RTS_DISABLED)
1188 		rts_thr = MLAN_RTS_MAX_VALUE;
1189 	if (frag_thr == MLAN_FRAG_RTS_DISABLED)
1190 		frag_thr = MLAN_FRAG_MAX_VALUE;
1191 
1192 #ifdef UAP_CFG80211
1193 #ifdef UAP_SUPPORT
1194 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
1195 		sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
1196 		if (!sys_cfg) {
1197 			PRINTM(MERROR,
1198 			       "Fail to alloc memory for mlan_uap_bss_param\n");
1199 			LEAVE();
1200 			return -EFAULT;
1201 		}
1202 		/* Initialize the invalid values so that the correct
1203 		 * values below are downloaded to firmware */
1204 		woal_set_sys_config_invalid_data(sys_cfg);
1205 		sys_cfg->frag_threshold = frag_thr;
1206 		sys_cfg->rts_threshold = rts_thr;
1207 		sys_cfg->retry_limit = retry;
1208 
1209 		if ((changed & WIPHY_PARAM_RTS_THRESHOLD) ||
1210 		    (changed & WIPHY_PARAM_FRAG_THRESHOLD) ||
1211 		    (changed &
1212 		     (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))) {
1213 			if (woal_set_get_sys_config
1214 			    (priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, sys_cfg)) {
1215 				kfree(sys_cfg);
1216 				goto fail;
1217 			}
1218 		}
1219 		kfree(sys_cfg);
1220 	}
1221 #endif
1222 #endif
1223 
1224 #ifdef STA_CFG80211
1225 #ifdef STA_SUPPORT
1226 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1227 		if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
1228 			if (woal_set_get_rts
1229 			    (priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rts_thr))
1230 				goto fail;
1231 		}
1232 		if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
1233 			if (woal_set_get_frag
1234 			    (priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &frag_thr))
1235 				goto fail;
1236 		}
1237 		if (changed &
1238 		    (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))
1239 			if (woal_set_get_retry
1240 			    (priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &retry))
1241 				goto fail;
1242 	}
1243 #endif
1244 #endif
1245 	LEAVE();
1246 	return 0;
1247 
1248 fail:
1249 	PRINTM(MERROR, "Failed to change wiphy params %x\n", changed);
1250 	LEAVE();
1251 	return -EFAULT;
1252 }
1253 
1254 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
1255 /**
1256  * @brief Request the driver to add a key
1257  *
1258  * @param wiphy         A pointer to wiphy structure
1259  * @param netdev        A pointer to net_device structure
1260  * @param key_index     Key index
1261  * @param pairwise      Flag to indicate pairwise or group (for kernel > 2.6.36)
1262  * @param mac_addr      MAC address (NULL for group key)
1263  * @param params        A pointer to key_params structure
1264  *
1265  * @return              0 -- success, otherwise fail
1266  */
1267 #else
1268 /**
1269  * @brief Request the driver to add a key
1270  *
1271  * @param wiphy         A pointer to wiphy structure
1272  * @param netdev        A pointer to net_device structure
1273  * @param key_index     Key index
1274  * @param mac_addr      MAC address (NULL for group key)
1275  * @param params        A pointer to key_params structure
1276  *
1277  * @return              0 -- success, otherwise fail
1278  */
1279 #endif
1280 int
woal_cfg80211_add_key(struct wiphy * wiphy,struct net_device * netdev,t_u8 key_index,bool pairwise,const t_u8 * mac_addr,struct key_params * params)1281 woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
1282 		      t_u8 key_index,
1283 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
1284 		      bool pairwise,
1285 #endif
1286 		      const t_u8 *mac_addr, struct key_params *params)
1287 {
1288 	moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
1289 
1290 	ENTER();
1291 	if (priv->ft_pre_connect) {
1292 		PRINTM(MINFO, "Skip set keys during ft connecting\n");
1293 		return -EFAULT;
1294 	}
1295 	if (woal_cfg80211_set_key(priv, 0, params->cipher, params->key,
1296 				  params->key_len, params->seq, params->seq_len,
1297 				  key_index, mac_addr, 0, MOAL_IOCTL_WAIT)) {
1298 		PRINTM(MERROR, "Error adding the crypto keys\n");
1299 		LEAVE();
1300 		return -EFAULT;
1301 	}
1302 
1303 	PRINTM(MINFO, "Crypto keys added\n");
1304 
1305 	LEAVE();
1306 	return 0;
1307 }
1308 
1309 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
1310 /**
1311  * @brief Request the driver to delete a key
1312  *
1313  * @param wiphy         A pointer to wiphy structure
1314  * @param netdev        A pointer to net_device structure
1315  * @param key_index     Key index
1316  * @param pairwise      Flag to indicate pairwise or group (for kernel > 2.6.36)
1317  * @param mac_addr      MAC address (NULL for group key)
1318  *
1319  * @return              0 -- success, otherwise fail
1320  */
1321 #else
1322 /**
1323  * @brief Request the driver to delete a key
1324  *
1325  * @param wiphy         A pointer to wiphy structure
1326  * @param netdev        A pointer to net_device structure
1327  * @param key_index     Key index
1328  * @param mac_addr      MAC address (NULL for group key)
1329  *
1330  * @return              0 -- success, otherwise fail
1331  */
1332 #endif
1333 int
woal_cfg80211_del_key(struct wiphy * wiphy,struct net_device * netdev,t_u8 key_index,bool pairwise,const t_u8 * mac_addr)1334 woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
1335 		      t_u8 key_index,
1336 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 36)
1337 		      bool pairwise,
1338 #endif
1339 		      const t_u8 *mac_addr)
1340 {
1341 	moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
1342 
1343 	ENTER();
1344 	priv->phandle->driver_state = woal_check_driver_status(priv->phandle);
1345 	if (priv->phandle->driver_state) {
1346 		PRINTM(MERROR,
1347 		       "Block woal_cfg80211_del_key in abnormal driver state\n");
1348 		LEAVE();
1349 		return -EFAULT;
1350 	}
1351 
1352 	if (MLAN_STATUS_FAILURE ==
1353 	    woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, key_index,
1354 				  mac_addr, 1, MOAL_NO_WAIT)) {
1355 		PRINTM(MERROR, "Error deleting the crypto keys\n");
1356 		LEAVE();
1357 		return -EFAULT;
1358 	}
1359 
1360 	PRINTM(MINFO, "Crypto keys deleted\n");
1361 	LEAVE();
1362 	return 0;
1363 }
1364 
1365 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 37)
1366 /**
1367  * @brief Request to enable WEP key to driver
1368  *
1369  * @param wiphy         A pointer to wiphy structure
1370  * @param netdev        A pointer to net_device structure
1371  * @param key_index     Key index
1372  * @param ucast         Unicast flag (for kernel > 2.6.37)
1373  * @param mcast         Multicast flag (for kernel > 2.6.37)
1374  *
1375  * @return              0 -- success, otherwise fail
1376  */
1377 #else
1378 /**
1379  * @brief Request to enable WEP key to driver
1380  *
1381  * @param wiphy         A pointer to wiphy structure
1382  * @param netdev        A pointer to net_device structure
1383  * @param key_index     Key index
1384  *
1385  * @return              0 -- success, otherwise fail
1386  */
1387 #endif
1388 int
woal_cfg80211_set_default_key(struct wiphy * wiphy,struct net_device * netdev,t_u8 key_index,bool ucast,bool mcast)1389 woal_cfg80211_set_default_key(struct wiphy *wiphy,
1390 			      struct net_device *netdev, t_u8 key_index
1391 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 37)
1392 			      , bool ucast, bool mcast
1393 #endif
1394 	)
1395 {
1396 	int ret = 0;
1397 	moal_private *priv = (moal_private *)woal_get_netdev_priv(netdev);
1398 	mlan_bss_info bss_info;
1399 
1400 	ENTER();
1401 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1402 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
1403 		if (!bss_info.wep_status) {
1404 			LEAVE();
1405 			return ret;
1406 		}
1407 	}
1408 	if (MLAN_STATUS_SUCCESS !=
1409 	    woal_cfg80211_set_wep_keys(priv, NULL, 0, key_index,
1410 				       MOAL_IOCTL_WAIT)) {
1411 		ret = -EFAULT;
1412 	}
1413 	LEAVE();
1414 	return ret;
1415 }
1416 
1417 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
1418 int
woal_cfg80211_set_default_mgmt_key(struct wiphy * wiphy,struct net_device * netdev,t_u8 key_index)1419 woal_cfg80211_set_default_mgmt_key(struct wiphy *wiphy,
1420 				   struct net_device *netdev, t_u8 key_index)
1421 {
1422 	PRINTM(MINFO, "set default mgmt key, key index=%d\n", key_index);
1423 
1424 	return 0;
1425 }
1426 #endif
1427 
1428 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
1429 /**
1430  *  @brief  Set GTK rekey data to driver
1431  *
1432  *  @param priv         A pointer to moal_private structure
1433  *  @param gtk_rekey     A pointer to mlan_ds_misc_gtk_rekey_data structure
1434  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
1435  *
1436  *  @return             0 --success, otherwise fail
1437  */
1438 mlan_status
woal_set_rekey_data(moal_private * priv,mlan_ds_misc_gtk_rekey_data * gtk_rekey,t_u8 action)1439 woal_set_rekey_data(moal_private *priv, mlan_ds_misc_gtk_rekey_data * gtk_rekey,
1440 		    t_u8 action)
1441 {
1442 	mlan_ioctl_req *req;
1443 	mlan_ds_misc_cfg *misc_cfg;
1444 	int ret = 0;
1445 	mlan_status status;
1446 
1447 	ENTER();
1448 
1449 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1450 
1451 	if (NULL == req) {
1452 		ret = -ENOMEM;
1453 	} else {
1454 		misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
1455 		misc_cfg->sub_command = MLAN_OID_MISC_GTK_REKEY_OFFLOAD;
1456 		req->req_id = MLAN_IOCTL_MISC_CFG;
1457 
1458 		req->action = action;
1459 		if (action == MLAN_ACT_SET)
1460 			memcpy(&misc_cfg->param.gtk_rekey, gtk_rekey,
1461 			       sizeof(mlan_ds_misc_gtk_rekey_data));
1462 
1463 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1464 		if (MLAN_STATUS_SUCCESS != status)
1465 			ret = -EFAULT;
1466 		if (status != MLAN_STATUS_PENDING)
1467 			kfree(req);
1468 	}
1469 
1470 	LEAVE();
1471 	return ret;
1472 }
1473 
1474 /**
1475  * @brief Give the data necessary for GTK rekeying to the driver
1476  *
1477  * @param wiphy         A pointer to wiphy structure
1478  * @param dev           A pointer to net_device structure
1479  * @param data        A pointer to cfg80211_gtk_rekey_data structure
1480  *
1481  * @return              0 -- success, otherwise fail
1482  */
1483 int
woal_cfg80211_set_rekey_data(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_gtk_rekey_data * data)1484 woal_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev,
1485 			     struct cfg80211_gtk_rekey_data *data)
1486 {
1487 	int ret = 0;
1488 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1489 	mlan_ds_misc_gtk_rekey_data rekey;
1490 	mlan_fw_info fw_info;
1491 
1492 	ENTER();
1493 
1494 	if (gtk_rekey_offload == GTK_REKEY_OFFLOAD_DISABLE) {
1495 		PRINTM(MMSG,
1496 		       "woal_cfg80211_set_rekey_data return: gtk_rekey_offload is DISABLE\n");
1497 		LEAVE();
1498 		return ret;
1499 	}
1500 
1501 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
1502 	if (!fw_info.fw_supplicant_support) {
1503 		LEAVE();
1504 		return -1;
1505 	}
1506 
1507 	memcpy(rekey.kek, data->kek, MLAN_KEK_LEN);
1508 	memcpy(rekey.kck, data->kck, MLAN_KCK_LEN);
1509 	memcpy(rekey.replay_ctr, data->replay_ctr, MLAN_REPLAY_CTR_LEN);
1510 
1511 	memcpy(&priv->gtk_rekey_data, &rekey,
1512 	       sizeof(mlan_ds_misc_gtk_rekey_data));
1513 	if (gtk_rekey_offload == GTK_REKEY_OFFLOAD_SUSPEND) {
1514 		priv->gtk_data_ready = MTRUE;
1515 		LEAVE();
1516 		return ret;
1517 	}
1518 
1519 	if (MLAN_STATUS_SUCCESS !=
1520 	    woal_set_rekey_data(priv, &rekey, MLAN_ACT_SET)) {
1521 		ret = -EFAULT;
1522 	}
1523 
1524 	LEAVE();
1525 	return ret;
1526 }
1527 #endif
1528 
1529 #ifdef STA_SUPPORT
1530 /* Opportunistic Key Caching APIs functions support
1531  *
1532  * this function get pmksa entry list in private structure
1533  * @param priv         A pointer to moal_private structure
1534  * @param bssid        A pointer to bssid
1535  * @return             pointer to target entry or NULL
1536  */
1537 struct pmksa_entry *
woal_get_pmksa_entry(moal_private * priv,const u8 * bssid)1538 woal_get_pmksa_entry(moal_private *priv, const u8 *bssid)
1539 {
1540 	struct pmksa_entry *entry = NULL;
1541 	unsigned long flags;
1542 
1543 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1544 		PRINTM(MERROR, "Invalid interface structure\n");
1545 		return NULL;
1546 	}
1547 
1548 	spin_lock_irqsave(&priv->pmksa_list_lock, flags);
1549 	list_for_each_entry(entry, &priv->pmksa_cache_list, link) {
1550 		if (!memcmp(entry->bssid, bssid, ETH_ALEN)) {
1551 			spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1552 			return entry;
1553 		}
1554 	}
1555 	spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1556 
1557 	return NULL;
1558 }
1559 
1560 /**
1561  * This function flush pmksa entry list in private structure
1562  * @param priv         A pointer to moal_private structure
1563  * @return             success of failure
1564  */
1565 int
woal_flush_pmksa_list(moal_private * priv)1566 woal_flush_pmksa_list(moal_private *priv)
1567 {
1568 	struct pmksa_entry *entry, *tmp;
1569 	unsigned long flags;
1570 
1571 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1572 		PRINTM(MERROR, "Invalid interface structure\n");
1573 		return -1;
1574 	}
1575 
1576 	spin_lock_irqsave(&priv->pmksa_list_lock, flags);
1577 	list_for_each_entry_safe(entry, tmp, &priv->pmksa_cache_list, link) {
1578 		list_del(&entry->link);
1579 		kfree(entry);
1580 	}
1581 	INIT_LIST_HEAD(&priv->pmksa_cache_list);
1582 	spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1583 
1584 	return 0;
1585 }
1586 
1587 /**
1588  *  This function add new pmksa entry to list
1589  *  @param wiphy        A pointer to struct wiphy
1590  *  @param dev          A pointer to net_device structure
1591  *  @param pmksa        A pointer to cfg80211_pmksa structure
1592  *  @return             success of failure
1593  */
1594 int
woal_cfg80211_set_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)1595 woal_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
1596 			struct cfg80211_pmksa *pmksa)
1597 {
1598 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1599 	struct pmksa_entry *entry = NULL;
1600 	unsigned long flags;
1601 	int ret = 0;
1602 
1603 	ENTER();
1604 
1605 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1606 		PRINTM(MERROR, "Invalid interface structure\n");
1607 		ret = -1;
1608 		goto done;
1609 	}
1610 
1611 	PRINTM(MIOCTL, "Set pmksa entry: bssid=" MACSTR "\n",
1612 	       MAC2STR(pmksa->bssid));
1613 	entry = woal_get_pmksa_entry(priv, pmksa->bssid);
1614 	if (!entry) {
1615 		entry = kzalloc(sizeof(struct pmksa_entry), GFP_ATOMIC);
1616 		if (!entry) {
1617 			PRINTM(MERROR, "Fail to allocate pmksa entry\n");
1618 			goto done;
1619 		}
1620 		INIT_LIST_HEAD(&entry->link);
1621 		memcpy(entry->bssid, pmksa->bssid, ETH_ALEN);
1622 		memcpy(entry->pmkid, pmksa->pmkid, PMKID_LEN);
1623 		spin_lock_irqsave(&priv->pmksa_list_lock, flags);
1624 		list_add_tail(&entry->link, &priv->pmksa_cache_list);
1625 		spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1626 	} else {
1627 		/** pmkid is differnt from previous value? */
1628 		memset(entry->pmkid, 0, PMKID_LEN);
1629 		memcpy(entry->pmkid, pmksa->pmkid, PMKID_LEN);
1630 	}
1631 
1632 	/** Check if current roaming is going and received target pmkid */
1633 	if (priv->wait_target_ap_pmkid) {
1634 		struct cfg80211_connect_params *param = &priv->sme_current;
1635 		if (param && !memcmp(pmksa->bssid, param->bssid, ETH_ALEN)) {
1636 			PRINTM(MIOCTL,
1637 			       "Current roaming target bssid=" MACSTR "\n",
1638 			       MAC2STR(param->bssid));
1639 			priv->target_ap_pmksa = entry;
1640 			priv->wait_target_ap_pmkid = MFALSE;
1641 			wake_up_interruptible(&priv->okc_wait_q);
1642 		}
1643 	}
1644 
1645 done:
1646 	LEAVE();
1647 	return ret;
1648 }
1649 
1650 /**
1651  *  This function delete pmksa entry
1652  *  @param wiphy        A pointer to struct wiphy
1653  *  @param dev          A pointer to net_device structure
1654  *  @param pmksa        A pointer to cfg80211_pmksa structure
1655  *  @return             success of failure
1656  */
1657 int
woal_cfg80211_del_pmksa(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_pmksa * pmksa)1658 woal_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
1659 			struct cfg80211_pmksa *pmksa)
1660 {
1661 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1662 	struct pmksa_entry *entry, *tmp;
1663 	unsigned long flags;
1664 
1665 	ENTER();
1666 
1667 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1668 		PRINTM(MERROR, "Invalid interface structure\n");
1669 		LEAVE();
1670 		return -1;
1671 	}
1672 
1673 	PRINTM(MIOCTL, "Delete pmksa: bssid=" MACSTR "\n",
1674 	       MAC2STR(pmksa->bssid));
1675 	spin_lock_irqsave(&priv->pmksa_list_lock, flags);
1676 	list_for_each_entry_safe(entry, tmp, &priv->pmksa_cache_list, link) {
1677 		if (!memcmp(entry->bssid, pmksa->bssid, ETH_ALEN)) {
1678 			list_del(&entry->link);
1679 			kfree(entry);
1680 		}
1681 	}
1682 	spin_unlock_irqrestore(&priv->pmksa_list_lock, flags);
1683 
1684 	LEAVE();
1685 	return 0;
1686 }
1687 
1688 /**
1689  *  This function flush pmksa entry list
1690  *  @param wiphy        A pointer to struct wiphy
1691  *  @param dev          A pointer to net_device structure
1692  *  @return             success of failure
1693  */
1694 int
woal_cfg80211_flush_pmksa(struct wiphy * wiphy,struct net_device * dev)1695 woal_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
1696 {
1697 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
1698 
1699 	if (!priv || priv->bss_type != MLAN_BSS_TYPE_STA) {
1700 		return -1;
1701 	}
1702 
1703 	PRINTM(MIOCTL, "Flush pmksa list.\n");
1704 	return woal_flush_pmksa_list(priv);
1705 }
1706 #endif
1707 
1708 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
1709 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 34)
1710 /**
1711  * @brief Request the driver to change the channel
1712  *
1713  * @param wiphy           A pointer to wiphy structure
1714  * @param dev             A pointer to net_device structure
1715  * @param chan            A pointer to ieee80211_channel structure
1716  * @param channel_type    Channel type of nl80211_channel_type
1717  *
1718  * @return                0 -- success, otherwise fail
1719  */
1720 #else
1721 /**
1722  * @brief Request the driver to change the channel
1723  *
1724  * @param wiphy           A pointer to wiphy structure
1725  * @param chan            A pointer to ieee80211_channel structure
1726  * @param channel_type    Channel type of nl80211_channel_type
1727  *
1728  * @return                0 -- success, otherwise fail
1729  */
1730 #endif
1731 int
woal_cfg80211_set_channel(struct wiphy * wiphy,struct net_device * dev,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type)1732 woal_cfg80211_set_channel(struct wiphy *wiphy,
1733 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 34)
1734 			  struct net_device *dev,
1735 #endif
1736 			  struct ieee80211_channel *chan,
1737 			  enum nl80211_channel_type channel_type)
1738 {
1739 	int ret = 0;
1740 	moal_private *priv = NULL;
1741 
1742 	ENTER();
1743 
1744 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
1745 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 34)
1746 	if (dev)
1747 		priv = woal_get_netdev_priv(dev);
1748 #endif
1749 #endif
1750 	if (!priv) {
1751 		moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
1752 		if (handle)
1753 			priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
1754 	}
1755 	if (priv) {
1756 #ifdef STA_CFG80211
1757 #ifdef STA_SUPPORT
1758 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
1759 			if (priv->media_connected == MTRUE) {
1760 				PRINTM(MERROR,
1761 				       "This configuration is valid only when station "
1762 				       "is not connected\n");
1763 				LEAVE();
1764 				return -EINVAL;
1765 			}
1766 			ret = woal_set_rf_channel(priv, chan, channel_type,
1767 						  MOAL_IOCTL_WAIT);
1768 		}
1769 #endif
1770 #endif
1771 		priv->channel =
1772 			ieee80211_frequency_to_channel(chan->center_freq);
1773 	}
1774 	/* set monitor channel support */
1775 
1776 	LEAVE();
1777 	return ret;
1778 }
1779 #endif
1780 
1781 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
1782 /**
1783  * @brief Functions check whether the pattern is supported
1784  *
1785  * @param pat             A pointer to cfg80211_pkt_pattern structure
1786  * @param byte_seq        Byte sequence
1787  * @param max_byte_seq    Maximum byte sequence
1788  *
1789  * @return                true -- success, otherwise false
1790  */
1791 static bool
woal_is_pattern_supported(struct cfg80211_pkt_pattern * pat,t_u8 * byte_seq,t_u8 max_byte_seq)1792 woal_is_pattern_supported(struct cfg80211_pkt_pattern *pat, t_u8 *byte_seq,
1793 			  t_u8 max_byte_seq)
1794 {
1795 	int j, k, valid_byte_cnt = 0;
1796 	bool dont_care_byte = false;
1797 
1798 	for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) {
1799 		for (k = 0; k < 8; k++) {
1800 			if (pat->mask[j] & 1 << k) {
1801 				memcpy(byte_seq + valid_byte_cnt,
1802 				       &pat->pattern[j * 8 + k], 1);
1803 				valid_byte_cnt++;
1804 				if (dont_care_byte)
1805 					return false;
1806 			} else {
1807 				if (valid_byte_cnt)
1808 					dont_care_byte = true;
1809 			}
1810 
1811 			if (valid_byte_cnt > max_byte_seq)
1812 				return false;
1813 		}
1814 	}
1815 
1816 	byte_seq[max_byte_seq] = valid_byte_cnt;
1817 
1818 	return true;
1819 }
1820 
1821 /**
1822  * @brief Get coalesce packet type
1823  *
1824  * @param byte_seq        Byte Sequence
1825 
1826  * @return                0 -- success, otherwise fail
1827  */
1828 static int
woal_get_coalesce_pkt_type(t_u8 * byte_seq)1829 woal_get_coalesce_pkt_type(t_u8 *byte_seq)
1830 {
1831 	const t_u8 ipv4_mc_mac[] = { 0x33, 0x33 };
1832 	const t_u8 ipv6_mc_mac[] = { 0x01, 0x00, 0x5e };
1833 	const t_u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff };
1834 
1835 	if ((byte_seq[0] & 0x01) && (byte_seq[COALESCE_MAX_BYTESEQ] == 1))
1836 		return PACKET_TYPE_UNICAST;
1837 	else if (!memcmp(byte_seq, bc_mac, 4))
1838 		return PACKET_TYPE_BROADCAST;
1839 	else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
1840 		  byte_seq[COALESCE_MAX_BYTESEQ] == 2) ||
1841 		 (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
1842 		  byte_seq[COALESCE_MAX_BYTESEQ] == 3))
1843 		return PACKET_TYPE_MULTICAST;
1844 
1845 	return 0;
1846 }
1847 
1848 /**
1849  * @brief Functions fills the coalesce rule information
1850  *
1851  * @param crule           A pointer to cfg80211_coalesce_rules structure
1852  * @param mrule           A pointer to coalesce_rules structure
1853  *
1854  * @return                0-- success, otherwise fail
1855  */
1856 static int
woal_fill_coalesce_rule_info(struct cfg80211_coalesce_rules * crule,struct coalesce_rule * mrule)1857 woal_fill_coalesce_rule_info(struct cfg80211_coalesce_rules *crule,
1858 			     struct coalesce_rule *mrule)
1859 {
1860 	t_u8 byte_seq[COALESCE_MAX_BYTESEQ + 1];
1861 	struct filt_field_param *param;
1862 	int i;
1863 
1864 	mrule->max_coalescing_delay = crule->delay;
1865 
1866 	param = mrule->params;
1867 
1868 	for (i = 0; i < crule->n_patterns; i++) {
1869 		memset(byte_seq, 0, sizeof(byte_seq));
1870 		if (!woal_is_pattern_supported(&crule->patterns[i],
1871 					       byte_seq,
1872 					       COALESCE_MAX_BYTESEQ)) {
1873 			PRINTM(MERROR, "Pattern not supported\n");
1874 			return -EOPNOTSUPP;
1875 		}
1876 
1877 		if (!crule->patterns[i].pkt_offset) {
1878 			u8 pkt_type;
1879 
1880 			pkt_type = woal_get_coalesce_pkt_type(byte_seq);
1881 			if (pkt_type && mrule->pkt_type) {
1882 				PRINTM(MERROR,
1883 				       "Multiple packet types not allowed\n");
1884 				return -EOPNOTSUPP;
1885 			} else if (pkt_type) {
1886 				mrule->pkt_type = pkt_type;
1887 				continue;
1888 			}
1889 		}
1890 
1891 		if (crule->condition == NL80211_COALESCE_CONDITION_MATCH)
1892 			param->operation = RECV_FILTER_MATCH_TYPE_EQ;
1893 		else
1894 			param->operation = RECV_FILTER_MATCH_TYPE_NE;
1895 
1896 		param->operand_len = byte_seq[COALESCE_MAX_BYTESEQ];
1897 		memcpy(param->operand_byte_stream, byte_seq,
1898 		       param->operand_len);
1899 		param->offset = crule->patterns[i].pkt_offset;
1900 		param++;
1901 
1902 		mrule->num_of_fields++;
1903 	}
1904 
1905 	if (!mrule->pkt_type) {
1906 		PRINTM(MERROR, "Packet type can not be determined\n");
1907 		return -EOPNOTSUPP;
1908 	}
1909 
1910 	return 0;
1911 }
1912 
1913 /**
1914  *  @brief Set coalesce parameter
1915  *
1916  *  @param priv             A pointer to moal_private structure
1917  *  @param action           MLAN_ACT_SET or MLAN_ACT_GET
1918  *  @param coalesce_cfg     A pointer to coalesce structure
1919  *
1920  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1921  */
1922 mlan_status
woal_set_coalesce(moal_private * priv,t_u16 action,mlan_ds_coalesce_cfg * coalesce_cfg)1923 woal_set_coalesce(moal_private *priv, t_u16 action,
1924 		  mlan_ds_coalesce_cfg * coalesce_cfg)
1925 {
1926 	mlan_status ret = MLAN_STATUS_SUCCESS;
1927 	mlan_ds_misc_cfg *misc_cfg = NULL;
1928 	mlan_ioctl_req *req = NULL;
1929 
1930 	ENTER();
1931 
1932 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1933 	if (req == NULL) {
1934 		ret = MLAN_STATUS_FAILURE;
1935 		goto done;
1936 	}
1937 
1938 	misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
1939 	misc_cfg->sub_command = MLAN_OID_MISC_COALESCE_CFG;
1940 	req->req_id = MLAN_IOCTL_MISC_CFG;
1941 	req->action = action;
1942 
1943 	memcpy(&misc_cfg->param.coalesce_cfg, coalesce_cfg,
1944 	       sizeof(mlan_ds_coalesce_cfg));
1945 
1946 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1947 	if (ret != MLAN_STATUS_SUCCESS)
1948 		goto done;
1949 
1950 done:
1951 	if (ret != MLAN_STATUS_PENDING)
1952 		kfree(req);
1953 	LEAVE();
1954 	return ret;
1955 }
1956 
1957 /**
1958  * @brief Request the driver to set the coalesce
1959  *
1960  * @param wiphy           A pointer to wiphy structure
1961  * @param coalesce        A pointer to cfg80211_coalesce structure
1962  *
1963  * @return                0 -- success, otherwise fail
1964  */
1965 int
woal_cfg80211_set_coalesce(struct wiphy * wiphy,struct cfg80211_coalesce * coalesce)1966 woal_cfg80211_set_coalesce(struct wiphy *wiphy,
1967 			   struct cfg80211_coalesce *coalesce)
1968 {
1969 	int ret = 0;
1970 	int i;
1971 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
1972 	moal_private *priv = NULL;
1973 	mlan_ds_coalesce_cfg coalesce_cfg;
1974 
1975 	ENTER();
1976 
1977 	if (!handle) {
1978 		PRINTM(MFATAL, "Unable to get handle\n");
1979 		ret = -EINVAL;
1980 		goto done;
1981 	}
1982 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
1983 	if (!priv) {
1984 		ret = -EINVAL;
1985 		goto done;
1986 	}
1987 
1988 	memset(&coalesce_cfg, 0, sizeof(coalesce_cfg));
1989 	if (!coalesce) {
1990 		PRINTM(MMSG, "Disable coalesce and reset all previous rules\n");
1991 	} else {
1992 		coalesce_cfg.num_of_rules = coalesce->n_rules;
1993 		for (i = 0; i < coalesce->n_rules; i++) {
1994 			ret = woal_fill_coalesce_rule_info(&coalesce->rules[i],
1995 							   &coalesce_cfg.
1996 							   rule[i]);
1997 			if (ret) {
1998 				PRINTM(MERROR,
1999 				       "Recheck the patterns provided for rule %d\n",
2000 				       i + 1);
2001 				return ret;
2002 			}
2003 		}
2004 	}
2005 
2006 	if (MLAN_STATUS_SUCCESS !=
2007 	    woal_set_coalesce(priv, MLAN_ACT_SET, &coalesce_cfg)) {
2008 		PRINTM(MERROR, "wlan: Fail to set coalesce\n");
2009 		ret = -EFAULT;
2010 	}
2011 
2012 done:
2013 	LEAVE();
2014 	return ret;
2015 }
2016 #endif
2017 
2018 /**
2019  * @brief Request the driver to set the bitrate
2020  *
2021  * @param wiphy           A pointer to wiphy structure
2022  * @param dev             A pointer to net_device structure
2023  * @param peer            A pointer to peer address
2024  * @param mask            A pointer to cfg80211_bitrate_mask structure
2025  *
2026  * @return                0 -- success, otherwise fail
2027  */
2028 int
woal_cfg80211_set_bitrate_mask(struct wiphy * wiphy,struct net_device * dev,const u8 * peer,const struct cfg80211_bitrate_mask * mask)2029 woal_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
2030 			       struct net_device *dev,
2031 			       const u8 *peer,
2032 			       const struct cfg80211_bitrate_mask *mask)
2033 {
2034 	int ret = 0;
2035 	mlan_status status = MLAN_STATUS_SUCCESS;
2036 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2037 	mlan_bss_info bss_info;
2038 	enum ieee80211_band band;
2039 	mlan_ioctl_req *req = NULL;
2040 	mlan_ds_rate *rate = NULL;
2041 	mlan_rate_cfg_t *rate_cfg = NULL;
2042 
2043 	ENTER();
2044 
2045 	if (priv->media_connected == MFALSE) {
2046 		PRINTM(MERROR, "Can not set data rate in disconnected state\n");
2047 		ret = -EINVAL;
2048 		goto done;
2049 	}
2050 
2051 	status = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
2052 	if (status)
2053 		goto done;
2054 	band = woal_band_cfg_to_ieee_band(bss_info.bss_band);
2055 
2056 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2057 	if (req == NULL) {
2058 		ret = -ENOMEM;
2059 		goto done;
2060 	}
2061 	rate = (mlan_ds_rate *)req->pbuf;
2062 	rate_cfg = &rate->param.rate_cfg;
2063 	rate->sub_command = MLAN_OID_RATE_CFG;
2064 	req->req_id = MLAN_IOCTL_RATE;
2065 	req->action = MLAN_ACT_SET;
2066 	rate_cfg->rate_type = MLAN_RATE_BITMAP;
2067 
2068 	/* Fill HR/DSSS rates. */
2069 	if (band == IEEE80211_BAND_2GHZ)
2070 		rate_cfg->bitmap_rates[0] = mask->control[band].legacy & 0x000f;
2071 
2072 	/* Fill OFDM rates */
2073 	if (band == IEEE80211_BAND_2GHZ)
2074 		rate_cfg->bitmap_rates[1] =
2075 			(mask->control[band].legacy & 0x0ff0) >> 4;
2076 	else
2077 		rate_cfg->bitmap_rates[1] = mask->control[band].legacy;
2078 
2079 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
2080 	/* Fill MCS rates */
2081 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2082 	rate_cfg->bitmap_rates[2] = mask->control[band].ht_mcs[0];
2083 #else
2084 	rate_cfg->bitmap_rates[2] = mask->control[band].mcs[0];
2085 #endif
2086 #endif
2087 
2088 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2089 	if (MLAN_STATUS_SUCCESS != status) {
2090 		ret = -EFAULT;
2091 		goto done;
2092 	}
2093 
2094 done:
2095 	if (status != MLAN_STATUS_PENDING)
2096 		kfree(req);
2097 	LEAVE();
2098 	return ret;
2099 }
2100 
2101 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
2102 /**
2103  * @brief Request the driver to get antenna configuration
2104  *
2105  * @param wiphy           A pointer to wiphy structure
2106  * @param tx_ant          Bitmaps of allowed antennas to use for TX
2107  * @param rx_ant          Bitmaps of allowed antennas to use for RX
2108  *
2109  * @return                0 -- success, otherwise fail
2110  */
2111 int
woal_cfg80211_get_antenna(struct wiphy * wiphy,u32 * tx_ant,u32 * rx_ant)2112 woal_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant)
2113 {
2114 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
2115 	moal_private *priv = NULL;
2116 	mlan_ds_radio_cfg *radio = NULL;
2117 	mlan_ioctl_req *req = NULL;
2118 	mlan_status status = MLAN_STATUS_SUCCESS;
2119 	int ret = 0;
2120 
2121 	ENTER();
2122 
2123 	if (!handle) {
2124 		PRINTM(MFATAL, "Unable to get handle\n");
2125 		ret = -EINVAL;
2126 		goto done;
2127 	}
2128 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
2129 	if (!priv) {
2130 		ret = -EINVAL;
2131 		goto done;
2132 	}
2133 
2134 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
2135 	if (req == NULL) {
2136 		ret = -ENOMEM;
2137 		goto done;
2138 	}
2139 
2140 	radio = (mlan_ds_radio_cfg *)req->pbuf;
2141 	radio->sub_command = MLAN_OID_ANT_CFG;
2142 	req->req_id = MLAN_IOCTL_RADIO_CFG;
2143 	req->action = MLAN_ACT_GET;
2144 
2145 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2146 	if (MLAN_STATUS_SUCCESS != status) {
2147 		ret = -EFAULT;
2148 		goto done;
2149 	}
2150 
2151 	*tx_ant = radio->param.ant_cfg_1x1.antenna;
2152 	*rx_ant = radio->param.ant_cfg_1x1.antenna;
2153 
2154 done:
2155 	if (status != MLAN_STATUS_PENDING)
2156 		kfree(req);
2157 	/* Driver must return -EINVAL to cfg80211 */
2158 	if (ret)
2159 		ret = -EINVAL;
2160 	LEAVE();
2161 	return ret;
2162 
2163 }
2164 
2165 /**
2166  * @brief Request the driver to set antenna configuration
2167  *
2168  * @param wiphy           A pointer to wiphy structure
2169  * @param tx_ant          Bitmaps of allowed antennas to use for TX
2170  * @param rx_ant          Bitmaps of allowed antennas to use for RX
2171  *
2172  * @return                0 -- success, otherwise fail
2173  */
2174 int
woal_cfg80211_set_antenna(struct wiphy * wiphy,u32 tx_ant,u32 rx_ant)2175 woal_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant)
2176 {
2177 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
2178 	moal_private *priv = NULL;
2179 	mlan_ds_radio_cfg *radio = NULL;
2180 	mlan_ioctl_req *req = NULL;
2181 	mlan_status status = MLAN_STATUS_SUCCESS;
2182 	int ret = 0;
2183 
2184 	ENTER();
2185 
2186 	if (!handle) {
2187 		PRINTM(MFATAL, "Unable to get handle\n");
2188 		ret = -EINVAL;
2189 		goto done;
2190 	}
2191 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
2192 	if (!priv) {
2193 		ret = -EINVAL;
2194 		goto done;
2195 	}
2196 
2197 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
2198 	if (req == NULL) {
2199 		ret = -ENOMEM;
2200 		goto done;
2201 	}
2202 	radio = (mlan_ds_radio_cfg *)req->pbuf;
2203 	radio->sub_command = MLAN_OID_ANT_CFG;
2204 	req->req_id = MLAN_IOCTL_RADIO_CFG;
2205 	req->action = MLAN_ACT_SET;
2206 	radio->param.ant_cfg_1x1.antenna = tx_ant;
2207 
2208 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2209 	if (MLAN_STATUS_SUCCESS != status) {
2210 		ret = -EFAULT;
2211 		goto done;
2212 	}
2213 
2214 done:
2215 	if (status != MLAN_STATUS_PENDING)
2216 		kfree(req);
2217 	/* Driver must return -EINVAL to cfg80211 */
2218 	if (ret)
2219 		ret = -EINVAL;
2220 	LEAVE();
2221 	return ret;
2222 }
2223 #endif
2224 
2225 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
2226 /**
2227  * @brief register/unregister mgmt frame forwarding
2228  *
2229  * @param wiphy           A pointer to wiphy structure
2230  * @param dev             A pointer to net_device structure
2231  * @param frame_type      Bit mask for mgmt frame type
2232  * @param reg             Register or unregister
2233  *
2234  * @return                0 -- success, otherwise fail
2235  */
2236 void
woal_cfg80211_mgmt_frame_register(struct wiphy * wiphy,struct net_device * dev,u16 frame_type,bool reg)2237 woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
2238 				  struct net_device *dev, u16 frame_type,
2239 				  bool reg)
2240 #else
2241 /**
2242  * @brief register/unregister mgmt frame forwarding
2243  *
2244  * @param wiphy           A pointer to wiphy structure
2245  * @param wdev            A pointer to wireless_dev structure
2246  * @param frame_type      Bit mask for mgmt frame type
2247  * @param reg             Register or unregister
2248  *
2249  * @return                0 -- success, otherwise fail
2250  */
2251 void
2252 woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
2253 				  struct wireless_dev *wdev, u16 frame_type,
2254 				  bool reg)
2255 #endif
2256 {
2257 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
2258 	struct net_device *dev = wdev->netdev;
2259 #endif
2260 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2261 	mlan_status status = MLAN_STATUS_SUCCESS;
2262 	t_u32 mgmt_subtype_mask = 0x0;
2263 	t_u32 last_mgmt_subtype_mask = priv->mgmt_subtype_mask;
2264 
2265 	ENTER();
2266 	if (reg == MTRUE) {
2267 		/* set mgmt_subtype_mask based on origin value */
2268 		mgmt_subtype_mask =
2269 			last_mgmt_subtype_mask | BIT(frame_type >> 4);
2270 	} else {
2271 		/* clear mgmt_subtype_mask */
2272 		mgmt_subtype_mask =
2273 			last_mgmt_subtype_mask & ~BIT(frame_type >> 4);
2274 	}
2275 	PRINTM(MIOCTL,
2276 	       "%s: mgmt_subtype_mask=0x%x last_mgmt_subtype_mask=0x%x\n",
2277 	       dev->name, mgmt_subtype_mask, last_mgmt_subtype_mask);
2278 	if (mgmt_subtype_mask != last_mgmt_subtype_mask) {
2279 
2280 		last_mgmt_subtype_mask = mgmt_subtype_mask;
2281 		/* Notify driver that a mgmt frame type was registered.
2282 		 * Note that this callback may not sleep, and cannot run
2283 		 * concurrently with itself. */
2284 		status = woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET,
2285 					      &mgmt_subtype_mask, MOAL_NO_WAIT);
2286 		priv->mgmt_subtype_mask = last_mgmt_subtype_mask;
2287 	}
2288 
2289 	LEAVE();
2290 }
2291 
2292 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
2293 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
2294 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
2295 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
2296 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2297 /**
2298  * @brief tx mgmt frame
2299  *
2300  * @param wiphy                 A pointer to wiphy structure
2301  * @param wdev                  A pointer to wireless_dev structure
2302  * @param params                A pointer to cfg80211_mgmt_tx_params structure
2303  * @param cookie                A pointer to frame cookie
2304  *
2305  * @return                0 -- success, otherwise fail
2306  */
2307 #else
2308 /**
2309  * @brief tx mgmt frame
2310  *
2311  * @param wiphy                 A pointer to wiphy structure
2312  * @param wdev                  A pointer to wireless_dev structure
2313  * @param chan                  A pointer to ieee80211_channel structure
2314  * @param offchan               Off channel or not
2315  * @param wait                  Duration to wait
2316  * @param buf                   Frame buffer
2317  * @param len                   Frame length
2318  * @param no_cck                No CCK check
2319  * @param dont_wait_for_ack     Do not wait for ACK
2320  * @param cookie                A pointer to frame cookie
2321  *
2322  * @return                0 -- success, otherwise fail
2323  */
2324 #endif
2325 #else
2326 /**
2327  * @brief tx mgmt frame
2328  *
2329  * @param wiphy                 A pointer to wiphy structure
2330  * @param wdev                  A pointer to wireless_dev structure
2331  * @param chan                  A pointer to ieee80211_channel structure
2332  * @param offchan               Off channel or not
2333  * @param channel_type          Channel type
2334  * @param channel_type_valid    Is channel type valid or not
2335  * @param wait                  Duration to wait
2336  * @param buf                   Frame buffer
2337  * @param len                   Frame length
2338  * @param no_cck                No CCK check
2339  * @param dont_wait_for_ack     Do not wait for ACK
2340  * @param cookie                A pointer to frame cookie
2341  *
2342  * @return                0 -- success, otherwise fail
2343  */
2344 #endif
2345 #else
2346 /**
2347  * @brief tx mgmt frame
2348  *
2349  * @param wiphy                 A pointer to wiphy structure
2350  * @param dev                   A pointer to net_device structure
2351  * @param chan                  A pointer to ieee80211_channel structure
2352  * @param offchan               Off channel or not
2353  * @param channel_type          Channel type
2354  * @param channel_type_valid    Is channel type valid or not
2355  * @param wait                  Duration to wait
2356  * @param buf                   Frame buffer
2357  * @param len                   Frame length
2358  * @param no_cck                No CCK check
2359  * @param dont_wait_for_ack     Do not wait for ACK
2360  * @param cookie                A pointer to frame cookie
2361  *
2362  * @return                0 -- success, otherwise fail
2363  */
2364 #endif
2365 #else
2366 /**
2367  * @brief tx mgmt frame
2368  *
2369  * @param wiphy                 A pointer to wiphy structure
2370  * @param dev                   A pointer to net_device structure
2371  * @param chan                  A pointer to ieee80211_channel structure
2372  * @param offchan               Off channel or not
2373  * @param channel_type          Channel type
2374  * @param channel_type_valid    Is channel type valid or not
2375  * @param wait                  Duration to wait
2376  * @param buf                   Frame buffer
2377  * @param len                   Frame length
2378  * @param no_cck                No CCK check
2379  * @param cookie                A pointer to frame cookie
2380  *
2381  * @return                0 -- success, otherwise fail
2382  */
2383 #endif
2384 #else
2385 /**
2386  * @brief tx mgmt frame
2387  *
2388  * @param wiphy                 A pointer to wiphy structure
2389  * @param dev                   A pointer to net_device structure
2390  * @param chan                  A pointer to ieee80211_channel structure
2391  * @param offchan               Off channel or not
2392  * @param channel_type          Channel type
2393  * @param channel_type_valid    Is channel type valid or not
2394  * @param wait                  Duration to wait
2395  * @param buf                   Frame buffer
2396  * @param len                   Frame length
2397  * @param cookie                A pointer to frame cookie
2398  *
2399  * @return                0 -- success, otherwise fail
2400  */
2401 #endif
2402 int
woal_cfg80211_mgmt_tx(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_mgmt_tx_params * params,u64 * cookie)2403 woal_cfg80211_mgmt_tx(struct wiphy *wiphy,
2404 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
2405 		      struct net_device *dev,
2406 #else
2407 		      struct wireless_dev *wdev,
2408 #endif
2409 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2410 		      struct cfg80211_mgmt_tx_params *params,
2411 #else
2412 		      struct ieee80211_channel *chan, bool offchan,
2413 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
2414 		      enum nl80211_channel_type channel_type,
2415 		      bool channel_type_valid,
2416 #endif
2417 		      unsigned int wait, const u8 *buf, size_t len,
2418 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
2419 		      bool no_cck,
2420 #endif
2421 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
2422 		      bool dont_wait_for_ack,
2423 #endif
2424 #endif
2425 		      u64 * cookie)
2426 {
2427 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
2428 	struct net_device *dev = wdev->netdev;
2429 #endif
2430 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2431 	struct ieee80211_channel *chan = params->chan;
2432 	unsigned int wait = params->wait;
2433 	const u8 *buf = params->buf;
2434 	size_t len = params->len;
2435 #endif
2436 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2437 	int ret = 0;
2438 	pmlan_buffer pmbuf = NULL;
2439 	mlan_status status = MLAN_STATUS_SUCCESS;
2440 	t_u16 packet_len = 0;
2441 	t_u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
2442 	t_u32 pkt_type;
2443 	t_u32 tx_control;
2444 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
2445 	t_u8 channel_status;
2446 	t_u32 duration;
2447 	moal_private *remain_priv = NULL;
2448 #endif
2449 	unsigned long flags;
2450 	struct sk_buff *skb = NULL;
2451 	struct tx_status_info *tx_info = NULL;
2452 
2453 	ENTER();
2454 
2455 	if (buf == NULL || len == 0) {
2456 		PRINTM(MERROR, "woal_cfg80211_mgmt_tx() corrupt data\n");
2457 		LEAVE();
2458 		return -EFAULT;
2459 	}
2460 
2461 	/* If the packet is probe response, that means we are in listen phase,
2462 	   so we should not call remain_on_channel_cfg because
2463 	   remain_on_channl already handled it. If the packet if action, that
2464 	   means we are in PD/GO negotiation, so we should call
2465 	   remain_on_channel_cfg in order to receive action frame from peer
2466 	   device */
2467 	if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
2468 	    ieee80211_is_probe_resp(((struct ieee80211_mgmt *)buf)->
2469 				    frame_control)) {
2470 		PRINTM(MIOCTL, "Skip send probe_resp in GO/UAP mode\n");
2471 		goto done;
2472 	}
2473 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
2474 	if (ieee80211_is_action(((struct ieee80211_mgmt *)buf)->frame_control)) {
2475 #ifdef WIFI_DIRECT_SUPPORT
2476 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
2477 			woal_cfg80211_display_p2p_actframe(buf, len, chan,
2478 							   MTRUE);
2479 		if (priv->phandle->is_go_timer_set) {
2480 			woal_cancel_timer(&priv->phandle->go_timer);
2481 			priv->phandle->is_go_timer_set = MFALSE;
2482 		}
2483 #endif
2484 		if (priv->phandle->is_remain_timer_set) {
2485 			woal_cancel_timer(&priv->phandle->remain_timer);
2486 			woal_remain_timer_func(priv->phandle);
2487 		}
2488 		/* With sd8777 We have difficulty to receive response packet in 500ms */
2489 #define MGMT_TX_DEFAULT_WAIT_TIME	   1500
2490 		if (priv->phandle->remain_on_channel)
2491 			remain_priv =
2492 				priv->phandle->priv[priv->phandle->
2493 						    remain_bss_index];
2494 		/** cancel previous remain on channel */
2495 		if (priv->phandle->remain_on_channel && remain_priv) {
2496 			if ((priv->phandle->chan.center_freq !=
2497 			     chan->center_freq)
2498 				) {
2499 				if (woal_cfg80211_remain_on_channel_cfg
2500 				    (remain_priv, MOAL_IOCTL_WAIT, MTRUE,
2501 				     &channel_status, NULL, 0, 0))
2502 					PRINTM(MERROR,
2503 					       "mgmt_tx:Fail to cancel remain on channel\n");
2504 			}
2505 			if (priv->phandle->cookie) {
2506 				cfg80211_remain_on_channel_expired(
2507 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
2508 									  remain_priv->
2509 									  netdev,
2510 #else
2511 									  remain_priv->
2512 									  wdev,
2513 #endif
2514 									  priv->
2515 									  phandle->
2516 									  cookie,
2517 									  &priv->
2518 									  phandle->
2519 									  chan,
2520 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
2521 									  priv->
2522 									  phandle->
2523 									  channel_type,
2524 #endif
2525 									  GFP_ATOMIC);
2526 				priv->phandle->cookie = 0;
2527 			}
2528 			priv->phandle->remain_on_channel = MFALSE;
2529 		}
2530 #ifdef STA_CFG80211
2531 		/** cancel pending scan */
2532 		woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
2533 #endif
2534 
2535 		duration =
2536 			(wait >
2537 			 MGMT_TX_DEFAULT_WAIT_TIME) ? wait :
2538 			MGMT_TX_DEFAULT_WAIT_TIME;
2539 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
2540 		if (channel_type_valid)
2541 			ret = woal_cfg80211_remain_on_channel_cfg(priv,
2542 								  MOAL_IOCTL_WAIT,
2543 								  MFALSE,
2544 								  &channel_status,
2545 								  chan,
2546 								  channel_type,
2547 								  duration);
2548 		else
2549 #endif
2550 			ret = woal_cfg80211_remain_on_channel_cfg(priv,
2551 								  MOAL_IOCTL_WAIT,
2552 								  MFALSE,
2553 								  &channel_status,
2554 								  chan, 0,
2555 								  duration);
2556 		if (ret) {
2557 			/* Return fail will cause p2p connnection fail */
2558 			woal_sched_timeout(2);
2559 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
2560 			if (channel_type_valid)
2561 				ret = woal_cfg80211_remain_on_channel_cfg(priv,
2562 									  MOAL_IOCTL_WAIT,
2563 									  MFALSE,
2564 									  &channel_status,
2565 									  chan,
2566 									  channel_type,
2567 									  duration);
2568 			else
2569 #endif
2570 				ret = woal_cfg80211_remain_on_channel_cfg(priv,
2571 									  MOAL_IOCTL_WAIT,
2572 									  MFALSE,
2573 									  &channel_status,
2574 									  chan,
2575 									  0,
2576 									  duration);
2577 			PRINTM(MERROR,
2578 			       "Try configure remain on channel again, ret=%d\n",
2579 			       ret);
2580 			ret = 0;
2581 		} else {
2582 			priv->phandle->remain_on_channel = MTRUE;
2583 			priv->phandle->remain_bss_index = priv->bss_index;
2584 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
2585 			priv->phandle->channel_type = channel_type;
2586 #endif
2587 			memcpy(&priv->phandle->chan, chan,
2588 			       sizeof(struct ieee80211_channel));
2589 			PRINTM(MIOCTL,
2590 			       "%s: Mgmt Tx: Set remain channel=%d duration=%d\n",
2591 			       dev->name,
2592 			       ieee80211_frequency_to_channel(chan->
2593 							      center_freq),
2594 			       duration);
2595 		}
2596 	}
2597 #endif
2598 
2599 	/* pkt_type + tx_control */
2600 #define HEADER_SIZE				8
2601 	packet_len = (t_u16)len + MLAN_MAC_ADDR_LENGTH;
2602 	pmbuf = woal_alloc_mlan_buffer(priv->phandle,
2603 				       MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
2604 				       packet_len + sizeof(packet_len));
2605 	if (!pmbuf) {
2606 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
2607 		ret = -ENOMEM;
2608 		goto done;
2609 	}
2610 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
2611 	*cookie = random32() | 1;
2612 #else
2613 	*cookie = prandom_u32() | 1;
2614 #endif
2615 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
2616 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
2617 	tx_control = 0;
2618 	/* Add pkt_type and tx_control */
2619 	memcpy(pmbuf->pbuf + pmbuf->data_offset, &pkt_type, sizeof(pkt_type));
2620 	memcpy(pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type), &tx_control,
2621 	       sizeof(tx_control));
2622 	/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */
2623 #define PACKET_ADDR4_POS		(2 + 2 + 6 + 6 + 6 + 2)
2624 	memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE, &packet_len,
2625 	       sizeof(packet_len));
2626 	memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
2627 	       sizeof(packet_len), buf, PACKET_ADDR4_POS);
2628 	memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
2629 	       sizeof(packet_len)
2630 	       + PACKET_ADDR4_POS, addr, MLAN_MAC_ADDR_LENGTH);
2631 	memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE +
2632 	       sizeof(packet_len)
2633 	       + PACKET_ADDR4_POS + MLAN_MAC_ADDR_LENGTH,
2634 	       buf + PACKET_ADDR4_POS, len - PACKET_ADDR4_POS);
2635 
2636 	pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
2637 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
2638 	pmbuf->bss_index = priv->bss_index;
2639 	if (ieee80211_is_action(((struct ieee80211_mgmt *)buf)->frame_control)) {
2640 		pmbuf->flags = MLAN_BUF_FLAG_TX_STATUS;
2641 		pmbuf->tx_seq_num = ++priv->tx_seq_num;
2642 		tx_info = kzalloc(sizeof(struct tx_status_info), GFP_ATOMIC);
2643 		if (tx_info) {
2644 			skb = alloc_skb(len, GFP_ATOMIC);
2645 			if (skb) {
2646 				memcpy(skb->data, buf, len);
2647 				skb_put(skb, len);
2648 				spin_lock_irqsave(&priv->tx_stat_lock, flags);
2649 				tx_info->tx_cookie = *cookie;
2650 				tx_info->tx_skb = skb;
2651 				tx_info->tx_seq_num = pmbuf->tx_seq_num;
2652 				INIT_LIST_HEAD(&tx_info->link);
2653 				list_add_tail(&tx_info->link,
2654 					      &priv->tx_stat_queue);
2655 				spin_unlock_irqrestore(&priv->tx_stat_lock,
2656 						       flags);
2657 			} else {
2658 				kfree(tx_info);
2659 				tx_info = NULL;
2660 			}
2661 		}
2662 	}
2663 
2664 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
2665 
2666 	switch (status) {
2667 	case MLAN_STATUS_PENDING:
2668 		atomic_inc(&priv->phandle->tx_pending);
2669 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
2670 
2671 		/* Delay 30ms to guarantee the packet has been already tx'ed,
2672 		 * becuase if we call cfg80211_mgmt_tx_status() immediately,
2673 		 * then wpa_supplicant will call cancel_remain_on_channel(),
2674 		 * which may affect the mgmt frame tx. Meanwhile it is only
2675 		 * necessary for P2P action handshake to wait 30ms. */
2676 		if (ieee80211_is_action
2677 		    (((struct ieee80211_mgmt *)buf)->frame_control)) {
2678 			if (tx_info)
2679 				break;
2680 			else
2681 				woal_sched_timeout(30);
2682 		}
2683 
2684 		/* Notify the mgmt tx status */
2685 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
2686 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
2687 		cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true,
2688 					GFP_ATOMIC);
2689 #else
2690 		cfg80211_mgmt_tx_status(priv->wdev, *cookie, buf, len, true,
2691 					GFP_ATOMIC);
2692 #endif
2693 #endif
2694 		break;
2695 	case MLAN_STATUS_SUCCESS:
2696 		woal_free_mlan_buffer(priv->phandle, pmbuf);
2697 		break;
2698 	case MLAN_STATUS_FAILURE:
2699 	default:
2700 		woal_free_mlan_buffer(priv->phandle, pmbuf);
2701 		ret = -EFAULT;
2702 		break;
2703 	}
2704 
2705 done:
2706 	if (status != MLAN_STATUS_PENDING) {
2707 		if (tx_info)
2708 			woal_remove_tx_info(priv, tx_info->tx_seq_num);
2709 
2710 	}
2711 
2712 	LEAVE();
2713 	return ret;
2714 }
2715 
2716 /**
2717  * @brief Add custom ie to mgmt frames.
2718  *
2719  * @param priv                  A pointer to moal private structure
2720  * @param beacon_ies_data       Beacon ie
2721  * @param beacon_index          The index for beacon when auto index
2722  * @param proberesp_ies_data    Probe resp ie
2723  * @param proberesp_index       The index for probe resp when auto index
2724  * @param assocresp_ies_data    Assoc resp ie
2725  * @param assocresp_index       The index for assoc resp when auto index
2726  * @param probereq_ies_data     Probe req ie
2727  * @param probereq_index        The index for probe req when auto index
2728  * @param wait_option           wait option
2729  *
2730  * @return              0 -- success, otherwise fail
2731  */
2732 static int
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)2733 woal_cfg80211_custom_ie(moal_private *priv,
2734 			custom_ie *beacon_ies_data, t_u16 *beacon_index,
2735 			custom_ie *proberesp_ies_data, t_u16 *proberesp_index,
2736 			custom_ie *assocresp_ies_data, t_u16 *assocresp_index,
2737 			custom_ie *probereq_ies_data, t_u16 *probereq_index,
2738 			t_u8 wait_option)
2739 {
2740 	mlan_ioctl_req *ioctl_req = NULL;
2741 	mlan_ds_misc_cfg *misc = NULL;
2742 	mlan_ds_misc_custom_ie *custom_ie = NULL;
2743 	t_u8 *pos = NULL;
2744 	t_u16 len = 0;
2745 	int ret = 0;
2746 	mlan_status status = MLAN_STATUS_SUCCESS;
2747 
2748 	ENTER();
2749 
2750 	custom_ie = kzalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL);
2751 	if (!custom_ie) {
2752 		ret = -ENOMEM;
2753 		goto done;
2754 	}
2755 
2756 	custom_ie->type = TLV_TYPE_MGMT_IE;
2757 
2758 	pos = (t_u8 *)custom_ie->ie_data_list;
2759 	if (beacon_ies_data) {
2760 		len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
2761 			+ beacon_ies_data->ie_length;
2762 		memcpy(pos, beacon_ies_data, len);
2763 		pos += len;
2764 		custom_ie->len += len;
2765 	}
2766 
2767 	if (proberesp_ies_data) {
2768 		len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
2769 			+ proberesp_ies_data->ie_length;
2770 		memcpy(pos, proberesp_ies_data, len);
2771 		pos += len;
2772 		custom_ie->len += len;
2773 	}
2774 
2775 	if (assocresp_ies_data) {
2776 		len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
2777 			+ assocresp_ies_data->ie_length;
2778 		memcpy(pos, assocresp_ies_data, len);
2779 		custom_ie->len += len;
2780 	}
2781 
2782 	if (probereq_ies_data) {
2783 		len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
2784 			+ probereq_ies_data->ie_length;
2785 		memcpy(pos, probereq_ies_data, len);
2786 		pos += len;
2787 		custom_ie->len += len;
2788 	}
2789 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
2790 	if (ioctl_req == NULL) {
2791 		ret = -ENOMEM;
2792 		goto done;
2793 	}
2794 
2795 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
2796 	misc->sub_command = MLAN_OID_MISC_CUSTOM_IE;
2797 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
2798 	ioctl_req->action = MLAN_ACT_SET;
2799 
2800 	memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie));
2801 
2802 	status = woal_request_ioctl(priv, ioctl_req, wait_option);
2803 	if (MLAN_STATUS_SUCCESS != status) {
2804 		ret = -EFAULT;
2805 		goto done;
2806 	}
2807 
2808 	/* get the assigned index */
2809 	pos = (t_u8 *)(&misc->param.cust_ie.ie_data_list[0].ie_index);
2810 	if (beacon_ies_data && beacon_ies_data->ie_length
2811 	    && beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
2812 		/* save beacon ie index after auto-indexing */
2813 		*beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index;
2814 		len = sizeof(*beacon_ies_data) - MAX_IE_SIZE
2815 			+ beacon_ies_data->ie_length;
2816 		pos += len;
2817 	}
2818 
2819 	if (proberesp_ies_data && proberesp_ies_data->ie_length
2820 	    && proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
2821 		/* save probe resp ie index after auto-indexing */
2822 		*proberesp_index = *((t_u16 *)pos);
2823 		len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE
2824 			+ proberesp_ies_data->ie_length;
2825 		pos += len;
2826 	}
2827 
2828 	if (assocresp_ies_data && assocresp_ies_data->ie_length
2829 	    && assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
2830 		/* save assoc resp ie index after auto-indexing */
2831 		*assocresp_index = *((t_u16 *)pos);
2832 		len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE
2833 			+ assocresp_ies_data->ie_length;
2834 		pos += len;
2835 	}
2836 	if (probereq_ies_data && probereq_ies_data->ie_length
2837 	    && probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
2838 		/* save probe resp ie index after auto-indexing */
2839 		*probereq_index = *((t_u16 *)pos);
2840 		len = sizeof(*probereq_ies_data) - MAX_IE_SIZE
2841 			+ probereq_ies_data->ie_length;
2842 		pos += len;
2843 	}
2844 
2845 	if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL)
2846 		ret = -EFAULT;
2847 
2848 done:
2849 	if (status != MLAN_STATUS_PENDING)
2850 		kfree(ioctl_req);
2851 	kfree(custom_ie);
2852 	LEAVE();
2853 	return ret;
2854 }
2855 
2856 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,14,0)
2857 /**
2858  * @brief set Qos map
2859  *
2860  * @param wiphy         A pointer to wiphy structure
2861  * @param dev           A pointer to net_device structure
2862  * @param qos_map       A pointer to cfg80211_qos_map structure
2863  *
2864  *
2865  * @return              0 -- success, otherwise fail
2866  */
2867 int
woal_cfg80211_set_qos_map(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_qos_map * qos_map)2868 woal_cfg80211_set_qos_map(struct wiphy *wiphy,
2869 			  struct net_device *dev,
2870 			  struct cfg80211_qos_map *qos_map)
2871 {
2872 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2873 	int i, j, ret = 0;
2874 
2875 	ENTER();
2876     /**clear dscp map*/
2877 	if (!qos_map) {
2878 		memset(priv->dscp_map, 0xFF, sizeof(priv->dscp_map));
2879 		goto done;
2880 	}
2881 
2882     /**update dscp map*/
2883 	for (i = 0; i < MAX_NUM_TID; i++) {
2884 		PRINTM(MINFO, "TID %d: dscp_low=%d, dscp_high=%d\n", i,
2885 		       qos_map->up[i].low, qos_map->up[i].high);
2886 		if (qos_map->up[i].low != 0xff && qos_map->up[i].high != 0xff
2887 		    && qos_map->up[i].high <= 63) {
2888 			for (j = qos_map->up[i].low; j <= qos_map->up[i].high;
2889 			     j++)
2890 				priv->dscp_map[j] = i;
2891 		}
2892 	}
2893 
2894 	for (i = 0; i < qos_map->num_des; i++) {
2895 		if ((qos_map->dscp_exception[i].dscp <= 63) &&
2896 		    (qos_map->dscp_exception[i].up <= 7)) {
2897 			PRINTM(MINFO, "dscp excpt: value=%d priority=%d\n",
2898 			       qos_map->dscp_exception[i].dscp,
2899 			       qos_map->dscp_exception[i].up);
2900 			priv->dscp_map[qos_map->dscp_exception[i].dscp] =
2901 				qos_map->dscp_exception[i].up;
2902 		}
2903 	}
2904 
2905     /**UAP update (re)associate response*/
2906 	if (priv->bss_type == MLAN_BSS_TYPE_UAP) {
2907 		IEEEtypes_Generic_t qos_map_ie;
2908 		t_u16 qos_map_ies_len;
2909 
2910 		memcpy(qos_map_ie.data, (t_u8 *)qos_map->dscp_exception,
2911 		       2 * qos_map->num_des);
2912 		memcpy(&qos_map_ie.data[2 * qos_map->num_des],
2913 		       (t_u8 *)qos_map->up, sizeof(qos_map->up));
2914 		qos_map_ie.ieee_hdr.element_id = QOS_MAPPING;
2915 		qos_map_ie.ieee_hdr.len =
2916 			2 * qos_map->num_des + sizeof(qos_map->up);
2917 		qos_map_ies_len =
2918 			qos_map_ie.ieee_hdr.len + sizeof(qos_map_ie.ieee_hdr);
2919 
2920 		/* set the assoc response ies */
2921 		ret = woal_cfg80211_mgmt_frame_ie(priv,
2922 						  NULL, 0, NULL, 0,
2923 						  (t_u8 *)&qos_map_ie,
2924 						  qos_map_ies_len, NULL, 0,
2925 						  MGMT_MASK_ASSOC_RESP_QOS_MAP,
2926 						  MOAL_IOCTL_WAIT);
2927 		if (ret) {
2928 			PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n");
2929 			goto done;
2930 		}
2931 
2932 	}
2933 
2934 done:
2935 	LEAVE();
2936 	return ret;
2937 }
2938 #endif
2939 
2940 /**
2941  * @brief get specific ie
2942  *
2943  * @param ie              Pointer to IEs
2944  * @param len             Total length of ie
2945  * @param ie_out		  Pointer to out IE buf
2946  * @param mask            IE mask
2947  *
2948  * @return                out IE length
2949  */
2950 static t_u16
woal_get_specific_ie(const t_u8 * ie,int len,t_u8 * ie_out,t_u16 mask)2951 woal_get_specific_ie(const t_u8 *ie, int len, t_u8 *ie_out, t_u16 mask)
2952 {
2953 	int left_len = len;
2954 	const t_u8 *pos = ie;
2955 	int length;
2956 	t_u8 id = 0;
2957 	t_u16 out_len = 0;
2958 	IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
2959 	const u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
2960 	const u8 p2p_oui[4] = { 0x50, 0x6f, 0x9a, 0x09 };
2961 	const u8 wfd_oui[4] = { 0x50, 0x6f, 0x9a, 0x0a };
2962 	const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
2963 
2964 	ENTER();
2965 	while (left_len >= 2) {
2966 		length = *(pos + 1);
2967 		id = *pos;
2968 		if ((length + 2) > left_len)
2969 			break;
2970 		if (id == VENDOR_SPECIFIC_221) {
2971 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
2972 			if (!memcmp
2973 			    (pvendor_ie->vend_hdr.oui, wmm_oui,
2974 			     sizeof(pvendor_ie->vend_hdr.oui)) &&
2975 			    pvendor_ie->vend_hdr.oui_type == wmm_oui[3]) {
2976 				PRINTM(MIOCTL, "find WMM IE\n");
2977 			} else if (!memcmp
2978 				   (pvendor_ie->vend_hdr.oui, p2p_oui,
2979 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
2980 				   pvendor_ie->vend_hdr.oui_type ==
2981 				   p2p_oui[3]) {
2982 				if (mask & IE_MASK_P2P) {
2983 		    /** only get first p2p ie here */
2984 					memcpy(ie_out + out_len, pos,
2985 					       length + 2);
2986 					out_len += length + 2;
2987 					break;
2988 				}
2989 			} else if (!memcmp
2990 				   (pvendor_ie->vend_hdr.oui, wps_oui,
2991 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
2992 				   pvendor_ie->vend_hdr.oui_type ==
2993 				   wps_oui[3]) {
2994 				if (mask & IE_MASK_WPS) {
2995 					memcpy(ie_out + out_len, pos,
2996 					       length + 2);
2997 					out_len += length + 2;
2998 				}
2999 			} else if (!memcmp
3000 				   (pvendor_ie->vend_hdr.oui, wfd_oui,
3001 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
3002 				   pvendor_ie->vend_hdr.oui_type ==
3003 				   wfd_oui[3]) {
3004 				if (mask & IE_MASK_WFD) {
3005 					memcpy(ie_out + out_len, pos,
3006 					       length + 2);
3007 					out_len += length + 2;
3008 				}
3009 			} else if (mask & IE_MASK_VENDOR) {
3010 				memcpy(ie_out + out_len, pos, length + 2);
3011 				out_len += length + 2;
3012 			}
3013 		}
3014 		pos += (length + 2);
3015 		left_len -= (length + 2);
3016 	}
3017 	LEAVE();
3018 	return out_len;
3019 }
3020 
3021 /**
3022  * @brief Find specific IE from IE buffer
3023  *
3024  * @param ie              Pointer to IEs
3025  * @param len             Total length of ie
3026  * @param spec_ie         Pointer to specific IE buffer
3027  * @param spec_len        Total length of specifc IE
3028  *
3029  * @return                out IE length
3030  */
3031 static t_u8
woal_find_ie(const t_u8 * ie,int len,const t_u8 * spec_ie,int spec_len)3032 woal_find_ie(const t_u8 *ie, int len, const t_u8 *spec_ie, int spec_len)
3033 {
3034 	int left_len = len;
3035 	const t_u8 *pos = ie;
3036 	int length;
3037 	t_u8 id = 0;
3038 
3039 	while (left_len >= 2) {
3040 		length = *(pos + 1);
3041 		id = *pos;
3042 		if ((length + 2) > left_len)
3043 			break;
3044 		if ((length + 2) == spec_len) {
3045 			if (!memcmp(pos, spec_ie, spec_len)) {
3046 				return MTRUE;
3047 			}
3048 		}
3049 		pos += (length + 2);
3050 		left_len -= (length + 2);
3051 	}
3052 	return MFALSE;
3053 }
3054 
3055 /**
3056  * @brief Filter specific IE in ie buf
3057  *
3058  * @param priv            pointer to moal private structure
3059  * @param ie              Pointer to IEs
3060  * @param len             Total length of ie
3061  * @param ie_out		  Pointer to out IE buf
3062  * @param wps_flag	      flag for wps/p2p
3063  * @param dup_ie          Pointer to duplicate ie
3064  * @param dup_ie_len 	  duplicate IE len
3065  *
3066  * @return                out IE length
3067  */
3068 static t_u16
woal_filter_beacon_ies(moal_private * priv,const t_u8 * ie,int len,t_u8 * ie_out,t_u16 wps_flag,const t_u8 * dup_ie,int dup_ie_len)3069 woal_filter_beacon_ies(moal_private *priv, const t_u8 *ie, int len,
3070 		       t_u8 *ie_out, t_u16 wps_flag, const t_u8 *dup_ie,
3071 		       int dup_ie_len)
3072 {
3073 	int left_len = len;
3074 	const t_u8 *pos = ie;
3075 	int length;
3076 	t_u8 id = 0;
3077 	t_u16 out_len = 0;
3078 	IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
3079 	const u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
3080 	const u8 p2p_oui[4] = { 0x50, 0x6f, 0x9a, 0x09 };
3081 	const u8 wfd_oui[4] = { 0x50, 0x6f, 0x9a, 0x0a };
3082 	const t_u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
3083 	t_u8 find_p2p_ie = MFALSE;
3084 	t_u8 enable_11d = MFALSE;
3085 
3086 	/* ERP_INFO/EXTENDED_SUPPORT_RATES/HT_CAPABILITY/HT_OPERATION/WMM
3087 	 * and WPS/P2P/WFD IE will be fileter out */
3088 	while (left_len >= 2) {
3089 		length = *(pos + 1);
3090 		id = *pos;
3091 		if ((length + 2) > left_len)
3092 			break;
3093 		if (dup_ie && dup_ie_len &&
3094 		    woal_find_ie(dup_ie, dup_ie_len, pos, length + 2)) {
3095 			PRINTM(MIOCTL, "skip duplicate IE\n");
3096 			pos += (length + 2);
3097 			left_len -= (length + 2);
3098 			continue;
3099 		}
3100 		switch (id) {
3101 		case COUNTRY_INFO:
3102 			enable_11d = MTRUE;
3103 			break;
3104 		case EXTENDED_SUPPORTED_RATES:
3105 		case WLAN_EID_ERP_INFO:
3106 		case HT_CAPABILITY:
3107 		case HT_OPERATION:
3108 		case REGULATORY_CLASS:
3109 		case OVERLAPBSSSCANPARAM:
3110 		case WAPI_IE:
3111 			break;
3112 		case VENDOR_SPECIFIC_221:
3113 			/* filter out wmm ie */
3114 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
3115 			if (!memcmp
3116 			    (pvendor_ie->vend_hdr.oui, wmm_oui,
3117 			     sizeof(pvendor_ie->vend_hdr.oui)) &&
3118 			    pvendor_ie->vend_hdr.oui_type == wmm_oui[3]) {
3119 				break;
3120 			}
3121 			/* filter out wps ie */
3122 			else if (!memcmp
3123 				 (pvendor_ie->vend_hdr.oui, wps_oui,
3124 				  sizeof(pvendor_ie->vend_hdr.oui)) &&
3125 				 pvendor_ie->vend_hdr.oui_type == wps_oui[3]) {
3126 				if (wps_flag & IE_MASK_WPS)
3127 					break;
3128 			}
3129 			/* filter out first p2p ie */
3130 			else if (!memcmp
3131 				 (pvendor_ie->vend_hdr.oui, p2p_oui,
3132 				  sizeof(pvendor_ie->vend_hdr.oui)) &&
3133 				 pvendor_ie->vend_hdr.oui_type == p2p_oui[3]) {
3134 				if (!find_p2p_ie && (wps_flag & IE_MASK_P2P)) {
3135 					find_p2p_ie = MTRUE;
3136 					break;
3137 				}
3138 			}
3139 			/* filter out wfd ie */
3140 			else if (!memcmp
3141 				 (pvendor_ie->vend_hdr.oui, wfd_oui,
3142 				  sizeof(pvendor_ie->vend_hdr.oui)) &&
3143 				 pvendor_ie->vend_hdr.oui_type == wfd_oui[3]) {
3144 				if (wps_flag & IE_MASK_WFD)
3145 					break;
3146 			} else if (wps_flag & IE_MASK_VENDOR) {
3147 				//filter out vendor IE
3148 				break;
3149 			}
3150 			memcpy(ie_out + out_len, pos, length + 2);
3151 			out_len += length + 2;
3152 			break;
3153 		default:
3154 			memcpy(ie_out + out_len, pos, length + 2);
3155 			out_len += length + 2;
3156 			break;
3157 		}
3158 		pos += (length + 2);
3159 		left_len -= (length + 2);
3160 	}
3161 
3162 	if (enable_11d)
3163 		woal_set_11d(priv, MOAL_IOCTL_WAIT, MTRUE);
3164 	return out_len;
3165 }
3166 
3167 #ifdef WIFI_DIRECT_SUPPORT
3168 /**
3169  * @brief Check if selected_registrar_on in wps_ie
3170  *
3171  * @param ie              Pointer to IEs
3172  * @param len             Total length of ie
3173  *
3174  * @return                MTRUE/MFALSE
3175  */
3176 t_u8
is_selected_registrar_on(const t_u8 * ie,int len)3177 is_selected_registrar_on(const t_u8 *ie, int len)
3178 {
3179 #define WPS_IE_FIX_LEN		6
3180 #define TLV_ID_SELECTED_REGISTRAR 0x1041
3181 	int left_len = len - WPS_IE_FIX_LEN;
3182 	TLV_Generic_t *tlv = (TLV_Generic_t *)(ie + WPS_IE_FIX_LEN);
3183 	u16 tlv_type, tlv_len;
3184 	u8 *pos = NULL;
3185 	while (left_len > sizeof(TLV_Generic_t)) {
3186 		tlv_type = ntohs(tlv->type);
3187 		tlv_len = ntohs(tlv->len);
3188 		if (tlv_type == TLV_ID_SELECTED_REGISTRAR) {
3189 			PRINTM(MIOCTL, "Selected Registrar found !");
3190 			pos = (u8 *)tlv + sizeof(TLV_Generic_t);
3191 			if (*pos == 1)
3192 				return MTRUE;
3193 			else
3194 				return MFALSE;
3195 		}
3196 		tlv = (TLV_Generic_t *)((u8 *)tlv + tlv_len +
3197 					sizeof(TLV_Generic_t));
3198 		left_len -= tlv_len + sizeof(TLV_Generic_t);
3199 	}
3200 	return MFALSE;
3201 }
3202 
3203 /**
3204  * @brief Check if selected_registrar_on in ies
3205  *
3206  * @param ie              Pointer to IEs
3207  * @param len             Total length of ie
3208  *
3209  *
3210  * @return                MTRUE/MFALSE
3211  */
3212 static t_u16
woal_is_selected_registrar_on(const t_u8 * ie,int len)3213 woal_is_selected_registrar_on(const t_u8 *ie, int len)
3214 {
3215 	int left_len = len;
3216 	const t_u8 *pos = ie;
3217 	int length;
3218 	t_u8 id = 0;
3219 	IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
3220 	const u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
3221 
3222 	while (left_len >= 2) {
3223 		length = *(pos + 1);
3224 		id = *pos;
3225 		if ((length + 2) > left_len)
3226 			break;
3227 		switch (id) {
3228 		case VENDOR_SPECIFIC_221:
3229 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
3230 			if (!memcmp
3231 			    (pvendor_ie->vend_hdr.oui, wps_oui,
3232 			     sizeof(pvendor_ie->vend_hdr.oui)) &&
3233 			    pvendor_ie->vend_hdr.oui_type == wps_oui[3]) {
3234 				PRINTM(MIOCTL, "Find WPS ie\n");
3235 				return is_selected_registrar_on(pos,
3236 								length + 2);
3237 			}
3238 			break;
3239 		default:
3240 			break;
3241 		}
3242 		pos += (length + 2);
3243 		left_len -= (length + 2);
3244 	}
3245 	return MFALSE;
3246 }
3247 #endif
3248 
3249 /**
3250  * @brief config AP or GO for mgmt frame ies.
3251  *
3252  * @param priv                  A pointer to moal private structure
3253  * @param beacon_ies            A pointer to beacon ies
3254  * @param beacon_ies_len        Beacon ies length
3255  * @param proberesp_ies         A pointer to probe resp ies
3256  * @param proberesp_ies_len     Probe resp ies length
3257  * @param assocresp_ies         A pointer to probe resp ies
3258  * @param assocresp_ies_len     Assoc resp ies length
3259  * @param probereq_ies          A pointer to probe req ies
3260  * @param probereq_ies_len      Probe req ies length *
3261  * @param mask					Mgmt frame mask
3262  * @param wait_option           wait_option
3263  *
3264  * @return                      0 -- success, otherwise fail
3265  */
3266 int
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)3267 woal_cfg80211_mgmt_frame_ie(moal_private *priv,
3268 			    const t_u8 *beacon_ies, size_t beacon_ies_len,
3269 			    const t_u8 *proberesp_ies, size_t proberesp_ies_len,
3270 			    const t_u8 *assocresp_ies, size_t assocresp_ies_len,
3271 			    const t_u8 *probereq_ies, size_t probereq_ies_len,
3272 			    t_u16 mask, t_u8 wait_option)
3273 {
3274 	int ret = 0;
3275 	t_u8 *pos = NULL;
3276 	custom_ie *beacon_ies_data = NULL;
3277 	custom_ie *proberesp_ies_data = NULL;
3278 	custom_ie *assocresp_ies_data = NULL;
3279 	custom_ie *probereq_ies_data = NULL;
3280 
3281 	/* static variables for mgmt frame ie auto-indexing */
3282 	t_u16 beacon_index = priv->beacon_index;
3283 	t_u16 proberesp_index = priv->proberesp_index;
3284 	t_u16 assocresp_index = priv->assocresp_index;
3285 	t_u16 probereq_index = priv->probereq_index;
3286 	t_u16 beacon_wps_index = priv->beacon_wps_index;
3287 	t_u16 proberesp_p2p_index = priv->proberesp_p2p_index;
3288 	t_u16 assocrep_qos_map_index = priv->assocresp_qos_map_index;
3289 	t_u16 proberesp_vendor_index = priv->proberesp_vendor_index;
3290 
3291 	ENTER();
3292 
3293 	/* we need remove vendor IE from beacon extra IE, vendor IE will be configure through proberesp_vendor_index */
3294 	if (mask & MGMT_MASK_BEACON_WPS_P2P) {
3295 		beacon_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
3296 		if (!beacon_ies_data) {
3297 			ret = -ENOMEM;
3298 			goto done;
3299 		}
3300 		if (beacon_ies && beacon_ies_len) {
3301 #ifdef WIFI_DIRECT_SUPPORT
3302 			if (woal_is_selected_registrar_on
3303 			    (beacon_ies, beacon_ies_len)) {
3304 				PRINTM(MIOCTL, "selected_registrar is on\n");
3305 				priv->phandle->is_go_timer_set = MTRUE;
3306 				woal_mod_timer(&priv->phandle->go_timer,
3307 					       MOAL_TIMER_10S);
3308 			} else
3309 				PRINTM(MIOCTL, "selected_registrar is off\n");
3310 #endif
3311 			beacon_ies_data->ie_index = beacon_wps_index;
3312 			beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON;
3313 			beacon_ies_data->ie_length =
3314 				woal_filter_beacon_ies(priv, beacon_ies,
3315 						       beacon_ies_len,
3316 						       beacon_ies_data->
3317 						       ie_buffer,
3318 						       IE_MASK_VENDOR, NULL, 0);
3319 			DBG_HEXDUMP(MCMD_D, "beacon extra ie",
3320 				    beacon_ies_data->ie_buffer,
3321 				    beacon_ies_data->ie_length);
3322 		} else {
3323 			/* clear the beacon wps ies */
3324 			if (beacon_wps_index > MAX_MGMT_IE_INDEX) {
3325 				PRINTM(MERROR,
3326 				       "Invalid beacon wps index for mgmt frame ie.\n");
3327 				goto done;
3328 			}
3329 
3330 			beacon_ies_data->ie_index = beacon_wps_index;
3331 			beacon_ies_data->mgmt_subtype_mask =
3332 				MLAN_CUSTOM_IE_DELETE_MASK;
3333 			beacon_ies_data->ie_length = 0;
3334 			beacon_wps_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3335 		}
3336 		if (MLAN_STATUS_SUCCESS !=
3337 		    woal_cfg80211_custom_ie(priv, beacon_ies_data,
3338 					    &beacon_wps_index,
3339 					    proberesp_ies_data,
3340 					    &proberesp_index,
3341 					    assocresp_ies_data,
3342 					    &assocresp_index, probereq_ies_data,
3343 					    &probereq_index, wait_option)) {
3344 			PRINTM(MERROR, "Fail to set beacon wps IE\n");
3345 			ret = -EFAULT;
3346 		}
3347 		priv->beacon_wps_index = beacon_wps_index;
3348 		PRINTM(MCMND, "beacon_wps_index=0x%x len=%d\n",
3349 		       beacon_wps_index, beacon_ies_data->ie_length);
3350 		goto done;
3351 	}
3352 
3353 	if (mask & MGMT_MASK_ASSOC_RESP_QOS_MAP) {
3354 		assocresp_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
3355 		if (!assocresp_ies_data) {
3356 			ret = -ENOMEM;
3357 			goto done;
3358 		}
3359 		if (assocresp_ies && assocresp_ies_len) {
3360 			/* set the assoc response qos map ies */
3361 			assocresp_ies_data->ie_index = assocrep_qos_map_index;
3362 			assocresp_ies_data->mgmt_subtype_mask =
3363 				MGMT_MASK_ASSOC_RESP;
3364 			if (MLAN_CUSTOM_IE_AUTO_IDX_MASK ==
3365 			    assocrep_qos_map_index)
3366 				assocresp_ies_data->mgmt_subtype_mask |=
3367 					MLAN_CUSTOM_IE_NEW_MASK;
3368 			assocresp_ies_data->ie_length = assocresp_ies_len;
3369 			pos = assocresp_ies_data->ie_buffer;
3370 			memcpy(pos, assocresp_ies, assocresp_ies_len);
3371 			DBG_HEXDUMP(MCMD_D, "Qos Map",
3372 				    assocresp_ies_data->ie_buffer,
3373 				    assocresp_ies_data->ie_length);
3374 		} else {
3375 			/* clear the assoc response qos map ie */
3376 			if (assocrep_qos_map_index > MAX_MGMT_IE_INDEX) {
3377 				PRINTM(MERROR,
3378 				       "Invalid Qos map index for mgmt frame ie.\n");
3379 				goto done;
3380 			}
3381 
3382 			assocresp_ies_data->ie_index = assocrep_qos_map_index;
3383 			assocresp_ies_data->mgmt_subtype_mask =
3384 				MLAN_CUSTOM_IE_DELETE_MASK;
3385 			assocresp_ies_data->ie_length = 0;
3386 			assocrep_qos_map_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3387 		}
3388 		if (MLAN_STATUS_SUCCESS !=
3389 		    woal_cfg80211_custom_ie(priv, NULL, &beacon_wps_index,
3390 					    NULL, &proberesp_index,
3391 					    assocresp_ies_data,
3392 					    &assocrep_qos_map_index, NULL,
3393 					    &probereq_index, wait_option)) {
3394 			PRINTM(MERROR, "Fail to set Qos map IE\n");
3395 			ret = -EFAULT;
3396 		}
3397 		priv->assocresp_qos_map_index = assocrep_qos_map_index;
3398 		PRINTM(MCMND, "qos map ie index=0x%x len=%d\n",
3399 		       assocrep_qos_map_index, assocresp_ies_data->ie_length);
3400 		goto done;
3401 	}
3402 
3403 	if (mask & MGMT_MASK_BEACON) {
3404 		beacon_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
3405 		if (!beacon_ies_data) {
3406 			ret = -ENOMEM;
3407 			goto done;
3408 		}
3409 	}
3410 
3411 	if (mask & MGMT_MASK_PROBE_RESP) {
3412 		/** set or clear proberesp ie */
3413 		if (proberesp_ies_len ||
3414 		    (!proberesp_ies_len && !beacon_ies_len)) {
3415 			proberesp_ies_data =
3416 				kzalloc(sizeof(custom_ie), GFP_KERNEL);
3417 			if (!proberesp_ies_data) {
3418 				ret = -ENOMEM;
3419 				goto done;
3420 			}
3421 		}
3422 	}
3423 
3424 	if (mask & MGMT_MASK_ASSOC_RESP) {
3425 		/** set or clear assocresp ie */
3426 		if (assocresp_ies_len ||
3427 		    (!assocresp_ies_len && !beacon_ies_len)) {
3428 			assocresp_ies_data =
3429 				kzalloc(sizeof(custom_ie), GFP_KERNEL);
3430 			if (!assocresp_ies_data) {
3431 				ret = -ENOMEM;
3432 				goto done;
3433 			}
3434 		}
3435 	}
3436 	if (mask & MGMT_MASK_PROBE_REQ) {
3437 		probereq_ies_data = kzalloc(sizeof(custom_ie), GFP_KERNEL);
3438 		if (!probereq_ies_data) {
3439 			ret = -ENOMEM;
3440 			goto done;
3441 		}
3442 	}
3443 
3444 	if (beacon_ies_data) {
3445 		if (beacon_ies && beacon_ies_len) {
3446 			/* set the beacon ies */
3447 			/* we need remove vendor IE from beacon tail, vendor IE will be configure through proberesp_vendor_index */
3448 			beacon_ies_data->ie_index = beacon_index;
3449 			beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON |
3450 				MGMT_MASK_ASSOC_RESP | MGMT_MASK_PROBE_RESP;
3451 			beacon_ies_data->ie_length =
3452 				woal_filter_beacon_ies(priv, beacon_ies,
3453 						       beacon_ies_len,
3454 						       beacon_ies_data->
3455 						       ie_buffer,
3456 						       IE_MASK_WPS | IE_MASK_WFD
3457 						       | IE_MASK_P2P |
3458 						       IE_MASK_VENDOR,
3459 						       proberesp_ies,
3460 						       proberesp_ies_len);
3461 			DBG_HEXDUMP(MCMD_D, "beacon ie",
3462 				    beacon_ies_data->ie_buffer,
3463 				    beacon_ies_data->ie_length);
3464 		} else {
3465 			/* clear the beacon ies */
3466 			if (beacon_index > MAX_MGMT_IE_INDEX) {
3467 				PRINTM(MINFO,
3468 				       "Invalid beacon index for mgmt frame ie.\n");
3469 				goto done;
3470 			}
3471 
3472 			beacon_ies_data->ie_index = beacon_index;
3473 			beacon_ies_data->mgmt_subtype_mask =
3474 				MLAN_CUSTOM_IE_DELETE_MASK;
3475 			beacon_ies_data->ie_length = 0;
3476 			beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3477 		}
3478 	}
3479 
3480 	if (proberesp_ies_data) {
3481 		if (proberesp_ies && proberesp_ies_len) {
3482 			/* set the probe response p2p ies */
3483 			proberesp_ies_data->ie_index = proberesp_p2p_index;
3484 			proberesp_ies_data->mgmt_subtype_mask =
3485 				MGMT_MASK_PROBE_RESP;
3486 			proberesp_ies_data->ie_length =
3487 				woal_get_specific_ie(proberesp_ies,
3488 						     proberesp_ies_len,
3489 						     proberesp_ies_data->
3490 						     ie_buffer, IE_MASK_P2P);
3491 			DBG_HEXDUMP(MCMD_D, "proberesp p2p ie",
3492 				    proberesp_ies_data->ie_buffer,
3493 				    proberesp_ies_data->ie_length);
3494 		} else if (proberesp_p2p_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
3495 			/* clear the probe response p2p ies */
3496 			if (proberesp_p2p_index > MAX_MGMT_IE_INDEX) {
3497 				PRINTM(MERROR,
3498 				       "Invalid proberesp_p2p_index for mgmt frame ie.\n");
3499 				goto done;
3500 			}
3501 			proberesp_ies_data->ie_index = proberesp_p2p_index;
3502 			proberesp_ies_data->mgmt_subtype_mask =
3503 				MLAN_CUSTOM_IE_DELETE_MASK;
3504 			proberesp_ies_data->ie_length = 0;
3505 			proberesp_p2p_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3506 		}
3507 		if (MLAN_STATUS_SUCCESS !=
3508 		    woal_cfg80211_custom_ie(priv, NULL, &beacon_index,
3509 					    proberesp_ies_data,
3510 					    &proberesp_p2p_index, NULL,
3511 					    &assocresp_index, NULL,
3512 					    &probereq_index, wait_option)) {
3513 			PRINTM(MERROR, "Fail to set proberesp p2p IE\n");
3514 			ret = -EFAULT;
3515 			goto done;
3516 		}
3517 		priv->proberesp_p2p_index = proberesp_p2p_index;
3518 		PRINTM(MCMND, "proberesp_p2p=0x%x len=%d\n",
3519 		       proberesp_p2p_index, proberesp_ies_data->ie_length);
3520 		memset(proberesp_ies_data, 0x00, sizeof(custom_ie));
3521 		if (proberesp_ies && proberesp_ies_len) {
3522 			/* set the probe response/beacon vendor ies */
3523 			proberesp_ies_data->ie_index = proberesp_vendor_index;
3524 			proberesp_ies_data->mgmt_subtype_mask =
3525 				MGMT_MASK_PROBE_RESP | MGMT_MASK_BEACON;
3526 			if (MLAN_CUSTOM_IE_AUTO_IDX_MASK ==
3527 			    proberesp_vendor_index)
3528 				proberesp_ies_data->mgmt_subtype_mask |=
3529 					MLAN_CUSTOM_IE_NEW_MASK;
3530 			proberesp_ies_data->ie_length =
3531 				woal_get_specific_ie(proberesp_ies,
3532 						     proberesp_ies_len,
3533 						     proberesp_ies_data->
3534 						     ie_buffer, IE_MASK_VENDOR);
3535 			DBG_HEXDUMP(MCMD_D, "proberesp vendor IE",
3536 				    proberesp_ies_data->ie_buffer,
3537 				    proberesp_ies_data->ie_length);
3538 		} else if (proberesp_vendor_index !=
3539 			   MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
3540 			/* clear the probe response p2p ies */
3541 			if (proberesp_vendor_index > MAX_MGMT_IE_INDEX) {
3542 				PRINTM(MERROR,
3543 				       "Invalid proberesp_vendor_index for mgmt frame ie.\n");
3544 				goto done;
3545 			}
3546 			proberesp_ies_data->ie_index = proberesp_vendor_index;
3547 			proberesp_ies_data->mgmt_subtype_mask =
3548 				MLAN_CUSTOM_IE_DELETE_MASK;
3549 			proberesp_ies_data->ie_length = 0;
3550 			proberesp_vendor_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3551 		}
3552 		if (MLAN_STATUS_SUCCESS !=
3553 		    woal_cfg80211_custom_ie(priv, NULL, &beacon_index,
3554 					    proberesp_ies_data,
3555 					    &proberesp_vendor_index, NULL,
3556 					    &assocresp_index, NULL,
3557 					    &probereq_index, wait_option)) {
3558 			PRINTM(MERROR, "Fail to set proberesp vendor IE\n");
3559 			ret = -EFAULT;
3560 			goto done;
3561 		}
3562 		priv->proberesp_vendor_index = proberesp_vendor_index;
3563 		PRINTM(MCMND, "proberesp_vendor=0x%x len=%d\n",
3564 		       proberesp_vendor_index, proberesp_ies_data->ie_length);
3565 		memset(proberesp_ies_data, 0x00, sizeof(custom_ie));
3566 		if (proberesp_ies && proberesp_ies_len) {
3567 			/* set the probe response ies */
3568 			proberesp_ies_data->ie_index = proberesp_index;
3569 			proberesp_ies_data->mgmt_subtype_mask =
3570 				MGMT_MASK_PROBE_RESP;
3571 			if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == proberesp_index)
3572 				proberesp_ies_data->mgmt_subtype_mask |=
3573 					MLAN_CUSTOM_IE_NEW_MASK;
3574 			proberesp_ies_data->ie_length =
3575 				woal_filter_beacon_ies(priv, proberesp_ies,
3576 						       proberesp_ies_len,
3577 						       proberesp_ies_data->
3578 						       ie_buffer,
3579 						       IE_MASK_P2P |
3580 						       IE_MASK_VENDOR, NULL, 0);
3581 			DBG_HEXDUMP(MCMD_D, "proberesp ie",
3582 				    proberesp_ies_data->ie_buffer,
3583 				    proberesp_ies_data->ie_length);
3584 		} else {
3585 			/* clear the probe response ies */
3586 			if (proberesp_index > MAX_MGMT_IE_INDEX) {
3587 				PRINTM(MERROR,
3588 				       "Invalid probe resp index for mgmt frame ie.\n");
3589 				goto done;
3590 			}
3591 			proberesp_ies_data->ie_index = proberesp_index;
3592 			proberesp_ies_data->mgmt_subtype_mask =
3593 				MLAN_CUSTOM_IE_DELETE_MASK;
3594 			proberesp_ies_data->ie_length = 0;
3595 			proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3596 		}
3597 	}
3598 	if (assocresp_ies_data) {
3599 		if (assocresp_ies && assocresp_ies_len) {
3600 			/* set the assoc response ies */
3601 			assocresp_ies_data->ie_index = assocresp_index;
3602 			assocresp_ies_data->mgmt_subtype_mask =
3603 				MGMT_MASK_ASSOC_RESP;
3604 			if (MLAN_CUSTOM_IE_AUTO_IDX_MASK == assocresp_index)
3605 				assocresp_ies_data->mgmt_subtype_mask |=
3606 					MLAN_CUSTOM_IE_NEW_MASK;
3607 			assocresp_ies_data->ie_length = assocresp_ies_len;
3608 			pos = assocresp_ies_data->ie_buffer;
3609 			memcpy(pos, assocresp_ies, assocresp_ies_len);
3610 			DBG_HEXDUMP(MCMD_D, "assocresp ie",
3611 				    assocresp_ies_data->ie_buffer,
3612 				    assocresp_ies_data->ie_length);
3613 		} else {
3614 			/* clear the assoc response ies */
3615 			if (assocresp_index > MAX_MGMT_IE_INDEX) {
3616 				PRINTM(MERROR,
3617 				       "Invalid assoc resp index for mgmt frame ie.\n");
3618 				goto done;
3619 			}
3620 
3621 			assocresp_ies_data->ie_index = assocresp_index;
3622 			assocresp_ies_data->mgmt_subtype_mask =
3623 				MLAN_CUSTOM_IE_DELETE_MASK;
3624 			assocresp_ies_data->ie_length = 0;
3625 			assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3626 		}
3627 	}
3628 
3629 	if (probereq_ies_data) {
3630 		if (probereq_ies && probereq_ies_len) {
3631 			/* set the probe req ies */
3632 			probereq_ies_data->ie_index = probereq_index;
3633 			probereq_ies_data->mgmt_subtype_mask =
3634 				MGMT_MASK_PROBE_REQ;
3635 #if defined(WIFI_DIRECT_SUPPORT)
3636 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
3637 			if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) {
3638 				/* filter out P2P/WFD ie */
3639 				probereq_ies_data->ie_length =
3640 					woal_filter_beacon_ies(priv,
3641 							       probereq_ies,
3642 							       probereq_ies_len,
3643 							       probereq_ies_data->
3644 							       ie_buffer,
3645 							       IE_MASK_P2P |
3646 							       IE_MASK_WFD,
3647 							       NULL, 0);
3648 			} else {
3649 #endif /* KERNEL_VERSION */
3650 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
3651 				probereq_ies_data->ie_length = probereq_ies_len;
3652 				pos = probereq_ies_data->ie_buffer;
3653 				memcpy(pos, probereq_ies, probereq_ies_len);
3654 #if defined(WIFI_DIRECT_SUPPORT)
3655 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
3656 			}
3657 #endif /* KERNEL_VERSION */
3658 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
3659 			DBG_HEXDUMP(MCMD_D, "probereq ie",
3660 				    probereq_ies_data->ie_buffer,
3661 				    probereq_ies_data->ie_length);
3662 		} else {
3663 			/* clear the probe req ies */
3664 			if (probereq_index > MAX_MGMT_IE_INDEX) {
3665 				PRINTM(MERROR,
3666 				       "Invalid probe req index for mgmt frame ie.\n");
3667 				goto done;
3668 			}
3669 			probereq_ies_data->ie_index = probereq_index;
3670 			probereq_ies_data->mgmt_subtype_mask =
3671 				MLAN_CUSTOM_IE_DELETE_MASK;
3672 			probereq_ies_data->ie_length = 0;
3673 			probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK;
3674 		}
3675 	}
3676 
3677 	if (MLAN_STATUS_SUCCESS !=
3678 	    woal_cfg80211_custom_ie(priv, beacon_ies_data, &beacon_index,
3679 				    proberesp_ies_data, &proberesp_index,
3680 				    assocresp_ies_data, &assocresp_index,
3681 				    probereq_ies_data, &probereq_index,
3682 				    wait_option)) {
3683 		PRINTM(MERROR,
3684 		       "Fail to set beacon proberesp assoc probereq IES\n");
3685 		ret = -EFAULT;
3686 		goto done;
3687 	}
3688 	if (beacon_ies_data) {
3689 		priv->beacon_index = beacon_index;
3690 		PRINTM(MCMND, "beacon ie length = %d\n",
3691 		       beacon_ies_data->ie_length);
3692 	}
3693 	if (assocresp_ies_data) {
3694 		priv->assocresp_index = assocresp_index;
3695 		PRINTM(MCMND, "assocresp ie length = %d\n",
3696 		       assocresp_ies_data->ie_length);
3697 	}
3698 	if (proberesp_ies_data) {
3699 		priv->proberesp_index = proberesp_index;
3700 		PRINTM(MCMND, "proberesp ie length = %d\n",
3701 		       proberesp_ies_data->ie_length);
3702 	}
3703 	if (probereq_ies_data) {
3704 		priv->probereq_index = probereq_index;
3705 		PRINTM(MCMND, "probereq ie length = %d\n",
3706 		       probereq_ies_data->ie_length);
3707 	}
3708 	PRINTM(MCMND, "beacon=%x assocresp=%x proberesp=%x probereq=%x\n",
3709 	       beacon_index, assocresp_index, proberesp_index, probereq_index);
3710 done:
3711 	kfree(beacon_ies_data);
3712 	kfree(proberesp_ies_data);
3713 	kfree(assocresp_ies_data);
3714 	kfree(probereq_ies_data);
3715 
3716 	LEAVE();
3717 
3718 	return ret;
3719 }
3720 
3721 /**
3722  *  @brief Sets up the CFG802.11 specific HT capability fields
3723  *  with default values
3724  *
3725  *  @param ht_info      A pointer to ieee80211_sta_ht_cap structure
3726  *  @param dev_cap      Device capability informations
3727  *  @param mcs_set      Device MCS sets
3728  *
3729  *  @return             N/A
3730  */
3731 void
woal_cfg80211_setup_ht_cap(struct ieee80211_sta_ht_cap * ht_info,t_u32 dev_cap,t_u8 * mcs_set)3732 woal_cfg80211_setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info,
3733 			   t_u32 dev_cap, t_u8 *mcs_set)
3734 {
3735 	ENTER();
3736 
3737 	ht_info->ht_supported = true;
3738 	ht_info->ampdu_factor = 0x3;
3739 	ht_info->ampdu_density = 0;
3740 
3741 	memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
3742 	ht_info->cap = 0;
3743 	if (mcs_set)
3744 		memcpy(ht_info->mcs.rx_mask, mcs_set,
3745 		       sizeof(ht_info->mcs.rx_mask));
3746 	if (dev_cap & MBIT(8))	/* 40Mhz intolarance enabled */
3747 		ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT;
3748 	if (dev_cap & MBIT(17))	/* Channel width 20/40Mhz support */
3749 		ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
3750 	if ((dev_cap >> 20) & 0x03)	/* Delayed ACK supported */
3751 		ht_info->cap |= IEEE80211_HT_CAP_DELAY_BA;
3752 	if (dev_cap & MBIT(22))	/* Rx LDPC supported */
3753 		ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
3754 	if (dev_cap & MBIT(23))	/* Short GI @ 20Mhz supported */
3755 		ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
3756 	if (dev_cap & MBIT(24))	/* Short GI @ 40Mhz supported */
3757 		ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
3758 	if (dev_cap & MBIT(25))	/* Tx STBC supported */
3759 		ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
3760 	if (dev_cap & MBIT(26))	/* Rx STBC supported */
3761 		ht_info->cap |= IEEE80211_HT_CAP_RX_STBC;
3762 	if (dev_cap & MBIT(27))	/* MIMO PS supported */
3763 		ht_info->cap |= 0;	/* WLAN_HT_CAP_SM_PS_STATIC */
3764 	else			/* Disable HT SM PS */
3765 		ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
3766 	if (dev_cap & MBIT(29))	/* Green field supported */
3767 		ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD;
3768 	if (dev_cap & MBIT(31))	/* MAX AMSDU supported */
3769 		ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
3770 	/* DSSS/CCK in 40Mhz supported */
3771 	ht_info->cap |= IEEE80211_HT_CAP_DSSSCCK40;
3772 	ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
3773 
3774 	LEAVE();
3775 }
3776 
3777 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
3778 /**
3779  * @brief create cfg80211_chan_def structure based on chan_band info
3780  *
3781  * @param priv          A pointer moal_private structure
3782  * @param chandef       A pointer to cfg80211_chan_def structure
3783  * @param pchan_info    A pointer to chan_band_info structure
3784  *
3785  * @return              MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE
3786  */
3787 mlan_status
woal_chandef_create(moal_private * priv,struct cfg80211_chan_def * chandef,chan_band_info * pchan_info)3788 woal_chandef_create(moal_private *priv, struct cfg80211_chan_def *chandef,
3789 		    chan_band_info * pchan_info)
3790 {
3791 	enum ieee80211_band band = IEEE80211_BAND_2GHZ;
3792 	mlan_status status = MLAN_STATUS_SUCCESS;
3793 
3794 	ENTER();
3795 	chandef->center_freq2 = 0;
3796 	if (pchan_info->bandcfg.chanBand == BAND_2GHZ)
3797 		band = IEEE80211_BAND_2GHZ;
3798 	else if (pchan_info->bandcfg.chanBand == BAND_5GHZ)
3799 		band = IEEE80211_BAND_5GHZ;
3800 	chandef->chan = ieee80211_get_channel(priv->wdev->wiphy,
3801 					      ieee80211_channel_to_frequency
3802 					      (pchan_info->channel, band));
3803 	if (chandef->chan == NULL) {
3804 		PRINTM(MERROR,
3805 		       "Fail on ieee80211_get_channel, channel=%d, band=%d\n",
3806 		       pchan_info->channel, band);
3807 		status = MLAN_STATUS_FAILURE;
3808 		goto done;
3809 	}
3810 	switch (pchan_info->bandcfg.chanWidth) {
3811 	case CHAN_BW_20MHZ:
3812 		if (pchan_info->is_11n_enabled)
3813 			chandef->width = NL80211_CHAN_WIDTH_20;
3814 		else
3815 			chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
3816 		chandef->center_freq1 = chandef->chan->center_freq;
3817 		break;
3818 	case CHAN_BW_40MHZ:
3819 		chandef->width = NL80211_CHAN_WIDTH_40;
3820 		if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_ABOVE)
3821 			chandef->center_freq1 = chandef->chan->center_freq + 10;
3822 		else if (pchan_info->bandcfg.chan2Offset == SEC_CHAN_BELOW)
3823 			chandef->center_freq1 = chandef->chan->center_freq - 10;
3824 		break;
3825 	default:
3826 		break;
3827 	}
3828 done:
3829 	LEAVE();
3830 	return status;
3831 }
3832 #endif
3833 
3834 /**
3835  * @brief Get second channel offset
3836  *
3837  * @param chan             channel num
3838  * @return                second channel offset
3839  */
3840 t_u8
woal_get_second_channel_offset(int chan)3841 woal_get_second_channel_offset(int chan)
3842 {
3843 	t_u8 chan2Offset = SEC_CHAN_NONE;
3844 
3845 	switch (chan) {
3846 	case 36:
3847 	case 44:
3848 	case 52:
3849 	case 60:
3850 	case 100:
3851 	case 108:
3852 	case 116:
3853 	case 124:
3854 	case 132:
3855 	case 149:
3856 	case 157:
3857 		chan2Offset = SEC_CHAN_ABOVE;
3858 		break;
3859 	case 40:
3860 	case 48:
3861 	case 56:
3862 	case 64:
3863 	case 104:
3864 	case 112:
3865 	case 120:
3866 	case 128:
3867 	case 136:
3868 	case 153:
3869 	case 161:
3870 		chan2Offset = SEC_CHAN_BELOW;
3871 		break;
3872 	case 165:
3873 		/* Special Case: 20Mhz-only Channel */
3874 		chan2Offset = SEC_CHAN_NONE;
3875 		break;
3876 	}
3877 	return chan2Offset;
3878 }
3879