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