xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/nxp/mlinux/moal_sta_cfg80211.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file moal_sta_cfg80211.c
2  *
3  * @brief This file contains the functions for STA CFG80211.
4  *
5  *
6  * Copyright 2011-2022 NXP
7  *
8  * This software file (the File) is distributed by NXP
9  * under the terms of the GNU General Public License Version 2, June 1991
10  * (the License).  You may use, redistribute and/or modify the File in
11  * accordance with the terms and conditions of the License, a copy of which
12  * is available by writing to the Free Software Foundation, Inc.,
13  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
14  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
15  *
16  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
18  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
19  * this warranty disclaimer.
20  *
21  */
22 
23 #include "moal_cfg80211.h"
24 #include "moal_cfg80211_util.h"
25 #include "moal_sta_cfg80211.h"
26 #include "moal_eth_ioctl.h"
27 #ifdef UAP_SUPPORT
28 #include "moal_uap.h"
29 #endif
30 #include <linux/sort.h>
31 
32 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
33 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
34 extern int fw_region;
35 #endif
36 #endif
37 /* Supported crypto cipher suits to be advertised to cfg80211 */
38 static const u32 cfg80211_cipher_suites[] = {
39 	WLAN_CIPHER_SUITE_WEP40,	WLAN_CIPHER_SUITE_WEP104,
40 	WLAN_CIPHER_SUITE_TKIP,		WLAN_CIPHER_SUITE_CCMP,
41 	WLAN_CIPHER_SUITE_SMS4,		WLAN_CIPHER_SUITE_AES_CMAC,
42 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
43 	WLAN_CIPHER_SUITE_BIP_GMAC_128, WLAN_CIPHER_SUITE_BIP_GMAC_256,
44 #endif
45 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
46 	WLAN_CIPHER_SUITE_GCMP,
47 #endif
48 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
49 	WLAN_CIPHER_SUITE_GCMP_256,
50 #endif
51 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
52 	WLAN_CIPHER_SUITE_CCMP_256,
53 #endif
54 };
55 
56 #ifdef UAP_SUPPORT
57 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
58 static int woal_cfg80211_set_monitor_channel(struct wiphy *wiphy,
59 					     struct cfg80211_chan_def *chandef);
60 #endif
61 #endif
62 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
63 static void
64 #else
65 static int
66 #endif
67 woal_cfg80211_reg_notifier(struct wiphy *wiphy,
68 			   struct regulatory_request *request);
69 
70 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
71 static int woal_cfg80211_scan(struct wiphy *wiphy,
72 			      struct cfg80211_scan_request *request);
73 #else
74 static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
75 			      struct cfg80211_scan_request *request);
76 #endif
77 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
78 static void woal_cfg80211_abort_scan(struct wiphy *wiphy,
79 				     struct wireless_dev *wdev);
80 #endif
81 static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
82 				 struct cfg80211_connect_params *sme);
83 
84 static int woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
85 				    t_u16 reason_code);
86 
87 static int woal_cfg80211_get_station(struct wiphy *wiphy,
88 				     struct net_device *dev,
89 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
90 				     const u8 *mac,
91 #else
92 				     u8 *mac,
93 #endif
94 				     struct station_info *sinfo);
95 
96 static int woal_cfg80211_dump_station(struct wiphy *wiphy,
97 				      struct net_device *dev, int idx,
98 				      t_u8 *mac, struct station_info *sinfo);
99 
100 static int woal_cfg80211_dump_survey(struct wiphy *wiphy,
101 				     struct net_device *dev, int idx,
102 				     struct survey_info *survey);
103 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
104 static int woal_cfg80211_get_channel(struct wiphy *wiphy,
105 				     struct wireless_dev *wdev,
106 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
107 				     unsigned int link_id,
108 #endif
109 				     struct cfg80211_chan_def *chandef);
110 #endif
111 static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
112 					struct net_device *dev, bool enabled,
113 					int timeout);
114 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
115 static int woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
116 					     struct net_device *dev,
117 					     s32 rssi_thold, u32 rssi_hyst);
118 #endif
119 
120 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
121 static int woal_cfg80211_get_tx_power(struct wiphy *wiphy,
122 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
123 				      struct wireless_dev *wdev,
124 #endif
125 				      int *dbm);
126 
127 static int woal_cfg80211_set_tx_power(struct wiphy *wiphy,
128 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
129 				      struct wireless_dev *wdev,
130 #endif
131 #if CFG80211_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
132 				      enum tx_power_setting type,
133 #else
134 				      enum nl80211_tx_power_setting type,
135 #endif
136 				      int dbm);
137 #endif
138 
139 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
140 static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
141 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
142 					     struct wireless_dev *wdev,
143 #else
144 					     struct net_device *dev,
145 #endif
146 					     u64 cookie);
147 
148 static int
149 woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
150 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
151 				struct wireless_dev *wdev,
152 #else
153 				struct net_device *dev,
154 #endif
155 				struct ieee80211_channel *chan,
156 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
157 				enum nl80211_channel_type channel_type,
158 #endif
159 				unsigned int duration, u64 *cookie);
160 
161 static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
162 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
163 						  struct wireless_dev *wdev,
164 #else
165 						  struct net_device *dev,
166 #endif
167 						  u64 cookie);
168 #endif /* KERNEL_VERSION */
169 
170 #ifdef CONFIG_NL80211_TESTMODE
171 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
172 static int woal_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
173 			     void *data, int len);
174 #else
175 static int woal_testmode_cmd(struct wiphy *wiphy, void *data, int len);
176 #endif
177 #endif
178 
179 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
180 int woal_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *dev,
181 				   struct cfg80211_sched_scan_request *request);
182 int woal_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
183 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
184 				  ,
185 				  u64 reqid
186 #endif
187 );
188 #endif
189 
190 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
191 int woal_cfg80211_resume(struct wiphy *wiphy);
192 int woal_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
193 #endif
194 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
195 static void woal_cfg80211_set_wakeup(struct wiphy *wiphy, bool enabled);
196 #endif
197 
198 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
199 void woal_check_auto_tdls(struct wiphy *wiphy, struct net_device *dev);
200 int woal_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
201 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
202 			    const u8 *peer,
203 #else
204 			    u8 *peer,
205 #endif
206 			    enum nl80211_tdls_operation oper);
207 int woal_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
208 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
209 			    const u8 *peer,
210 #else
211 			    u8 *peer,
212 #endif
213 			    u8 action_code, u8 dialog_token, u16 status_code,
214 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
215 			    u32 peer_capability,
216 #endif
217 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
218 			    bool initiator,
219 #endif
220 			    const u8 *extra_ies, size_t extra_ies_len);
221 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
222 static int woal_cfg80211_tdls_channel_switch(struct wiphy *wiphy,
223 					     struct net_device *dev,
224 					     const u8 *addr, u8 oper_class,
225 					     struct cfg80211_chan_def *chandef);
226 
227 void woal_cfg80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
228 					      struct net_device *dev,
229 					      const u8 *addr);
230 #endif
231 #endif
232 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
233 static int woal_cfg80211_change_station(struct wiphy *wiphy,
234 					struct net_device *dev,
235 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
236 					const u8 *mac,
237 #else
238 					u8 *mac,
239 #endif
240 					struct station_parameters *params);
241 #endif
242 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
243 int woal_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
244 				struct cfg80211_update_ft_ies_params *ftie);
245 #endif
246 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
247 static int woal_cfg80211_authenticate(struct wiphy *wiphy,
248 				      struct net_device *dev,
249 				      struct cfg80211_auth_request *req);
250 
251 static int woal_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev,
252 				   struct cfg80211_assoc_request *req);
253 #ifdef UAP_SUPPORT
254 int woal_cfg80211_uap_add_station(struct wiphy *wiphy, struct net_device *dev,
255 				  u8 *mac, struct station_parameters *params);
256 #endif
257 #endif
258 
259 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
260 #ifdef UAP_SUPPORT
261 static int woal_cfg80211_add_station(struct wiphy *wiphy,
262 				     struct net_device *dev,
263 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
264 				     const u8 *mac,
265 #else
266 				     u8 *mac,
267 #endif
268 				     struct station_parameters *params);
269 #endif
270 #endif
271 
272 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
273 static int woal_cfg80211_deauthenticate(struct wiphy *wiphy,
274 					struct net_device *dev,
275 					struct cfg80211_deauth_request *req);
276 
277 static int woal_cfg80211_disassociate(struct wiphy *wiphy,
278 				      struct net_device *dev,
279 				      struct cfg80211_disassoc_request *req);
280 #endif
281 
282 #ifdef UAP_CFG80211
283 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
284 int woal_cfg80211_set_radar_background(struct wiphy *wiphy,
285 				       struct cfg80211_chan_def *chandef);
286 #endif
287 #endif
288 
289 /** cfg80211 operations */
290 static struct cfg80211_ops woal_cfg80211_ops = {
291 	.change_virtual_intf = woal_cfg80211_change_virtual_intf,
292 	.scan = woal_cfg80211_scan,
293 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
294 	.abort_scan = woal_cfg80211_abort_scan,
295 #endif
296 	.connect = woal_cfg80211_connect,
297 	.disconnect = woal_cfg80211_disconnect,
298 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
299 	.deauth = woal_cfg80211_deauthenticate,
300 	.disassoc = woal_cfg80211_disassociate,
301 #endif
302 	.get_station = woal_cfg80211_get_station,
303 	.dump_station = woal_cfg80211_dump_station,
304 	.dump_survey = woal_cfg80211_dump_survey,
305 	.set_wiphy_params = woal_cfg80211_set_wiphy_params,
306 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
307 	.set_channel = woal_cfg80211_set_channel,
308 #endif
309 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
310 	.get_channel = woal_cfg80211_get_channel,
311 #endif
312 	.add_key = woal_cfg80211_add_key,
313 	.del_key = woal_cfg80211_del_key,
314 	.set_default_key = woal_cfg80211_set_default_key,
315 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
316 	.set_default_mgmt_key = woal_cfg80211_set_default_mgmt_key,
317 #endif
318 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
319 	.set_default_beacon_key = woal_cfg80211_set_default_beacon_key,
320 #endif
321 
322 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
323 	.set_rekey_data = woal_cfg80211_set_rekey_data,
324 #endif
325 	.set_pmksa = woal_cfg80211_set_pmksa,
326 	.del_pmksa = woal_cfg80211_del_pmksa,
327 	.flush_pmksa = woal_cfg80211_flush_pmksa,
328 	.set_power_mgmt = woal_cfg80211_set_power_mgmt,
329 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
330 	.set_tx_power = woal_cfg80211_set_tx_power,
331 	.get_tx_power = woal_cfg80211_get_tx_power,
332 #endif
333 	.set_bitrate_mask = woal_cfg80211_set_bitrate_mask,
334 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
335 	.sched_scan_start = woal_cfg80211_sched_scan_start,
336 	.sched_scan_stop = woal_cfg80211_sched_scan_stop,
337 #endif
338 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
339 	.suspend = woal_cfg80211_suspend,
340 	.resume = woal_cfg80211_resume,
341 #endif
342 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
343 	.set_wakeup = woal_cfg80211_set_wakeup,
344 #endif
345 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
346 	.set_antenna = woal_cfg80211_set_antenna,
347 	.get_antenna = woal_cfg80211_get_antenna,
348 #endif
349 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
350 	.set_cqm_rssi_config = woal_cfg80211_set_cqm_rssi_config,
351 #endif
352 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
353 	.tdls_oper = woal_cfg80211_tdls_oper,
354 	.tdls_mgmt = woal_cfg80211_tdls_mgmt,
355 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
356 	.tdls_channel_switch = woal_cfg80211_tdls_channel_switch,
357 	.tdls_cancel_channel_switch = woal_cfg80211_tdls_cancel_channel_switch,
358 #endif
359 #endif
360 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
361 	.change_station = woal_cfg80211_change_station,
362 #endif
363 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
364 	.update_ft_ies = woal_cfg80211_update_ft_ies,
365 #endif
366 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
367 	.set_qos_map = woal_cfg80211_set_qos_map,
368 #endif
369 #ifdef UAP_CFG80211
370 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
371 	.set_coalesce = woal_cfg80211_set_coalesce,
372 #endif
373 	.add_virtual_intf = woal_cfg80211_add_virtual_intf,
374 	.del_virtual_intf = woal_cfg80211_del_virtual_intf,
375 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
376 	.start_ap = woal_cfg80211_add_beacon,
377 	.change_beacon = woal_cfg80211_set_beacon,
378 	.stop_ap = woal_cfg80211_del_beacon,
379 #else
380 	.add_beacon = woal_cfg80211_add_beacon,
381 	.set_beacon = woal_cfg80211_set_beacon,
382 	.del_beacon = woal_cfg80211_del_beacon,
383 #endif
384 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
385 	.change_bss = woal_cfg80211_change_bss,
386 #endif
387 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
388 	.add_station = woal_cfg80211_add_station,
389 #endif
390 	.del_station = woal_cfg80211_del_station,
391 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
392 	.set_txq_params = woal_cfg80211_set_txq_params,
393 #endif
394 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
395 	.set_mac_acl = woal_cfg80211_set_mac_acl,
396 #endif
397 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
398 	.start_radar_detection = woal_cfg80211_start_radar_detection,
399 
400 	.channel_switch = woal_cfg80211_channel_switch,
401 #endif
402 #endif
403 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
404 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
405 	.update_mgmt_frame_registrations = woal_cfg80211_mgmt_frame_register,
406 #else
407 	.mgmt_frame_register = woal_cfg80211_mgmt_frame_register,
408 #endif
409 	.mgmt_tx = woal_cfg80211_mgmt_tx,
410 #endif
411 
412 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
413 	.mgmt_tx_cancel_wait = woal_cfg80211_mgmt_tx_cancel_wait,
414 	.remain_on_channel = woal_cfg80211_remain_on_channel,
415 	.cancel_remain_on_channel = woal_cfg80211_cancel_remain_on_channel,
416 #endif
417 
418 #ifdef UAP_SUPPORT
419 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
420 	.set_monitor_channel = woal_cfg80211_set_monitor_channel,
421 #endif
422 #endif
423 #ifdef CONFIG_NL80211_TESTMODE
424 	.testmode_cmd = woal_testmode_cmd,
425 #endif
426 };
427 
428 /** Region code mapping */
429 typedef struct _region_code_t {
430 	/** Region */
431 	t_u8 region[COUNTRY_CODE_LEN];
432 } region_code_t;
433 
434 static const struct ieee80211_regdomain mrvl_regdom = {
435 	.n_reg_rules = 4,
436 	.alpha2 = "99",
437 	.reg_rules = {
438 		/* IEEE 802.11b/g, channels 1..11 */
439 		REG_RULE(2412 - 10, 2472 + 10, 40, 6, 20, 0),
440 		/* If any */
441 		/* IEEE 802.11 channel 14 - Only JP enables
442 		 * this and for 802.11b only
443 		 */
444 		REG_RULE(2484 - 10, 2484 + 10, 20, 6, 20, 0),
445 		/* IEEE 802.11a, channel 36..64 */
446 		REG_RULE(5150 - 10, 5350 + 10, 80, 6, 20, 0),
447 		/* IEEE 802.11a, channel 100..165 */
448 		REG_RULE(5470 - 10, 5850 + 10, 80, 6, 20, 0),
449 	}};
450 
451 #define AUTH_TX_DEFAULT_WAIT_TIME 2400
452 /********************************************************
453 				Local Variables
454 ********************************************************/
455 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
456 // clang-format off
457 static const struct ieee80211_txrx_stypes
458 	ieee80211_mgmt_stypes[NUM_NL80211_IFTYPES] = {
459 		[NL80211_IFTYPE_STATION] = {
460 			.tx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
461 			      MBIT(IEEE80211_STYPE_PROBE_RESP >> 4),
462 			.rx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
463 			      MBIT(IEEE80211_STYPE_PROBE_REQ >> 4),
464 		},
465 		[NL80211_IFTYPE_AP] = {
466 			.tx = 0xffff,
467 			.rx = MBIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
468 			      MBIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
469 			      MBIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
470 			      MBIT(IEEE80211_STYPE_DISASSOC >> 4) |
471 			      MBIT(IEEE80211_STYPE_AUTH >> 4) |
472 			      MBIT(IEEE80211_STYPE_DEAUTH >> 4) |
473 			      MBIT(IEEE80211_STYPE_ACTION >> 4),
474 		},
475 		[NL80211_IFTYPE_AP_VLAN] = {
476 			.tx = 0x0000,
477 			.rx = 0x0000,
478 		},
479 #ifdef WIFI_DIRECT_SUPPORT
480 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
481 		[NL80211_IFTYPE_P2P_CLIENT] = {
482 			.tx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
483 			      MBIT(IEEE80211_STYPE_PROBE_RESP >> 4),
484 			.rx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
485 			      MBIT(IEEE80211_STYPE_PROBE_REQ >> 4),
486 		},
487 		[NL80211_IFTYPE_P2P_GO] = {
488 			.tx = MBIT(IEEE80211_STYPE_ACTION >> 4) |
489 			      MBIT(IEEE80211_STYPE_AUTH >> 4) |
490 			      MBIT(IEEE80211_STYPE_ASSOC_RESP >> 4) |
491 			      MBIT(IEEE80211_STYPE_REASSOC_RESP >> 4) |
492 			      MBIT(IEEE80211_STYPE_PROBE_RESP >> 4),
493 			.rx = MBIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
494 			      MBIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
495 			      MBIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
496 			      MBIT(IEEE80211_STYPE_DISASSOC >> 4) |
497 			      MBIT(IEEE80211_STYPE_AUTH >> 4) |
498 			      MBIT(IEEE80211_STYPE_DEAUTH >> 4) |
499 			      MBIT(IEEE80211_STYPE_ACTION >> 4),
500 		},
501 #endif
502 #endif
503 		[NL80211_IFTYPE_MESH_POINT] = {
504 			.tx = 0x0000,
505 			.rx = 0x0000,
506 		},
507 
508 };
509 // clang-format on
510 #endif
511 
512 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
513 /**
514  * NOTE: types in all the sets must be equals to the
515  * initial value of wiphy->interface_modes
516  */
517 static const struct ieee80211_iface_limit cfg80211_ap_sta_limits[] = {
518 	{.max = 4,
519 	 .types = MBIT(NL80211_IFTYPE_STATION)
520 #ifdef UAP_CFG80211
521 		  | MBIT(NL80211_IFTYPE_AP) | MBIT(NL80211_IFTYPE_MONITOR)
522 #endif
523 #ifdef WIFI_DIRECT_SUPPORT
524 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
525 		  | MBIT(NL80211_IFTYPE_P2P_GO) |
526 		  MBIT(NL80211_IFTYPE_P2P_CLIENT)
527 #endif
528 #endif
529 	}};
530 
531 static struct ieee80211_iface_combination cfg80211_iface_comb_ap_sta = {
532 	.limits = cfg80211_ap_sta_limits,
533 	.num_different_channels = 1,
534 	.n_limits = ARRAY_SIZE(cfg80211_ap_sta_limits),
535 	.max_interfaces = 4,
536 	.beacon_int_infra_match = MTRUE,
537 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
538 	.radar_detect_widths =
539 		MBIT(NL80211_CHAN_WIDTH_20_NOHT) | MBIT(NL80211_CHAN_WIDTH_20),
540 #endif
541 };
542 #endif
543 
544 extern pmoal_handle m_handle[];
545 
546 #ifdef CONFIG_PM
547 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
548 static const struct wiphy_wowlan_support wowlan_support = {
549 	.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT,
550 	.n_patterns = MAX_NUM_FILTERS,
551 	.pattern_min_len = 1,
552 	.pattern_max_len = WOWLAN_MAX_PATTERN_LEN,
553 	.max_pkt_offset = WOWLAN_MAX_OFFSET_LEN,
554 };
555 static const struct wiphy_wowlan_support wowlan_support_with_gtk = {
556 	.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT |
557 		 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
558 		 WIPHY_WOWLAN_GTK_REKEY_FAILURE,
559 	.n_patterns = MAX_NUM_FILTERS,
560 	.pattern_min_len = 1,
561 	.pattern_max_len = WOWLAN_MAX_PATTERN_LEN,
562 	.max_pkt_offset = WOWLAN_MAX_OFFSET_LEN,
563 };
564 #endif
565 #endif
566 
567 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
568 static const struct wiphy_coalesce_support coalesce_support = {
569 	.n_rules = COALESCE_MAX_RULES,
570 	.max_delay = MAX_COALESCING_DELAY,
571 	.n_patterns = COALESCE_MAX_FILTERS,
572 	.pattern_min_len = 1,
573 	.pattern_max_len = MAX_PATTERN_LEN,
574 	.max_pkt_offset = MAX_OFFSET_LEN,
575 };
576 #endif
577 
578 /********************************************************
579 				Global Variables
580 ********************************************************/
581 
582 /********************************************************
583 				Local Functions
584 ********************************************************/
585 #ifdef UAP_SUPPORT
586 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
woal_cfg80211_set_monitor_channel(struct wiphy * wiphy,struct cfg80211_chan_def * chandef)587 static int woal_cfg80211_set_monitor_channel(struct wiphy *wiphy,
588 					     struct cfg80211_chan_def *chandef)
589 {
590 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
591 	moal_private *priv =
592 		(moal_private *)woal_get_priv(handle, MLAN_BSS_ROLE_STA);
593 	netmon_band_chan_cfg band_chan_cfg;
594 	t_u32 bandwidth = 0;
595 	int ret = -EFAULT;
596 
597 	ENTER();
598 
599 	if (!priv) {
600 		ret = -EFAULT;
601 		goto done;
602 	}
603 	if (handle->mon_if) {
604 		if (cfg80211_chandef_identical(&handle->mon_if->chandef,
605 					       chandef)) {
606 			ret = 0;
607 			goto done;
608 		}
609 
610 		memset(&band_chan_cfg, 0x00, sizeof(band_chan_cfg));
611 		/* Set channel */
612 		band_chan_cfg.channel = ieee80211_frequency_to_channel(
613 			chandef->chan->center_freq);
614 		/* Set band */
615 		if (chandef->chan->band == IEEE80211_BAND_2GHZ)
616 			band_chan_cfg.band |= (BAND_B | BAND_G);
617 		if (chandef->chan->band == IEEE80211_BAND_5GHZ)
618 			band_chan_cfg.band |= BAND_A;
619 		if (chandef->chan->band == IEEE80211_BAND_2GHZ)
620 			band_chan_cfg.band |= BAND_GN;
621 		if (chandef->chan->band == IEEE80211_BAND_5GHZ)
622 			band_chan_cfg.band |= BAND_AN;
623 		if (chandef->chan->band == IEEE80211_BAND_2GHZ)
624 			band_chan_cfg.band |= BAND_GAC;
625 		if (chandef->chan->band == IEEE80211_BAND_5GHZ)
626 			band_chan_cfg.band |= BAND_AAC;
627 		/* Set bandwidth */
628 		if (chandef->width == NL80211_CHAN_WIDTH_20)
629 			bandwidth = CHANNEL_BW_20MHZ;
630 		else if (chandef->width == NL80211_CHAN_WIDTH_40)
631 			bandwidth = chandef->center_freq1 >
632 						    chandef->chan->center_freq ?
633 					    CHANNEL_BW_40MHZ_ABOVE :
634 					    CHANNEL_BW_40MHZ_BELOW;
635 		else if (chandef->width == NL80211_CHAN_WIDTH_80)
636 			bandwidth = CHANNEL_BW_80MHZ;
637 		band_chan_cfg.chan_bandwidth = bandwidth;
638 
639 		if (MLAN_STATUS_SUCCESS !=
640 		    woal_set_net_monitor(priv, MOAL_IOCTL_WAIT,
641 					 CHANNEL_SPEC_SNIFFER_MODE, 0x7,
642 					 &band_chan_cfg)) {
643 			PRINTM(MERROR, "%s: woal_set_net_monitor fail\n",
644 			       __func__);
645 			ret = -EFAULT;
646 			goto done;
647 		}
648 
649 		moal_memcpy_ext(priv->phandle, &handle->mon_if->band_chan_cfg,
650 				&band_chan_cfg,
651 				sizeof(handle->mon_if->band_chan_cfg),
652 				sizeof(handle->mon_if->band_chan_cfg));
653 		handle->mon_if->chandef = *chandef;
654 
655 		if (handle->mon_if->chandef.chan)
656 			PRINTM(MINFO,
657 			       "set_monitor_channel+++ chan[band=%d center_freq=%d hw_value=%d] width=%d center_freq1=%d center_freq2=%d\n",
658 			       handle->mon_if->chandef.chan->band,
659 			       handle->mon_if->chandef.chan->center_freq,
660 			       handle->mon_if->chandef.chan->hw_value,
661 			       handle->mon_if->chandef.width,
662 			       handle->mon_if->chandef.center_freq1,
663 			       handle->mon_if->chandef.center_freq2);
664 		PRINTM(MINFO,
665 		       "set_monitor_channel+++ band=%x channel=%d bandwidth=%d\n",
666 		       handle->mon_if->band_chan_cfg.band,
667 		       handle->mon_if->band_chan_cfg.channel,
668 		       handle->mon_if->band_chan_cfg.chan_bandwidth);
669 		ret = 0;
670 	}
671 
672 done:
673 	LEAVE();
674 	return ret;
675 }
676 #endif
677 #endif
678 
679 /**
680  *  @brief This function check cfg80211 special region code.
681  *
682  *  @param region_string         Region string
683  *
684  *  @return     MTRUE/MFALSE
685  */
is_cfg80211_special_region_code(t_u8 * region_string)686 t_u8 is_cfg80211_special_region_code(t_u8 *region_string)
687 {
688 	t_u8 i;
689 	region_code_t cfg80211_special_region_code[] = {
690 		{"00 "}, {"99 "}, {"98 "}, {"97 "}};
691 
692 	for (i = 0; i < COUNTRY_CODE_LEN && region_string[i]; i++)
693 		region_string[i] = toupper(region_string[i]);
694 
695 	for (i = 0; i < ARRAY_SIZE(cfg80211_special_region_code); i++) {
696 		if (!memcmp(region_string,
697 			    cfg80211_special_region_code[i].region,
698 			    COUNTRY_CODE_LEN)) {
699 			PRINTM(MIOCTL, "special region code=%s\n",
700 			       region_string);
701 			return MTRUE;
702 		}
703 	}
704 	return MFALSE;
705 }
706 
707 /**
708  * @brief Get the encryption mode from cipher
709  *
710  * @param cipher        Cipher cuite
711  * @param wpa_enabled   WPA enable or disable
712  *
713  * @return              MLAN_ENCRYPTION_MODE_*
714  */
woal_cfg80211_get_encryption_mode(t_u32 cipher,int * wpa_enabled)715 static int woal_cfg80211_get_encryption_mode(t_u32 cipher, int *wpa_enabled)
716 {
717 	int encrypt_mode;
718 
719 	ENTER();
720 
721 	*wpa_enabled = 0;
722 	switch (cipher) {
723 	case MW_AUTH_CIPHER_NONE:
724 		encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
725 		break;
726 	case WLAN_CIPHER_SUITE_WEP40:
727 		encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
728 		break;
729 	case WLAN_CIPHER_SUITE_WEP104:
730 		encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
731 		break;
732 	case WLAN_CIPHER_SUITE_TKIP:
733 		encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
734 		*wpa_enabled = 1;
735 		break;
736 	case WLAN_CIPHER_SUITE_CCMP:
737 		encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
738 		*wpa_enabled = 1;
739 		break;
740 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
741 	case WLAN_CIPHER_SUITE_CCMP_256:
742 		encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP_256;
743 		*wpa_enabled = 1;
744 		break;
745 #endif
746 
747 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
748 	case WLAN_CIPHER_SUITE_GCMP:
749 		encrypt_mode = MLAN_ENCRYPTION_MODE_GCMP;
750 		*wpa_enabled = 1;
751 		break;
752 #endif
753 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
754 	case WLAN_CIPHER_SUITE_GCMP_256:
755 		encrypt_mode = MLAN_ENCRYPTION_MODE_GCMP_256;
756 		*wpa_enabled = 1;
757 		break;
758 #endif
759 	default:
760 		encrypt_mode = -1;
761 	}
762 
763 	LEAVE();
764 	return encrypt_mode;
765 }
766 
767 /**
768  *  @brief get associate failure status code
769  *
770  *  @param priv     Pointer to the moal_private driver data struct
771  *
772  *  @return         IEEE status code
773  */
woal_get_assoc_status(moal_private * priv)774 static int woal_get_assoc_status(moal_private *priv)
775 {
776 	int ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
777 	t_u16 status = (t_u16)(priv->assoc_status & 0xffff);
778 	t_u16 cap = (t_u16)(priv->assoc_status >> 16);
779 
780 	switch (cap) {
781 	case 0xfffd:
782 	case 0xfffe:
783 		ret = status;
784 		break;
785 	case 0xfffc:
786 		ret = WLAN_STATUS_AUTH_TIMEOUT;
787 		break;
788 	default:
789 		break;
790 	}
791 	PRINTM(MCMND, "Assoc fail: status=%d, cap=0x%x, IEEE status=%d\n",
792 	       status, cap, ret);
793 	return ret;
794 }
795 
796 /**
797  *  @brief Check the pairwise or group cipher for
798  *  WEP enabled or not
799  *
800  *  @param cipher       MLAN Cipher cuite
801  *
802  *  @return             1 -- enable or 0 -- disable
803  */
woal_cfg80211_is_alg_wep(t_u32 cipher)804 static int woal_cfg80211_is_alg_wep(t_u32 cipher)
805 {
806 	int alg = 0;
807 	ENTER();
808 
809 	if (cipher == MLAN_ENCRYPTION_MODE_WEP40 ||
810 	    cipher == MLAN_ENCRYPTION_MODE_WEP104)
811 		alg = 1;
812 
813 	LEAVE();
814 	return alg;
815 }
816 
817 /**
818  *  @brief Convert NL80211 interface type to MLAN_BSS_MODE_*
819  *
820  *  @param iftype   Interface type of NL80211
821  *
822  *  @return         Driver bss mode
823  */
woal_nl80211_iftype_to_mode(enum nl80211_iftype iftype)824 static t_u32 woal_nl80211_iftype_to_mode(enum nl80211_iftype iftype)
825 {
826 	switch (iftype) {
827 	case NL80211_IFTYPE_STATION:
828 		return MLAN_BSS_MODE_INFRA;
829 	case NL80211_IFTYPE_UNSPECIFIED:
830 	default:
831 		return MLAN_BSS_MODE_AUTO;
832 	}
833 }
834 
835 /**
836  *  @brief Control WPS Session Enable/Disable
837  *
838  *  @param priv     Pointer to the moal_private driver data struct
839  *  @param enable   enable/disable flag
840  *
841  *  @return          0 --success, otherwise fail
842  */
woal_wps_cfg(moal_private * priv,int enable)843 static int woal_wps_cfg(moal_private *priv, int enable)
844 {
845 	int ret = 0;
846 	mlan_ds_wps_cfg *pwps = NULL;
847 	mlan_ioctl_req *req = NULL;
848 	mlan_status status = MLAN_STATUS_SUCCESS;
849 
850 	ENTER();
851 
852 	PRINTM(MINFO, "WOAL_WPS_SESSION\n");
853 
854 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
855 	if (req == NULL) {
856 		ret = -ENOMEM;
857 		goto done;
858 	}
859 
860 	pwps = (mlan_ds_wps_cfg *)req->pbuf;
861 	req->req_id = MLAN_IOCTL_WPS_CFG;
862 	req->action = MLAN_ACT_SET;
863 	pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
864 	if (enable)
865 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
866 	else
867 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
868 
869 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
870 	if (status != MLAN_STATUS_SUCCESS) {
871 		ret = -EFAULT;
872 		goto done;
873 	}
874 
875 done:
876 	if (status != MLAN_STATUS_PENDING)
877 		kfree(req);
878 	LEAVE();
879 	return ret;
880 }
881 
882 /**
883  * @brief configure ASSOC IE
884  *
885  * @param priv				A pointer to moal private structure
886  * @param ie				A pointer to ie data
887  * @param ie_len			The length of ie data
888  * @param wait_option       wait option
889  *
890  * @return                  0 -- success, otherwise fail
891  */
woal_cfg80211_assoc_ies_cfg(moal_private * priv,t_u8 * ie,int ie_len,t_u8 wait_option)892 static int woal_cfg80211_assoc_ies_cfg(moal_private *priv, t_u8 *ie, int ie_len,
893 				       t_u8 wait_option)
894 {
895 	int bytes_left = ie_len;
896 	t_u8 *pcurrent_ptr = ie;
897 	int total_ie_len;
898 	t_u8 element_len;
899 	int ret = MLAN_STATUS_SUCCESS;
900 	IEEEtypes_ElementId_e element_id;
901 	IEEEtypes_VendorSpecific_t *pvendor_ie;
902 	t_u8 wps_oui[] = {0x00, 0x50, 0xf2, 0x04};
903 	t_u8 hs20_oui[] = {0x50, 0x6f, 0x9a, 0x10};
904 
905 	while (bytes_left >= 2) {
906 		element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
907 		element_len = *((t_u8 *)pcurrent_ptr + 1);
908 		total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
909 		if (bytes_left < total_ie_len) {
910 			PRINTM(MERROR,
911 			       "InterpretIE: Error in processing IE, bytes left < IE length\n");
912 			bytes_left = 0;
913 			continue;
914 		}
915 		switch (element_id) {
916 		case RSN_IE:
917 			if (MLAN_STATUS_SUCCESS !=
918 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
919 						pcurrent_ptr, &total_ie_len,
920 						wait_option)) {
921 				PRINTM(MERROR, "Fail to set RSN IE\n");
922 				ret = -EFAULT;
923 				goto done;
924 			}
925 			PRINTM(MIOCTL, "Set RSN IE\n");
926 			break;
927 		case VENDOR_SPECIFIC_221:
928 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
929 			if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
930 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
931 			    (pvendor_ie->vend_hdr.oui_type == wps_oui[3])) {
932 				PRINTM(MIOCTL, "Enable WPS session\n");
933 				if (woal_wps_cfg(priv, MTRUE)) {
934 					PRINTM(MERROR,
935 					       "%s: Enable WPS session failed\n",
936 					       __func__);
937 					ret = -EFAULT;
938 					goto done;
939 				}
940 			}
941 
942 			if (!memcmp(pvendor_ie->vend_hdr.oui, hs20_oui,
943 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
944 			    (pvendor_ie->vend_hdr.oui_type == hs20_oui[3])) {
945 				PRINTM(MIOCTL,
946 				       "Hotspot2.0 is enabled for this bss\n");
947 				if (MLAN_STATUS_SUCCESS !=
948 				    woal_set_hotspotcfg(priv, wait_option,
949 							(HOTSPOT_BY_SUPPLICANT |
950 							 HOTSPOT_ENABLED))) {
951 					PRINTM(MERROR,
952 					       "Fail to enable hotspot 2.0\n");
953 					ret = -EFAULT;
954 					goto done;
955 				}
956 			}
957 			if (MLAN_STATUS_SUCCESS !=
958 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
959 						pcurrent_ptr, &total_ie_len,
960 						wait_option)) {
961 				PRINTM(MERROR,
962 				       "Fail to Set VENDOR SPECIFIC IE\n");
963 				ret = -EFAULT;
964 				goto done;
965 			}
966 			PRINTM(MIOCTL,
967 			       "Set VENDOR SPECIFIC IE, OUI: %02x:%02x:%02x:%02x\n",
968 			       pvendor_ie->vend_hdr.oui[0],
969 			       pvendor_ie->vend_hdr.oui[1],
970 			       pvendor_ie->vend_hdr.oui[2],
971 			       pvendor_ie->vend_hdr.oui_type);
972 			break;
973 		case MOBILITY_DOMAIN:
974 			break;
975 		case FAST_BSS_TRANSITION:
976 			if (MLAN_STATUS_SUCCESS !=
977 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
978 						pcurrent_ptr, &total_ie_len,
979 						wait_option)) {
980 				PRINTM(MERROR, "Fail to set"
981 					       "FAST_BSS_TRANSITION IE\n");
982 				ret = -EFAULT;
983 				goto done;
984 			}
985 			PRINTM(MIOCTL, "Set FAST_BSS_TRANSITION IE\n");
986 			break;
987 		case RIC:
988 			if (MLAN_STATUS_SUCCESS !=
989 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
990 						pcurrent_ptr, &total_ie_len,
991 						wait_option)) {
992 				PRINTM(MERROR,
993 				       "Fail to set"
994 				       "RESOURCE INFORMATION CONTAINER IE\n");
995 				ret = -EFAULT;
996 				goto done;
997 			}
998 			PRINTM(MIOCTL,
999 			       "Set RESOURCE INFORMATION CONTAINER IE\n");
1000 			break;
1001 		case EXT_CAPABILITY:
1002 			if (MLAN_STATUS_SUCCESS !=
1003 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
1004 						pcurrent_ptr, &total_ie_len,
1005 						wait_option)) {
1006 				PRINTM(MERROR,
1007 				       "Fail to set Extended Capabilites IE\n");
1008 				ret = -EFAULT;
1009 				goto done;
1010 			}
1011 			PRINTM(MIOCTL, "Set Extended Capabilities IE\n");
1012 			break;
1013 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
1014 		case EXTENSION:
1015 			if (MLAN_STATUS_SUCCESS !=
1016 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
1017 						pcurrent_ptr, &total_ie_len,
1018 						wait_option)) {
1019 				PRINTM(MERROR, "Fail to set Extension IE\n");
1020 				ret = -EFAULT;
1021 				goto done;
1022 			}
1023 			PRINTM(MIOCTL, "Set Extension IE\n");
1024 			break;
1025 		case FRAGMENT:
1026 			if (MLAN_STATUS_SUCCESS !=
1027 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
1028 						pcurrent_ptr, &total_ie_len,
1029 						wait_option)) {
1030 				PRINTM(MERROR, "Fail to set Fragmented IE\n");
1031 				ret = -EFAULT;
1032 				goto done;
1033 			}
1034 			PRINTM(MIOCTL, "Set Fragmented IE\n");
1035 			break;
1036 #endif
1037 		default:
1038 			if (MLAN_STATUS_SUCCESS !=
1039 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
1040 						pcurrent_ptr, &total_ie_len,
1041 						wait_option)) {
1042 				PRINTM(MERROR, "Fail to set GEN IE\n");
1043 				ret = -EFAULT;
1044 				goto done;
1045 			}
1046 			PRINTM(MIOCTL, "Set GEN IE\n");
1047 			break;
1048 		}
1049 		pcurrent_ptr += element_len + 2;
1050 		/* Need to account for IE ID and IE Len */
1051 		bytes_left -= (element_len + 2);
1052 	}
1053 done:
1054 	return ret;
1055 }
1056 
1057 #ifdef CONFIG_NL80211_TESTMODE
1058 enum moal_tm_attr {
1059 	__MOAL_TM_ATTR_INVALID = 0,
1060 	MOAL_TM_ATTR_CMD = 1,
1061 	MOAL_TM_ATTR_DATA = 2,
1062 
1063 	/* keep last */
1064 	__MOAL_TM_ATTR_AFTER_LAST,
1065 	MOAL_TM_ATTR_MAX = __MOAL_TM_ATTR_AFTER_LAST - 1,
1066 };
1067 
1068 static const struct nla_policy moal_tm_policy[MOAL_TM_ATTR_MAX + 1] = {
1069 	[MOAL_TM_ATTR_CMD] = {.type = NLA_U32},
1070 	[MOAL_TM_ATTR_DATA] = {.type = NLA_BINARY,
1071 			       .len = MRVDRV_SIZE_OF_CMD_BUFFER},
1072 };
1073 
1074 enum moal_tm_command {
1075 	MOAL_TM_CMD_HOSTCMD = 0,
1076 };
1077 
1078 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
woal_testmode_cmd(struct wiphy * wiphy,struct wireless_dev * wdev,void * data,int len)1079 static int woal_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev,
1080 			     void *data, int len)
1081 #else
1082 static int woal_testmode_cmd(struct wiphy *wiphy, void *data, int len)
1083 #endif
1084 {
1085 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
1086 	moal_private *priv =
1087 		(moal_private *)woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
1088 	mlan_ioctl_req *req = NULL;
1089 	mlan_ds_misc_cfg *misc_cfg = NULL;
1090 	mlan_status status = MLAN_STATUS_SUCCESS;
1091 	struct nlattr *tb[MOAL_TM_ATTR_MAX + 1];
1092 	struct sk_buff *skb;
1093 	int err;
1094 
1095 	if (!priv)
1096 		return -EINVAL;
1097 
1098 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
1099 	err = nla_parse(tb, MOAL_TM_ATTR_MAX, data, len, moal_tm_policy, NULL);
1100 #else
1101 	err = nla_parse(tb, MOAL_TM_ATTR_MAX, data, len, moal_tm_policy);
1102 #endif
1103 	if (err)
1104 		return err;
1105 
1106 	if (!tb[MOAL_TM_ATTR_CMD])
1107 		return -EINVAL;
1108 
1109 	switch (nla_get_u32(tb[MOAL_TM_ATTR_CMD])) {
1110 	case MOAL_TM_CMD_HOSTCMD:
1111 		if (!tb[MOAL_TM_ATTR_DATA])
1112 			return -EINVAL;
1113 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
1114 		if (req == NULL)
1115 			return -ENOMEM;
1116 		misc_cfg = (mlan_ds_misc_cfg *)req->pbuf;
1117 		misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD;
1118 		req->req_id = MLAN_IOCTL_MISC_CFG;
1119 		req->action = MLAN_ACT_SET;
1120 		misc_cfg->param.hostcmd.len = nla_len(tb[MOAL_TM_ATTR_DATA]);
1121 		moal_memcpy_ext(priv->phandle, misc_cfg->param.hostcmd.cmd,
1122 				nla_data(tb[MOAL_TM_ATTR_DATA]),
1123 				misc_cfg->param.hostcmd.len,
1124 				MRVDRV_SIZE_OF_CMD_BUFFER);
1125 		status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1126 		if (status != MLAN_STATUS_SUCCESS) {
1127 			err = -EFAULT;
1128 			goto error;
1129 		}
1130 		/* process hostcmd response*/
1131 		skb = cfg80211_testmode_alloc_reply_skb(
1132 			wiphy, misc_cfg->param.hostcmd.len);
1133 		if (!skb) {
1134 			kfree(req);
1135 			return -ENOMEM;
1136 		}
1137 		err = nla_put(skb, MOAL_TM_ATTR_DATA,
1138 			      misc_cfg->param.hostcmd.len,
1139 			      misc_cfg->param.hostcmd.cmd);
1140 		if (err) {
1141 			kfree(req);
1142 			kfree_skb(skb);
1143 			return -EMSGSIZE;
1144 		}
1145 		err = cfg80211_testmode_reply(skb);
1146 		kfree(req);
1147 		return err;
1148 	default:
1149 		return -EOPNOTSUPP;
1150 	}
1151 error:
1152 	if (status != MLAN_STATUS_PENDING)
1153 		kfree(req);
1154 	return err;
1155 }
1156 #endif
1157 
1158 /**
1159  * @brief Send domain info command to FW
1160  *
1161  * @param priv      A pointer to moal_private structure
1162  * @param wait_option  wait option
1163  *
1164  * @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1165  */
woal_send_domain_info_cmd_fw(moal_private * priv,t_u8 wait_option)1166 static mlan_status woal_send_domain_info_cmd_fw(moal_private *priv,
1167 						t_u8 wait_option)
1168 {
1169 	mlan_status ret = MLAN_STATUS_SUCCESS;
1170 	enum ieee80211_band band;
1171 	struct ieee80211_supported_band *sband = NULL;
1172 	struct ieee80211_channel *channel = NULL;
1173 	t_u8 no_of_sub_band = 0;
1174 	t_u8 no_of_parsed_chan = 0;
1175 	t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
1176 	t_u8 i, flag = 0;
1177 	mlan_ds_11d_cfg *cfg_11d = NULL;
1178 	mlan_ioctl_req *req = NULL;
1179 	mlan_status status = MLAN_STATUS_SUCCESS;
1180 
1181 	ENTER();
1182 
1183 	if (!priv->wdev || !priv->wdev->wiphy) {
1184 		PRINTM(MERROR, "No wdev or wiphy in priv\n");
1185 		ret = MLAN_STATUS_FAILURE;
1186 		goto done;
1187 	}
1188 	band = priv->phandle->band;
1189 	if (!priv->wdev->wiphy->bands[band]) {
1190 		PRINTM(MERROR, "11D: setting domain info in FW failed band=%d",
1191 		       band);
1192 		ret = MLAN_STATUS_FAILURE;
1193 		goto done;
1194 	}
1195 
1196 	PRINTM(MCMD_D, "Send domain info: country=%c%c band=%d dfs_region=%d\n",
1197 	       priv->phandle->country_code[0], priv->phandle->country_code[1],
1198 	       band, priv->phandle->dfs_region);
1199 	/* Allocate an IOCTL request buffer */
1200 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
1201 	if (req == NULL) {
1202 		ret = MLAN_STATUS_FAILURE;
1203 		goto done;
1204 	}
1205 	cfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
1206 	cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO_EXT;
1207 	req->req_id = MLAN_IOCTL_11D_CFG;
1208 	req->action = MLAN_ACT_SET;
1209 	cfg_11d->param.domain_info.dfs_region = priv->phandle->dfs_region;
1210 	if (is_cfg80211_special_region_code(priv->phandle->country_code)) {
1211 		/* Set country code */
1212 		cfg_11d->param.domain_info.country_code[0] = 'W';
1213 		cfg_11d->param.domain_info.country_code[1] = 'W';
1214 	} else {
1215 		/* Set country code */
1216 		cfg_11d->param.domain_info.country_code[0] =
1217 			priv->phandle->country_code[0];
1218 		cfg_11d->param.domain_info.country_code[1] =
1219 			priv->phandle->country_code[1];
1220 	}
1221 	cfg_11d->param.domain_info.country_code[2] = ' ';
1222 	cfg_11d->param.domain_info.band = band;
1223 
1224 	sband = priv->wdev->wiphy->bands[band];
1225 	for (i = 0; (i < sband->n_channels) &&
1226 		    (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D);
1227 	     i++) {
1228 		channel = &sband->channels[i];
1229 		if (channel->flags & IEEE80211_CHAN_DISABLED)
1230 			continue;
1231 
1232 		if (!flag) {
1233 			flag = 1;
1234 			next_chan = first_chan = (t_u32)channel->hw_value;
1235 			max_pwr = channel->max_power;
1236 			no_of_parsed_chan = 1;
1237 			continue;
1238 		}
1239 
1240 		if (channel->hw_value == next_chan + 1 &&
1241 		    channel->max_power == max_pwr) {
1242 			next_chan++;
1243 			no_of_parsed_chan++;
1244 		} else {
1245 			cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1246 				.first_chan = first_chan;
1247 			cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1248 				.no_of_chan = no_of_parsed_chan;
1249 			cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1250 				.max_tx_pwr = max_pwr;
1251 			no_of_sub_band++;
1252 			next_chan = first_chan = (t_u32)channel->hw_value;
1253 			max_pwr = channel->max_power;
1254 			no_of_parsed_chan = 1;
1255 		}
1256 	}
1257 
1258 	if (flag && (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D)) {
1259 		cfg_11d->param.domain_info.sub_band[no_of_sub_band].first_chan =
1260 			first_chan;
1261 		cfg_11d->param.domain_info.sub_band[no_of_sub_band].no_of_chan =
1262 			no_of_parsed_chan;
1263 		cfg_11d->param.domain_info.sub_band[no_of_sub_band].max_tx_pwr =
1264 			max_pwr;
1265 		no_of_sub_band++;
1266 	}
1267 	cfg_11d->param.domain_info.no_of_sub_band = no_of_sub_band;
1268 
1269 	PRINTM(MCMND, "CFG80211: Country=%c%c, band=%d, no_of_sub_band=%d\n",
1270 	       priv->phandle->country_code[0], priv->phandle->country_code[1],
1271 	       priv->phandle->band, cfg_11d->param.domain_info.no_of_sub_band);
1272 	/* Send domain info command to FW */
1273 	status = woal_request_ioctl(priv, req, wait_option);
1274 	if (status != MLAN_STATUS_SUCCESS) {
1275 		ret = MLAN_STATUS_FAILURE;
1276 		PRINTM(MERROR, "11D: Error setting domain info in FW\n");
1277 		goto done;
1278 	}
1279 
1280 done:
1281 	if (status != MLAN_STATUS_PENDING)
1282 		kfree(req);
1283 	LEAVE();
1284 	return ret;
1285 }
1286 
1287 /**
1288  * @brief Request the driver to change the channel and
1289  * change domain info according to that channel
1290  *
1291  * @param priv            A pointer to moal_private structure
1292  * @param chan            A pointer to ieee80211_channel structure
1293  * @param channel_type    Channel type of nl80211_channel_type
1294  * @param wait_option     wait option
1295  *
1296  * @return                0 -- success, otherwise fail
1297  */
woal_set_rf_channel(moal_private * priv,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type,t_u8 wait_option)1298 int woal_set_rf_channel(moal_private *priv, struct ieee80211_channel *chan,
1299 			enum nl80211_channel_type channel_type,
1300 			t_u8 wait_option)
1301 {
1302 	int ret = 0;
1303 	t_u32 mode, config_bands = 0;
1304 	mlan_ioctl_req *req = NULL;
1305 	mlan_ds_radio_cfg *radio_cfg = NULL;
1306 	mlan_status status = MLAN_STATUS_SUCCESS;
1307 
1308 	ENTER();
1309 
1310 	if (!chan) {
1311 		LEAVE();
1312 		return -EINVAL;
1313 	}
1314 	mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
1315 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
1316 	if (req == NULL) {
1317 		ret = -ENOMEM;
1318 		goto done;
1319 	}
1320 	radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
1321 	radio_cfg->sub_command = MLAN_OID_BAND_CFG;
1322 	req->req_id = MLAN_IOCTL_RADIO_CFG;
1323 	/* Get config_bands, adhoc_start_band and adhoc_channel values from MLAN
1324 	 */
1325 	req->action = MLAN_ACT_GET;
1326 	status = woal_request_ioctl(priv, req, wait_option);
1327 	if (status != MLAN_STATUS_SUCCESS) {
1328 		ret = -EFAULT;
1329 		goto done;
1330 	}
1331 	req->action = MLAN_ACT_SET;
1332 	priv->phandle->band = chan->band;
1333 	/* Set appropriate bands */
1334 	if (chan->band == IEEE80211_BAND_2GHZ)
1335 		config_bands = BAND_B | BAND_G | BAND_GN;
1336 	else {
1337 		config_bands = BAND_AN | BAND_A;
1338 	}
1339 	if (mode == MLAN_BSS_MODE_IBSS) {
1340 		radio_cfg->param.band_cfg.adhoc_start_band = config_bands;
1341 		radio_cfg->param.band_cfg.adhoc_channel =
1342 			ieee80211_frequency_to_channel(chan->center_freq);
1343 	}
1344 
1345 	status = woal_request_ioctl(priv, req, wait_option);
1346 	if (status != MLAN_STATUS_SUCCESS) {
1347 		ret = -EFAULT;
1348 		goto done;
1349 	}
1350 	woal_send_domain_info_cmd_fw(priv, wait_option);
1351 
1352 	PRINTM(MINFO, "Setting band %d, and mode = %d channel=%d\n",
1353 	       config_bands, mode,
1354 	       ieee80211_frequency_to_channel(chan->center_freq));
1355 
1356 	if (MLAN_STATUS_SUCCESS !=
1357 	    woal_change_adhoc_chan(
1358 		    priv, ieee80211_frequency_to_channel(chan->center_freq),
1359 		    wait_option)) {
1360 		ret = -EFAULT;
1361 		goto done;
1362 	}
1363 
1364 done:
1365 	if (status != MLAN_STATUS_PENDING)
1366 		kfree(req);
1367 	LEAVE();
1368 	return ret;
1369 }
1370 
1371 /**
1372  *  @brief Set ewpa mode
1373  *
1374  *  @param priv                 A pointer to moal_private structure
1375  *  @param wait_option          Wait option
1376  *  @param ssid_bssid           A pointer to mlan_ssid_bssid structure
1377  *
1378  *  @return                     MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --
1379  * success, otherwise fail
1380  */
woal_set_ewpa_mode(moal_private * priv,t_u8 wait_option,mlan_ssid_bssid * ssid_bssid)1381 static mlan_status woal_set_ewpa_mode(moal_private *priv, t_u8 wait_option,
1382 				      mlan_ssid_bssid *ssid_bssid)
1383 {
1384 	mlan_ioctl_req *req = NULL;
1385 	mlan_ds_sec_cfg *sec = NULL;
1386 	mlan_status status = MLAN_STATUS_SUCCESS;
1387 
1388 	ENTER();
1389 
1390 	if (!priv->phandle->card_info->embedded_supp)
1391 		goto error;
1392 
1393 	/* Allocate an IOCTL request buffer */
1394 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1395 	if (req == NULL) {
1396 		status = MLAN_STATUS_FAILURE;
1397 		goto error;
1398 	}
1399 
1400 	/* Fill request buffer */
1401 	sec = (mlan_ds_sec_cfg *)req->pbuf;
1402 	sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
1403 	req->req_id = MLAN_IOCTL_SEC_CFG;
1404 	req->action = MLAN_ACT_GET;
1405 
1406 	/* Try Get All */
1407 	memset(&sec->param.passphrase, 0, sizeof(mlan_ds_passphrase));
1408 	moal_memcpy_ext(priv->phandle, &sec->param.passphrase.ssid,
1409 			&ssid_bssid->ssid, sizeof(sec->param.passphrase.ssid),
1410 			sizeof(sec->param.passphrase.ssid));
1411 	moal_memcpy_ext(priv->phandle, &sec->param.passphrase.bssid,
1412 			&ssid_bssid->bssid, MLAN_MAC_ADDR_LENGTH,
1413 			sizeof(sec->param.passphrase.bssid));
1414 	sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
1415 
1416 	/* Send IOCTL request to MLAN */
1417 	status = woal_request_ioctl(priv, req, wait_option);
1418 	if (status != MLAN_STATUS_SUCCESS)
1419 		goto error;
1420 	sec->param.ewpa_enabled = MFALSE;
1421 	if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
1422 		if (sec->param.passphrase.psk.passphrase.passphrase_len > 0)
1423 			sec->param.ewpa_enabled = MTRUE;
1424 	} else if (sec->param.passphrase.psk_type == MLAN_PSK_PMK)
1425 		sec->param.ewpa_enabled = MTRUE;
1426 
1427 	sec->sub_command = MLAN_OID_SEC_CFG_EWPA_ENABLED;
1428 	req->action = MLAN_ACT_SET;
1429 
1430 	/* Send IOCTL request to MLAN */
1431 	status = woal_request_ioctl(priv, req, wait_option);
1432 
1433 error:
1434 	if (status != MLAN_STATUS_PENDING)
1435 		kfree(req);
1436 	LEAVE();
1437 	return status;
1438 }
1439 
1440 /**
1441  * @brief Set encryption mode and enable WPA
1442  *
1443  * @param priv          A pointer to moal_private structure
1444  * @param encrypt_mode  Encryption mode
1445  * @param wpa_enabled   WPA enable or not
1446  * @param wait_option   wait option
1447  *
1448  * @return              0 -- success, otherwise fail
1449  */
woal_cfg80211_set_auth(moal_private * priv,int encrypt_mode,int wpa_enabled,t_u8 wait_option)1450 static int woal_cfg80211_set_auth(moal_private *priv, int encrypt_mode,
1451 				  int wpa_enabled, t_u8 wait_option)
1452 {
1453 	int ret = 0;
1454 
1455 	ENTER();
1456 
1457 	if (MLAN_STATUS_SUCCESS !=
1458 	    woal_set_encrypt_mode(priv, wait_option, encrypt_mode))
1459 		ret = -EFAULT;
1460 
1461 	if (wpa_enabled) {
1462 		if (MLAN_STATUS_SUCCESS !=
1463 		    woal_set_wpa_enable(priv, wait_option, 1))
1464 			ret = -EFAULT;
1465 	}
1466 
1467 	LEAVE();
1468 	return ret;
1469 }
1470 
1471 /**
1472  * @brief Informs the CFG802.11 subsystem of a new BSS connection.
1473  *
1474  * The following information are sent to the CFG802.11 subsystem
1475  * to register the new BSS connection. If we do not register the new BSS,
1476  * a kernel panic will result.
1477  *      - MAC address
1478  *      - Capabilities
1479  *      - Beacon period
1480  *      - RSSI value
1481  *      - Channel
1482  *      - Supported rates IE
1483  *      - Extended capabilities IE
1484  *      - DS parameter set IE
1485  *      - HT Capability IE
1486  *      - Vendor Specific IE (221)
1487  *      - WPA IE
1488  *      - RSN IE
1489  *
1490  * @param priv            A pointer to moal_private structure
1491  * @param ssid_bssid      A pointer to A pointer to mlan_ssid_bssid structure
1492  * @param wait_option     wait_option
1493  *
1494  * @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1495  */
woal_inform_bss_from_scan_result(moal_private * priv,mlan_ssid_bssid * ssid_bssid,t_u8 wait_option)1496 mlan_status woal_inform_bss_from_scan_result(moal_private *priv,
1497 					     mlan_ssid_bssid *ssid_bssid,
1498 					     t_u8 wait_option)
1499 {
1500 	mlan_status ret = MLAN_STATUS_SUCCESS;
1501 	struct ieee80211_channel *chan;
1502 	mlan_scan_resp scan_resp;
1503 	BSSDescriptor_t *scan_table;
1504 	t_u64 ts = 0;
1505 	u16 cap_info = 0;
1506 	int i = 0;
1507 	struct cfg80211_bss *pub = NULL;
1508 
1509 	ENTER();
1510 	if (!priv->wdev || !priv->wdev->wiphy) {
1511 		LEAVE();
1512 		return MLAN_STATUS_FAILURE;
1513 	}
1514 
1515 	memset(&scan_resp, 0, sizeof(scan_resp));
1516 	if (MLAN_STATUS_SUCCESS !=
1517 	    woal_get_scan_table(priv, wait_option, &scan_resp)) {
1518 		ret = MLAN_STATUS_FAILURE;
1519 		goto done;
1520 	}
1521 
1522 	if (scan_resp.num_in_scan_table) {
1523 		scan_table = (BSSDescriptor_t *)scan_resp.pscan_table;
1524 		for (i = 0; i < (int)scan_resp.num_in_scan_table; i++) {
1525 			if (ssid_bssid) {
1526 				/* Inform specific BSS only */
1527 				if (memcmp(ssid_bssid->ssid.ssid,
1528 					   scan_table[i].ssid.ssid,
1529 					   ssid_bssid->ssid.ssid_len) ||
1530 				    memcmp(ssid_bssid->bssid,
1531 					   scan_table[i].mac_address, ETH_ALEN))
1532 					continue;
1533 			}
1534 			if (!scan_table[i].freq) {
1535 				scan_table[i].freq =
1536 					ieee80211_channel_to_frequency(
1537 						(int)scan_table[i].channel
1538 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
1539 						,
1540 						woal_band_cfg_to_ieee_band(
1541 							scan_table[i].bss_band)
1542 #endif
1543 					);
1544 			}
1545 			chan = ieee80211_get_channel(priv->wdev->wiphy,
1546 						     scan_table[i].freq);
1547 			if (!chan) {
1548 				PRINTM(MCMND,
1549 				       "Fail to get chan with freq: channel=%d freq=%d\n",
1550 				       (int)scan_table[i].channel,
1551 				       (int)scan_table[i].freq);
1552 				continue;
1553 			}
1554 #if defined(WIFI_DIRECT_SUPPORT)
1555 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1556 			if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
1557 			    !ssid_bssid) {
1558 				if (!strncmp(scan_table[i].ssid.ssid, "DIRECT-",
1559 					     strlen("DIRECT-"))) {
1560 					PRINTM(MCMND,
1561 					       "wlan: P2P device " MACSTR
1562 					       " found, channel=%d\n",
1563 					       MAC2STR(scan_table[i]
1564 							       .mac_address),
1565 					       (int)chan->hw_value);
1566 				}
1567 			}
1568 #endif
1569 #endif
1570 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
1571 			/** Andorid's Location service is expecting timestamp to
1572 			 * be local time (in microsecond) since boot; and not
1573 			 * the TSF found in the beacon. */
1574 			ts = ktime_to_us(ktime_get_boottime());
1575 #else
1576 			moal_memcpy_ext(priv->phandle, &ts,
1577 					scan_table[i].time_stamp, sizeof(ts),
1578 					sizeof(ts));
1579 #endif
1580 			moal_memcpy_ext(priv->phandle, &cap_info,
1581 					&scan_table[i].cap_info,
1582 					sizeof(cap_info), sizeof(cap_info));
1583 			pub = cfg80211_inform_bss(
1584 				priv->wdev->wiphy, chan,
1585 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
1586 				CFG80211_BSS_FTYPE_UNKNOWN,
1587 #endif
1588 				scan_table[i].mac_address, ts, cap_info,
1589 				scan_table[i].beacon_period,
1590 				scan_table[i].pbeacon_buf +
1591 					WLAN_802_11_FIXED_IE_SIZE,
1592 				scan_table[i].beacon_buf_size -
1593 					WLAN_802_11_FIXED_IE_SIZE,
1594 				-RSSI_DBM_TO_MDM(scan_table[i].rssi),
1595 				GFP_KERNEL);
1596 			if (pub) {
1597 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
1598 				pub->len_information_elements =
1599 					pub->len_beacon_ies;
1600 #endif
1601 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
1602 				cfg80211_put_bss(priv->wdev->wiphy, pub);
1603 #else
1604 				cfg80211_put_bss(pub);
1605 #endif
1606 			}
1607 		}
1608 	}
1609 done:
1610 	LEAVE();
1611 	return ret;
1612 }
1613 
1614 /**
1615  * @brief Informs the CFG802.11 subsystem of a new IBSS connection.
1616  *
1617  * The following information are sent to the CFG802.11 subsystem
1618  * to register the new IBSS connection. If we do not register the
1619  * new IBSS, a kernel panic will result.
1620  *      - MAC address
1621  *      - Capabilities
1622  *      - Beacon period
1623  *      - RSSI value
1624  *      - Channel
1625  *      - Supported rates IE
1626  *      - Extended capabilities IE
1627  *      - DS parameter set IE
1628  *      - HT Capability IE
1629  *      - Vendor Specific IE (221)
1630  *      - WPA IE
1631  *      - RSN IE
1632  *
1633  * @param priv              A pointer to moal_private structure
1634  * @param cahn              A pointer to ieee80211_channel structure
1635  * @param beacon_interval   Beacon interval
1636  *
1637  * @return                  MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1638  */
woal_cfg80211_inform_ibss_bss(moal_private * priv,struct ieee80211_channel * chan,t_u16 beacon_interval)1639 static mlan_status woal_cfg80211_inform_ibss_bss(moal_private *priv,
1640 						 struct ieee80211_channel *chan,
1641 						 t_u16 beacon_interval)
1642 {
1643 	mlan_status ret = MLAN_STATUS_SUCCESS;
1644 	mlan_bss_info bss_info;
1645 	mlan_ds_get_signal signal;
1646 	t_u8 ie_buf[MLAN_MAX_SSID_LENGTH + sizeof(IEEEtypes_Header_t)];
1647 	int ie_len = 0;
1648 	struct cfg80211_bss *bss = NULL;
1649 
1650 	ENTER();
1651 
1652 	ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
1653 	if (ret)
1654 		goto done;
1655 
1656 	memset(ie_buf, 0, sizeof(ie_buf));
1657 	ie_buf[0] = WLAN_EID_SSID;
1658 	ie_buf[1] = bss_info.ssid.ssid_len;
1659 
1660 	moal_memcpy_ext(priv->phandle, &ie_buf[sizeof(IEEEtypes_Header_t)],
1661 			&bss_info.ssid.ssid, bss_info.ssid.ssid_len,
1662 			sizeof(ie_buf) - sizeof(IEEEtypes_Header_t));
1663 	ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t);
1664 
1665 	/* Get signal information from the firmware */
1666 	memset(&signal, 0, sizeof(mlan_ds_get_signal));
1667 	if (MLAN_STATUS_SUCCESS !=
1668 	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
1669 		PRINTM(MERROR, "Error getting signal information\n");
1670 		ret = MLAN_STATUS_FAILURE;
1671 		goto done;
1672 	}
1673 
1674 	bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
1675 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
1676 				  CFG80211_BSS_FTYPE_UNKNOWN,
1677 #endif
1678 				  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
1679 				  beacon_interval, ie_buf, ie_len,
1680 				  signal.bcn_rssi_avg, GFP_KERNEL);
1681 	if (bss)
1682 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
1683 		cfg80211_put_bss(priv->wdev->wiphy, bss);
1684 #else
1685 		cfg80211_put_bss(bss);
1686 #endif
1687 done:
1688 	LEAVE();
1689 	return ret;
1690 }
1691 
1692 /**
1693  * @brief Process country IE before assoicate
1694  *
1695  * @param priv            A pointer to moal_private structure
1696  * @param bss             A pointer to cfg80211_bss structure
1697  *
1698  * @return                0 -- success, otherwise fail
1699  */
woal_process_country_ie(moal_private * priv,struct cfg80211_bss * bss)1700 static int woal_process_country_ie(moal_private *priv, struct cfg80211_bss *bss)
1701 {
1702 	u8 *country_ie, country_ie_len;
1703 	int ret = 0;
1704 	mlan_ioctl_req *req = NULL;
1705 	mlan_ds_11d_cfg *cfg_11d = NULL;
1706 	mlan_status status = MLAN_STATUS_SUCCESS;
1707 
1708 	ENTER();
1709 	rcu_read_lock();
1710 	country_ie = (u8 *)ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
1711 	if (!country_ie) {
1712 		rcu_read_unlock();
1713 		PRINTM(MIOCTL, "No country IE found!\n");
1714 		woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
1715 		LEAVE();
1716 		return 0;
1717 	}
1718 
1719 	country_ie_len = country_ie[1];
1720 	if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
1721 		rcu_read_unlock();
1722 		PRINTM(MIOCTL, "Wrong Country IE length!\n");
1723 		woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
1724 		LEAVE();
1725 		return 0;
1726 	}
1727 	priv->phandle->country_code[0] = country_ie[2];
1728 	priv->phandle->country_code[1] = country_ie[3];
1729 	priv->phandle->country_code[2] = ' ';
1730 	if (is_cfg80211_special_region_code(priv->phandle->country_code)) {
1731 		rcu_read_unlock();
1732 		PRINTM(MIOCTL, "Skip special region code in CountryIE");
1733 		LEAVE();
1734 		return 0;
1735 	}
1736 	if (MLAN_STATUS_SUCCESS !=
1737 	    woal_set_region_code(priv, priv->phandle->country_code))
1738 		PRINTM(MERROR, "Set country code failed!\n");
1739 
1740 	/* Allocate an IOCTL request buffer */
1741 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
1742 	if (req == NULL) {
1743 		rcu_read_unlock();
1744 		PRINTM(MERROR, "Fail to allocate mlan_ds_11d_cfg buffer\n");
1745 		ret = MLAN_STATUS_FAILURE;
1746 		goto done;
1747 	}
1748 
1749 	cfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
1750 	cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO_EXT;
1751 	req->req_id = MLAN_IOCTL_11D_CFG;
1752 	req->action = MLAN_ACT_SET;
1753 
1754 	cfg_11d->param.domain_info.dfs_region = NXP_DFS_UNKNOWN;
1755 	/* Set country code */
1756 	cfg_11d->param.domain_info.country_code[0] =
1757 		priv->phandle->country_code[0];
1758 	cfg_11d->param.domain_info.country_code[1] =
1759 		priv->phandle->country_code[1];
1760 	cfg_11d->param.domain_info.country_code[2] = ' ';
1761 
1762 	/** IEEE80211_BAND_2GHZ or IEEE80211_BAND_5GHZ */
1763 	cfg_11d->param.domain_info.band = priv->phandle->band;
1764 
1765 	country_ie_len -= COUNTRY_CODE_LEN;
1766 	cfg_11d->param.domain_info.no_of_sub_band = MIN(
1767 		MRVDRV_MAX_SUBBAND_802_11D,
1768 		(country_ie_len / sizeof(struct ieee80211_country_ie_triplet)));
1769 	moal_memcpy_ext(priv->phandle,
1770 			(u8 *)cfg_11d->param.domain_info.sub_band,
1771 			&country_ie[2] + COUNTRY_CODE_LEN,
1772 			cfg_11d->param.domain_info.no_of_sub_band *
1773 				sizeof(mlan_ds_subband_set_t),
1774 			sizeof(cfg_11d->param.domain_info.sub_band));
1775 
1776 	PRINTM(MCMND, "11D: Country IE: %c%c band=%d no_of_sub_band=%d\n",
1777 	       country_ie[2], country_ie[3], priv->phandle->band,
1778 	       cfg_11d->param.domain_info.no_of_sub_band);
1779 	rcu_read_unlock();
1780 
1781 	/* Send domain info command to FW */
1782 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1783 	if (status != MLAN_STATUS_SUCCESS) {
1784 		ret = MLAN_STATUS_FAILURE;
1785 		PRINTM(MERROR, "11D: Error setting domain info in FW\n");
1786 		goto done;
1787 	}
1788 done:
1789 	if (status != MLAN_STATUS_PENDING)
1790 		kfree(req);
1791 	LEAVE();
1792 	return ret;
1793 }
1794 
1795 /**
1796  * @brief Request scan based on connect parameter
1797  *
1798  * @param priv            A pointer to moal_private structure
1799  * @param conn_param      A pointer to connect parameters
1800  * @param wait_option     wait option
1801  *
1802  * @return                0 -- success, otherwise fail
1803  */
1804 static int
woal_cfg80211_connect_scan(moal_private * priv,struct cfg80211_connect_params * conn_param,t_u8 wait_option)1805 woal_cfg80211_connect_scan(moal_private *priv,
1806 			   struct cfg80211_connect_params *conn_param,
1807 			   t_u8 wait_option)
1808 {
1809 	moal_handle *handle = priv->phandle;
1810 	int ret = 0;
1811 	wlan_user_scan_cfg *scan_req;
1812 	enum ieee80211_band band;
1813 	struct ieee80211_supported_band *sband;
1814 	struct ieee80211_channel *ch;
1815 	int chan_idx = 0, i;
1816 
1817 	ENTER();
1818 	if (handle->scan_pending_on_block == MTRUE) {
1819 		PRINTM(MINFO, "scan already in processing...\n");
1820 		LEAVE();
1821 		return ret;
1822 	}
1823 #ifdef REASSOCIATION
1824 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
1825 		PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
1826 		LEAVE();
1827 		return -EBUSY;
1828 	}
1829 #endif /* REASSOCIATION */
1830 	scan_req = (wlan_user_scan_cfg *)kmalloc(sizeof(wlan_user_scan_cfg),
1831 						 GFP_KERNEL);
1832 	if (!scan_req) {
1833 		PRINTM(MERROR, "Malloc buffer failed\n");
1834 		LEAVE();
1835 		return -ENOMEM;
1836 	}
1837 
1838 	priv->report_scan_result = MTRUE;
1839 	memset(scan_req, 0x00, sizeof(wlan_user_scan_cfg));
1840 	moal_memcpy_ext(priv->phandle, scan_req->ssid_list[0].ssid,
1841 			conn_param->ssid, conn_param->ssid_len,
1842 			sizeof(scan_req->ssid_list[0].ssid));
1843 	scan_req->ssid_list[0].max_len = 0;
1844 	if (conn_param->channel) {
1845 		scan_req->chan_list[0].chan_number =
1846 			conn_param->channel->hw_value;
1847 		scan_req->chan_list[0].radio_type =
1848 			woal_ieee_band_to_radio_type(conn_param->channel->band);
1849 		if (conn_param->channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
1850 			scan_req->chan_list[0].scan_type =
1851 				MLAN_SCAN_TYPE_PASSIVE;
1852 		else if (conn_param->channel->flags & IEEE80211_CHAN_RADAR)
1853 			scan_req->chan_list[0].scan_type =
1854 				MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
1855 		else
1856 			scan_req->chan_list[0].scan_type =
1857 				MLAN_SCAN_TYPE_ACTIVE;
1858 		scan_req->chan_list[0].scan_time = 0;
1859 	} else {
1860 		for (band = 0; (band < IEEE80211_NUM_BANDS); band++) {
1861 			if (!priv->wdev->wiphy->bands[band])
1862 				continue;
1863 			sband = priv->wdev->wiphy->bands[band];
1864 			for (i = 0; (i < sband->n_channels); i++) {
1865 				ch = &sband->channels[i];
1866 				if (ch->flags & IEEE80211_CHAN_DISABLED)
1867 					continue;
1868 				scan_req->chan_list[chan_idx].radio_type =
1869 					woal_ieee_band_to_radio_type(band);
1870 				if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
1871 					scan_req->chan_list[chan_idx].scan_type =
1872 						MLAN_SCAN_TYPE_PASSIVE;
1873 				else if (ch->flags & IEEE80211_CHAN_RADAR)
1874 					scan_req->chan_list[chan_idx].scan_type =
1875 						MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
1876 				else
1877 					scan_req->chan_list[chan_idx].scan_type =
1878 						MLAN_SCAN_TYPE_ACTIVE;
1879 				scan_req->chan_list[chan_idx].chan_number =
1880 					(u32)ch->hw_value;
1881 				chan_idx++;
1882 			}
1883 		}
1884 	}
1885 	moal_memcpy_ext(priv->phandle, scan_req->random_mac, priv->random_mac,
1886 			ETH_ALEN, sizeof(scan_req->random_mac));
1887 	ret = woal_request_userscan(priv, wait_option, scan_req);
1888 	kfree(scan_req);
1889 #ifdef REASSOCIATION
1890 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
1891 #endif
1892 	LEAVE();
1893 	return ret;
1894 }
1895 
1896 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
1897 /**
1898  * @brief Save assoc parameters for roaming
1899  *
1900  * @param priv            A pointer to moal_private
1901  * @param req             A pointer to cfg80211_assoc_request structure
1902  */
woal_save_assoc_params(moal_private * priv,struct cfg80211_assoc_request * req,mlan_ssid_bssid * ssid_bssid)1903 static void woal_save_assoc_params(moal_private *priv,
1904 				   struct cfg80211_assoc_request *req,
1905 				   mlan_ssid_bssid *ssid_bssid)
1906 {
1907 	ENTER();
1908 
1909 	priv->assoc_bss = req->bss;
1910 	if (req->bss->channel) {
1911 		priv->sme_current.channel = &priv->conn_chan;
1912 		moal_memcpy_ext(priv->phandle, priv->sme_current.channel,
1913 				req->bss->channel,
1914 				sizeof(struct ieee80211_channel),
1915 				sizeof(struct ieee80211_channel));
1916 	}
1917 	priv->sme_current.bssid = priv->conn_bssid;
1918 	moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.bssid,
1919 			req->bss->bssid, MLAN_MAC_ADDR_LENGTH,
1920 			MLAN_MAC_ADDR_LENGTH);
1921 	if (req->ie && req->ie_len) {
1922 		priv->sme_current.ie = kzalloc(req->ie_len, GFP_ATOMIC);
1923 		priv->sme_current.ie_len = req->ie_len;
1924 		moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ie,
1925 				req->ie, req->ie_len, priv->sme_current.ie_len);
1926 	}
1927 	moal_memcpy_ext(priv->phandle, &priv->sme_current.crypto, &req->crypto,
1928 			sizeof(struct cfg80211_crypto_settings),
1929 			sizeof(struct cfg80211_crypto_settings));
1930 	priv->sme_current.flags = req->flags;
1931 	moal_memcpy_ext(priv->phandle, &priv->sme_current.ht_capa,
1932 			&req->ht_capa, sizeof(struct ieee80211_ht_cap),
1933 			sizeof(struct ieee80211_ht_cap));
1934 	moal_memcpy_ext(priv->phandle, &priv->sme_current.ht_capa_mask,
1935 			&req->ht_capa_mask, sizeof(struct ieee80211_ht_cap),
1936 			sizeof(struct ieee80211_ht_cap));
1937 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
1938 	moal_memcpy_ext(priv->phandle, &priv->sme_current.vht_capa,
1939 			&req->vht_capa, sizeof(struct ieee80211_vht_cap),
1940 			sizeof(struct ieee80211_vht_cap));
1941 	moal_memcpy_ext(priv->phandle, &priv->sme_current.vht_capa_mask,
1942 			&req->vht_capa_mask, sizeof(struct ieee80211_vht_cap),
1943 			sizeof(struct ieee80211_vht_cap));
1944 #endif
1945 	if (ssid_bssid && ssid_bssid->ssid.ssid_len) {
1946 		priv->sme_current.ssid = priv->conn_ssid;
1947 		priv->sme_current.ssid_len = ssid_bssid->ssid.ssid_len;
1948 		memset(priv->conn_ssid, 0, MLAN_MAX_SSID_LENGTH);
1949 		moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ssid,
1950 				ssid_bssid->ssid.ssid,
1951 				ssid_bssid->ssid.ssid_len,
1952 				sizeof(priv->conn_ssid));
1953 		priv->conn_ssid_len = ssid_bssid->ssid.ssid_len;
1954 	}
1955 	LEAVE();
1956 }
1957 
1958 /**
1959  * @brief Save auth parameters for roaming
1960  *
1961  * @param priv            A pointer to moal_private
1962  * @param req             A pointer to struct cfg80211_auth_request
1963  */
woal_save_auth_params(moal_private * priv,struct cfg80211_auth_request * req)1964 static void woal_save_auth_params(moal_private *priv,
1965 				  struct cfg80211_auth_request *req)
1966 {
1967 	ENTER();
1968 	woal_clear_conn_params(priv);
1969 	priv->assoc_bss = req->bss;
1970 	priv->sme_current.auth_type = req->auth_type;
1971 	priv->sme_current.key_idx = req->key_idx;
1972 	priv->sme_current.key_len = req->key_len;
1973 	if (req->key && req->key_len && (req->key_len <= MAX_WEP_KEY_SIZE)) {
1974 		priv->sme_current.key = priv->conn_wep_key;
1975 		moal_memcpy_ext(priv->phandle, (t_u8 *)priv->sme_current.key,
1976 				req->key, req->key_len,
1977 				sizeof(priv->conn_wep_key));
1978 	}
1979 	LEAVE();
1980 }
1981 
1982 /**
1983  * @brief Request scan based on auth_request parameter
1984  *
1985  * @param priv            A pointer to moal_private structure
1986  * @param req             A pointer to cfg80211_auth_request
1987  * @param wait_option     wait option
1988  *
1989  * @return                0 -- success, otherwise fail
1990  */
woal_cfg80211_auth_scan(moal_private * priv,struct cfg80211_auth_request * req,t_u8 wait_option)1991 static int woal_cfg80211_auth_scan(moal_private *priv,
1992 				   struct cfg80211_auth_request *req,
1993 				   t_u8 wait_option)
1994 {
1995 	moal_handle *handle = priv->phandle;
1996 	int ret = 0;
1997 	wlan_user_scan_cfg *scan_req;
1998 	enum ieee80211_band band;
1999 	struct ieee80211_supported_band *sband;
2000 	struct ieee80211_channel *ch;
2001 	int chan_idx = 0, i;
2002 	const u8 *ssid;
2003 
2004 	ENTER();
2005 	if (handle->scan_pending_on_block == MTRUE) {
2006 		PRINTM(MINFO, "scan already in processing...\n");
2007 		LEAVE();
2008 		return ret;
2009 	}
2010 #ifdef REASSOCIATION
2011 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
2012 		PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
2013 		LEAVE();
2014 		return -EBUSY;
2015 	}
2016 #endif /* REASSOCIATION */
2017 	scan_req = (wlan_user_scan_cfg *)kmalloc(sizeof(wlan_user_scan_cfg),
2018 						 GFP_KERNEL);
2019 	if (!scan_req) {
2020 		PRINTM(MERROR, "Malloc buffer failed\n");
2021 		LEAVE();
2022 		return -ENOMEM;
2023 	}
2024 
2025 	priv->report_scan_result = MTRUE;
2026 	memset(scan_req, 0x00, sizeof(wlan_user_scan_cfg));
2027 	rcu_read_lock();
2028 	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
2029 	if (ssid) {
2030 		moal_memcpy_ext(priv->phandle, scan_req->ssid_list[0].ssid,
2031 				ssid + 2, ssid[1],
2032 				sizeof(scan_req->ssid_list[0].ssid));
2033 		scan_req->ssid_list[0].max_len = 0;
2034 	}
2035 	rcu_read_unlock();
2036 	moal_memcpy_ext(priv->phandle, scan_req->specific_bssid,
2037 			req->bss->bssid, ETH_ALEN, ETH_ALEN);
2038 	if (req->bss->channel) {
2039 		scan_req->chan_list[0].chan_number =
2040 			req->bss->channel->hw_value;
2041 		scan_req->chan_list[0].radio_type =
2042 			woal_ieee_band_to_radio_type(req->bss->channel->band);
2043 		if (req->bss->channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
2044 			scan_req->chan_list[0].scan_type =
2045 				MLAN_SCAN_TYPE_PASSIVE;
2046 		else if (req->bss->channel->flags & IEEE80211_CHAN_RADAR)
2047 			scan_req->chan_list[0].scan_type =
2048 				MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
2049 		else
2050 			scan_req->chan_list[0].scan_type =
2051 				MLAN_SCAN_TYPE_ACTIVE;
2052 		scan_req->chan_list[0].scan_time = 0;
2053 	} else {
2054 		for (band = 0; (band < IEEE80211_NUM_BANDS); band++) {
2055 			if (!priv->wdev->wiphy->bands[band])
2056 				continue;
2057 			sband = priv->wdev->wiphy->bands[band];
2058 			for (i = 0; (i < sband->n_channels); i++) {
2059 				ch = &sband->channels[i];
2060 				if (ch->flags & IEEE80211_CHAN_DISABLED)
2061 					continue;
2062 				scan_req->chan_list[chan_idx].radio_type =
2063 					woal_ieee_band_to_radio_type(band);
2064 				if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
2065 					scan_req->chan_list[chan_idx].scan_type =
2066 						MLAN_SCAN_TYPE_PASSIVE;
2067 				else if (ch->flags & IEEE80211_CHAN_RADAR)
2068 					scan_req->chan_list[chan_idx].scan_type =
2069 						MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
2070 				else
2071 					scan_req->chan_list[chan_idx].scan_type =
2072 						MLAN_SCAN_TYPE_ACTIVE;
2073 				scan_req->chan_list[chan_idx].chan_number =
2074 					(u32)ch->hw_value;
2075 				chan_idx++;
2076 			}
2077 		}
2078 	}
2079 	moal_memcpy_ext(priv->phandle, scan_req->random_mac, priv->random_mac,
2080 			ETH_ALEN, sizeof(scan_req->random_mac));
2081 	ret = woal_request_userscan(priv, wait_option, scan_req);
2082 	kfree(scan_req);
2083 #ifdef REASSOCIATION
2084 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2085 #endif
2086 	LEAVE();
2087 	return ret;
2088 }
2089 
2090 /**
2091  *  @brief This function is authentication handler when host MLME
2092  *          enable.
2093  *          In this case driver will prepare and send Auth Req.
2094  *
2095  *  @param wiphy       A pointer to wiphy.
2096  *
2097  *  @param dev         A pointer to net_device
2098  *
2099  *  @param req         A pointer to cfg80211_auth_request
2100  *
2101  *  @return            0 -- success, otherwise fail
2102  */
woal_cfg80211_authenticate(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_auth_request * req)2103 static int woal_cfg80211_authenticate(struct wiphy *wiphy,
2104 				      struct net_device *dev,
2105 				      struct cfg80211_auth_request *req)
2106 {
2107 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2108 	IEEE80211_MGMT *mgmt = NULL;
2109 	mlan_status status = MLAN_STATUS_SUCCESS;
2110 	pmlan_buffer pmbuf = NULL;
2111 	t_u32 pkt_type, tx_control;
2112 	t_u16 packet_len = 0, auth_alg;
2113 	t_u8 addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
2114 	int ret = 0;
2115 
2116 	t_u8 trans = 1, status_code = 0;
2117 	t_u8 *varptr = NULL;
2118 	mlan_ssid_bssid *ssid_bssid;
2119 	moal_handle *handle = priv->phandle;
2120 	int i;
2121 
2122 	ENTER();
2123 
2124 	priv->cfg_disconnect = MFALSE;
2125 #ifdef UAP_CFG80211
2126 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
2127 		PRINTM(MERROR, "ERR: Role is AP\n");
2128 		LEAVE();
2129 		return -EFAULT;
2130 	}
2131 #endif
2132 	if (priv->wdev->iftype != NL80211_IFTYPE_STATION
2133 #ifdef WIFI_DIRECT_SUPPORT
2134 	    && priv->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT
2135 
2136 #endif /* WIFI_DIRECT_SUPPORT */
2137 	) {
2138 		PRINTM(MERROR,
2139 		       "Received infra auth request when interface not in infra mode\n");
2140 		LEAVE();
2141 		return -EINVAL;
2142 	}
2143 
2144 	/** cancel pending scan */
2145 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
2146 
2147 	ssid_bssid = kzalloc(sizeof(mlan_ssid_bssid), GFP_ATOMIC);
2148 	if (!ssid_bssid) {
2149 		PRINTM(MERROR, "Fail to allocate ssid_bssid buffer\n");
2150 		LEAVE();
2151 		return -ENOMEM;
2152 	}
2153 	moal_memcpy_ext(priv->phandle, ssid_bssid->bssid, req->bss->bssid,
2154 			ETH_ALEN, sizeof(ssid_bssid->bssid));
2155 	/* Not allowed to connect to the same AP which is already connected
2156 	with other interface */
2157 	for (i = 0; i < handle->priv_num; i++) {
2158 		if (handle->priv[i] != priv &&
2159 		    MTRUE == woal_is_connected(handle->priv[i], ssid_bssid)) {
2160 			PRINTM(MMSG,
2161 			       "wlan: already connected with other interface, bssid " MACSTR
2162 			       "\n",
2163 			       MAC2STR(handle->priv[i]->cfg_bssid));
2164 			kfree(ssid_bssid);
2165 			LEAVE();
2166 			return -EINVAL;
2167 		}
2168 	}
2169 	if (MLAN_STATUS_SUCCESS != woal_find_bssid(priv, req->bss->bssid)) {
2170 		woal_cfg80211_auth_scan(priv, req, MOAL_IOCTL_WAIT);
2171 		if (MLAN_STATUS_SUCCESS !=
2172 		    woal_find_bssid(priv, req->bss->bssid)) {
2173 			PRINTM(MMSG, "bssid not find in scan list\n");
2174 			kfree(ssid_bssid);
2175 			LEAVE();
2176 			return -EFAULT;
2177 		}
2178 	}
2179 	kfree(ssid_bssid);
2180 
2181 	if ((priv->auth_alg != WLAN_AUTH_SAE) &&
2182 	    (priv->auth_flag & HOST_MLME_AUTH_PENDING)) {
2183 		PRINTM(MERROR, "pending auth on going\n");
2184 		LEAVE();
2185 		return -EBUSY;
2186 	}
2187 #ifdef WIFI_DIRECT_SUPPORT
2188 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
2189 	    (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
2190 	     priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
2191 		/* if bsstype == wifi direct, and iftype == station or p2p
2192 		 * client, that means wpa_supplicant wants to enable wifi direct
2193 		 * functionality, so we should init p2p client.
2194 		 *
2195 		 * Note that due to kernel iftype check, ICS wpa_supplicant
2196 		 * could not updaet iftype to init p2p client, so we have to
2197 		 * done it here.
2198 		 * */
2199 		if (MLAN_STATUS_SUCCESS !=
2200 		    woal_cfg80211_init_p2p_client(priv)) {
2201 			PRINTM(MERROR,
2202 			       "Init p2p client for wpa_supplicant failed.\n");
2203 			ret = -EFAULT;
2204 			LEAVE();
2205 			return ret;
2206 		}
2207 	}
2208 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
2209 		/* WAR for P2P connection with vendor TV */
2210 		woal_sched_timeout(200);
2211 	}
2212 #endif
2213 
2214 	/*enable auth register frame*/
2215 	if (priv->auth_flag == 0) {
2216 		woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MTRUE);
2217 		woal_mgmt_frame_register(priv, IEEE80211_STYPE_DEAUTH, MTRUE);
2218 		woal_mgmt_frame_register(priv, IEEE80211_STYPE_DISASSOC, MTRUE);
2219 	}
2220 
2221 #define HEADER_SIZE 8
2222 	// frmctl + durationid + addr1 + addr2 + addr3 + seqctl + addr4
2223 #define MGMT_HEADER_LEN (2 + 2 + 6 + 6 + 6 + 2 + 6)
2224 	// 6   = auth_alg + auth_transaction +auth_status
2225 #define AUTH_BODY_LEN 6
2226 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
2227 	packet_len = (t_u16)req->ie_len + req->auth_data_len + MGMT_HEADER_LEN +
2228 		     AUTH_BODY_LEN;
2229 #else
2230 	packet_len = (t_u16)req->ie_len + req->sae_data_len + MGMT_HEADER_LEN +
2231 		     AUTH_BODY_LEN;
2232 #endif
2233 	pmbuf = woal_alloc_mlan_buffer(priv->phandle,
2234 				       MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
2235 					       packet_len + sizeof(packet_len));
2236 
2237 	if (!pmbuf) {
2238 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
2239 		ret = -ENOMEM;
2240 		goto done;
2241 	}
2242 
2243 	if (MLAN_STATUS_SUCCESS !=
2244 	    woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0,
2245 				  KEY_INDEX_CLEAR_ALL, NULL, 1,
2246 				  MOAL_IOCTL_WAIT)) {
2247 		/* Disable keys and clear all previous security settings */
2248 		PRINTM(MERROR, "Fail to clear previous keys\n");
2249 		ret = -EFAULT;
2250 		goto done;
2251 	}
2252 
2253 	switch (req->auth_type) {
2254 	case NL80211_AUTHTYPE_OPEN_SYSTEM:
2255 		auth_alg = WLAN_AUTH_OPEN;
2256 		break;
2257 	case NL80211_AUTHTYPE_SHARED_KEY:
2258 		auth_alg = WLAN_AUTH_SHARED_KEY;
2259 		break;
2260 	case NL80211_AUTHTYPE_FT:
2261 		auth_alg = WLAN_AUTH_FT;
2262 		break;
2263 	case NL80211_AUTHTYPE_NETWORK_EAP:
2264 		auth_alg = WLAN_AUTH_LEAP;
2265 		break;
2266 	case NL80211_AUTHTYPE_SAE:
2267 		auth_alg = WLAN_AUTH_SAE;
2268 		break;
2269 	default:
2270 		PRINTM(MERROR, "Unsupported auth type=%d\n", req->auth_type);
2271 		ret = -EOPNOTSUPP;
2272 		break;
2273 	}
2274 	if (ret)
2275 		goto done;
2276 	if (MLAN_STATUS_SUCCESS !=
2277 	    woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_alg)) {
2278 		PRINTM(MERROR, "Fail to set auth mode\n");
2279 		ret = -EFAULT;
2280 		goto done;
2281 	}
2282 
2283 	if (req->key && ((auth_alg == WLAN_AUTH_OPEN) ||
2284 			 (auth_alg == WLAN_AUTH_SHARED_KEY))) {
2285 		PRINTM(MMSG, "Setting wep encryption with key len %d\n",
2286 		       req->key_len);
2287 		/* Set the WEP key */
2288 		if (MLAN_STATUS_SUCCESS !=
2289 		    woal_cfg80211_set_wep_keys(priv, req->key, req->key_len,
2290 					       req->key_idx, MOAL_IOCTL_WAIT)) {
2291 			PRINTM(MERROR, "Fail to set wep key idx %d\n",
2292 			       req->key_idx);
2293 			ret = -EFAULT;
2294 			goto done;
2295 		}
2296 		/* Enable the WEP key by key index */
2297 		if (MLAN_STATUS_SUCCESS !=
2298 		    woal_cfg80211_set_wep_keys(priv, NULL, 0, req->key_idx,
2299 					       MOAL_IOCTL_WAIT)) {
2300 			PRINTM(MERROR, "Fail to enable wep key idx %d\n",
2301 			       req->key_idx);
2302 			ret = -EFAULT;
2303 			goto done;
2304 		}
2305 	}
2306 
2307 	if (priv->auth_flag == 0) {
2308 		if (woal_cfg80211_remain_on_channel_cfg(
2309 			    priv, MOAL_IOCTL_WAIT, MFALSE, (t_u8 *)&status,
2310 			    req->bss->channel, 0, AUTH_TX_DEFAULT_WAIT_TIME)) {
2311 			PRINTM(MERROR, "Fail to configure remain on channel\n");
2312 			ret = -EFAULT;
2313 			goto done;
2314 		}
2315 		if (status == MLAN_STATUS_SUCCESS) {
2316 			priv->phandle->remain_on_channel = MTRUE;
2317 			moal_memcpy_ext(priv->phandle, &(priv->phandle->chan),
2318 					req->bss->channel,
2319 					sizeof(struct ieee80211_channel),
2320 					sizeof(priv->phandle->chan));
2321 		} else {
2322 			PRINTM(MERROR,
2323 			       "HostMlme %s: Set remain on Channel: with status=%d\n",
2324 			       dev->name, status);
2325 		}
2326 	}
2327 
2328 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
2329 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
2330 	tx_control = 0;
2331 	/* Add pkt_type and tx_control */
2332 	moal_memcpy_ext(priv->phandle, pmbuf->pbuf + pmbuf->data_offset,
2333 			&pkt_type, sizeof(pkt_type), sizeof(pkt_type));
2334 	moal_memcpy_ext(priv->phandle,
2335 			pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
2336 			&tx_control, sizeof(tx_control), sizeof(tx_control));
2337 
2338 	mgmt = (IEEE80211_MGMT *)(pmbuf->pbuf + pmbuf->data_offset +
2339 				  HEADER_SIZE + sizeof(packet_len));
2340 	memset(mgmt, 0, MGMT_HEADER_LEN);
2341 	/**Authentication Frame: Frame Control*/
2342 	mgmt->frame_control =
2343 		woal_cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
2344 	/**Authentication Frame: Destination Address*/
2345 	moal_memcpy_ext(priv->phandle, mgmt->da, req->bss->bssid, ETH_ALEN,
2346 			sizeof(mgmt->da));
2347 	/**Authentication Frame: Source Address*/
2348 	moal_memcpy_ext(priv->phandle, mgmt->sa, priv->current_addr, ETH_ALEN,
2349 			sizeof(mgmt->sa));
2350 	/**Authentication Frame: BSSID*/
2351 	moal_memcpy_ext(priv->phandle, mgmt->bssid, req->bss->bssid, ETH_ALEN,
2352 			sizeof(mgmt->bssid));
2353 	moal_memcpy_ext(priv->phandle, mgmt->addr4, addr, ETH_ALEN,
2354 			sizeof(mgmt->addr4));
2355 
2356 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
2357 	if (req->auth_data_len >= 4) {
2358 		if (req->auth_type == NL80211_AUTHTYPE_SAE) {
2359 			__le16 *pos = (__le16 *)req->auth_data;
2360 
2361 			trans = le16_to_cpu(pos[0]);
2362 			status_code = le16_to_cpu(pos[1]);
2363 		}
2364 		moal_memcpy_ext(priv->phandle, (t_u8 *)(&mgmt->u.auth.variable),
2365 				req->auth_data + 4, req->auth_data_len - 4,
2366 				req->auth_data_len - 4);
2367 		varptr = (t_u8 *)&mgmt->u.auth.variable +
2368 			 (req->auth_data_len - 4);
2369 		packet_len -= 4;
2370 	}
2371 #else
2372 	if (req->sae_data_len >= 4) {
2373 		if (req->auth_type == NL80211_AUTHTYPE_SAE) {
2374 			__le16 *pos = (__le16 *)req->sae_data;
2375 
2376 			trans = le16_to_cpu(pos[0]);
2377 			status_code = le16_to_cpu(pos[1]);
2378 		}
2379 		moal_memcpy_ext(priv->phandle, (t_u8 *)(&mgmt->u.auth.variable),
2380 				req->sae_data + 4, req->sae_data_len - 4,
2381 				req->sae_data_len - 4);
2382 		varptr = (t_u8 *)&mgmt->u.auth.variable +
2383 			 (req->sae_data_len - 4);
2384 		packet_len -= 4;
2385 	}
2386 #endif
2387 	/*Add packet len*/
2388 	moal_memcpy_ext(priv->phandle,
2389 			pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
2390 			&packet_len, sizeof(packet_len), sizeof(packet_len));
2391 
2392 	/**Authentication Frame: Authentication Alg*/
2393 	mgmt->u.auth.auth_alg = woal_cpu_to_le16(auth_alg);
2394 	mgmt->u.auth.auth_transaction = trans;
2395 	/**Authentication Frame: Status code*/
2396 	mgmt->u.auth.status_code = status_code;
2397 
2398 	if (req->ie && req->ie_len) {
2399 		if (!varptr) {
2400 			varptr = (t_u8 *)&mgmt->u.auth.variable;
2401 		}
2402 		moal_memcpy_ext(priv->phandle, (t_u8 *)varptr, req->ie,
2403 				req->ie_len, req->ie_len);
2404 	}
2405 
2406 	pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
2407 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
2408 	pmbuf->bss_index = priv->bss_index;
2409 	pmbuf->priority = 7;
2410 
2411 	priv->host_mlme = MTRUE;
2412 	priv->auth_flag = HOST_MLME_AUTH_PENDING;
2413 	priv->auth_alg = woal_cpu_to_le16(auth_alg);
2414 
2415 	PRINTM(MMSG, "wlan: HostMlme %s send auth to bssid " MACSTR "\n",
2416 	       dev->name, MAC2STR(req->bss->bssid));
2417 	DBG_HEXDUMP(MDAT_D, "Auth:", pmbuf->pbuf + pmbuf->data_offset,
2418 		    pmbuf->data_len);
2419 	woal_save_auth_params(priv, req);
2420 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
2421 
2422 	switch (status) {
2423 	case MLAN_STATUS_PENDING:
2424 		atomic_inc(&priv->phandle->tx_pending);
2425 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
2426 		break;
2427 	case MLAN_STATUS_SUCCESS:
2428 		woal_free_mlan_buffer(priv->phandle, pmbuf);
2429 		break;
2430 	case MLAN_STATUS_FAILURE:
2431 	default:
2432 		woal_free_mlan_buffer(priv->phandle, pmbuf);
2433 		priv->host_mlme = MFALSE;
2434 		priv->auth_flag = 0;
2435 		priv->auth_alg = 0xFFFF;
2436 		ret = -EFAULT;
2437 		PRINTM(MERROR, "Fail to send packet status=%d\n", status);
2438 		break;
2439 	}
2440 done:
2441 	if (ret) {
2442 		woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MFALSE);
2443 		if (priv->phandle->remain_on_channel) {
2444 			woal_cfg80211_remain_on_channel_cfg(
2445 				priv, MOAL_IOCTL_WAIT, MTRUE, (t_u8 *)&status,
2446 				NULL, 0, 0);
2447 			priv->phandle->remain_on_channel = MFALSE;
2448 		}
2449 	}
2450 	LEAVE();
2451 	return ret;
2452 }
2453 
2454 /**
2455  *  @brief This workqueue function handles association response in host mlme
2456  * case
2457  *
2458  *  @param work    A pointer to work_struct
2459  *
2460  *  @return        N/A
2461  */
woal_host_mlme_work_queue(struct work_struct * work)2462 void woal_host_mlme_work_queue(struct work_struct *work)
2463 {
2464 	moal_handle *handle = container_of(work, moal_handle, host_mlme_work);
2465 	moal_private *priv = (moal_private *)handle->host_mlme_priv;
2466 	mlan_status status = MLAN_STATUS_SUCCESS;
2467 
2468 	if (priv) {
2469 		if (priv->auth_flag & HOST_MLME_AUTH_DONE) {
2470 			priv->auth_flag = 0;
2471 			woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH,
2472 						 MFALSE);
2473 
2474 			if (priv->phandle->remain_on_channel) {
2475 				woal_cfg80211_remain_on_channel_cfg(
2476 					priv, MOAL_IOCTL_WAIT, MTRUE,
2477 					(t_u8 *)&status, NULL, 0, 0);
2478 				priv->phandle->remain_on_channel = MFALSE;
2479 			}
2480 			PRINTM(MCMND, "wlan: HostMlme %s auth success\n",
2481 			       priv->netdev->name);
2482 		}
2483 	}
2484 }
2485 
2486 /**
2487  *  @brief This workqueue function handles association response in event queue
2488  * case
2489  *
2490  *  @param priv  	pointer to moal_private
2491  *  @param assoc_info	pointer to mlan_ds_assoc_info
2492  *
2493  *  @return        N/A
2494  */
woal_host_mlme_process_assoc_resp(moal_private * priv,mlan_ds_assoc_info * assoc_info)2495 void woal_host_mlme_process_assoc_resp(moal_private *priv,
2496 				       mlan_ds_assoc_info *assoc_info)
2497 {
2498 	struct cfg80211_bss *bss = NULL;
2499 	unsigned long flags;
2500 	u8 *assoc_req_buf = NULL;
2501 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
2502 	struct cfg80211_rx_assoc_resp resp = {
2503 		.uapsd_queues = -1,
2504 	};
2505 #endif
2506 
2507 	if (priv) {
2508 		if (priv->auth_flag & HOST_MLME_ASSOC_DONE) {
2509 			priv->auth_flag = 0;
2510 			bss = priv->assoc_bss;
2511 			if (!bss) {
2512 				PRINTM(MERROR,
2513 				       "HostMlme %s:assoc_bss is null\n",
2514 				       priv->netdev->name);
2515 				return;
2516 			}
2517 
2518 			if (assoc_info->assoc_resp_len) {
2519 				PRINTM(MCMND,
2520 				       "HostMlme: %s assoc_resp_len=%d, frame_control=0x%x\n",
2521 				       priv->netdev->name,
2522 				       assoc_info->assoc_resp_len,
2523 				       ((struct ieee80211_mgmt *)
2524 						assoc_info->assoc_resp_buf)
2525 					       ->frame_control);
2526 				if (ieee80211_is_assoc_resp(
2527 					    ((struct ieee80211_mgmt *)
2528 						     assoc_info->assoc_resp_buf)
2529 						    ->frame_control) ||
2530 				    ieee80211_is_reassoc_resp(
2531 					    ((struct ieee80211_mgmt *)
2532 						     assoc_info->assoc_resp_buf)
2533 						    ->frame_control)) {
2534 					spin_lock_irqsave(&priv->connect_lock,
2535 							  flags);
2536 					if (le16_to_cpu(
2537 						    ((struct ieee80211_mgmt
2538 							      *)assoc_info
2539 							     ->assoc_resp_buf)
2540 							    ->u.assoc_resp
2541 							    .status_code) !=
2542 					    WLAN_STATUS_SUCCESS) {
2543 						memset(priv->cfg_bssid, 0,
2544 						       ETH_ALEN);
2545 						woal_clear_conn_params(priv);
2546 					} else {
2547 						priv->cfg_disconnect = MFALSE;
2548 					}
2549 					spin_unlock_irqrestore(
2550 						&priv->connect_lock, flags);
2551 					/*Populate Assoc req buf only if len is
2552 					 * non zero . i.e. we received assoc req
2553 					 * buffer from fw.*/
2554 					if (assoc_info->assoc_req_len)
2555 						assoc_req_buf =
2556 							assoc_info
2557 								->assoc_req_buf;
2558 
2559 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
2560 					resp.links[0].bss = bss;
2561 					resp.buf = assoc_info->assoc_resp_buf;
2562 					resp.len = assoc_info->assoc_resp_len;
2563 					resp.req_ies = assoc_req_buf;
2564 					resp.req_ies_len =
2565 						assoc_info->assoc_req_len;
2566 					mutex_lock(&priv->wdev->mtx);
2567 					cfg80211_rx_assoc_resp(priv->netdev,
2568 							       &resp);
2569 					mutex_unlock(&priv->wdev->mtx);
2570 #else
2571 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
2572 					mutex_lock(&priv->wdev->mtx);
2573 					cfg80211_rx_assoc_resp(
2574 						priv->netdev, bss,
2575 						assoc_info->assoc_resp_buf,
2576 						assoc_info->assoc_resp_len, -1,
2577 						assoc_req_buf,
2578 						assoc_info->assoc_req_len);
2579 					mutex_unlock(&priv->wdev->mtx);
2580 #else
2581 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
2582 					mutex_lock(&priv->wdev->mtx);
2583 					cfg80211_rx_assoc_resp(
2584 						priv->netdev, bss,
2585 						assoc_info->assoc_resp_buf,
2586 						assoc_info->assoc_resp_len, -1);
2587 					mutex_unlock(&priv->wdev->mtx);
2588 #else
2589 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
2590 					mutex_lock(&priv->wdev->mtx);
2591 					cfg80211_rx_assoc_resp(
2592 						priv->netdev, bss,
2593 						assoc_info->assoc_resp_buf,
2594 						assoc_info->assoc_resp_len);
2595 					mutex_unlock(&priv->wdev->mtx);
2596 #else
2597 					cfg80211_send_rx_assoc(
2598 						priv->netdev, bss,
2599 						assoc_info->assoc_resp_buf,
2600 						assoc_info->assoc_resp_len);
2601 #endif
2602 #endif
2603 #endif
2604 #endif
2605 				}
2606 			}
2607 		}
2608 	}
2609 }
2610 
2611 /**
2612  * @brief   Handle assoc response event
2613  *
2614  * @param priv          A pointer moal_private structure
2615  * @param pchan_info    A pointer to mlan_ds_misc_assoc_rsp structure
2616  *
2617  * @return          N/A
2618  */
2619 
woal_assoc_resp_event(moal_private * priv,mlan_ds_misc_assoc_rsp * passoc_rsp)2620 static void woal_assoc_resp_event(moal_private *priv,
2621 				  mlan_ds_misc_assoc_rsp *passoc_rsp)
2622 {
2623 	struct woal_event *evt;
2624 	unsigned long flags;
2625 	moal_handle *handle = priv->phandle;
2626 	mlan_ds_misc_assoc_req assoc_req;
2627 	memset(&assoc_req, 0, sizeof(mlan_ds_misc_assoc_req));
2628 	woal_get_assoc_req(priv, &assoc_req, MOAL_IOCTL_WAIT);
2629 
2630 	evt = kzalloc(sizeof(struct woal_event), GFP_ATOMIC);
2631 	if (evt) {
2632 		evt->priv = priv;
2633 		evt->type = WOAL_EVENT_ASSOC_RESP;
2634 		moal_memcpy_ext(priv->phandle, evt->assoc_info.assoc_resp_buf,
2635 				passoc_rsp->assoc_resp_buf,
2636 				passoc_rsp->assoc_resp_len, ASSOC_RSP_BUF_SIZE);
2637 		evt->assoc_info.assoc_resp_len =
2638 			MIN(passoc_rsp->assoc_resp_len, ASSOC_RSP_BUF_SIZE);
2639 		moal_memcpy_ext(priv->phandle, evt->assoc_info.assoc_req_buf,
2640 				assoc_req.assoc_req_buf,
2641 				assoc_req.assoc_req_len, ASSOC_RSP_BUF_SIZE);
2642 		evt->assoc_info.assoc_req_len =
2643 			MIN(assoc_req.assoc_req_len, ASSOC_RSP_BUF_SIZE);
2644 
2645 		INIT_LIST_HEAD(&evt->link);
2646 		spin_lock_irqsave(&handle->evt_lock, flags);
2647 		list_add_tail(&evt->link, &handle->evt_queue);
2648 		spin_unlock_irqrestore(&handle->evt_lock, flags);
2649 		queue_work(handle->evt_workqueue, &handle->evt_work);
2650 	}
2651 }
2652 
2653 /**
2654  *  @brief This function is association handler when host MLME
2655  *          enable.
2656  *          In this case driver will prepare and send Assoc Req.
2657  *
2658  *  @param wiphy       A pointer to wiphy.
2659  *
2660  *  @param dev         A pointer to net_device
2661  *
2662  *  @param req         A pointer to cfg80211_assoc_request
2663  *
2664  *  @return            0 -- success, otherwise fail
2665  */
woal_cfg80211_associate(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_assoc_request * req)2666 static int woal_cfg80211_associate(struct wiphy *wiphy, struct net_device *dev,
2667 				   struct cfg80211_assoc_request *req)
2668 {
2669 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2670 	int ret = 0;
2671 	mlan_ssid_bssid *ssid_bssid = NULL;
2672 	unsigned long flags;
2673 	const u8 *ssid_ie;
2674 	int wpa_enabled = 0, group_enc_mode = 0, pairwise_enc_mode = 0;
2675 	mlan_bss_info bss_info;
2676 	mlan_status status = MLAN_STATUS_SUCCESS;
2677 
2678 	ENTER();
2679 
2680 	ssid_bssid = kmalloc(sizeof(mlan_ssid_bssid), GFP_KERNEL);
2681 	if (!ssid_bssid) {
2682 		LEAVE();
2683 		return -EFAULT;
2684 	}
2685 
2686 	if (priv->auth_alg == WLAN_AUTH_SAE) {
2687 		priv->auth_flag = HOST_MLME_AUTH_DONE;
2688 
2689 		woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MFALSE);
2690 		PRINTM(MINFO, "wlan: HostMlme %s auth exchange successful\n",
2691 		       priv->netdev->name);
2692 
2693 		if (priv->phandle->remain_on_channel) {
2694 			if (woal_cfg80211_remain_on_channel_cfg(
2695 				    priv, MOAL_IOCTL_WAIT, MTRUE,
2696 				    (t_u8 *)&status, NULL, 0, 0)) {
2697 				PRINTM(MERROR,
2698 				       "Failed to cancel remain on channel\n");
2699 				ret = -EFAULT;
2700 				goto done;
2701 			}
2702 			priv->phandle->remain_on_channel = MFALSE;
2703 		}
2704 	}
2705 
2706 	if (priv->auth_flag && !(priv->auth_flag & HOST_MLME_AUTH_DONE)) {
2707 		kfree(ssid_bssid);
2708 		LEAVE();
2709 		return -EBUSY;
2710 	}
2711 
2712 	/** cancel pending scan */
2713 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
2714 
2715 	priv->cfg_connect = MTRUE;
2716 	priv->assoc_status = 0;
2717 	priv->auth_alg = 0xFFFF;
2718 
2719 	memset(ssid_bssid, 0, sizeof(mlan_ssid_bssid));
2720 	rcu_read_lock();
2721 	ssid_ie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
2722 	moal_memcpy_ext(priv->phandle, ssid_bssid->bssid, req->bss->bssid,
2723 			ETH_ALEN, sizeof(ssid_bssid->bssid));
2724 
2725 	if (!ssid_ie) {
2726 		rcu_read_unlock();
2727 		ret = -EINVAL;
2728 		goto done;
2729 	}
2730 
2731 	moal_memcpy_ext(priv->phandle, ssid_bssid->ssid.ssid, ssid_ie + 2,
2732 			ssid_ie[1], sizeof(ssid_bssid->ssid.ssid));
2733 	ssid_bssid->ssid.ssid_len = ssid_ie[1];
2734 	rcu_read_unlock();
2735 
2736 	if (ssid_bssid->ssid.ssid_len > MW_ESSID_MAX_SIZE) {
2737 		PRINTM(MERROR, "Invalid SSID - aborting\n");
2738 		ret = -EINVAL;
2739 		goto done;
2740 	}
2741 
2742 	if (!ssid_bssid->ssid.ssid_len || ssid_bssid->ssid.ssid[0] < 0x20) {
2743 		PRINTM(MERROR, "Invalid SSID - aborting\n");
2744 		ret = -EINVAL;
2745 		goto done;
2746 	}
2747 
2748 #ifdef STA_WEXT
2749 	if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) {
2750 		switch (req->crypto.wpa_versions) {
2751 		case NL80211_WPA_VERSION_2:
2752 			priv->wpa_version = IW_AUTH_WPA_VERSION_WPA2;
2753 			break;
2754 		case NL80211_WPA_VERSION_1:
2755 			priv->wpa_version = IW_AUTH_WPA_VERSION_WPA;
2756 			break;
2757 		default:
2758 			priv->wpa_version = 0;
2759 			break;
2760 		}
2761 		if (req->crypto.n_akm_suites) {
2762 			switch (req->crypto.akm_suites[0]) {
2763 			case WLAN_AKM_SUITE_PSK:
2764 				priv->key_mgmt = IW_AUTH_KEY_MGMT_PSK;
2765 				break;
2766 			case WLAN_AKM_SUITE_8021X:
2767 				priv->key_mgmt = IW_AUTH_KEY_MGMT_802_1X;
2768 				break;
2769 			default:
2770 				priv->key_mgmt = 0;
2771 				break;
2772 			}
2773 		}
2774 	}
2775 #endif
2776 
2777 	if (req->ie && req->ie_len) { /* Set the IE */
2778 		if (MLAN_STATUS_SUCCESS !=
2779 		    woal_cfg80211_assoc_ies_cfg(priv, (t_u8 *)req->ie,
2780 						req->ie_len, MOAL_IOCTL_WAIT)) {
2781 			ret = -EFAULT;
2782 			goto done;
2783 		}
2784 	}
2785 
2786 	if (req->crypto.n_ciphers_pairwise) {
2787 		pairwise_enc_mode = woal_cfg80211_get_encryption_mode(
2788 			req->crypto.ciphers_pairwise[0], &wpa_enabled);
2789 		ret = woal_cfg80211_set_auth(priv, pairwise_enc_mode,
2790 					     wpa_enabled, MOAL_IOCTL_WAIT);
2791 		if (ret)
2792 			goto done;
2793 	}
2794 
2795 	if (req->crypto.cipher_group) {
2796 		group_enc_mode = woal_cfg80211_get_encryption_mode(
2797 			req->crypto.cipher_group, &wpa_enabled);
2798 		ret = woal_cfg80211_set_auth(priv, group_enc_mode, wpa_enabled,
2799 					     MOAL_IOCTL_WAIT);
2800 		if (ret)
2801 			goto done;
2802 	}
2803 	ssid_bssid->host_mlme = priv->host_mlme;
2804 
2805 	if (req->bss->channel) {
2806 		ssid_bssid->channel_flags = req->bss->channel->flags;
2807 		ssid_bssid->channel_flags |= CHAN_FLAGS_MAX;
2808 		PRINTM(MCMND, "channel flags=0x%x\n", req->bss->channel->flags);
2809 	}
2810 	if (req->prev_bssid) {
2811 		moal_memcpy_ext(priv->phandle, ssid_bssid->prev_bssid,
2812 				req->prev_bssid, ETH_ALEN,
2813 				sizeof(ssid_bssid->prev_bssid));
2814 	}
2815 
2816 	PRINTM(MCMND, "wlan: HostMlme %s send assoicate to bssid " MACSTR "\n",
2817 	       priv->netdev->name, MAC2STR(req->bss->bssid));
2818 	if (MLAN_STATUS_SUCCESS !=
2819 	    woal_bss_start(priv, MOAL_IOCTL_WAIT_TIMEOUT, ssid_bssid)) {
2820 		PRINTM(MERROR, "HostMlme %s: bss_start Fails\n",
2821 		       priv->netdev->name);
2822 		priv->host_mlme = MFALSE;
2823 		priv->auth_flag = 0;
2824 		ret = -EFAULT;
2825 	}
2826 
2827 done:
2828 
2829 	if (!ret) {
2830 		priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD;
2831 
2832 		woal_save_assoc_params(priv, req, ssid_bssid);
2833 
2834 		memset(&bss_info, 0, sizeof(bss_info));
2835 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
2836 		priv->channel = bss_info.bss_chan;
2837 	}
2838 
2839 	spin_lock_irqsave(&priv->connect_lock, flags);
2840 	priv->cfg_connect = MFALSE;
2841 	if (!ret && priv->media_connected) {
2842 		PRINTM(MMSG,
2843 		       "wlan: HostMlme %s Connected to bssid " MACSTR
2844 		       " successfully\n",
2845 		       priv->netdev->name, MAC2STR(priv->cfg_bssid));
2846 		spin_unlock_irqrestore(&priv->connect_lock, flags);
2847 	} else {
2848 		PRINTM(MERROR,
2849 		       "wlan: HostMlme %s Failed to connect to bssid " MACSTR
2850 		       "\n",
2851 		       priv->netdev->name, MAC2STR(req->bss->bssid));
2852 		if (ssid_bssid->assoc_rsp.assoc_resp_len &&
2853 		    ssid_bssid->assoc_rsp.assoc_resp_len >
2854 			    sizeof(IEEEtypes_MgmtHdr_t)) {
2855 			// save the connection param when send assoc_resp to
2856 			// kernel
2857 			woal_save_assoc_params(priv, req, ssid_bssid);
2858 			ret = 0;
2859 		} else {
2860 			ssid_bssid->assoc_rsp.assoc_resp_len = 0;
2861 			ret = -EFAULT;
2862 			memset(priv->cfg_bssid, 0, ETH_ALEN);
2863 			woal_clear_conn_params(priv);
2864 		}
2865 		priv->host_mlme = MFALSE;
2866 		priv->auth_flag = 0;
2867 		spin_unlock_irqrestore(&priv->connect_lock, flags);
2868 	}
2869 	/*Association Response should also be send when ret is non-zero.
2870 	  We also need to return success when we have association response
2871 	  available*/
2872 	if (ssid_bssid->assoc_rsp.assoc_resp_len) {
2873 		priv->auth_flag |= HOST_MLME_ASSOC_DONE;
2874 		woal_assoc_resp_event(priv, &ssid_bssid->assoc_rsp);
2875 	}
2876 	kfree(ssid_bssid);
2877 	LEAVE();
2878 	return ret;
2879 }
2880 #endif
2881 
2882 /**
2883  * @brief Request the driver for (re)association
2884  *
2885  * @param priv            A pointer to moal_private structure
2886  * @param sme             A pointer to connect parameters
2887  * @param wait_option     wait option
2888  * @param assoc_resp      A pointer to assoc_rsp structure;
2889  *
2890  * @return                0 -- success, otherwise fail
2891  */
woal_cfg80211_assoc(moal_private * priv,void * sme,t_u8 wait_option,mlan_ds_misc_assoc_rsp * assoc_rsp)2892 int woal_cfg80211_assoc(moal_private *priv, void *sme, t_u8 wait_option,
2893 			mlan_ds_misc_assoc_rsp *assoc_rsp)
2894 {
2895 	struct cfg80211_ibss_params *ibss_param = NULL;
2896 	struct cfg80211_connect_params *conn_param = NULL;
2897 	mlan_802_11_ssid req_ssid;
2898 	mlan_ssid_bssid *ssid_bssid = NULL;
2899 	mlan_ioctl_req *req = NULL;
2900 	int ret = 0;
2901 	t_u32 auth_type = 0, mode;
2902 	int wpa_enabled = 0;
2903 	int group_enc_mode = 0, pairwise_enc_mode = 0;
2904 	int alg_is_wep = 0;
2905 
2906 	t_u8 *ssid, ssid_len = 0, *bssid;
2907 	t_u8 *ie = NULL;
2908 	int ie_len = 0;
2909 	struct ieee80211_channel *channel = NULL;
2910 	t_u16 beacon_interval = 0;
2911 	bool privacy;
2912 	struct cfg80211_bss *pub = NULL;
2913 	mlan_status status = MLAN_STATUS_SUCCESS;
2914 
2915 	ENTER();
2916 
2917 	if (!sme) {
2918 		LEAVE();
2919 		return -EFAULT;
2920 	}
2921 	ssid_bssid = kmalloc(sizeof(mlan_ssid_bssid), GFP_KERNEL);
2922 	if (!ssid_bssid) {
2923 		LEAVE();
2924 		return -EFAULT;
2925 	}
2926 
2927 	mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
2928 
2929 	if (mode == MLAN_BSS_MODE_IBSS) {
2930 		ibss_param = (struct cfg80211_ibss_params *)sme;
2931 		ssid = (t_u8 *)ibss_param->ssid;
2932 		ssid_len = ibss_param->ssid_len;
2933 		bssid = (t_u8 *)ibss_param->bssid;
2934 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
2935 		channel = ibss_param->channel;
2936 #else
2937 		channel = ibss_param->chandef.chan;
2938 #endif
2939 		if (channel)
2940 			priv->phandle->band = channel->band;
2941 		if (ibss_param->ie_len)
2942 			ie = (t_u8 *)ibss_param->ie;
2943 		ie_len = ibss_param->ie_len;
2944 		beacon_interval = ibss_param->beacon_interval;
2945 		privacy = ibss_param->privacy;
2946 
2947 	} else {
2948 		conn_param = (struct cfg80211_connect_params *)sme;
2949 		ssid = (t_u8 *)conn_param->ssid;
2950 		ssid_len = conn_param->ssid_len;
2951 		bssid = (t_u8 *)conn_param->bssid;
2952 		channel = conn_param->channel;
2953 		if (channel)
2954 			priv->phandle->band = channel->band;
2955 		if (conn_param->ie_len)
2956 			ie = (t_u8 *)conn_param->ie;
2957 		ie_len = conn_param->ie_len;
2958 		privacy = conn_param->privacy;
2959 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2960 		pub = cfg80211_get_bss(priv->wdev->wiphy, channel, bssid, ssid,
2961 				       ssid_len, IEEE80211_BSS_TYPE_ESS,
2962 				       IEEE80211_PRIVACY_ANY);
2963 #else
2964 		pub = cfg80211_get_bss(priv->wdev->wiphy, channel, bssid, ssid,
2965 				       ssid_len, WLAN_CAPABILITY_ESS,
2966 				       WLAN_CAPABILITY_ESS);
2967 #endif
2968 		if (pub) {
2969 			if ((!priv->phandle->params.reg_alpha2 ||
2970 			     strncmp(priv->phandle->params.reg_alpha2, "99",
2971 				     strlen("99")))
2972 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2973 			    && (!moal_extflg_isset(priv->phandle,
2974 						   EXT_COUNTRY_IE_IGNORE))
2975 #endif
2976 			)
2977 				woal_process_country_ie(priv, pub);
2978 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
2979 			cfg80211_put_bss(priv->wdev->wiphy, pub);
2980 #else
2981 			cfg80211_put_bss(pub);
2982 #endif
2983 		} else
2984 			woal_send_domain_info_cmd_fw(priv, wait_option);
2985 #ifdef STA_WEXT
2986 		if (IS_STA_WEXT(priv->phandle->params.cfg80211_wext)) {
2987 			switch (conn_param->crypto.wpa_versions) {
2988 			case NL80211_WPA_VERSION_2:
2989 				priv->wpa_version = IW_AUTH_WPA_VERSION_WPA2;
2990 				break;
2991 			case NL80211_WPA_VERSION_1:
2992 				priv->wpa_version = IW_AUTH_WPA_VERSION_WPA;
2993 				break;
2994 			default:
2995 				priv->wpa_version = 0;
2996 				break;
2997 			}
2998 			if (conn_param->crypto.n_akm_suites) {
2999 				switch (conn_param->crypto.akm_suites[0]) {
3000 				case WLAN_AKM_SUITE_PSK:
3001 					priv->key_mgmt = IW_AUTH_KEY_MGMT_PSK;
3002 					break;
3003 				case WLAN_AKM_SUITE_8021X:
3004 					priv->key_mgmt =
3005 						IW_AUTH_KEY_MGMT_802_1X;
3006 					break;
3007 				default:
3008 					priv->key_mgmt = 0;
3009 					break;
3010 				}
3011 			}
3012 		}
3013 #endif
3014 	}
3015 
3016 	memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
3017 	memset(ssid_bssid, 0, sizeof(mlan_ssid_bssid));
3018 
3019 	req_ssid.ssid_len = ssid_len;
3020 	if (ssid_len > MW_ESSID_MAX_SIZE) {
3021 		PRINTM(MERROR, "Invalid SSID - aborting\n");
3022 		ret = -EINVAL;
3023 		goto done;
3024 	}
3025 
3026 	moal_memcpy_ext(priv->phandle, req_ssid.ssid, ssid, ssid_len,
3027 			sizeof(req_ssid.ssid));
3028 	if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
3029 		PRINTM(MERROR, "Invalid SSID - aborting\n");
3030 		ret = -EINVAL;
3031 		goto done;
3032 	}
3033 
3034 	if (priv->phandle->card_info->embedded_supp)
3035 		if (MLAN_STATUS_SUCCESS !=
3036 		    woal_set_ewpa_mode(priv, wait_option, ssid_bssid)) {
3037 			ret = -EFAULT;
3038 			goto done;
3039 		}
3040 
3041 	if (MLAN_STATUS_SUCCESS !=
3042 	    woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0,
3043 				  KEY_INDEX_CLEAR_ALL, NULL, 1, wait_option)) {
3044 		/* Disable keys and clear all previous security settings */
3045 		ret = -EFAULT;
3046 		goto done;
3047 	}
3048 #ifdef STA_CFG80211
3049 	if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
3050 		/** Check if current roaming support OKC offload roaming */
3051 		if (conn_param && conn_param->crypto.n_akm_suites &&
3052 		    conn_param->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X) {
3053 			if (priv->okc_roaming_ie && priv->okc_ie_len) {
3054 				ie = priv->okc_roaming_ie;
3055 				ie_len = priv->okc_ie_len;
3056 			}
3057 		}
3058 	}
3059 #endif
3060 
3061 	if ((priv->ft_pre_connect ||
3062 	     (conn_param && conn_param->auth_type == NL80211_AUTHTYPE_FT)) &&
3063 	    priv->ft_ie_len) {
3064 		ie = priv->ft_ie;
3065 		ie_len = priv->ft_ie_len;
3066 		priv->ft_ie_len = 0;
3067 	}
3068 	if (ie && ie_len) { /* Set the IE */
3069 		if (MLAN_STATUS_SUCCESS !=
3070 		    woal_cfg80211_assoc_ies_cfg(priv, ie, ie_len,
3071 						wait_option)) {
3072 			ret = -EFAULT;
3073 			goto done;
3074 		}
3075 	}
3076 
3077 	if (conn_param && mode != MLAN_BSS_MODE_IBSS) {
3078 		/* These parameters are only for managed mode */
3079 		if (conn_param->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
3080 			auth_type = MLAN_AUTH_MODE_OPEN;
3081 		else if (conn_param->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
3082 			auth_type = MLAN_AUTH_MODE_SHARED;
3083 		else if (conn_param->auth_type == NL80211_AUTHTYPE_NETWORK_EAP)
3084 			auth_type = MLAN_AUTH_MODE_NETWORKEAP;
3085 		else if (conn_param->auth_type == NL80211_AUTHTYPE_FT)
3086 			auth_type = MLAN_AUTH_MODE_FT;
3087 		else
3088 			auth_type = MLAN_AUTH_MODE_AUTO;
3089 		if (priv->ft_pre_connect)
3090 			auth_type = MLAN_AUTH_MODE_FT;
3091 		if (MLAN_STATUS_SUCCESS !=
3092 		    woal_set_auth_mode(priv, wait_option, auth_type)) {
3093 			ret = -EFAULT;
3094 			goto done;
3095 		}
3096 
3097 		if (conn_param->crypto.n_ciphers_pairwise) {
3098 			pairwise_enc_mode = woal_cfg80211_get_encryption_mode(
3099 				conn_param->crypto.ciphers_pairwise[0],
3100 				&wpa_enabled);
3101 			ret = woal_cfg80211_set_auth(priv, pairwise_enc_mode,
3102 						     wpa_enabled, wait_option);
3103 			if (ret)
3104 				goto done;
3105 		}
3106 
3107 		if (conn_param->crypto.cipher_group) {
3108 			group_enc_mode = woal_cfg80211_get_encryption_mode(
3109 				conn_param->crypto.cipher_group, &wpa_enabled);
3110 			ret = woal_cfg80211_set_auth(priv, group_enc_mode,
3111 						     wpa_enabled, wait_option);
3112 			if (ret)
3113 				goto done;
3114 		}
3115 
3116 		if (conn_param->key) {
3117 			alg_is_wep =
3118 				woal_cfg80211_is_alg_wep(pairwise_enc_mode) |
3119 				woal_cfg80211_is_alg_wep(group_enc_mode);
3120 			if (alg_is_wep) {
3121 				PRINTM(MINFO,
3122 				       "Setting wep encryption with key len %d\n",
3123 				       conn_param->key_len);
3124 				/* Set the WEP key */
3125 				if (MLAN_STATUS_SUCCESS !=
3126 				    woal_cfg80211_set_wep_keys(
3127 					    priv, conn_param->key,
3128 					    conn_param->key_len,
3129 					    conn_param->key_idx, wait_option)) {
3130 					ret = -EFAULT;
3131 					goto done;
3132 				}
3133 				/* Enable the WEP key by key index */
3134 				if (MLAN_STATUS_SUCCESS !=
3135 				    woal_cfg80211_set_wep_keys(
3136 					    priv, NULL, 0, conn_param->key_idx,
3137 					    wait_option)) {
3138 					ret = -EFAULT;
3139 					goto done;
3140 				}
3141 			}
3142 		}
3143 	}
3144 
3145 	if (mode == MLAN_BSS_MODE_IBSS) {
3146 		mlan_ds_bss *bss = NULL;
3147 		/* Change beacon interval */
3148 		if ((beacon_interval < MLAN_MIN_BEACON_INTERVAL) ||
3149 		    (beacon_interval > MLAN_MAX_BEACON_INTERVAL)) {
3150 			ret = -EINVAL;
3151 			goto done;
3152 		}
3153 		kfree(req);
3154 		req = NULL;
3155 
3156 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
3157 		if (req == NULL) {
3158 			ret = -ENOMEM;
3159 			goto done;
3160 		}
3161 		bss = (mlan_ds_bss *)req->pbuf;
3162 		req->req_id = MLAN_IOCTL_BSS;
3163 		req->action = MLAN_ACT_SET;
3164 		bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
3165 		bss->param.bcn_interval = beacon_interval;
3166 		status = woal_request_ioctl(priv, req, wait_option);
3167 		if (status != MLAN_STATUS_SUCCESS) {
3168 			ret = -EFAULT;
3169 			goto done;
3170 		}
3171 
3172 		/* "privacy" is set only for ad-hoc mode */
3173 		if (privacy) {
3174 			/*
3175 			 * Keep MLAN_ENCRYPTION_MODE_WEP40 for now so that
3176 			 * the firmware can find a matching network from the
3177 			 * scan. cfg80211 does not give us the encryption
3178 			 * mode at this stage so just setting it to wep here
3179 			 */
3180 			if (MLAN_STATUS_SUCCESS !=
3181 			    woal_set_auth_mode(priv, wait_option,
3182 					       MLAN_AUTH_MODE_OPEN)) {
3183 				ret = -EFAULT;
3184 				goto done;
3185 			}
3186 
3187 			wpa_enabled = 0;
3188 			ret = woal_cfg80211_set_auth(
3189 				priv, MLAN_ENCRYPTION_MODE_WEP104, wpa_enabled,
3190 				wait_option);
3191 			if (ret)
3192 				goto done;
3193 		}
3194 	}
3195 	moal_memcpy_ext(priv->phandle, &ssid_bssid->ssid, &req_ssid,
3196 			sizeof(mlan_802_11_ssid), sizeof(ssid_bssid->ssid));
3197 	if (bssid)
3198 		moal_memcpy_ext(priv->phandle, &ssid_bssid->bssid, bssid,
3199 				ETH_ALEN, sizeof(ssid_bssid->bssid));
3200 	if (MLAN_STATUS_SUCCESS !=
3201 	    woal_find_essid(priv, ssid_bssid, wait_option)) {
3202 		/* Do specific SSID scanning */
3203 		if (mode != MLAN_BSS_MODE_IBSS)
3204 			ret = woal_cfg80211_connect_scan(priv, conn_param,
3205 							 wait_option);
3206 		else
3207 			ret = woal_request_scan(priv, wait_option, &req_ssid);
3208 		if (ret) {
3209 			ret = -EFAULT;
3210 			goto done;
3211 		}
3212 	}
3213 
3214 	/* Disconnect before try to associate */
3215 	if (mode == MLAN_BSS_MODE_IBSS)
3216 		woal_disconnect(priv, wait_option, NULL,
3217 				DEF_DEAUTH_REASON_CODE);
3218 
3219 	if (mode != MLAN_BSS_MODE_IBSS) {
3220 		if (MLAN_STATUS_SUCCESS !=
3221 		    woal_find_best_network(priv, wait_option, ssid_bssid)) {
3222 			ret = -EFAULT;
3223 			goto done;
3224 		}
3225 		/* Inform the BSS information to kernel, otherwise
3226 		 * kernel will give a panic after successful assoc */
3227 		if (MLAN_STATUS_SUCCESS !=
3228 		    woal_inform_bss_from_scan_result(priv, ssid_bssid,
3229 						     wait_option)) {
3230 			ret = -EFAULT;
3231 			goto done;
3232 		}
3233 	} else if (MLAN_STATUS_SUCCESS !=
3234 		   woal_find_best_network(priv, wait_option, ssid_bssid))
3235 		/* Adhoc start, Check the channel command */
3236 		woal_11h_channel_check_ioctl(priv, wait_option);
3237 
3238 	PRINTM(MINFO, "Trying to associate to %s and bssid " MACSTR "\n",
3239 	       (char *)req_ssid.ssid, MAC2STR(ssid_bssid->bssid));
3240 
3241 	/* Zero SSID implies use BSSID to connect */
3242 	if (bssid)
3243 		memset(&ssid_bssid->ssid, 0, sizeof(mlan_802_11_ssid));
3244 	else /* Connect to BSS by ESSID */
3245 		memset(&ssid_bssid->bssid, 0, MLAN_MAC_ADDR_LENGTH);
3246 	if (channel) {
3247 		ssid_bssid->channel_flags = channel->flags;
3248 		ssid_bssid->channel_flags |= CHAN_FLAGS_MAX;
3249 		PRINTM(MCMND, "channel flags=0x%x\n", channel->flags);
3250 	}
3251 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
3252 	if (conn_param && conn_param->prev_bssid) {
3253 		moal_memcpy_ext(priv->phandle, ssid_bssid->prev_bssid,
3254 				conn_param->prev_bssid, ETH_ALEN,
3255 				sizeof(ssid_bssid->prev_bssid));
3256 	}
3257 #endif
3258 
3259 	if (MLAN_STATUS_SUCCESS !=
3260 	    woal_bss_start(priv, MOAL_IOCTL_WAIT_TIMEOUT, ssid_bssid)) {
3261 		ret = -EFAULT;
3262 		goto done;
3263 	}
3264 
3265 	/* Inform the IBSS information to kernel, otherwise
3266 	 * kernel will give a panic after successful assoc */
3267 	if (mode == MLAN_BSS_MODE_IBSS) {
3268 		if (MLAN_STATUS_SUCCESS !=
3269 		    woal_cfg80211_inform_ibss_bss(priv, channel,
3270 						  beacon_interval)) {
3271 			ret = -EFAULT;
3272 			goto done;
3273 		}
3274 	} else if (assoc_rsp) {
3275 		moal_memcpy_ext(priv->phandle, assoc_rsp,
3276 				&ssid_bssid->assoc_rsp,
3277 				sizeof(mlan_ds_misc_assoc_rsp),
3278 				sizeof(mlan_ds_misc_assoc_rsp));
3279 		PRINTM(MCMND, "assoc_rsp ie len=%d\n",
3280 		       assoc_rsp->assoc_resp_len);
3281 	}
3282 done:
3283 	kfree(ssid_bssid);
3284 	if (ret) {
3285 		/* clear the encryption mode */
3286 		if (MLAN_STATUS_SUCCESS !=
3287 		    woal_cfg80211_set_auth(priv, MLAN_ENCRYPTION_MODE_NONE,
3288 					   MFALSE, wait_option)) {
3289 			PRINTM(MERROR, "Could not clear encryption \n");
3290 			ret = -EFAULT;
3291 		}
3292 		/* clear IE */
3293 		ie_len = 0;
3294 		if (MLAN_STATUS_SUCCESS !=
3295 		    woal_set_get_gen_ie(priv, MLAN_ACT_SET, NULL, &ie_len,
3296 					wait_option)) {
3297 			PRINTM(MERROR, "Could not clear RSN IE\n");
3298 			ret = -EFAULT;
3299 		}
3300 	}
3301 	if (status != MLAN_STATUS_PENDING)
3302 		kfree(req);
3303 	LEAVE();
3304 	return ret;
3305 }
3306 
3307 /**
3308  * @brief Request the driver to fill the tx/rx rate info
3309  *
3310  * @param priv            A pointer to moal_private structure
3311  * @param sinfo           A pointer to station_info structure
3312  *
3313  * @return                0 -- success, otherwise fail
3314  */
woal_cfg80211_fill_rate_info(moal_private * priv,struct station_info * sinfo)3315 static void woal_cfg80211_fill_rate_info(moal_private *priv,
3316 					 struct station_info *sinfo)
3317 {
3318 	mlan_status ret = MLAN_STATUS_SUCCESS;
3319 	mlan_ioctl_req *req = NULL;
3320 	mlan_ds_rate *rate = NULL;
3321 	t_u16 Rates[12] = {0x02, 0x04, 0x0B, 0x16, 0x0C, 0x12,
3322 			   0x18, 0x24, 0x30, 0x48, 0x60, 0x6c};
3323 	ENTER();
3324 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
3325 	if (req == NULL) {
3326 		ret = MLAN_STATUS_FAILURE;
3327 		goto done;
3328 	}
3329 	rate = (mlan_ds_rate *)req->pbuf;
3330 	rate->sub_command = MLAN_OID_GET_DATA_RATE;
3331 	req->req_id = MLAN_IOCTL_RATE;
3332 	req->action = MLAN_ACT_GET;
3333 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3334 	if (ret != MLAN_STATUS_SUCCESS)
3335 		goto done;
3336 	if (rate->param.data_rate.tx_rate_format != MLAN_RATE_FORMAT_LG) {
3337 		if (rate->param.data_rate.tx_rate_format ==
3338 		    MLAN_RATE_FORMAT_HT) {
3339 			sinfo->txrate.flags = RATE_INFO_FLAGS_MCS;
3340 			if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40)
3341 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3342 				sinfo->txrate.bw = RATE_INFO_BW_40;
3343 #else
3344 				sinfo->txrate.flags |=
3345 					RATE_INFO_FLAGS_40_MHZ_WIDTH;
3346 #endif
3347 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3348 			else
3349 				sinfo->txrate.bw = RATE_INFO_BW_20;
3350 #endif
3351 		}
3352 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
3353 		else if (rate->param.data_rate.tx_rate_format ==
3354 			 MLAN_RATE_FORMAT_VHT) {
3355 			sinfo->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
3356 			sinfo->txrate.nss = rate->param.data_rate.tx_nss + 1;
3357 			if (rate->param.data_rate.tx_ht_bw == MLAN_VHT_BW80)
3358 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3359 				sinfo->txrate.bw = RATE_INFO_BW_80;
3360 #else
3361 				sinfo->txrate.flags |=
3362 					RATE_INFO_FLAGS_80_MHZ_WIDTH;
3363 #endif
3364 			else if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40)
3365 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3366 				sinfo->txrate.bw = RATE_INFO_BW_40;
3367 #else
3368 				sinfo->txrate.flags |=
3369 					RATE_INFO_FLAGS_40_MHZ_WIDTH;
3370 #endif
3371 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3372 			else
3373 				sinfo->txrate.bw = RATE_INFO_BW_20;
3374 #endif
3375 		}
3376 #endif
3377 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 1, 18)
3378 		else if (rate->param.data_rate.tx_rate_format ==
3379 			 MLAN_RATE_FORMAT_HE) {
3380 			sinfo->txrate.flags = RATE_INFO_FLAGS_HE_MCS;
3381 			sinfo->txrate.nss = rate->param.data_rate.tx_nss + 1;
3382 			sinfo->txrate.mcs = rate->param.data_rate.tx_mcs_index;
3383 			sinfo->txrate.he_gi = rate->param.data_rate.tx_ht_gi;
3384 			if (rate->param.data_rate.tx_ht_bw == MLAN_VHT_BW80)
3385 				sinfo->txrate.bw = RATE_INFO_BW_80;
3386 			else if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40)
3387 				sinfo->txrate.bw = RATE_INFO_BW_40;
3388 			else
3389 				sinfo->txrate.bw = RATE_INFO_BW_20;
3390 		}
3391 #endif
3392 		if (rate->param.data_rate.tx_ht_gi == MLAN_HT_SGI)
3393 			sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3394 		sinfo->txrate.mcs = rate->param.data_rate.tx_mcs_index;
3395 	} else {
3396 		/* Bit rate is in 500 kb/s units. Convert it to 100kb/s units */
3397 		if (rate->param.data_rate.tx_data_rate < 12) {
3398 			sinfo->txrate.legacy =
3399 				Rates[rate->param.data_rate.tx_data_rate] * 5;
3400 		} else
3401 			sinfo->txrate.legacy = Rates[0] * 5;
3402 	}
3403 	// Fill Rx rate
3404 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3405 	if (rate->param.data_rate.rx_rate_format != MLAN_RATE_FORMAT_LG) {
3406 		if (rate->param.data_rate.rx_rate_format ==
3407 		    MLAN_RATE_FORMAT_HT) {
3408 			sinfo->rxrate.flags = RATE_INFO_FLAGS_MCS;
3409 			if (rate->param.data_rate.rx_ht_bw == MLAN_HT_BW40)
3410 				sinfo->rxrate.bw = RATE_INFO_BW_40;
3411 			else
3412 				sinfo->rxrate.bw = RATE_INFO_BW_20;
3413 		} else if (rate->param.data_rate.rx_rate_format ==
3414 			   MLAN_RATE_FORMAT_VHT) {
3415 			sinfo->rxrate.flags = RATE_INFO_FLAGS_VHT_MCS;
3416 			sinfo->rxrate.nss = rate->param.data_rate.rx_nss + 1;
3417 			if (rate->param.data_rate.rx_ht_bw == MLAN_VHT_BW80)
3418 				sinfo->rxrate.bw = RATE_INFO_BW_80;
3419 			else if (rate->param.data_rate.rx_ht_bw == MLAN_HT_BW40)
3420 				sinfo->rxrate.bw = RATE_INFO_BW_40;
3421 			else
3422 				sinfo->rxrate.bw = RATE_INFO_BW_20;
3423 		}
3424 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 1, 18)
3425 		else if (rate->param.data_rate.rx_rate_format ==
3426 			 MLAN_RATE_FORMAT_HE) {
3427 			sinfo->rxrate.flags = RATE_INFO_FLAGS_HE_MCS;
3428 			sinfo->rxrate.nss = rate->param.data_rate.rx_nss + 1;
3429 			sinfo->rxrate.mcs = rate->param.data_rate.rx_mcs_index;
3430 			sinfo->rxrate.he_gi = rate->param.data_rate.rx_ht_gi;
3431 			if (rate->param.data_rate.rx_ht_bw == MLAN_VHT_BW80)
3432 				sinfo->rxrate.bw = RATE_INFO_BW_80;
3433 			else if (rate->param.data_rate.rx_ht_bw == MLAN_HT_BW40)
3434 				sinfo->rxrate.bw = RATE_INFO_BW_40;
3435 			else
3436 				sinfo->rxrate.bw = RATE_INFO_BW_20;
3437 		}
3438 #endif
3439 		if (rate->param.data_rate.rx_ht_gi == MLAN_HT_SGI)
3440 			sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
3441 		sinfo->rxrate.mcs = rate->param.data_rate.rx_mcs_index;
3442 	} else {
3443 		/* Bit rate is in 500 kb/s units. Convert it to 100kb/s units */
3444 		if (rate->param.data_rate.rx_data_rate < 12) {
3445 			sinfo->rxrate.legacy =
3446 				Rates[rate->param.data_rate.rx_data_rate] * 5;
3447 		} else
3448 			sinfo->rxrate.legacy = 0;
3449 	}
3450 #endif
3451 done:
3452 	if (ret != MLAN_STATUS_PENDING)
3453 		kfree(req);
3454 	LEAVE();
3455 	return;
3456 }
3457 /**
3458  * @brief Request the driver to dump the station information
3459  *
3460  * @param priv            A pointer to moal_private structure
3461  * @param sinfo           A pointer to station_info structure
3462  *
3463  * @return                0 -- success, otherwise fail
3464  */
woal_cfg80211_dump_station_info(moal_private * priv,struct station_info * sinfo)3465 static mlan_status woal_cfg80211_dump_station_info(moal_private *priv,
3466 						   struct station_info *sinfo)
3467 {
3468 	mlan_status ret = MLAN_STATUS_SUCCESS;
3469 	mlan_ds_get_signal signal;
3470 	mlan_ds_get_stats stats;
3471 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
3472 	mlan_bss_info bss_info;
3473 	t_u8 dtim_period = 0;
3474 #endif
3475 
3476 	ENTER();
3477 
3478 	if (priv->phandle->scan_pending_on_block) {
3479 		if (priv->sinfo)
3480 			moal_memcpy_ext(priv->phandle, sinfo, priv->sinfo,
3481 					sizeof(struct station_info),
3482 					sizeof(struct station_info));
3483 		LEAVE();
3484 		return ret;
3485 	}
3486 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3487 	sinfo->filled = MBIT(NL80211_STA_INFO_RX_BYTES) |
3488 			MBIT(NL80211_STA_INFO_TX_BYTES) |
3489 			MBIT(NL80211_STA_INFO_RX_PACKETS) |
3490 			MBIT(NL80211_STA_INFO_TX_PACKETS) |
3491 			MBIT(NL80211_STA_INFO_SIGNAL) |
3492 			MBIT(NL80211_STA_INFO_TX_BITRATE) |
3493 			MBIT(NL80211_STA_INFO_RX_BITRATE);
3494 #else
3495 	sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
3496 			STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
3497 			STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
3498 #endif
3499 
3500 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
3501 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3502 	sinfo->filled |= MBIT(NL80211_STA_INFO_TX_FAILED);
3503 #else
3504 	sinfo->filled |= STATION_INFO_TX_FAILED;
3505 #endif
3506 #endif
3507 
3508 	/* Get signal information from the firmware */
3509 	memset(&signal, 0, sizeof(mlan_ds_get_signal));
3510 	if (MLAN_STATUS_SUCCESS !=
3511 	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
3512 		PRINTM(MERROR, "Error getting signal information\n");
3513 		ret = MLAN_STATUS_FAILURE;
3514 		goto done;
3515 	}
3516 
3517 	/* Get stats information from the firmware */
3518 	memset(&stats, 0, sizeof(mlan_ds_get_stats));
3519 	if (MLAN_STATUS_SUCCESS !=
3520 	    woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
3521 		PRINTM(MERROR, "Error getting stats information\n");
3522 		ret = MLAN_STATUS_FAILURE;
3523 		goto done;
3524 	}
3525 
3526 	sinfo->rx_bytes = priv->stats.rx_bytes;
3527 	sinfo->tx_bytes = priv->stats.tx_bytes;
3528 	sinfo->rx_packets = priv->stats.rx_packets;
3529 	sinfo->tx_packets = priv->stats.tx_packets;
3530 	sinfo->signal = signal.bcn_rssi_avg;
3531 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
3532 	sinfo->tx_failed = stats.failed;
3533 #endif
3534 
3535 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
3536 	/* Update BSS information */
3537 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3538 	sinfo->filled |= MBIT(NL80211_STA_INFO_BSS_PARAM);
3539 #else
3540 	sinfo->filled |= STATION_INFO_BSS_PARAM;
3541 #endif
3542 	sinfo->bss_param.flags = 0;
3543 	ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
3544 	if (ret)
3545 		goto done;
3546 	if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_PREAMBLE)
3547 		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
3548 	if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_SLOT_TIME)
3549 		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
3550 	sinfo->bss_param.beacon_interval = bss_info.beacon_interval;
3551 	/* Get DTIM period */
3552 	ret = woal_set_get_dtim_period(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
3553 				       &dtim_period);
3554 	if (ret) {
3555 		PRINTM(MERROR, "Get DTIM period failed\n");
3556 		goto done;
3557 	}
3558 	sinfo->bss_param.dtim_period = dtim_period;
3559 #endif
3560 	woal_cfg80211_fill_rate_info(priv, sinfo);
3561 	if (priv->sinfo)
3562 		moal_memcpy_ext(priv->phandle, priv->sinfo, sinfo,
3563 				sizeof(struct station_info),
3564 				sizeof(struct station_info));
3565 
3566 done:
3567 	LEAVE();
3568 	return ret;
3569 }
3570 
3571 /********************************************************
3572 				Global Functions
3573 ********************************************************/
3574 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3575 
3576 /**
3577  *  @brief This function will be used by sort, to compare LHS & RHS
3578  *
3579  *  @param lhs              LHS value
3580  *  @param rhs              RHS value
3581  *  @return                 0
3582  */
compare(const void * lhs,const void * rhs)3583 static int compare(const void *lhs, const void *rhs)
3584 {
3585 	const chan_freq_power_t *lhs_cfp = (const chan_freq_power_t *)(lhs);
3586 	const chan_freq_power_t *rhs_cfp = (const chan_freq_power_t *)(rhs);
3587 
3588 	if (lhs_cfp->channel < rhs_cfp->channel)
3589 		return -1;
3590 	if (lhs_cfp->channel > rhs_cfp->channel)
3591 		return 1;
3592 
3593 	return 0;
3594 }
3595 
3596 /**
3597  *  @brief This function get channel reg_rule flags
3598  *
3599  *  @param buf              Buffer containing channel region config
3600  *  @param num_chan         Length of buffer
3601  *  @param regd             ieee80211_regdomain to be updated
3602  *
3603  *  @return                 N/A
3604  */
woal_get_chan_rule_flags(mlan_ds_custom_reg_domain * custom_reg,t_u8 channel)3605 t_u32 woal_get_chan_rule_flags(mlan_ds_custom_reg_domain *custom_reg,
3606 			       t_u8 channel)
3607 {
3608 	t_u16 num_chan = 0;
3609 	t_u32 flags = 0;
3610 	int idx;
3611 	t_u16 chflags;
3612 
3613 	num_chan = custom_reg->num_bg_chan;
3614 	num_chan += custom_reg->num_a_chan;
3615 	for (idx = 0; idx < num_chan; idx++) {
3616 		chflags = custom_reg->cfp_tbl[idx].dynamic.flags;
3617 		if (chflags & NXP_CHANNEL_DISABLED)
3618 			continue;
3619 		if (custom_reg->cfp_tbl[idx].channel == channel) {
3620 			if (chflags & NXP_CHANNEL_PASSIVE)
3621 				flags |= NL80211_RRF_NO_IR;
3622 			if (chflags & NXP_CHANNEL_DFS)
3623 				flags |= NL80211_RRF_DFS;
3624 			if (chflags & NXP_CHANNEL_NO_OFDM)
3625 				flags |= NL80211_RRF_NO_OFDM;
3626 			break;
3627 		}
3628 	}
3629 	return flags;
3630 }
3631 
3632 /**
3633  *  @brief This function update the beaconng flags of channel
3634  *
3635  *  @param custom_reg       pointer to mlan_ds_custom_reg_domain
3636  *
3637  *  @return                 pointer to ieee80211_regdomain
3638  */
3639 
3640 static void
woal_reg_apply_beaconing_flags(struct wiphy * wiphy,mlan_ds_custom_reg_domain * custom_reg)3641 woal_reg_apply_beaconing_flags(struct wiphy *wiphy,
3642 			       mlan_ds_custom_reg_domain *custom_reg)
3643 {
3644 	struct ieee80211_supported_band *sband;
3645 	struct ieee80211_channel *ch;
3646 	int band, i;
3647 	t_u32 rule_flags = 0;
3648 
3649 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
3650 		sband = wiphy->bands[band];
3651 		if (!sband)
3652 			continue;
3653 
3654 		for (i = 0; i < sband->n_channels; i++) {
3655 			ch = &sband->channels[i];
3656 
3657 			if (ch->flags &
3658 			    (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR))
3659 				continue;
3660 
3661 			rule_flags = woal_get_chan_rule_flags(custom_reg,
3662 							      ch->hw_value);
3663 
3664 			if (!(rule_flags & NL80211_RRF_NO_IR))
3665 				ch->flags &= ~IEEE80211_CHAN_NO_IR;
3666 		}
3667 	}
3668 }
3669 
3670 /**
3671  *  @brief This function create the custom regdomain
3672  *
3673  *  @param priv       pointer to moal_private
3674  *  @param custom_reg       pointer to mlan_ds_custom_reg_domain
3675  *
3676  *  @return                 pointer to ieee80211_regdomain
3677  */
3678 static struct ieee80211_regdomain *
create_custom_regdomain(moal_private * priv,mlan_ds_custom_reg_domain * custom_reg)3679 create_custom_regdomain(moal_private *priv,
3680 			mlan_ds_custom_reg_domain *custom_reg)
3681 {
3682 	struct ieee80211_reg_rule *rule;
3683 	bool new_rule;
3684 	int idx, freq, prev_freq = 0;
3685 	t_u8 chan;
3686 	t_u16 num_chan = 0;
3687 	t_u32 bw, prev_bw = 0;
3688 	t_u16 chflags, prev_chflags = 0, valid_rules = 0;
3689 	struct ieee80211_regdomain *regd = NULL;
3690 	int regd_size;
3691 	const struct ieee80211_freq_range *freq_range = NULL;
3692 
3693 	num_chan = custom_reg->num_bg_chan;
3694 	num_chan += custom_reg->num_a_chan;
3695 
3696 	sort(&custom_reg->cfp_tbl[custom_reg->num_bg_chan],
3697 	     custom_reg->num_a_chan, sizeof(chan_freq_power_t), &compare, NULL);
3698 
3699 	regd_size = sizeof(struct ieee80211_regdomain) +
3700 		    num_chan * sizeof(struct ieee80211_reg_rule);
3701 
3702 	regd = kzalloc(regd_size, GFP_KERNEL);
3703 	if (!regd) {
3704 		return NULL;
3705 	}
3706 	for (idx = 0; idx < num_chan; idx++) {
3707 		enum ieee80211_band band;
3708 
3709 		chan = custom_reg->cfp_tbl[idx].channel;
3710 		if (!chan) {
3711 			if (regd)
3712 				kfree(regd);
3713 			return NULL;
3714 		}
3715 		chflags = custom_reg->cfp_tbl[idx].dynamic.flags;
3716 		band = (chan <= 14) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
3717 		freq = ieee80211_channel_to_frequency(chan, band);
3718 		PRINTM(MINFO, "chan=%d freq=%d chan_flag=0x%x\n", chan, freq,
3719 		       chflags);
3720 		new_rule = false;
3721 
3722 		if (chflags & NXP_CHANNEL_DISABLED)
3723 			continue;
3724 
3725 		if (band == IEEE80211_BAND_5GHZ) {
3726 			if (!(chflags & NXP_CHANNEL_NOHT80))
3727 				bw = MHZ_TO_KHZ(80);
3728 			else if (!(chflags & NXP_CHANNEL_NOHT40))
3729 				bw = MHZ_TO_KHZ(40);
3730 			else
3731 				bw = MHZ_TO_KHZ(20);
3732 		} else {
3733 			if (!(chflags & NXP_CHANNEL_NOHT40))
3734 				bw = MHZ_TO_KHZ(40);
3735 			else
3736 				bw = MHZ_TO_KHZ(20);
3737 		}
3738 
3739 		if (idx == 0 || prev_chflags != chflags || prev_bw != bw ||
3740 		    freq - prev_freq > 20) {
3741 			valid_rules++;
3742 			new_rule = true;
3743 		}
3744 
3745 		rule = &regd->reg_rules[valid_rules - 1];
3746 
3747 		rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10);
3748 
3749 		prev_chflags = chflags;
3750 		prev_freq = freq;
3751 		prev_bw = bw;
3752 
3753 		if (!new_rule)
3754 			continue;
3755 
3756 		rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq - 10);
3757 		rule->power_rule.max_eirp = DBM_TO_MBM(19);
3758 		rule->flags = 0;
3759 
3760 		if (chflags & NXP_CHANNEL_PASSIVE)
3761 			rule->flags |= NL80211_RRF_NO_IR;
3762 		if (chflags & NXP_CHANNEL_DFS)
3763 			rule->flags |= NL80211_RRF_DFS;
3764 		if (chflags & NXP_CHANNEL_NO_OFDM)
3765 			rule->flags |= NL80211_RRF_NO_OFDM;
3766 		rule->freq_range.max_bandwidth_khz = bw;
3767 	}
3768 
3769 	regd->n_reg_rules = valid_rules;
3770 
3771 	if (custom_reg->region.country_code[0] == 'W' &&
3772 	    custom_reg->region.country_code[1] == 'W') {
3773 		regd->alpha2[0] = '0';
3774 		regd->alpha2[1] = '0';
3775 	} else {
3776 		/* set alpha2 from FW. */
3777 		regd->alpha2[0] = custom_reg->region.country_code[0];
3778 		regd->alpha2[1] = custom_reg->region.country_code[1];
3779 	}
3780 
3781 	switch (custom_reg->region.dfs_region) {
3782 	case 1:
3783 		regd->dfs_region = NL80211_DFS_FCC;
3784 		break;
3785 	case 2:
3786 		regd->dfs_region = NL80211_DFS_ETSI;
3787 		break;
3788 	case 3:
3789 		regd->dfs_region = NL80211_DFS_JP;
3790 		break;
3791 	default:
3792 		regd->dfs_region = NL80211_DFS_UNSET;
3793 		break;
3794 	}
3795 	priv->phandle->dfs_region = regd->dfs_region;
3796 	PRINTM(MCMND, "create_custom_regdomain: %c%c rules=%d dfs_region=%d\n",
3797 	       regd->alpha2[0], regd->alpha2[1], valid_rules, regd->dfs_region);
3798 	for (idx = 0; idx < (int)regd->n_reg_rules; idx++) {
3799 		rule = &regd->reg_rules[idx];
3800 		freq_range = &rule->freq_range;
3801 		PRINTM(MCMND,
3802 		       "flags=0x%x star_freq=%d end_freq=%d freq_diff=%d max_bandwidth=%d\n",
3803 		       rule->flags, freq_range->start_freq_khz,
3804 		       freq_range->end_freq_khz,
3805 		       freq_range->end_freq_khz - freq_range->start_freq_khz,
3806 		       freq_range->max_bandwidth_khz);
3807 	}
3808 	if (!regd->n_reg_rules) {
3809 		kfree(regd);
3810 		regd = NULL;
3811 	}
3812 	return regd;
3813 }
3814 
3815 /**
3816  *  @brief create custom channel regulatory config
3817  *
3818  *  @param priv         A pointer to moal_private structure
3819  *
3820  *  @return		        0-success, otherwise failure
3821  */
woal_update_custom_regdomain(moal_private * priv,struct wiphy * wiphy)3822 static int woal_update_custom_regdomain(moal_private *priv, struct wiphy *wiphy)
3823 {
3824 	mlan_ds_misc_cfg *misc = NULL;
3825 	mlan_ioctl_req *req = NULL;
3826 	mlan_status status = MLAN_STATUS_SUCCESS;
3827 	t_u8 country_code[COUNTRY_CODE_LEN];
3828 
3829 	int ret = 0;
3830 	struct ieee80211_regdomain *regd = NULL;
3831 
3832 	ENTER();
3833 
3834 	if (!priv || !wiphy) {
3835 		LEAVE();
3836 		return -EFAULT;
3837 	}
3838 
3839 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
3840 	if (req == NULL) {
3841 		ret = -EFAULT;
3842 		goto done;
3843 	}
3844 	misc = (mlan_ds_misc_cfg *)req->pbuf;
3845 	misc->sub_command = MLAN_OID_MISC_GET_CHAN_REGION_CFG;
3846 	req->req_id = MLAN_IOCTL_MISC_CFG;
3847 	req->action = MLAN_ACT_GET;
3848 	memset(&misc->param.custom_reg_domain, 0,
3849 	       sizeof(misc->param.custom_reg_domain));
3850 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
3851 	if (status != MLAN_STATUS_SUCCESS) {
3852 		ret = -EFAULT;
3853 		goto done;
3854 	}
3855 	memset(country_code, 0, sizeof(country_code));
3856 	if (MTRUE ==
3857 	    is_cfg80211_special_region_code(priv->phandle->country_code)) {
3858 		country_code[0] = 'W';
3859 		country_code[1] = 'W';
3860 	} else {
3861 		country_code[0] = priv->phandle->country_code[0];
3862 		country_code[1] = priv->phandle->country_code[1];
3863 	}
3864 	if (misc->param.custom_reg_domain.region.country_code[0] == '\0' ||
3865 	    misc->param.custom_reg_domain.region.country_code[1] == '\0') {
3866 		PRINTM(MCMND, "FW country code not valid\n");
3867 		ret = -EFAULT;
3868 		goto done;
3869 	}
3870 	if (misc->param.custom_reg_domain.region.country_code[0] !=
3871 		    country_code[0] ||
3872 	    misc->param.custom_reg_domain.region.country_code[1] !=
3873 		    country_code[1]) {
3874 		PRINTM(MCMND, "FW country code %c%c not match %c%c\n",
3875 		       misc->param.custom_reg_domain.region.country_code[0],
3876 		       misc->param.custom_reg_domain.region.country_code[1],
3877 		       country_code[0], country_code[1]);
3878 	}
3879 	regd = create_custom_regdomain(priv, &misc->param.custom_reg_domain);
3880 	if (regd) {
3881 		PRINTM(MMSG, "call regulatory_set_wiphy_regd %c%c",
3882 		       misc->param.custom_reg_domain.region.country_code[0],
3883 		       misc->param.custom_reg_domain.region.country_code[1]);
3884 		wiphy->regulatory_flags &=
3885 			~(REGULATORY_STRICT_REG | REGULATORY_CUSTOM_REG);
3886 		wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
3887 		rtnl_lock();
3888 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
3889 		ret = regulatory_set_wiphy_regd_sync(wiphy, regd);
3890 #else
3891 		ret = regulatory_set_wiphy_regd_sync_rtnl(wiphy, regd);
3892 #endif
3893 		rtnl_unlock();
3894 		kfree(regd);
3895 		if (!ret)
3896 			woal_reg_apply_beaconing_flags(
3897 				wiphy, &misc->param.custom_reg_domain);
3898 	}
3899 done:
3900 	if (status != MLAN_STATUS_PENDING)
3901 		kfree(req);
3902 	LEAVE();
3903 	return ret;
3904 }
3905 
3906 /**
3907  *  @brief This workqueue handles create customer regulatory
3908  * case
3909  *
3910  *  @param work    A pointer to work_struct
3911  *
3912  *  @return        N/A
3913  */
woal_regulatory_work_queue(struct work_struct * work)3914 void woal_regulatory_work_queue(struct work_struct *work)
3915 {
3916 	moal_handle *handle = container_of(work, moal_handle, regulatory_work);
3917 	struct wiphy *wiphy = handle->wiphy;
3918 	moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
3919 	enum ieee80211_band band;
3920 
3921 	if (priv && wiphy) {
3922 		woal_update_custom_regdomain(priv, wiphy);
3923 		band = priv->phandle->band;
3924 		priv->phandle->band = IEEE80211_BAND_2GHZ;
3925 		woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
3926 		if (priv->phandle->fw_bands & BAND_A) {
3927 			priv->phandle->band = IEEE80211_BAND_5GHZ;
3928 			woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
3929 		}
3930 		priv->phandle->band = band;
3931 	}
3932 }
3933 #endif
3934 
3935 /**
3936  * @brief Request the driver to change regulatory domain
3937  *
3938  * @param wiphy           A pointer to wiphy structure
3939  * @param request         A pointer to regulatory_request structure
3940  *
3941  * @return                0
3942  */
3943 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
3944 static void
3945 #else
3946 static int
3947 #endif
woal_cfg80211_reg_notifier(struct wiphy * wiphy,struct regulatory_request * request)3948 woal_cfg80211_reg_notifier(struct wiphy *wiphy,
3949 			   struct regulatory_request *request)
3950 {
3951 	moal_private *priv = NULL;
3952 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
3953 	t_u8 region[COUNTRY_CODE_LEN];
3954 	enum ieee80211_band band;
3955 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
3956 	int ret = 0;
3957 #endif
3958 	t_u8 load_power_table = MFALSE;
3959 	mlan_fw_info fw_info;
3960 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3961 	char *reg_alpha2 = NULL;
3962 #endif
3963 	t_u8 dfs_region = NXP_DFS_UNKNOWN;
3964 
3965 	ENTER();
3966 
3967 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
3968 	if (!priv) {
3969 		PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
3970 		LEAVE();
3971 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
3972 		return -EINVAL;
3973 #else
3974 		return;
3975 #endif
3976 	}
3977 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
3978 	dfs_region = request->dfs_region;
3979 #endif
3980 	PRINTM(MCMND,
3981 	       "cfg80211 regulatory domain callback "
3982 	       "%c%c initiator=%d dfs_region=%d\n",
3983 	       request->alpha2[0], request->alpha2[1], request->initiator,
3984 	       dfs_region);
3985 
3986 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3987 	if (!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED))
3988 #endif
3989 		handle->dfs_region = dfs_region;
3990 
3991 	memset(&fw_info, 0, sizeof(mlan_fw_info));
3992 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
3993 	if (fw_info.force_reg) {
3994 		PRINTM(MINFO,
3995 		       "Regulatory domain is enforced in the on-chip OTP\n");
3996 		LEAVE();
3997 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
3998 		return -EINVAL;
3999 #else
4000 		return;
4001 #endif
4002 	}
4003 
4004 	memset(region, 0, sizeof(region));
4005 	moal_memcpy_ext(priv->phandle, region, request->alpha2,
4006 			sizeof(request->alpha2), sizeof(region));
4007 	region[2] = ' ';
4008 	if ((handle->country_code[0] != request->alpha2[0]) ||
4009 	    (handle->country_code[1] != request->alpha2[1])) {
4010 		if (handle->params.cntry_txpwr) {
4011 			t_u8 country_code[COUNTRY_CODE_LEN];
4012 			handle->country_code[0] = request->alpha2[0];
4013 			handle->country_code[1] = request->alpha2[1];
4014 			handle->country_code[2] = ' ';
4015 			memset(country_code, 0, sizeof(country_code));
4016 			if (MTRUE == is_cfg80211_special_region_code(region)) {
4017 				country_code[0] = 'W';
4018 				country_code[1] = 'W';
4019 			} else {
4020 				country_code[0] = request->alpha2[0];
4021 				country_code[1] = request->alpha2[1];
4022 			}
4023 			if (MLAN_STATUS_SUCCESS !=
4024 			    woal_request_country_power_table(priv,
4025 							     country_code)) {
4026 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
4027 				return -EFAULT;
4028 #else
4029 				return;
4030 #endif
4031 			}
4032 			load_power_table = MTRUE;
4033 		}
4034 	}
4035 	if (!handle->params.cntry_txpwr) {
4036 		handle->country_code[0] = request->alpha2[0];
4037 		handle->country_code[1] = request->alpha2[1];
4038 		handle->country_code[2] = ' ';
4039 		if (MTRUE != is_cfg80211_special_region_code(region)) {
4040 			if (MLAN_STATUS_SUCCESS !=
4041 			    woal_set_region_code(priv, handle->country_code))
4042 				PRINTM(MERROR, "Set country code failed!\n");
4043 		}
4044 	}
4045 	switch (request->initiator) {
4046 	case NL80211_REGDOM_SET_BY_DRIVER:
4047 		PRINTM(MCMND, "Regulatory domain BY_DRIVER\n");
4048 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
4049 		reg_alpha2 = priv->phandle->params.reg_alpha2;
4050 		if ((handle->params.cntry_txpwr == CNTRY_RGPOWER_MODE) &&
4051 		    !handle->params.txpwrlimit_cfg && load_power_table &&
4052 		    reg_alpha2 && woal_is_valid_alpha2(reg_alpha2))
4053 			queue_work(handle->evt_workqueue,
4054 				   &handle->regulatory_work);
4055 #endif
4056 		break;
4057 	case NL80211_REGDOM_SET_BY_CORE:
4058 		PRINTM(MCMND, "Regulatory domain BY_CORE\n");
4059 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
4060 		if (handle->params.cntry_txpwr == CNTRY_RGPOWER_MODE &&
4061 		    load_power_table && !handle->params.txpwrlimit_cfg)
4062 			queue_work(handle->evt_workqueue,
4063 				   &handle->regulatory_work);
4064 #endif
4065 		break;
4066 	case NL80211_REGDOM_SET_BY_USER:
4067 		PRINTM(MCMND, "Regulatory domain BY_USER\n");
4068 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
4069 		if (handle->params.cntry_txpwr == CNTRY_RGPOWER_MODE &&
4070 		    load_power_table && !handle->params.txpwrlimit_cfg)
4071 			queue_work(handle->evt_workqueue,
4072 				   &handle->regulatory_work);
4073 #endif
4074 		break;
4075 	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
4076 		PRINTM(MCMND, "Regulatory domain BY_COUNTRY_IE\n");
4077 		break;
4078 	}
4079 	if (priv->wdev && priv->wdev->wiphy &&
4080 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
4081 	    !(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
4082 #endif
4083 	    (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)) {
4084 		band = priv->phandle->band;
4085 		priv->phandle->band = IEEE80211_BAND_2GHZ;
4086 		woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
4087 		if (priv->phandle->fw_bands & BAND_A) {
4088 			priv->phandle->band = IEEE80211_BAND_5GHZ;
4089 			woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
4090 		}
4091 		priv->phandle->band = band;
4092 	}
4093 
4094 	LEAVE();
4095 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
4096 	return ret;
4097 #endif
4098 }
4099 
4100 #ifdef UAP_CFG80211
4101 /**
4102  * @brief Swithces BSS role of interface
4103  *
4104  * @param priv          A pointer to moal_private structure
4105  * @param wait_option   Wait option (MOAL_WAIT or MOAL_NO_WAIT)
4106  * @param bss_role      bss role
4107  *
4108  * @return         0 --success, otherwise fail
4109  */
woal_role_switch(moal_private * priv,t_u8 wait_option,t_u8 bss_role)4110 static mlan_status woal_role_switch(moal_private *priv, t_u8 wait_option,
4111 				    t_u8 bss_role)
4112 {
4113 	int ret = 0;
4114 	mlan_ds_bss *bss = NULL;
4115 	mlan_ioctl_req *req = NULL;
4116 	mlan_status status = MLAN_STATUS_SUCCESS;
4117 
4118 	ENTER();
4119 
4120 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
4121 	if (req == NULL) {
4122 		ret = -ENOMEM;
4123 		goto done;
4124 	}
4125 	bss = (mlan_ds_bss *)req->pbuf;
4126 	bss->sub_command = MLAN_OID_BSS_ROLE;
4127 	req->req_id = MLAN_IOCTL_BSS;
4128 	req->action = MLAN_ACT_SET;
4129 	bss->param.bss_role = bss_role;
4130 
4131 	status = woal_request_ioctl(priv, req, wait_option);
4132 	if (status != MLAN_STATUS_SUCCESS) {
4133 		ret = -EFAULT;
4134 		goto done;
4135 	}
4136 done:
4137 	if (status != MLAN_STATUS_PENDING)
4138 		kfree(req);
4139 	LEAVE();
4140 	return ret;
4141 }
4142 
4143 /**
4144  *  @brief set/get bandcfg
4145  *
4146  *  @param priv                 A pointer to moal_private structure
4147  *  @param action               get or set action
4148  *  @param band_cfg             A pointer to mlan_ds_band_cfg structure
4149  *
4150  *  @return                     0 -- success, otherwise fail
4151  */
woal_setget_bandcfg(moal_private * priv,t_u8 action,mlan_ds_band_cfg * band_cfg)4152 static int woal_setget_bandcfg(moal_private *priv, t_u8 action,
4153 			       mlan_ds_band_cfg *band_cfg)
4154 {
4155 	int ret = 0;
4156 	mlan_ioctl_req *req = NULL;
4157 	mlan_ds_radio_cfg *radio_cfg = NULL;
4158 	mlan_status status = MLAN_STATUS_SUCCESS;
4159 
4160 	ENTER();
4161 
4162 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
4163 	if (req == NULL) {
4164 		ret = -ENOMEM;
4165 		goto error;
4166 	}
4167 	radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
4168 	radio_cfg->sub_command = MLAN_OID_BAND_CFG;
4169 	req->req_id = MLAN_IOCTL_RADIO_CFG;
4170 	req->action = action;
4171 
4172 	if (req->action == MLAN_ACT_SET)
4173 		moal_memcpy_ext(priv->phandle, &radio_cfg->param.band_cfg,
4174 				band_cfg, sizeof(mlan_ds_band_cfg),
4175 				sizeof(radio_cfg->param.band_cfg));
4176 
4177 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
4178 	if (status != MLAN_STATUS_SUCCESS) {
4179 		ret = -EFAULT;
4180 		goto error;
4181 	}
4182 	moal_memcpy_ext(priv->phandle, band_cfg, &radio_cfg->param.band_cfg,
4183 			sizeof(mlan_ds_band_cfg), sizeof(mlan_ds_band_cfg));
4184 error:
4185 	if (status != MLAN_STATUS_PENDING)
4186 		kfree(req);
4187 
4188 	LEAVE();
4189 	return ret;
4190 }
4191 
4192 /**
4193  *  @brief request scan
4194  *
4195  *  @param priv                 A pointer to moal_private structure
4196  *  @param scan_cfg             A pointer to wlan_user_scan_cfg structure
4197  *
4198  *  @return                     MLAN_STATUS_SUCCESS -- success, otherwise fail
4199  */
woal_uap_scan(moal_private * priv,wlan_user_scan_cfg * scan_cfg)4200 static mlan_status woal_uap_scan(moal_private *priv,
4201 				 wlan_user_scan_cfg *scan_cfg)
4202 {
4203 	mlan_status ret = MLAN_STATUS_SUCCESS;
4204 	moal_handle *handle = priv->phandle;
4205 	moal_private *tmp_priv;
4206 	u8 role;
4207 	mlan_ds_band_cfg org_bandcfg;
4208 	mlan_ds_band_cfg bandcfg;
4209 	u8 band_change = MFALSE;
4210 	ENTER();
4211 	if (priv->bss_index > 0)
4212 		tmp_priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
4213 	else
4214 		tmp_priv = priv;
4215 	if (!tmp_priv) {
4216 		LEAVE();
4217 		return MLAN_STATUS_FAILURE;
4218 	}
4219 	role = GET_BSS_ROLE(tmp_priv);
4220 	if (role == MLAN_BSS_ROLE_UAP) {
4221 		if (MLAN_STATUS_SUCCESS !=
4222 		    woal_role_switch(tmp_priv, MOAL_IOCTL_WAIT,
4223 				     MLAN_BSS_ROLE_STA)) {
4224 			PRINTM(MERROR, "role switch from uap to sta fail\n");
4225 			LEAVE();
4226 			return MLAN_STATUS_FAILURE;
4227 		}
4228 	}
4229 	if (tmp_priv != priv) {
4230 		if (woal_setget_bandcfg(priv, MLAN_ACT_GET, &bandcfg)) {
4231 			PRINTM(MERROR, "get bandcfg fail\n");
4232 			ret = MLAN_STATUS_FAILURE;
4233 			goto done;
4234 		}
4235 		if (woal_setget_bandcfg(tmp_priv, MLAN_ACT_GET, &org_bandcfg)) {
4236 			PRINTM(MERROR, "get bandcfg fail\n");
4237 			ret = MLAN_STATUS_FAILURE;
4238 			goto done;
4239 		}
4240 		if (bandcfg.config_bands != org_bandcfg.config_bands) {
4241 			if (woal_setget_bandcfg(tmp_priv, MLAN_ACT_SET,
4242 						&bandcfg)) {
4243 				PRINTM(MERROR, "set bandcfg fail\n");
4244 				ret = MLAN_STATUS_FAILURE;
4245 				goto done;
4246 			}
4247 			band_change = MTRUE;
4248 		}
4249 	}
4250 #ifdef REASSOCIATION
4251 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
4252 		PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
4253 		goto done;
4254 	}
4255 #endif /* REASSOCIATION */
4256 	tmp_priv->report_scan_result = MTRUE;
4257 	ret = woal_request_userscan(tmp_priv, MOAL_IOCTL_WAIT, scan_cfg);
4258 	woal_sched_timeout(5);
4259 #ifdef REASSOCIATION
4260 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
4261 #endif
4262 done:
4263 	if (role == MLAN_BSS_ROLE_UAP) {
4264 		if (MLAN_STATUS_SUCCESS !=
4265 		    woal_role_switch(tmp_priv, MOAL_IOCTL_WAIT,
4266 				     MLAN_BSS_ROLE_UAP)) {
4267 			PRINTM(MERROR, "role switch back to uap fail\n");
4268 			ret = MLAN_STATUS_FAILURE;
4269 		}
4270 	}
4271 	if (band_change) {
4272 		if (woal_setget_bandcfg(tmp_priv, MLAN_ACT_SET, &org_bandcfg)) {
4273 			PRINTM(MERROR, "restore bandcfg fail\n");
4274 			ret = MLAN_STATUS_FAILURE;
4275 		}
4276 	}
4277 	LEAVE();
4278 	return ret;
4279 }
4280 #endif
4281 
woal_find_wps_ie_in_probereq(const t_u8 * ie,int len)4282 static int woal_find_wps_ie_in_probereq(const t_u8 *ie, int len)
4283 {
4284 	int left_len = len;
4285 	const t_u8 *pos = ie;
4286 	t_u8 ie_id, ie_len;
4287 	IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
4288 	const u8 wps_oui[4] = {0x00, 0x50, 0xf2, 0x04};
4289 
4290 	while (left_len >= 2) {
4291 		ie_id = *pos;
4292 		ie_len = *(pos + 1);
4293 		if ((ie_len + 2) > left_len)
4294 			break;
4295 		if (ie_id == VENDOR_SPECIFIC_221) {
4296 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
4297 			if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui,
4298 				    sizeof(pvendor_ie->vend_hdr.oui)) &&
4299 			    pvendor_ie->vend_hdr.oui_type == wps_oui[3])
4300 				return MTRUE;
4301 		}
4302 
4303 		pos += (ie_len + 2);
4304 		left_len -= (ie_len + 2);
4305 	}
4306 
4307 	return MFALSE;
4308 }
4309 
4310 #ifdef UAP_CFG80211
4311 /** scan result expired value */
4312 #define SCAN_RESULT_EXPIRTED 1
4313 /**
4314  *  @brief check if the scan result expired
4315  *
4316  *  @param priv         A pointer to moal_private
4317  *
4318  *
4319  *  @return             MTRUE/MFALSE;
4320  */
woal_is_uap_scan_result_expired(moal_private * priv)4321 static t_u8 woal_is_uap_scan_result_expired(moal_private *priv)
4322 {
4323 	mlan_scan_resp scan_resp;
4324 	wifi_timeval t;
4325 	ENTER();
4326 	if (MLAN_STATUS_SUCCESS !=
4327 	    woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
4328 		LEAVE();
4329 		return MTRUE;
4330 	}
4331 	if (!scan_resp.num_in_scan_table) {
4332 		LEAVE();
4333 		return MTRUE;
4334 	}
4335 	woal_get_monotonic_time(&t);
4336 	if (t.time_sec > (scan_resp.age_in_secs + SCAN_RESULT_EXPIRTED)) {
4337 		LEAVE();
4338 		return MTRUE;
4339 	}
4340 	LEAVE();
4341 	return MFALSE;
4342 }
4343 #endif
4344 
4345 /**
4346  *  @brief check if the scan result ageout
4347  *
4348  *  @param priv         A pointer to moal_private
4349  *
4350  *
4351  *  @return             MTRUE/MFALSE;
4352  */
wlan_check_scan_table_ageout(moal_private * priv)4353 t_u8 wlan_check_scan_table_ageout(moal_private *priv)
4354 {
4355 	mlan_scan_resp scan_resp;
4356 	wifi_timeval t;
4357 	ENTER();
4358 	if (MLAN_STATUS_SUCCESS !=
4359 	    woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
4360 		LEAVE();
4361 		return MFALSE;
4362 	}
4363 	woal_get_monotonic_time(&t);
4364 #define CFG80211_SCAN_RESULT_AGEOUT 10
4365 	if (t.time_sec >
4366 	    (scan_resp.age_in_secs + CFG80211_SCAN_RESULT_AGEOUT)) {
4367 		LEAVE();
4368 		return MFALSE;
4369 	}
4370 	PRINTM(MCMND, "Scan: Keep Previous result\n");
4371 	LEAVE();
4372 	return MTRUE;
4373 }
4374 
4375 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
4376 /**
4377  * @brief Request the driver to do a scan. Always returning
4378  * zero meaning that the scan request is given to driver,
4379  * and will be valid until passed to cfg80211_scan_done().
4380  * To inform scan results, call cfg80211_inform_bss().
4381  *
4382  * @param wiphy           A pointer to wiphy structure
4383  * @param request         A pointer to cfg80211_scan_request structure
4384  *
4385  * @return                0 -- success, otherwise fail
4386  */
woal_cfg80211_scan(struct wiphy * wiphy,struct cfg80211_scan_request * request)4387 static int woal_cfg80211_scan(struct wiphy *wiphy,
4388 			      struct cfg80211_scan_request *request)
4389 #else
4390 /**
4391  * @brief Request the driver to do a scan. Always returning
4392  * zero meaning that the scan request is given to driver,
4393  * and will be valid until passed to cfg80211_scan_done().
4394  * To inform scan results, call cfg80211_inform_bss().
4395  *
4396  * @param wiphy           A pointer to wiphy structure
4397  * @param dev             A pointer to net_device structure
4398  * @param request         A pointer to cfg80211_scan_request structure
4399  *
4400  * @return                0 -- success, otherwise fail
4401  */
4402 static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
4403 			      struct cfg80211_scan_request *request)
4404 #endif
4405 {
4406 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
4407 	struct net_device *dev = request->wdev->netdev;
4408 #endif
4409 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
4410 	wlan_user_scan_cfg *scan_req = NULL;
4411 	mlan_bss_info bss_info;
4412 	mlan_scan_cfg scan_cfg;
4413 	struct ieee80211_channel *chan;
4414 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
4415 	t_u8 buf[ETH_ALEN];
4416 #endif
4417 	int ret = 0, i;
4418 	unsigned long flags;
4419 
4420 	ENTER();
4421 
4422 	PRINTM(MINFO, "Received scan request on %s\n", dev->name);
4423 	if (priv->phandle->driver_status) {
4424 		PRINTM(MERROR,
4425 		       "Block woal_cfg80211_scan in abnormal driver state\n");
4426 		LEAVE();
4427 		return -EFAULT;
4428 	}
4429 	if (priv->phandle->scan_pending_on_block == MTRUE) {
4430 		PRINTM(MCMND, "scan already in processing...\n");
4431 		LEAVE();
4432 		return -EAGAIN;
4433 	}
4434 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
4435 	if (priv->last_event & EVENT_BG_SCAN_REPORT) {
4436 		PRINTM(MCMND, "block scan while pending BGSCAN result\n");
4437 		priv->last_event = 0;
4438 		LEAVE();
4439 		return -EAGAIN;
4440 	}
4441 #endif
4442 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
4443 #ifdef WIFI_DIRECT_SUPPORT
4444 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
4445 	if (priv->phandle->is_go_timer_set &&
4446 	    priv->wdev->iftype != NL80211_IFTYPE_P2P_GO) {
4447 		PRINTM(MCMND, "block scan in go timer....\n");
4448 		LEAVE();
4449 		return -EAGAIN;
4450 	}
4451 #endif
4452 #endif
4453 #endif
4454 	cancel_delayed_work(&priv->phandle->scan_timeout_work);
4455 	priv->phandle->fake_scan_complete = priv->fake_scan_complete;
4456 	if (priv->fake_scan_complete) {
4457 		PRINTM(MEVENT, "fake scan complete flag is on\n");
4458 		priv->phandle->scan_request = request;
4459 		queue_delayed_work(priv->phandle->evt_workqueue,
4460 				   &priv->phandle->scan_timeout_work,
4461 				   msecs_to_jiffies(1000));
4462 		return ret;
4463 	}
4464 	memset(&bss_info, 0, sizeof(bss_info));
4465 	if (MLAN_STATUS_SUCCESS ==
4466 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
4467 		if (bss_info.scan_block) {
4468 			PRINTM(MEVENT, "Block scan in mlan module\n");
4469 			return -EAGAIN;
4470 		}
4471 	}
4472 	if (priv->phandle->scan_request &&
4473 	    priv->phandle->scan_request != request) {
4474 		PRINTM(MCMND,
4475 		       "different scan_request is coming before previous one is finished on %s...\n",
4476 		       dev->name);
4477 		LEAVE();
4478 		return -EBUSY;
4479 	}
4480 
4481 	spin_lock_irqsave(&priv->phandle->scan_req_lock, flags);
4482 	priv->phandle->scan_request = request;
4483 	spin_unlock_irqrestore(&priv->phandle->scan_req_lock, flags);
4484 	if (is_zero_timeval(priv->phandle->scan_time_start)) {
4485 		woal_get_monotonic_time(&priv->phandle->scan_time_start);
4486 		PRINTM(MINFO, "%s : start_timeval=%d:%d \n", __func__,
4487 		       priv->phandle->scan_time_start.time_sec,
4488 		       priv->phandle->scan_time_start.time_usec);
4489 	}
4490 	scan_req = kmalloc(sizeof(wlan_user_scan_cfg), GFP_KERNEL);
4491 	if (!scan_req) {
4492 		PRINTM(MERROR, "Failed to alloc memory for scan_req\n");
4493 		LEAVE();
4494 		return -ENOMEM;
4495 	}
4496 	memset(scan_req, 0x00, sizeof(wlan_user_scan_cfg));
4497 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
4498 	if (!is_broadcast_ether_addr(request->bssid)) {
4499 		moal_memcpy_ext(priv->phandle, scan_req->specific_bssid,
4500 				request->bssid, ETH_ALEN,
4501 				sizeof(scan_req->specific_bssid));
4502 		PRINTM(MIOCTL, "scan: bssid=" MACSTR "\n",
4503 		       MAC2STR(scan_req->specific_bssid));
4504 	}
4505 #endif
4506 
4507 	memset(&scan_cfg, 0, sizeof(mlan_scan_cfg));
4508 	woal_get_scan_config(priv, &scan_cfg);
4509 #ifdef WIFI_DIRECT_SUPPORT
4510 	if (priv->phandle->miracast_mode)
4511 		scan_req->scan_chan_gap = priv->phandle->scan_chan_gap;
4512 	else {
4513 #endif
4514 		if (scan_cfg.scan_chan_gap)
4515 			scan_req->scan_chan_gap = scan_cfg.scan_chan_gap;
4516 		else if (woal_is_any_interface_active(priv->phandle))
4517 			scan_req->scan_chan_gap = priv->phandle->scan_chan_gap;
4518 		else
4519 			scan_req->scan_chan_gap = 0;
4520 #ifdef WIFI_DIRECT_SUPPORT
4521 	}
4522 #endif
4523 	/** indicate FW, gap is optional */
4524 	if (scan_req->scan_chan_gap && priv->phandle->pref_mac)
4525 		scan_req->scan_chan_gap |= GAP_FLAG_OPTIONAL;
4526 
4527 	scan_req->scan_cfg_only = MTRUE;
4528 	if (scan_cfg.ext_scan == 3)
4529 		scan_req->ext_scan_type = EXT_SCAN_ENHANCE;
4530 
4531 	for (i = 0; i < priv->phandle->scan_request->n_ssids; i++) {
4532 		moal_memcpy_ext(priv->phandle, scan_req->ssid_list[i].ssid,
4533 				priv->phandle->scan_request->ssids[i].ssid,
4534 				priv->phandle->scan_request->ssids[i].ssid_len,
4535 				sizeof(scan_req->ssid_list[i].ssid));
4536 		if (priv->phandle->scan_request->ssids[i].ssid_len)
4537 			scan_req->ssid_list[i].max_len = 0;
4538 		else
4539 			scan_req->ssid_list[i].max_len = 0xff;
4540 		PRINTM(MIOCTL, "scan: ssid=%s\n", scan_req->ssid_list[i].ssid);
4541 	}
4542 #if defined(WIFI_DIRECT_SUPPORT)
4543 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
4544 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
4545 	    priv->phandle->scan_request->n_ssids) {
4546 		if (!memcmp(scan_req->ssid_list[0].ssid, "DIRECT-", 7))
4547 			scan_req->ssid_list[0].max_len = 0xfe;
4548 	}
4549 #endif
4550 #endif
4551 	for (i = 0; i < (int)MIN(WLAN_USER_SCAN_CHAN_MAX,
4552 				 priv->phandle->scan_request->n_channels);
4553 	     i++) {
4554 		chan = priv->phandle->scan_request->channels[i];
4555 		scan_req->chan_list[i].chan_number = chan->hw_value;
4556 		scan_req->chan_list[i].radio_type =
4557 			woal_ieee_band_to_radio_type(chan->band);
4558 		if ((chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) ||
4559 		    !priv->phandle->scan_request->n_ssids)
4560 			scan_req->chan_list[i].scan_type =
4561 				MLAN_SCAN_TYPE_PASSIVE;
4562 		else if (chan->flags & IEEE80211_CHAN_RADAR)
4563 			scan_req->chan_list[i].scan_type =
4564 				MLAN_SCAN_TYPE_PASSIVE_TO_ACTIVE;
4565 		else
4566 			scan_req->chan_list[i].scan_type =
4567 				MLAN_SCAN_TYPE_ACTIVE;
4568 		PRINTM(MCMD_D, "cfg80211_scan: chan=%d chan->flag=0x%x\n",
4569 		       chan->hw_value, chan->flags);
4570 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
4571 		scan_req->chan_list[i].scan_time =
4572 			priv->phandle->scan_request->duration;
4573 #else
4574 		scan_req->chan_list[i].scan_time = 0;
4575 #endif
4576 #if defined(WIFI_DIRECT_SUPPORT)
4577 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
4578 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
4579 		    priv->phandle->scan_request->n_ssids) {
4580 			if (!memcmp(scan_req->ssid_list[0].ssid, "DIRECT-", 7))
4581 				scan_req->chan_list[i].scan_time =
4582 					MIN_SPECIFIC_SCAN_CHAN_TIME;
4583 		}
4584 #endif
4585 #endif
4586 #ifdef WIFI_DIRECT_SUPPORT
4587 		if (priv->phandle->miracast_mode)
4588 			scan_req->chan_list[i].scan_time =
4589 				priv->phandle->miracast_scan_time;
4590 		else if (woal_is_any_interface_active(priv->phandle)) {
4591 			if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
4592 				scan_req->chan_list[i].scan_time =
4593 					INIT_PASSIVE_SCAN_CHAN_TIME;
4594 			else
4595 				scan_req->chan_list[i].scan_time =
4596 					MIN_SPECIFIC_SCAN_CHAN_TIME;
4597 		}
4598 #endif
4599 #ifdef UAP_CFG80211
4600 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
4601 			if (!woal_is_uap_scan_result_expired(priv))
4602 				scan_req->chan_list[i].scan_time =
4603 					MIN_SPECIFIC_SCAN_CHAN_TIME;
4604 
4605 			else
4606 				scan_req->chan_list[i].scan_time =
4607 					PASSIVE_SCAN_CHAN_TIME;
4608 		}
4609 #endif
4610 	}
4611 	if (priv->phandle->scan_request->ie &&
4612 	    priv->phandle->scan_request->ie_len) {
4613 		if (woal_find_wps_ie_in_probereq(
4614 			    (t_u8 *)priv->phandle->scan_request->ie,
4615 			    priv->phandle->scan_request->ie_len)) {
4616 			PRINTM(MIOCTL,
4617 			       "Notify firmware only keep probe response\n");
4618 			scan_req->proberesp_only = MTRUE;
4619 		}
4620 		if (MLAN_STATUS_SUCCESS !=
4621 		    woal_cfg80211_mgmt_frame_ie(
4622 			    priv, NULL, 0, NULL, 0, NULL, 0,
4623 			    (t_u8 *)priv->phandle->scan_request->ie,
4624 			    priv->phandle->scan_request->ie_len,
4625 			    MGMT_MASK_PROBE_REQ, MOAL_IOCTL_WAIT)) {
4626 			PRINTM(MERROR, "Fail to set scan request IE\n");
4627 			ret = -EFAULT;
4628 			goto done;
4629 		}
4630 	} else {
4631 		/** Clear SCAN IE in Firmware */
4632 		if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
4633 			if (MLAN_STATUS_SUCCESS !=
4634 			    woal_cfg80211_mgmt_frame_ie(
4635 				    priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
4636 				    MGMT_MASK_PROBE_REQ, MOAL_IOCTL_WAIT)) {
4637 				PRINTM(MERROR,
4638 				       "Fail to clear scan request IE\n");
4639 				ret = -EFAULT;
4640 				goto done;
4641 			}
4642 		}
4643 	}
4644 #ifdef UAP_CFG80211
4645 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
4646 		/** use sync scan for uap */
4647 		ret = woal_uap_scan(priv, scan_req);
4648 		if (!ret) {
4649 			kfree(scan_req);
4650 			LEAVE();
4651 			return ret;
4652 		} else {
4653 			PRINTM(MERROR, "Uap SCAN failure\n");
4654 			goto done;
4655 		}
4656 	}
4657 #endif
4658 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
4659 	if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
4660 		PRINTM(MIOCTL, "NL80211_SCAN_FLAG_RANDOM_ADDR is set\n");
4661 		get_random_bytes(buf, ETH_ALEN);
4662 		for (i = 0; i < ETH_ALEN; i++) {
4663 			buf[i] &= ~request->mac_addr_mask[i];
4664 			buf[i] |= request->mac_addr[i] &
4665 				  request->mac_addr_mask[i];
4666 		}
4667 		moal_memcpy_ext(priv->phandle, scan_req->random_mac, buf,
4668 				ETH_ALEN, sizeof(scan_req->random_mac));
4669 	} else
4670 #endif
4671 		moal_memcpy_ext(priv->phandle, scan_req->random_mac,
4672 				priv->random_mac, ETH_ALEN,
4673 				sizeof(scan_req->random_mac));
4674 
4675 	PRINTM(MCMND, "wlan:random_mac " MACSTR "\n",
4676 	       MAC2STR(scan_req->random_mac));
4677 	if (priv->phandle->params.keep_previous_scan)
4678 		scan_req->keep_previous_scan =
4679 			wlan_check_scan_table_ageout(priv);
4680 
4681 	if (MLAN_STATUS_SUCCESS != woal_do_scan(priv, scan_req)) {
4682 		PRINTM(MERROR, "woal_do_scan fails!\n");
4683 		ret = -EAGAIN;
4684 		goto done;
4685 	}
4686 done:
4687 	if (ret) {
4688 		spin_lock_irqsave(&priv->phandle->scan_req_lock, flags);
4689 		woal_cfg80211_scan_done(request, MTRUE);
4690 		priv->phandle->scan_request = NULL;
4691 		priv->phandle->scan_priv = NULL;
4692 		spin_unlock_irqrestore(&priv->phandle->scan_req_lock, flags);
4693 	} else {
4694 		PRINTM(MMSG, "wlan: %s START SCAN\n", dev->name);
4695 		queue_delayed_work(
4696 			priv->phandle->evt_workqueue,
4697 			&priv->phandle->scan_timeout_work,
4698 			msecs_to_jiffies(priv->phandle->scan_timeout));
4699 	}
4700 	kfree(scan_req);
4701 	LEAVE();
4702 	return ret;
4703 }
4704 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
woal_cfg80211_abort_scan(struct wiphy * wiphy,struct wireless_dev * wdev)4705 static void woal_cfg80211_abort_scan(struct wiphy *wiphy,
4706 				     struct wireless_dev *wdev)
4707 {
4708 	moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
4709 	ENTER();
4710 	PRINTM(MMSG, "wlan: ABORT SCAN start\n");
4711 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
4712 	LEAVE();
4713 	return;
4714 }
4715 #endif
4716 /**
4717  * @brief construct and send ft action request
4718  *
4719  *  @param priv     A pointer to moal_private structure
4720  * @param ie       A pointer to ft ie
4721  * @param le       Value of ie len
4722  * @param bssid    A pointer to target ap bssid
4723  * @
4724  * @return         0 -- success, otherwise fail
4725  */
woal_send_ft_action_requst(moal_private * priv,t_u8 * ie,t_u8 len,t_u8 * bssid,t_u8 * target_ap)4726 static int woal_send_ft_action_requst(moal_private *priv, t_u8 *ie, t_u8 len,
4727 				      t_u8 *bssid, t_u8 *target_ap)
4728 {
4729 	IEEE80211_MGMT *mgmt = NULL;
4730 	mlan_status status = MLAN_STATUS_SUCCESS;
4731 	pmlan_buffer pmbuf = NULL;
4732 	t_u32 pkt_type;
4733 	t_u32 tx_control;
4734 	t_u16 packet_len = 0;
4735 	t_u8 addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
4736 	int ret = 0;
4737 
4738 	ENTER();
4739 
4740 	/* pkt_type + tx_control */
4741 #define HEADER_SIZE 8
4742 	/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl + addr4*/
4743 #define MGMT_HEADER_LEN (2 + 2 + 6 + 6 + 6 + 2 + 6)
4744 	/* 14   = category + action + sta addr + target ap */
4745 #define FT_REQUEST_LEN 14
4746 	packet_len = (t_u16)len + MGMT_HEADER_LEN + FT_REQUEST_LEN;
4747 	pmbuf = woal_alloc_mlan_buffer(priv->phandle,
4748 				       MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
4749 					       packet_len + sizeof(packet_len));
4750 	if (!pmbuf) {
4751 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
4752 		ret = -ENOMEM;
4753 		goto done;
4754 	}
4755 
4756 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
4757 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
4758 	tx_control = 0;
4759 	/* Add pkt_type and tx_control */
4760 	moal_memcpy_ext(priv->phandle, pmbuf->pbuf + pmbuf->data_offset,
4761 			&pkt_type, sizeof(pkt_type), sizeof(pkt_type));
4762 	moal_memcpy_ext(priv->phandle,
4763 			pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
4764 			&tx_control, sizeof(tx_control), sizeof(tx_control));
4765 	/*Add packet len*/
4766 	moal_memcpy_ext(priv->phandle,
4767 			pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
4768 			&packet_len, sizeof(packet_len), sizeof(packet_len));
4769 
4770 	mgmt = (IEEE80211_MGMT *)(pmbuf->pbuf + pmbuf->data_offset +
4771 				  HEADER_SIZE + sizeof(packet_len));
4772 	memset(mgmt, 0, MGMT_HEADER_LEN);
4773 	mgmt->frame_control =
4774 		woal_cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
4775 	moal_memcpy_ext(priv->phandle, mgmt->da, bssid, ETH_ALEN,
4776 			sizeof(mgmt->da));
4777 	moal_memcpy_ext(priv->phandle, mgmt->sa, priv->current_addr, ETH_ALEN,
4778 			sizeof(mgmt->sa));
4779 	moal_memcpy_ext(priv->phandle, mgmt->bssid, bssid, ETH_ALEN,
4780 			sizeof(mgmt->bssid));
4781 	moal_memcpy_ext(priv->phandle, mgmt->addr4, addr, ETH_ALEN,
4782 			sizeof(mgmt->addr4));
4783 
4784 	mgmt->u.ft_req.category = 0x06; /**ft action code 0x6*/
4785 	mgmt->u.ft_req.action = 0x1; /**ft action request*/
4786 	moal_memcpy_ext(priv->phandle, mgmt->u.ft_req.sta_addr,
4787 			priv->current_addr, ETH_ALEN,
4788 			sizeof(mgmt->u.ft_req.sta_addr));
4789 	moal_memcpy_ext(priv->phandle, mgmt->u.ft_req.target_ap_addr, target_ap,
4790 			ETH_ALEN, sizeof(mgmt->u.ft_req.target_ap_addr));
4791 
4792 	if (ie && len)
4793 		moal_memcpy_ext(priv->phandle,
4794 				(t_u8 *)(&mgmt->u.ft_req.variable), ie, len,
4795 				len);
4796 
4797 	pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
4798 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
4799 	pmbuf->bss_index = priv->bss_index;
4800 	pmbuf->priority = 7;
4801 
4802 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
4803 
4804 	switch (status) {
4805 	case MLAN_STATUS_PENDING:
4806 		atomic_inc(&priv->phandle->tx_pending);
4807 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
4808 		break;
4809 	case MLAN_STATUS_SUCCESS:
4810 		woal_free_mlan_buffer(priv->phandle, pmbuf);
4811 		break;
4812 	case MLAN_STATUS_FAILURE:
4813 	default:
4814 		woal_free_mlan_buffer(priv->phandle, pmbuf);
4815 		ret = -EFAULT;
4816 		break;
4817 	}
4818 
4819 done:
4820 	LEAVE();
4821 	return ret;
4822 }
4823 /**
4824  * @brief construct and send ft auth request
4825  *
4826  *  @param priv     A pointer to moal_private structure
4827  * @param ie       A pointer to ft ie
4828  * @param le       Value of ie len
4829  * @param bssid    A pointer to target ap bssid
4830  * @
4831  * @return         0 -- success, otherwise fail
4832  */
woal_send_ft_auth_requst(moal_private * priv,t_u8 * ie,t_u8 len,t_u8 * bssid)4833 static int woal_send_ft_auth_requst(moal_private *priv, t_u8 *ie, t_u8 len,
4834 				    t_u8 *bssid)
4835 {
4836 	IEEE80211_MGMT *mgmt = NULL;
4837 	mlan_status status = MLAN_STATUS_SUCCESS;
4838 	pmlan_buffer pmbuf = NULL;
4839 	t_u32 pkt_type;
4840 	t_u32 tx_control;
4841 	t_u16 packet_len = 0;
4842 	t_u8 addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
4843 	int ret = 0;
4844 
4845 	ENTER();
4846 	/* pkt_type + tx_control */
4847 #define HEADER_SIZE 8
4848 	/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl + addr4*/
4849 #define MGMT_HEADER_LEN (2 + 2 + 6 + 6 + 6 + 2 + 6)
4850 	/* 6   = auth_alg + auth_transaction +auth_status*/
4851 #define AUTH_BODY_LEN 6
4852 	packet_len = (t_u16)len + MGMT_HEADER_LEN + AUTH_BODY_LEN;
4853 	pmbuf = woal_alloc_mlan_buffer(priv->phandle,
4854 				       MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
4855 					       packet_len + sizeof(packet_len));
4856 	if (!pmbuf) {
4857 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
4858 		ret = -ENOMEM;
4859 		goto done;
4860 	}
4861 
4862 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
4863 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
4864 	tx_control = 0;
4865 	/* Add pkt_type and tx_control */
4866 	moal_memcpy_ext(priv->phandle, pmbuf->pbuf + pmbuf->data_offset,
4867 			&pkt_type, sizeof(pkt_type), sizeof(pkt_type));
4868 	moal_memcpy_ext(priv->phandle,
4869 			pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type),
4870 			&tx_control, sizeof(tx_control), sizeof(tx_control));
4871 	/*Add packet len*/
4872 	moal_memcpy_ext(priv->phandle,
4873 			pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
4874 			&packet_len, sizeof(packet_len), sizeof(packet_len));
4875 
4876 	mgmt = (IEEE80211_MGMT *)(pmbuf->pbuf + pmbuf->data_offset +
4877 				  HEADER_SIZE + sizeof(packet_len));
4878 	memset(mgmt, 0, MGMT_HEADER_LEN);
4879 	mgmt->frame_control =
4880 		woal_cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
4881 	moal_memcpy_ext(priv->phandle, mgmt->da, bssid, ETH_ALEN,
4882 			sizeof(mgmt->da));
4883 	moal_memcpy_ext(priv->phandle, mgmt->sa, priv->current_addr, ETH_ALEN,
4884 			sizeof(mgmt->sa));
4885 	moal_memcpy_ext(priv->phandle, mgmt->bssid, bssid, ETH_ALEN,
4886 			sizeof(mgmt->bssid));
4887 	moal_memcpy_ext(priv->phandle, mgmt->addr4, addr, ETH_ALEN,
4888 			sizeof(mgmt->addr4));
4889 
4890 	mgmt->u.auth.auth_alg = woal_cpu_to_le16(WLAN_AUTH_FT);
4891 	mgmt->u.auth.auth_transaction = woal_cpu_to_le16(1);
4892 	mgmt->u.auth.status_code = woal_cpu_to_le16(0);
4893 	if (ie && len)
4894 		moal_memcpy_ext(priv->phandle, (t_u8 *)(&mgmt->u.auth.variable),
4895 				ie, len, len);
4896 
4897 	pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
4898 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
4899 	pmbuf->bss_index = priv->bss_index;
4900 	pmbuf->priority = 7;
4901 
4902 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
4903 
4904 	switch (status) {
4905 	case MLAN_STATUS_PENDING:
4906 		atomic_inc(&priv->phandle->tx_pending);
4907 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
4908 		break;
4909 	case MLAN_STATUS_SUCCESS:
4910 		woal_free_mlan_buffer(priv->phandle, pmbuf);
4911 		break;
4912 	case MLAN_STATUS_FAILURE:
4913 	default:
4914 		woal_free_mlan_buffer(priv->phandle, pmbuf);
4915 		ret = -EFAULT;
4916 		break;
4917 	}
4918 
4919 done:
4920 	LEAVE();
4921 	return ret;
4922 }
4923 
4924 /**
4925  * @brief connect the AP through ft over air.
4926  *
4927  * @param priv            A pointer to moal_private structure
4928  * @param bssid           A pointer to bssid
4929  * @param chan            struct ieee80211_channel
4930  *
4931  * @return                0 -- success, otherwise fail
4932  */
woal_connect_ft_over_air(moal_private * priv,t_u8 * bssid,struct ieee80211_channel * chan)4933 static int woal_connect_ft_over_air(moal_private *priv, t_u8 *bssid,
4934 				    struct ieee80211_channel *chan)
4935 {
4936 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
4937 	t_u8 status = 0;
4938 #endif
4939 
4940 	t_u8 wait_option = MOAL_IOCTL_WAIT;
4941 	int ret = 0;
4942 	long timeout = 0;
4943 
4944 	ENTER();
4945 
4946 	if (!bssid) {
4947 		PRINTM(MERROR,
4948 		       "Invalid bssid, unable to connect AP to through FT\n");
4949 		LEAVE();
4950 		return -EFAULT;
4951 	}
4952 
4953 	/*enable auth register frame*/
4954 	woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MTRUE);
4955 
4956 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
4957 	woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MFALSE, &status,
4958 					    chan, 0, AUTH_TX_DEFAULT_WAIT_TIME);
4959 #endif
4960 
4961 	/*construct auth request and send out*/
4962 	woal_send_ft_auth_requst(priv, priv->ft_ie, priv->ft_ie_len, bssid);
4963 	PRINTM(MMSG, "wlan: send out FT auth,wait for auth response\n");
4964 	/*wait until received auth response*/
4965 	priv->ft_wait_condition = MFALSE;
4966 	timeout = wait_event_timeout(priv->ft_wait_q, priv->ft_wait_condition,
4967 				     1 * HZ);
4968 	if (!timeout) {
4969 		/*connet fail */
4970 		if (!priv->ft_roaming_triggered_by_driver) {
4971 			woal_inform_bss_from_scan_result(priv, NULL,
4972 							 wait_option);
4973 			cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
4974 						NULL, 0, NULL, 0,
4975 						WLAN_STATUS_SUCCESS,
4976 						GFP_KERNEL);
4977 		}
4978 		priv->ft_roaming_triggered_by_driver = MFALSE;
4979 		PRINTM(MMSG, "wlan: keep connected to bssid " MACSTR "\n",
4980 		       MAC2STR(priv->cfg_bssid));
4981 	} else {
4982 		PRINTM(MMSG, "wlan: FT auth received \n");
4983 		moal_memcpy_ext(priv->phandle, priv->target_ap_bssid, bssid,
4984 				ETH_ALEN, sizeof(priv->target_ap_bssid));
4985 	}
4986 
4987 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
4988 	woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MTRUE, &status,
4989 					    NULL, 0, 0);
4990 #endif
4991 
4992 	woal_mgmt_frame_register(priv, IEEE80211_STYPE_AUTH, MFALSE);
4993 
4994 	LEAVE();
4995 	return ret;
4996 }
4997 
4998 /**
4999  * @brief connect the AP through ft over DS.
5000  *
5001  * @param priv            A pointer to moal_private structure
5002  * @param bssid           A pointer to bssid
5003  * @param chan            struct ieee80211_channel
5004  *
5005  * @return                0 -- success, otherwise fail
5006  */
woal_connect_ft_over_ds(moal_private * priv,t_u8 * bssid,struct ieee80211_channel * pchan)5007 static int woal_connect_ft_over_ds(moal_private *priv, t_u8 *bssid,
5008 				   struct ieee80211_channel *pchan)
5009 {
5010 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
5011 	t_u8 status = 0;
5012 #endif
5013 	t_u8 wait_option = MOAL_IOCTL_WAIT;
5014 	int ret = 0;
5015 	long timeout = 0;
5016 
5017 	ENTER();
5018 
5019 	if (priv->media_connected) {
5020 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
5021 		woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MFALSE,
5022 						    &status, pchan, 0, 1200);
5023 #endif
5024 		/*construct ft action request and send out*/
5025 		woal_send_ft_action_requst(priv, priv->ft_ie, priv->ft_ie_len,
5026 					   (t_u8 *)priv->cfg_bssid, bssid);
5027 		PRINTM(MMSG,
5028 		       "wlan: send out FT request,wait for FT response\n");
5029 		/*wait until received auth response*/
5030 		priv->ft_wait_condition = MFALSE;
5031 		timeout = wait_event_timeout(priv->ft_wait_q,
5032 					     priv->ft_wait_condition, 1 * HZ);
5033 		if (!timeout) {
5034 			/*go over air, as current AP may be unreachable */
5035 			PRINTM(MMSG, "wlan: go over air\n");
5036 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
5037 			woal_cfg80211_remain_on_channel_cfg(
5038 				priv, wait_option, MTRUE, &status, NULL, 0, 0);
5039 #endif
5040 			woal_connect_ft_over_air(priv, bssid, pchan);
5041 			LEAVE();
5042 			return ret;
5043 		} else {
5044 			PRINTM(MMSG, "wlan: received FT response\n");
5045 			moal_memcpy_ext(priv->phandle, priv->target_ap_bssid,
5046 					bssid, ETH_ALEN,
5047 					sizeof(priv->target_ap_bssid));
5048 		}
5049 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
5050 		woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MTRUE,
5051 						    &status, NULL, 0, 0);
5052 #endif
5053 	}
5054 
5055 	LEAVE();
5056 	return ret;
5057 }
5058 
5059 /**
5060  * @brief start FT Roaming.
5061  *
5062  * @param priv               A pointer to moal_private structure
5063  * @param ssid_bssid         A pointer to mlan_ssid_bssid structure
5064  *
5065  *
5066  * @return                   0 -- success, otherwise fail
5067  */
woal_start_ft_roaming(moal_private * priv,mlan_ssid_bssid * ssid_bssid)5068 static int woal_start_ft_roaming(moal_private *priv,
5069 				 mlan_ssid_bssid *ssid_bssid)
5070 {
5071 	struct ieee80211_channel chan;
5072 	int ret = 0;
5073 
5074 	ENTER();
5075 
5076 	PRINTM(MEVENT, "Try to start FT roaming......\n");
5077 	chan.band = (ssid_bssid->channel < 36) ? IEEE80211_BAND_2GHZ :
5078 						 IEEE80211_BAND_5GHZ;
5079 	chan.center_freq = ieee80211_channel_to_frequency(ssid_bssid->channel
5080 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
5081 							  ,
5082 							  chan.band
5083 #endif
5084 	);
5085 
5086 	if (!(priv->last_event & EVENT_PRE_BCN_LOST) &&
5087 	    (ssid_bssid->ft_cap & MBIT(0))) {
5088 		woal_connect_ft_over_ds(priv, (t_u8 *)&ssid_bssid->bssid,
5089 					&chan);
5090 	} else {
5091 		/*if pre beacon lost, it need to send auth request instead ft
5092 		 * action request when ft over ds */
5093 		woal_connect_ft_over_air(priv, (t_u8 *)&ssid_bssid->bssid,
5094 					 &chan);
5095 	}
5096 
5097 	LEAVE();
5098 	return ret;
5099 }
5100 /**
5101  * @brief Request the driver to connect to the ESS with
5102  * the specified parameters from kernel
5103  *
5104  * @param wiphy           A pointer to wiphy structure
5105  * @param dev             A pointer to net_device structure
5106  * @param sme             A pointer to cfg80211_connect_params structure
5107  *
5108  * @return                0 -- success, otherwise fail
5109  */
woal_cfg80211_connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)5110 static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
5111 				 struct cfg80211_connect_params *sme)
5112 {
5113 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5114 	int ret = 0;
5115 	mlan_bss_info bss_info;
5116 	unsigned long flags;
5117 	mlan_ds_misc_assoc_rsp *assoc_rsp = NULL;
5118 	IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
5119 	mlan_ds_misc_assoc_req assoc_req;
5120 
5121 	mlan_ssid_bssid *ssid_bssid = NULL;
5122 	moal_handle *handle = priv->phandle;
5123 	int i;
5124 
5125 	ENTER();
5126 
5127 	PRINTM(MINFO, "Received association request on %s\n", dev->name);
5128 	priv->cfg_disconnect = MFALSE;
5129 #ifdef UAP_CFG80211
5130 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
5131 		LEAVE();
5132 		return 0;
5133 	}
5134 #endif
5135 	if (priv->wdev->iftype != NL80211_IFTYPE_STATION
5136 #ifdef WIFI_DIRECT_SUPPORT
5137 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
5138 	    && priv->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT
5139 #endif /* KERNEL_VERSION */
5140 #endif /* WIFI_DIRECT_SUPPORT */
5141 	) {
5142 		PRINTM(MERROR,
5143 		       "Received infra assoc request when station not in infra mode\n");
5144 		LEAVE();
5145 		return -EINVAL;
5146 	}
5147 	ssid_bssid = kmalloc(sizeof(mlan_ssid_bssid), GFP_KERNEL);
5148 	if (!ssid_bssid) {
5149 		LEAVE();
5150 		return -EFAULT;
5151 	}
5152 	memset(ssid_bssid, 0, sizeof(mlan_ssid_bssid));
5153 	moal_memcpy_ext(priv->phandle, &ssid_bssid->ssid.ssid, sme->ssid,
5154 			sme->ssid_len, sizeof(ssid_bssid->ssid.ssid));
5155 	ssid_bssid->ssid.ssid_len = sme->ssid_len;
5156 	if (sme->bssid)
5157 		moal_memcpy_ext(priv->phandle, &ssid_bssid->bssid, sme->bssid,
5158 				ETH_ALEN, sizeof(ssid_bssid->bssid));
5159 	/* Not allowed to connect to the same AP which is already connected
5160 		with other interface */
5161 	for (i = 0; i < handle->priv_num; i++) {
5162 		if (handle->priv[i] != priv &&
5163 		    MTRUE == woal_is_connected(handle->priv[i], ssid_bssid)) {
5164 			PRINTM(MMSG,
5165 			       "wlan: already connected with other interface, bssid " MACSTR
5166 			       "\n",
5167 			       MAC2STR(handle->priv[i]->cfg_bssid));
5168 			kfree(ssid_bssid);
5169 			LEAVE();
5170 			return -EINVAL;
5171 		}
5172 	}
5173 
5174 	/** cancel pending scan */
5175 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
5176 
5177 #ifdef WIFI_DIRECT_SUPPORT
5178 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
5179 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
5180 	    (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
5181 	     priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
5182 		/* if bsstype == wifi direct, and iftype == station or p2p
5183 		 * client, that means wpa_supplicant wants to enable wifi direct
5184 		 * functionality, so we should init p2p client.
5185 		 *
5186 		 * Note that due to kernel iftype check, ICS wpa_supplicant
5187 		 * could not updaet iftype to init p2p client, so we have to
5188 		 * done it here.
5189 		 * */
5190 		if (MLAN_STATUS_SUCCESS !=
5191 		    woal_cfg80211_init_p2p_client(priv)) {
5192 			PRINTM(MERROR,
5193 			       "Init p2p client for wpa_supplicant failed.\n");
5194 			ret = -EFAULT;
5195 
5196 			kfree(ssid_bssid);
5197 			LEAVE();
5198 			return ret;
5199 		}
5200 	}
5201 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
5202 		/* WAR for P2P connection with vendor TV */
5203 		woal_sched_timeout(200);
5204 	}
5205 #endif
5206 #endif
5207 	/*11r roaming triggered by supplicant */
5208 	if (priv->media_connected && priv->ft_ie_len &&
5209 	    !(priv->ft_cap & MBIT(0))) {
5210 		/** get current bss info */
5211 		memset(&bss_info, 0, sizeof(bss_info));
5212 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
5213 		/** get target bss info */
5214 		if (MLAN_STATUS_SUCCESS !=
5215 		    woal_find_essid(priv, ssid_bssid, MOAL_IOCTL_WAIT)) {
5216 			ret = woal_cfg80211_connect_scan(priv, sme,
5217 							 MOAL_IOCTL_WAIT);
5218 			if (!ret) {
5219 				if (MLAN_STATUS_SUCCESS !=
5220 				    woal_find_best_network(priv,
5221 							   MOAL_IOCTL_WAIT,
5222 							   ssid_bssid)) {
5223 					PRINTM(MERROR,
5224 					       "can't find targe AP \n");
5225 					// LEAVE();
5226 					// return -EFAULT;
5227 				}
5228 			}
5229 		}
5230 		if (bss_info.mdid == ssid_bssid->ft_md &&
5231 		    bss_info.ft_cap == ssid_bssid->ft_cap) {
5232 			ret = woal_start_ft_roaming(priv, ssid_bssid);
5233 			LEAVE();
5234 			return 0;
5235 		}
5236 	}
5237 
5238 	priv->cfg_connect = MTRUE;
5239 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
5240 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
5241 	priv->assoc_status = 0;
5242 	assoc_rsp = kzalloc(sizeof(mlan_ds_misc_assoc_rsp), GFP_ATOMIC);
5243 	if (!assoc_rsp) {
5244 		PRINTM(MERROR, "Failed to allocate memory for assoc_rsp\n");
5245 		ret = -ENOMEM;
5246 		LEAVE();
5247 		return ret;
5248 	}
5249 	ret = woal_cfg80211_assoc(priv, (void *)sme, MOAL_IOCTL_WAIT,
5250 				  assoc_rsp);
5251 
5252 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
5253 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
5254 	if (!ret) {
5255 		passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp->assoc_resp_buf;
5256 		priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD;
5257 		woal_save_conn_params(priv, sme);
5258 		memset(&bss_info, 0, sizeof(bss_info));
5259 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
5260 		priv->channel = bss_info.bss_chan;
5261 		if (!ssid_bssid->ft_md) {
5262 			priv->ft_ie_len = 0;
5263 			priv->ft_pre_connect = MFALSE;
5264 			priv->ft_md = 0;
5265 			priv->ft_cap = 0;
5266 		}
5267 		memset(&assoc_req, 0, sizeof(mlan_ds_misc_assoc_req));
5268 		woal_get_assoc_req(priv, &assoc_req, MOAL_IOCTL_WAIT);
5269 	}
5270 	spin_lock_irqsave(&priv->connect_lock, flags);
5271 	priv->cfg_connect = MFALSE;
5272 	if (!ret && priv->media_connected) {
5273 		PRINTM(MMSG,
5274 		       "wlan: Connected to bssid " MACSTR " successfully\n",
5275 		       MAC2STR(priv->cfg_bssid));
5276 		spin_unlock_irqrestore(&priv->connect_lock, flags);
5277 		cfg80211_connect_result(
5278 			priv->netdev, priv->cfg_bssid, assoc_req.assoc_req_buf,
5279 			assoc_req.assoc_req_len, passoc_rsp->ie_buffer,
5280 			assoc_rsp->assoc_resp_len - ASSOC_RESP_FIXED_SIZE,
5281 			WLAN_STATUS_SUCCESS, GFP_KERNEL);
5282 	} else {
5283 		PRINTM(MINFO, "wlan: Failed to connect to bssid " MACSTR "\n",
5284 		       MAC2STR(priv->cfg_bssid));
5285 		memset(priv->cfg_bssid, 0, ETH_ALEN);
5286 		spin_unlock_irqrestore(&priv->connect_lock, flags);
5287 		cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
5288 					NULL, 0, woal_get_assoc_status(priv),
5289 					GFP_KERNEL);
5290 	}
5291 	kfree(ssid_bssid);
5292 	kfree(assoc_rsp);
5293 	assoc_rsp = NULL;
5294 	LEAVE();
5295 	return 0;
5296 }
5297 
5298 /**
5299  *  @brief This function will print diconnect reason code according
5300  *  to IEEE 802.11 spec
5301  *
5302  *  @param reason_code    reason code for the deauth/disaccoc
5303  *                        received from firmware
5304  *  @return        N/A
5305  */
woal_print_disconnect_reason(t_u16 reason_code)5306 static void woal_print_disconnect_reason(t_u16 reason_code)
5307 {
5308 	ENTER();
5309 
5310 	switch (reason_code) {
5311 	case MLAN_REASON_UNSPECIFIED:
5312 		PRINTM(MMSG, "wlan: REASON: Unspecified reason\n");
5313 		break;
5314 	case MLAN_REASON_PREV_AUTH_NOT_VALID:
5315 		PRINTM(MMSG,
5316 		       "wlan: REASON: Previous authentication no longer valid\n");
5317 		break;
5318 	case MLAN_REASON_DEAUTH_LEAVING:
5319 		PRINTM(MMSG,
5320 		       "wlan: REASON: (Deauth) Sending STA is leaving (or has left) IBSS or ESS\n");
5321 		break;
5322 	case MLAN_REASON_DISASSOC_DUE_TO_INACTIVITY:
5323 		PRINTM(MMSG,
5324 		       "wlan: REASON: Disassociated due to inactivity \n");
5325 		break;
5326 	case MLAN_REASON_DISASSOC_AP_BUSY:
5327 		PRINTM(MMSG,
5328 		       "wlan: REASON: (Disassociated) AP unable to handle all connected STAs\n");
5329 		break;
5330 	case MLAN_REASON_CLASS2_FRAME_FROM_NOAUTH_STA:
5331 		PRINTM(MMSG,
5332 		       "wlan: REASON: Class 2 frame was received from nonauthenticated STA\n");
5333 		break;
5334 	case MLAN_REASON_CLASS3_FRAME_FROM_NOASSOC_STA:
5335 		PRINTM(MMSG,
5336 		       "wlan: REASON: Class 3 frame was received from nonassociated STA\n");
5337 		break;
5338 	case MLAN_REASON_DISASSOC_STA_HAS_LEFT:
5339 		PRINTM(MMSG,
5340 		       "wlan: REASON: (Disassocated) Sending STA is leaving (or has left) BSS\n");
5341 		break;
5342 	case MLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
5343 		PRINTM(MMSG,
5344 		       "wlan: REASON: STA requesting (re)assoc is not authenticated with responding STA\n");
5345 		break;
5346 	default:
5347 		break;
5348 	}
5349 
5350 	LEAVE();
5351 	return;
5352 }
5353 
5354 /**
5355  * @brief Request the driver to disconnect
5356  *
5357  * @param wiphy           A pointer to wiphy structure
5358  * @param dev             A pointer to net_device structure
5359  * @param reason_code     Reason code
5360  *
5361  * @return                0 -- success, otherwise fail
5362  */
woal_cfg80211_disconnect(struct wiphy * wiphy,struct net_device * dev,t_u16 reason_code)5363 static int woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
5364 				    t_u16 reason_code)
5365 {
5366 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5367 
5368 	ENTER();
5369 	PRINTM(MMSG,
5370 	       "wlan: Received disassociation request on %s, reason: %u\n",
5371 	       dev->name, reason_code);
5372 	woal_print_disconnect_reason(reason_code);
5373 #ifdef UAP_CFG80211
5374 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
5375 		LEAVE();
5376 		return 0;
5377 	}
5378 #endif
5379 	if (priv->phandle->driver_status) {
5380 		PRINTM(MERROR,
5381 		       "Block woal_cfg80211_disconnect in abnormal driver state\n");
5382 		LEAVE();
5383 		return -EFAULT;
5384 	}
5385 
5386 	if (priv->media_connected == MFALSE) {
5387 		PRINTM(MMSG, " Already disconnected\n");
5388 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
5389 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
5390 		if (priv->wdev->connected &&
5391 #else
5392 		if (priv->wdev->current_bss &&
5393 #endif
5394 		    (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
5395 		     priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
5396 			priv->cfg_disconnect = MTRUE;
5397 			cfg80211_disconnected(priv->netdev, 0, NULL, 0,
5398 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
5399 					      true,
5400 #endif
5401 					      GFP_KERNEL);
5402 		}
5403 #endif
5404 		LEAVE();
5405 		return 0;
5406 	}
5407 
5408 	if (priv->cfg_disconnect) {
5409 		PRINTM(MERROR, "Disassociation already in progress\n");
5410 		LEAVE();
5411 		return 0;
5412 	}
5413 
5414 	/** cancel pending scan */
5415 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
5416 	priv->cfg_disconnect = MTRUE;
5417 	if (woal_disconnect(priv, MOAL_IOCTL_WAIT_TIMEOUT, priv->cfg_bssid,
5418 			    reason_code) != MLAN_STATUS_SUCCESS) {
5419 		priv->cfg_disconnect = MFALSE;
5420 		LEAVE();
5421 		return -EFAULT;
5422 	}
5423 
5424 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
5425 	if (priv->wdev->iftype == NL80211_IFTYPE_STATION ||
5426 	    priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)
5427 		cfg80211_disconnected(priv->netdev, 0, NULL, 0,
5428 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
5429 				      true,
5430 #endif
5431 				      GFP_KERNEL);
5432 #endif
5433 
5434 	memset(priv->cfg_bssid, 0, ETH_ALEN);
5435 	woal_clear_conn_params(priv);
5436 	priv->channel = 0;
5437 
5438 	LEAVE();
5439 	return 0;
5440 }
5441 
5442 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
5443 /**
5444  *  @brief This function is deauthentication handler when host MLME
5445  *          enable.
5446  *          In this case driver will prepare and send Deauth Req.
5447  *
5448  *  @param wiphy       A pointer to wiphy.
5449  *
5450  *  @param dev         A pointer to net_device
5451  *
5452  *  @param req         A pointer to cfg80211_deauth_request
5453  *
5454  *  @return            0 -- success, otherwise fail
5455  */
5456 
woal_cfg80211_deauthenticate(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_deauth_request * req)5457 static int woal_cfg80211_deauthenticate(struct wiphy *wiphy,
5458 					struct net_device *dev,
5459 					struct cfg80211_deauth_request *req)
5460 {
5461 	int ret = 0;
5462 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
5463 	moal_private *pmpriv = (moal_private *)woal_get_netdev_priv(dev);
5464 #endif
5465 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
5466 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5467 	if (priv->host_mlme) {
5468 		priv->host_mlme = MFALSE;
5469 		priv->auth_flag = 0;
5470 		priv->auth_alg = 0xFFFF;
5471 		/*send deauth packet to notify disconnection to wpa_supplicant
5472 		 */
5473 		woal_deauth_event(priv, req->reason_code);
5474 	}
5475 #endif
5476 
5477 	ret = woal_cfg80211_disconnect(wiphy, dev, req->reason_code);
5478 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
5479 	if (pmpriv->wdev->iftype == NL80211_IFTYPE_STATION ||
5480 	    pmpriv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)
5481 		cfg80211_disconnected(pmpriv->netdev, 0, NULL, 0, GFP_KERNEL);
5482 #endif
5483 	return ret;
5484 }
5485 
5486 /**
5487  *  @brief This function is disassociation handler when host MLME
5488  *          enable.
5489  *          In this case driver will prepare and send Disassoc frame.
5490  *
5491  *  @param wiphy       A pointer to wiphy.
5492  *
5493  *  @param dev         A pointer to net_device
5494  *
5495  *  @param req         A pointer to cfg80211_disassoc_request
5496  *
5497  *  @return            0 -- success, otherwise fail
5498  */
woal_cfg80211_disassociate(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_disassoc_request * req)5499 static int woal_cfg80211_disassociate(struct wiphy *wiphy,
5500 				      struct net_device *dev,
5501 				      struct cfg80211_disassoc_request *req)
5502 {
5503 	int ret = 0;
5504 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
5505 	moal_private *pmpriv = (moal_private *)woal_get_netdev_priv(dev);
5506 #endif
5507 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
5508 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5509 	if (priv->host_mlme) {
5510 		priv->host_mlme = MFALSE;
5511 		priv->auth_flag = 0;
5512 		priv->auth_alg = 0xFFFF;
5513 		/*send deauth packet to notify disconnection to wpa_supplicant
5514 		 */
5515 		woal_deauth_event(priv, req->reason_code);
5516 	}
5517 #endif
5518 
5519 	ret = woal_cfg80211_disconnect(wiphy, dev, req->reason_code);
5520 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
5521 	if (pmpriv->wdev->iftype == NL80211_IFTYPE_STATION ||
5522 	    pmpriv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)
5523 		cfg80211_disconnected(pmpriv->netdev, 0, NULL, 0, GFP_KERNEL);
5524 #endif
5525 	return ret;
5526 }
5527 #endif
5528 
5529 /**
5530  * @brief Request the driver to get the station information
5531  *
5532  * @param wiphy           A pointer to wiphy structure
5533  * @param dev             A pointer to net_device structure
5534  * @param mac             MAC address of the station
5535  * @param sinfo           A pointer to station_info structure
5536  *
5537  * @return                0 -- success, otherwise fail
5538  */
woal_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_info * sinfo)5539 static int woal_cfg80211_get_station(struct wiphy *wiphy,
5540 				     struct net_device *dev,
5541 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
5542 				     const u8 *mac,
5543 #else
5544 				     u8 *mac,
5545 #endif
5546 				     struct station_info *sinfo)
5547 {
5548 	mlan_status ret = MLAN_STATUS_SUCCESS;
5549 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5550 
5551 	ENTER();
5552 
5553 #ifdef UAP_CFG80211
5554 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
5555 		LEAVE();
5556 		return woal_uap_cfg80211_get_station(wiphy, dev, mac, sinfo);
5557 	}
5558 #endif
5559 	if (priv->media_connected == MFALSE) {
5560 		PRINTM(MINFO, "cfg80211: Media not connected!\n");
5561 		LEAVE();
5562 		return -ENOENT;
5563 	}
5564 
5565 	if (MLAN_STATUS_SUCCESS !=
5566 	    woal_cfg80211_dump_station_info(priv, sinfo)) {
5567 		PRINTM(MERROR, "cfg80211: Failed to get station info\n");
5568 		ret = -EFAULT;
5569 	}
5570 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
5571 	woal_check_auto_tdls(wiphy, dev);
5572 #endif
5573 	LEAVE();
5574 	return ret;
5575 }
5576 
5577 /**
5578  * @brief Request the driver to dump the station information
5579  *
5580  * @param wiphy           A pointer to wiphy structure
5581  * @param dev             A pointer to net_device structure
5582  * @param idx             Station index
5583  * @param mac             MAC address of the station
5584  * @param sinfo           A pointer to station_info structure
5585  *
5586  * @return                0 -- success, otherwise fail
5587  */
woal_cfg80211_dump_station(struct wiphy * wiphy,struct net_device * dev,int idx,t_u8 * mac,struct station_info * sinfo)5588 static int woal_cfg80211_dump_station(struct wiphy *wiphy,
5589 				      struct net_device *dev, int idx,
5590 				      t_u8 *mac, struct station_info *sinfo)
5591 {
5592 	mlan_status ret = MLAN_STATUS_SUCCESS;
5593 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5594 
5595 	ENTER();
5596 
5597 #ifdef UAP_CFG80211
5598 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
5599 		LEAVE();
5600 		return woal_uap_cfg80211_dump_station(wiphy, dev, idx, mac,
5601 						      sinfo);
5602 	}
5603 #endif
5604 
5605 	if (!priv->media_connected || idx != 0) {
5606 		PRINTM(MINFO,
5607 		       "cfg80211: Media not connected or not for this station!\n");
5608 		LEAVE();
5609 		return -ENOENT;
5610 	}
5611 
5612 	moal_memcpy_ext(priv->phandle, mac, priv->cfg_bssid, ETH_ALEN,
5613 			ETH_ALEN);
5614 
5615 	if (MLAN_STATUS_SUCCESS !=
5616 	    woal_cfg80211_dump_station_info(priv, sinfo)) {
5617 		PRINTM(MERROR, "cfg80211: Failed to get station info\n");
5618 		ret = -EFAULT;
5619 	}
5620 
5621 	LEAVE();
5622 	return ret;
5623 }
5624 
5625 /**
5626  *  @brief Convert driver band configuration to IEEE band type
5627  *
5628  *  @param band     Driver band configuration
5629  *
5630  *  @return         IEEE band type
5631  */
woal_bandcfg_to_ieee_band(Band_Config_t bandcfg)5632 static t_u8 woal_bandcfg_to_ieee_band(Band_Config_t bandcfg)
5633 {
5634 	t_u8 ret_radio_type = 0;
5635 
5636 	ENTER();
5637 
5638 	switch (bandcfg.chanBand) {
5639 	case BAND_5GHZ:
5640 		ret_radio_type = IEEE80211_BAND_5GHZ;
5641 		break;
5642 	case BAND_2GHZ:
5643 	default:
5644 		ret_radio_type = IEEE80211_BAND_2GHZ;
5645 		break;
5646 	}
5647 	LEAVE();
5648 	return ret_radio_type;
5649 }
5650 
5651 /**
5652  * @brief Request the driver to dump survey info
5653  *
5654  * @param wiphy           A pointer to wiphy structure
5655  * @param dev             A pointer to net_device structure
5656  * @param idx             Station index
5657  * @param survey          A pointer to survey_info structure
5658  *
5659  * @return                0 -- success, otherwise fail
5660  */
woal_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * dev,int idx,struct survey_info * survey)5661 static int woal_cfg80211_dump_survey(struct wiphy *wiphy,
5662 				     struct net_device *dev, int idx,
5663 				     struct survey_info *survey)
5664 {
5665 	int ret = -ENOENT;
5666 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5667 	enum ieee80211_band band;
5668 	ChanStatistics_t *pchan_stats = NULL;
5669 	mlan_scan_resp scan_resp;
5670 
5671 	ENTER();
5672 	PRINTM(MIOCTL, "dump_survey idx=%d\n", idx);
5673 
5674 	memset(&scan_resp, 0, sizeof(scan_resp));
5675 	if (MLAN_STATUS_SUCCESS !=
5676 	    woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
5677 		ret = -EFAULT;
5678 		goto done;
5679 	}
5680 	pchan_stats = (ChanStatistics_t *)scan_resp.pchan_stats;
5681 	if (idx > (int)scan_resp.num_in_chan_stats || idx < 0) {
5682 		ret = -EFAULT;
5683 		goto done;
5684 	}
5685 	if (idx == (int)scan_resp.num_in_chan_stats ||
5686 	    !pchan_stats[idx].cca_scan_duration)
5687 		goto done;
5688 	ret = 0;
5689 	memset(survey, 0, sizeof(*survey));
5690 	band = woal_bandcfg_to_ieee_band(pchan_stats[idx].bandcfg);
5691 	survey->channel = ieee80211_get_channel(
5692 		wiphy, ieee80211_channel_to_frequency(pchan_stats[idx].chan_num
5693 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
5694 						      ,
5695 						      band
5696 #endif
5697 						      ));
5698 	survey->filled = SURVEY_INFO_NOISE_DBM;
5699 	survey->noise = pchan_stats[idx].noise;
5700 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
5701 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
5702 	survey->filled |= SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
5703 	survey->time = pchan_stats[idx].cca_scan_duration;
5704 	survey->time_busy = pchan_stats[idx].cca_busy_duration;
5705 #else
5706 	survey->filled |=
5707 		SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY;
5708 	survey->channel_time = pchan_stats[idx].cca_scan_duration;
5709 	survey->channel_time_busy = pchan_stats[idx].cca_busy_duration;
5710 #endif
5711 #endif
5712 done:
5713 	LEAVE();
5714 	return ret;
5715 }
5716 
5717 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
woal_cfg80211_get_channel(struct wiphy * wiphy,struct wireless_dev * wdev,unsigned int link_id,struct cfg80211_chan_def * chandef)5718 static int woal_cfg80211_get_channel(struct wiphy *wiphy,
5719 				     struct wireless_dev *wdev,
5720 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 19, 2)) || IMX_ANDROID_13)
5721 				     unsigned int link_id,
5722 #endif
5723 				     struct cfg80211_chan_def *chandef)
5724 {
5725 	moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
5726 	chan_band_info channel;
5727 #ifdef UAP_SUPPORT
5728 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
5729 #endif
5730 
5731 	memset(&channel, 0x00, sizeof(channel));
5732 
5733 #ifdef UAP_SUPPORT
5734 	if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
5735 		if ((handle->mon_if) &&
5736 		    (handle->mon_if->mon_ndev == wdev->netdev)) {
5737 			*chandef = handle->mon_if->chandef;
5738 			return 0;
5739 		}
5740 		return -EFAULT;
5741 	}
5742 #endif
5743 
5744 #ifdef UAP_SUPPORT
5745 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
5746 		if (priv->bss_started == MTRUE) {
5747 			if (MLAN_STATUS_SUCCESS !=
5748 			    woal_set_get_ap_channel(priv, MLAN_ACT_GET,
5749 						    MOAL_IOCTL_WAIT,
5750 						    &channel)) {
5751 				PRINTM(MERROR, "Fail to get ap channel \n");
5752 				return -EFAULT;
5753 			}
5754 		} else {
5755 			PRINTM(MIOCTL, "get_channel when AP is not started\n");
5756 			return -EFAULT;
5757 		}
5758 	} else
5759 #endif
5760 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
5761 		if (priv->media_connected == MTRUE) {
5762 			if (MLAN_STATUS_SUCCESS !=
5763 			    woal_get_sta_channel(priv, MOAL_IOCTL_WAIT,
5764 						 &channel)) {
5765 				PRINTM(MERROR, "Fail to get sta channel \n");
5766 				return -EFAULT;
5767 			}
5768 		} else {
5769 			PRINTM(MIOCTL,
5770 			       "get_channel when STA is not connected\n");
5771 			return -EFAULT;
5772 		}
5773 	} else {
5774 		PRINTM(MERROR, "BssRole not support %d.\n", GET_BSS_ROLE(priv));
5775 		return -EFAULT;
5776 	}
5777 
5778 	if (MLAN_STATUS_FAILURE == woal_chandef_create(priv, chandef, &channel))
5779 		return -EFAULT;
5780 	else
5781 		return 0;
5782 }
5783 #endif
5784 
5785 /**
5786  * @brief Request the driver to change the IEEE power save
5787  * mdoe
5788  *
5789  * @param wiphy           A pointer to wiphy structure
5790  * @param dev             A pointer to net_device structure
5791  * @param enabled         Enable or disable
5792  * @param timeout         Timeout value
5793  *
5794  * @return                0 -- success, otherwise fail
5795  */
woal_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,int timeout)5796 static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
5797 					struct net_device *dev, bool enabled,
5798 					int timeout)
5799 {
5800 	int ret = 0, disabled;
5801 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5802 
5803 	ENTER();
5804 	if (moal_extflg_isset(priv->phandle, EXT_HW_TEST) ||
5805 	    (priv->phandle->params.ps_mode == MLAN_INIT_PARA_DISABLED)) {
5806 		PRINTM(MIOCTL, "block set power hw_test=%d ps_mode=%d\n",
5807 		       moal_extflg_isset(priv->phandle, EXT_HW_TEST),
5808 		       priv->phandle->params.ps_mode);
5809 		LEAVE();
5810 		return -EFAULT;
5811 	}
5812 
5813 	if (priv->phandle->driver_status) {
5814 		PRINTM(MERROR,
5815 		       "Block woal_cfg80211_set_power_mgmt in abnormal driver state\n");
5816 		LEAVE();
5817 		return -EFAULT;
5818 	}
5819 #ifdef WIFI_DIRECT_SUPPORT
5820 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
5821 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
5822 		PRINTM(MIOCTL, "skip set power for p2p interface\n");
5823 		LEAVE();
5824 		return ret;
5825 	}
5826 #endif
5827 #endif
5828 	if (enabled)
5829 		disabled = 0;
5830 	else
5831 		disabled = 1;
5832 
5833 	if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_SET,
5834 							   &disabled, timeout,
5835 							   MOAL_IOCTL_WAIT)) {
5836 		ret = -EOPNOTSUPP;
5837 	}
5838 
5839 	LEAVE();
5840 	return ret;
5841 }
5842 
5843 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
5844 /**
5845  * @brief Request the driver to get the transmit power info
5846  *
5847  * @param wiphy           A pointer to wiphy structure
5848  * @param type            TX power adjustment type
5849  * @param dbm             TX power in dbm
5850  *
5851  * @return                0 -- success, otherwise fail
5852  */
woal_cfg80211_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)5853 static int woal_cfg80211_get_tx_power(struct wiphy *wiphy,
5854 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
5855 				      struct wireless_dev *wdev,
5856 #endif
5857 				      int *dbm)
5858 {
5859 	int ret = 0;
5860 	moal_private *priv = NULL;
5861 	mlan_power_cfg_t power_cfg;
5862 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
5863 
5864 	ENTER();
5865 
5866 	if (!handle) {
5867 		PRINTM(MFATAL, "Unable to get handle\n");
5868 		LEAVE();
5869 		return -EFAULT;
5870 	}
5871 
5872 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
5873 
5874 	if (!priv) {
5875 		PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
5876 		LEAVE();
5877 		return -EFAULT;
5878 	}
5879 
5880 	if (MLAN_STATUS_SUCCESS !=
5881 	    woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
5882 		LEAVE();
5883 		return -EFAULT;
5884 	}
5885 
5886 	*dbm = power_cfg.power_level;
5887 
5888 	LEAVE();
5889 	return ret;
5890 }
5891 /**
5892  * @brief Request the driver to change the transmit power
5893  *
5894  * @param wiphy           A pointer to wiphy structure
5895  * @param type            TX power adjustment type
5896  * @param dbm             TX power in dbm
5897  *
5898  * @return                0 -- success, otherwise fail
5899  */
woal_cfg80211_set_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,enum tx_power_setting type,int dbm)5900 static int woal_cfg80211_set_tx_power(struct wiphy *wiphy,
5901 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
5902 				      struct wireless_dev *wdev,
5903 #endif
5904 #if CFG80211_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
5905 				      enum tx_power_setting type,
5906 #else
5907 				      enum nl80211_tx_power_setting type,
5908 #endif
5909 				      int dbm)
5910 {
5911 	int ret = 0;
5912 	moal_private *priv = NULL;
5913 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
5914 	mlan_power_cfg_t power_cfg;
5915 
5916 	ENTER();
5917 
5918 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
5919 	if (!priv) {
5920 		PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
5921 		LEAVE();
5922 		return -EFAULT;
5923 	}
5924 
5925 	if (type) {
5926 		power_cfg.is_power_auto = 0;
5927 		power_cfg.power_level = dbm;
5928 	} else
5929 		power_cfg.is_power_auto = 1;
5930 
5931 	if (MLAN_STATUS_SUCCESS !=
5932 	    woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg))
5933 		ret = -EFAULT;
5934 
5935 	LEAVE();
5936 	return ret;
5937 }
5938 #endif
5939 
5940 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
5941 /**
5942  * CFG802.11 operation handler for connection quality monitoring.
5943  *
5944  * @param wiphy           A pointer to wiphy structure
5945  * @param dev             A pointer to net_device structure
5946  * @param rssi_thold	  rssi threshold
5947  * @param rssi_hyst		  rssi hysteresis
5948  */
woal_cfg80211_set_cqm_rssi_config(struct wiphy * wiphy,struct net_device * dev,s32 rssi_thold,u32 rssi_hyst)5949 static int woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
5950 					     struct net_device *dev,
5951 					     s32 rssi_thold, u32 rssi_hyst)
5952 {
5953 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5954 	ENTER();
5955 	priv->cqm_rssi_thold = rssi_thold;
5956 	priv->cqm_rssi_high_thold = rssi_thold;
5957 	priv->cqm_rssi_hyst = rssi_hyst;
5958 
5959 	PRINTM(MIOCTL, "rssi_thold=%d rssi_hyst=%d\n", (int)rssi_thold,
5960 	       (int)rssi_hyst);
5961 	woal_set_rssi_threshold(priv, 0, MOAL_IOCTL_WAIT);
5962 	LEAVE();
5963 	return 0;
5964 }
5965 #endif
5966 
5967 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
5968 /**
5969  * @brief remain on channel config
5970  *
5971  * @param priv              A pointer to moal_private structure
5972  * @param wait_option       Wait option
5973  * @param cancel			cancel remain on channel flag
5974  * @param status            A pointer to status, success, in process or reject
5975  * @param chan              A pointer to ieee80211_channel structure
5976  * @param channel_type      channel_type,
5977  * @param duration          Duration wait to receive frame
5978  *
5979  * @return                  0 -- success, otherwise fail
5980  */
woal_cfg80211_remain_on_channel_cfg(moal_private * priv,t_u8 wait_option,t_u8 remove,t_u8 * status,struct ieee80211_channel * chan,enum mlan_channel_type channel_type,t_u32 duration)5981 int woal_cfg80211_remain_on_channel_cfg(moal_private *priv, t_u8 wait_option,
5982 					t_u8 remove, t_u8 *status,
5983 					struct ieee80211_channel *chan,
5984 					enum mlan_channel_type channel_type,
5985 					t_u32 duration)
5986 {
5987 	mlan_ds_remain_chan chan_cfg;
5988 	int ret = 0;
5989 
5990 	ENTER();
5991 
5992 	if (!status || (!chan && !remove)) {
5993 		PRINTM(MERROR,
5994 		       "Invalid parameter status=%p, chan=%p, remove=%d\n",
5995 		       status, chan, remove);
5996 		LEAVE();
5997 		return -EFAULT;
5998 	}
5999 	memset(&chan_cfg, 0, sizeof(mlan_ds_remain_chan));
6000 	if (remove) {
6001 		chan_cfg.remove = MTRUE;
6002 	} else {
6003 #ifdef WIFI_DIRECT_SUPPORT
6004 		if (priv->phandle->is_go_timer_set) {
6005 			PRINTM(MINFO,
6006 			       "block remain on channel while go timer is on\n");
6007 			LEAVE();
6008 			return -EBUSY;
6009 		}
6010 #endif
6011 		chan_cfg.bandcfg.chanBand =
6012 			woal_ieee_band_to_radio_type(chan->band);
6013 		switch (channel_type) {
6014 		case CHAN_HT40MINUS:
6015 			chan_cfg.bandcfg.chan2Offset = SEC_CHAN_BELOW;
6016 			chan_cfg.bandcfg.chanWidth = CHAN_BW_40MHZ;
6017 			break;
6018 		case CHAN_HT40PLUS:
6019 			chan_cfg.bandcfg.chan2Offset = SEC_CHAN_ABOVE;
6020 			chan_cfg.bandcfg.chanWidth = CHAN_BW_40MHZ;
6021 			break;
6022 		case CHAN_VHT80:
6023 			chan_cfg.bandcfg.chanWidth = CHAN_BW_80MHZ;
6024 			break;
6025 		case CHAN_NO_HT:
6026 		case CHAN_HT20:
6027 		default:
6028 			break;
6029 		}
6030 		chan_cfg.channel =
6031 			ieee80211_frequency_to_channel(chan->center_freq);
6032 		chan_cfg.remain_period = duration;
6033 		PRINTM(MCMND,
6034 		       "Remain on Channel: chan=%d, offset=%d width=%d\n",
6035 		       chan_cfg.channel, chan_cfg.bandcfg.chan2Offset,
6036 		       chan_cfg.bandcfg.chanWidth);
6037 	}
6038 	if (MLAN_STATUS_SUCCESS ==
6039 	    woal_set_remain_channel_ioctl(priv, wait_option, &chan_cfg))
6040 		*status = chan_cfg.status;
6041 	else
6042 		ret = -EFAULT;
6043 	LEAVE();
6044 	return ret;
6045 }
6046 
6047 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
6048 /**
6049  * @brief tx mgmt frame
6050  *
6051  * @param wiphy                 A pointer to wiphy structure
6052  * @param wdev                  A pointer to wireless_dev structure
6053  * @param cookie                A pointer to frame cookie
6054  *
6055  * @return                0 -- success, otherwise fail
6056  */
woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy * wiphy,struct wireless_dev * wdev,u64 cookie)6057 static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
6058 					     struct wireless_dev *wdev,
6059 					     u64 cookie)
6060 #else
6061 /**
6062  * @brief tx mgmt frame
6063  *
6064  * @param wiphy                 A pointer to wiphy structure
6065  * @param dev                   A pointer to net_device structure
6066  * @param cookie                A pointer to frame cookie
6067  *
6068  * @return                0 -- success, otherwise fail
6069  */
6070 static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
6071 					     struct net_device *dev, u64 cookie)
6072 #endif
6073 {
6074 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
6075 	struct net_device *dev = wdev->netdev;
6076 #endif
6077 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
6078 	int ret = 0;
6079 	t_u8 status = 1;
6080 	moal_private *remain_priv = NULL;
6081 
6082 	ENTER();
6083 
6084 	if (priv->phandle->remain_on_channel) {
6085 		remain_priv =
6086 			priv->phandle->priv[priv->phandle->remain_bss_index];
6087 		if (!remain_priv) {
6088 			PRINTM(MERROR,
6089 			       "mgmt_tx_cancel_wait: Wrong remain_bss_index=%d\n",
6090 			       priv->phandle->remain_bss_index);
6091 			ret = -EFAULT;
6092 			goto done;
6093 		}
6094 		if (woal_cfg80211_remain_on_channel_cfg(remain_priv,
6095 							MOAL_IOCTL_WAIT, MTRUE,
6096 							&status, NULL, 0, 0)) {
6097 			PRINTM(MERROR,
6098 			       "mgmt_tx_cancel_wait: Fail to cancel remain on channel\n");
6099 			ret = -EFAULT;
6100 			goto done;
6101 		}
6102 		if (priv->phandle->cookie) {
6103 			cfg80211_remain_on_channel_expired(
6104 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
6105 				remain_priv->netdev,
6106 #else
6107 				remain_priv->wdev,
6108 #endif
6109 				priv->phandle->cookie, &priv->phandle->chan,
6110 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
6111 				priv->phandle->channel_type,
6112 #endif
6113 				GFP_ATOMIC);
6114 			priv->phandle->cookie = 0;
6115 		}
6116 		priv->phandle->remain_on_channel = MFALSE;
6117 	}
6118 
6119 done:
6120 	LEAVE();
6121 	return ret;
6122 }
6123 
6124 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
6125 /**
6126  * @brief Make chip remain on channel
6127  *
6128  * @param wiphy                 A pointer to wiphy structure
6129  * @param wdev                  A pointer to wireless_dev structure
6130  * @param chan                  A pointer to ieee80211_channel structure
6131  * @param channel_type          Channel type
6132  * @param duration              Duration for timer
6133  * @param cookie                A pointer to timer cookie
6134  *
6135  * @return                  0 -- success, otherwise fail
6136  */
6137 static int
woal_cfg80211_remain_on_channel(struct wiphy * wiphy,struct wireless_dev * wdev,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type,unsigned int duration,u64 * cookie)6138 woal_cfg80211_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
6139 				struct ieee80211_channel *chan,
6140 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
6141 				enum nl80211_channel_type channel_type,
6142 #endif
6143 				unsigned int duration, u64 *cookie)
6144 #else
6145 /**
6146  * @brief Make chip remain on channel
6147  *
6148  * @param wiphy                 A pointer to wiphy structure
6149  * @param dev                   A pointer to net_device structure
6150  * @param chan                  A pointer to ieee80211_channel structure
6151  * @param channel_type          Channel type
6152  * @param duration              Duration for timer
6153  * @param cookie                A pointer to timer cookie
6154  *
6155  * @return                  0 -- success, otherwise fail
6156  */
6157 static int
6158 woal_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
6159 				struct ieee80211_channel *chan,
6160 				enum nl80211_channel_type channel_type,
6161 				unsigned int duration, u64 *cookie)
6162 #endif
6163 {
6164 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
6165 	struct net_device *dev = wdev->netdev;
6166 #endif
6167 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
6168 	int ret = 0;
6169 	t_u8 status = 1;
6170 	moal_private *remain_priv = NULL;
6171 
6172 	ENTER();
6173 
6174 	if (!chan || !cookie) {
6175 		PRINTM(MERROR, "Invalid parameter for remain on channel\n");
6176 		ret = -EFAULT;
6177 		goto done;
6178 	}
6179 	/** cancel previous remain on channel */
6180 	if (priv->phandle->remain_on_channel &&
6181 	    ((priv->phandle->chan.center_freq != chan->center_freq))) {
6182 		remain_priv =
6183 			priv->phandle->priv[priv->phandle->remain_bss_index];
6184 		if (!remain_priv) {
6185 			PRINTM(MERROR,
6186 			       "remain_on_channel: Wrong remain_bss_index=%d\n",
6187 			       priv->phandle->remain_bss_index);
6188 			ret = -EFAULT;
6189 			goto done;
6190 		}
6191 		if (woal_cfg80211_remain_on_channel_cfg(remain_priv,
6192 							MOAL_IOCTL_WAIT, MTRUE,
6193 							&status, NULL, 0, 0)) {
6194 			PRINTM(MERROR,
6195 			       "remain_on_channel: Fail to cancel remain on channel\n");
6196 			ret = -EFAULT;
6197 			goto done;
6198 		}
6199 		priv->phandle->cookie = 0;
6200 		priv->phandle->remain_on_channel = MFALSE;
6201 	}
6202 	if (MLAN_STATUS_SUCCESS !=
6203 	    woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT, MFALSE,
6204 						&status, chan,
6205 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
6206 						channel_type,
6207 #else
6208 						0,
6209 #endif
6210 						(t_u32)duration)) {
6211 		ret = -EFAULT;
6212 		goto done;
6213 	}
6214 
6215 	if (status) {
6216 		PRINTM(MMSG,
6217 		       "%s: Set remain on Channel: channel=%d with status=%d\n",
6218 		       dev->name,
6219 		       ieee80211_frequency_to_channel(chan->center_freq),
6220 		       status);
6221 		if (!priv->phandle->remain_on_channel) {
6222 			priv->phandle->is_remain_timer_set = MTRUE;
6223 			woal_mod_timer(&priv->phandle->remain_timer, duration);
6224 		}
6225 	}
6226 
6227 	/* remain on channel operation success */
6228 	/* we need update the value cookie */
6229 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
6230 	*cookie = (u64)random32() | 1;
6231 #else
6232 #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)
6233 	*cookie = (u64)prandom_u32() | 1;
6234 #else
6235 	*cookie = (u64)get_random_u32() | 1;
6236 #endif
6237 #endif
6238 	priv->phandle->remain_on_channel = MTRUE;
6239 	priv->phandle->remain_bss_index = priv->bss_index;
6240 	priv->phandle->cookie = *cookie;
6241 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
6242 	priv->phandle->channel_type = channel_type;
6243 #endif
6244 	moal_memcpy_ext(priv->phandle, &priv->phandle->chan, chan,
6245 			sizeof(struct ieee80211_channel),
6246 			sizeof(priv->phandle->chan));
6247 
6248 	if (status == 0)
6249 		PRINTM(MIOCTL,
6250 		       "%s: Set remain on Channel: channel=%d cookie = %#llx\n",
6251 		       dev->name,
6252 		       ieee80211_frequency_to_channel(chan->center_freq),
6253 		       priv->phandle->cookie);
6254 
6255 	cfg80211_ready_on_channel(
6256 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
6257 		dev,
6258 #else
6259 		priv->wdev,
6260 #endif
6261 		*cookie, chan,
6262 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
6263 		channel_type,
6264 #endif
6265 		duration, GFP_KERNEL);
6266 
6267 done:
6268 	LEAVE();
6269 	return ret;
6270 }
6271 
6272 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
6273 /**
6274  * @brief Cancel remain on channel
6275  *
6276  * @param wiphy                 A pointer to wiphy structure
6277  * @param wdev                  A pointer to wireless_dev structure
6278  * @param cookie                A pointer to timer cookie
6279  *
6280  * @return                  0 -- success, otherwise fail
6281  */
woal_cfg80211_cancel_remain_on_channel(struct wiphy * wiphy,struct wireless_dev * wdev,u64 cookie)6282 static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
6283 						  struct wireless_dev *wdev,
6284 						  u64 cookie)
6285 #else
6286 /**
6287  * @brief Cancel remain on channel
6288  *
6289  * @param wiphy                 A pointer to wiphy structure
6290  * @param dev                   A pointer to net_device structure
6291  * @param cookie                A pointer to timer cookie
6292  *
6293  * @return                  0 -- success, otherwise fail
6294  */
6295 static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
6296 						  struct net_device *dev,
6297 						  u64 cookie)
6298 #endif
6299 {
6300 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
6301 	struct net_device *dev = wdev->netdev;
6302 #endif
6303 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
6304 	moal_private *remain_priv = NULL;
6305 	int ret = 0;
6306 	t_u8 status = 1;
6307 
6308 	ENTER();
6309 	PRINTM(MIOCTL, "Cancel remain on Channel: cookie = %#llx\n", cookie);
6310 	remain_priv = priv->phandle->priv[priv->phandle->remain_bss_index];
6311 	if (!remain_priv) {
6312 		PRINTM(MERROR,
6313 		       "cancel_remain_on_channel: Wrong remain_bss_index=%d\n",
6314 		       priv->phandle->remain_bss_index);
6315 		ret = -EFAULT;
6316 		goto done;
6317 	}
6318 	if (woal_cfg80211_remain_on_channel_cfg(remain_priv, MOAL_IOCTL_WAIT,
6319 						MTRUE, &status, NULL, 0, 0)) {
6320 		PRINTM(MERROR,
6321 		       "cancel_remain_on_channel: Fail to cancel remain on channel\n");
6322 		ret = -EFAULT;
6323 		goto done;
6324 	}
6325 
6326 	priv->phandle->remain_on_channel = MFALSE;
6327 	if (priv->phandle->cookie)
6328 		priv->phandle->cookie = 0;
6329 done:
6330 	LEAVE();
6331 	return ret;
6332 }
6333 #endif /* KERNEL_VERSION */
6334 
6335 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
6336 /**
6337  * @brief start sched scan
6338  *
6339  * @param wiphy                 A pointer to wiphy structure
6340  * @param dev                   A pointer to net_device structure
6341  * @param request               A pointer to struct cfg80211_sched_scan_request
6342  *
6343  * @return                  0 -- success, otherwise fail
6344  */
woal_cfg80211_sched_scan_start(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_sched_scan_request * request)6345 int woal_cfg80211_sched_scan_start(struct wiphy *wiphy, struct net_device *dev,
6346 				   struct cfg80211_sched_scan_request *request)
6347 {
6348 	struct ieee80211_channel *chan = NULL;
6349 	int i = 0;
6350 	int ret = 0;
6351 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
6352 	struct cfg80211_ssid *ssid = NULL;
6353 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
6354 	t_u8 buf[ETH_ALEN];
6355 #endif
6356 	ENTER();
6357 
6358 #ifdef UAP_CFG80211
6359 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
6360 		LEAVE();
6361 		return -EFAULT;
6362 	}
6363 #endif
6364 
6365 	memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg));
6366 	if (!request) {
6367 		PRINTM(MERROR, "Invalid sched_scan req parameter\n");
6368 		LEAVE();
6369 		return -EINVAL;
6370 	}
6371 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
6372 	PRINTM(MCMND,
6373 	       "%s sched scan: n_ssids=%d n_match_sets=%d n_channels=%d interval=%d iterations=%d ie_len=%d\n",
6374 	       priv->netdev->name, request->n_ssids, request->n_match_sets,
6375 	       request->n_channels, request->scan_plans[0].interval,
6376 	       request->scan_plans[0].iterations, (int)request->ie_len);
6377 #else
6378 	PRINTM(MCMND,
6379 	       "%s sched scan: n_ssids=%d n_match_sets=%d n_channels=%d interval=%d ie_len=%d\n",
6380 	       priv->netdev->name, request->n_ssids, request->n_match_sets,
6381 	       request->n_channels, request->interval, (int)request->ie_len);
6382 #endif
6383 	/** We have pending scan, start bgscan later */
6384 	if (priv->phandle->scan_pending_on_block)
6385 		priv->scan_cfg.start_later = MTRUE;
6386 	for (i = 0; i < request->n_match_sets; i++) {
6387 		ssid = &request->match_sets[i].ssid;
6388 		strncpy(priv->scan_cfg.ssid_list[i].ssid, ssid->ssid,
6389 			ssid->ssid_len);
6390 		priv->scan_cfg.ssid_list[i].max_len = 0;
6391 		PRINTM(MIOCTL, "sched scan: ssid=%s\n", ssid->ssid);
6392 	}
6393 	/** Add broadcast scan, when n_match_sets = 0 */
6394 	if (!request->n_match_sets)
6395 		priv->scan_cfg.ssid_list[0].max_len = 0xff;
6396 	for (i = 0; i < (int)MIN(WLAN_BG_SCAN_CHAN_MAX, request->n_channels);
6397 	     i++) {
6398 		chan = request->channels[i];
6399 		priv->scan_cfg.chan_list[i].chan_number = chan->hw_value;
6400 		priv->scan_cfg.chan_list[i].radio_type =
6401 			woal_ieee_band_to_radio_type(chan->band);
6402 		if (chan->flags &
6403 		    (IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_RADAR))
6404 			priv->scan_cfg.chan_list[i].scan_type =
6405 				MLAN_SCAN_TYPE_PASSIVE;
6406 		else
6407 			priv->scan_cfg.chan_list[i].scan_type =
6408 				MLAN_SCAN_TYPE_ACTIVE;
6409 		priv->scan_cfg.chan_list[i].scan_time = 0;
6410 #ifdef WIFI_DIRECT_SUPPORT
6411 		if (priv->phandle->miracast_mode)
6412 			priv->scan_cfg.chan_list[i].scan_time =
6413 				priv->phandle->miracast_scan_time;
6414 #endif
6415 	}
6416 	priv->scan_cfg.chan_per_scan =
6417 		MIN(WLAN_BG_SCAN_CHAN_MAX, request->n_channels);
6418 
6419 	/** set scan request IES */
6420 	if (request->ie && request->ie_len) {
6421 		if (MLAN_STATUS_SUCCESS !=
6422 		    woal_cfg80211_mgmt_frame_ie(
6423 			    priv, NULL, 0, NULL, 0, NULL, 0,
6424 			    (t_u8 *)request->ie, request->ie_len,
6425 			    MGMT_MASK_PROBE_REQ, MOAL_IOCTL_WAIT)) {
6426 			PRINTM(MERROR, "Fail to set sched scan IE\n");
6427 			ret = -EFAULT;
6428 			goto done;
6429 		}
6430 	} else {
6431 		/** Clear SCAN IE in Firmware */
6432 		if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) {
6433 			if (MLAN_STATUS_SUCCESS !=
6434 			    woal_cfg80211_mgmt_frame_ie(
6435 				    priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
6436 				    MGMT_MASK_PROBE_REQ, MOAL_IOCTL_WAIT)) {
6437 				PRINTM(MERROR, "Fail to clear sched scan IE\n");
6438 				ret = -EFAULT;
6439 				goto done;
6440 			}
6441 		}
6442 	}
6443 
6444 	/* Interval between scan cycles in milliseconds,supplicant set to 10
6445 	 * second */
6446 	/* We want to use 30 second for per scan cycle */
6447 	priv->scan_cfg.scan_interval = MIN_BGSCAN_INTERVAL;
6448 	priv->scan_cfg.repeat_count = 0;
6449 
6450 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
6451 	/* interval in seconds */
6452 	if (request->scan_plans[0].interval)
6453 		priv->scan_cfg.scan_interval =
6454 			request->scan_plans[0].interval * 1000;
6455 	priv->scan_cfg.repeat_count = request->scan_plans[0].iterations;
6456 	if (request->n_scan_plans >= 2) {
6457 		priv->scan_cfg.config_ees = MTRUE;
6458 		priv->scan_cfg.ees_mode =
6459 			MBIT(EES_MODE_HIGH) | MBIT(EES_MODE_MID);
6460 		/*High scan interval in milliseconds*/
6461 		priv->scan_cfg.high_period =
6462 			request->scan_plans[0].interval * 1000;
6463 		priv->scan_cfg.high_period_count =
6464 			request->scan_plans[0].iterations;
6465 		/*Mid scan interval in seconds*/
6466 		priv->scan_cfg.mid_period = request->scan_plans[1].interval;
6467 		priv->scan_cfg.mid_period_count =
6468 			request->scan_plans[1].iterations;
6469 		if (request->n_scan_plans == 3) {
6470 			priv->scan_cfg.ees_mode |= MBIT(EES_MODE_LOW);
6471 			/*low scan interval in seconds*/
6472 			priv->scan_cfg.low_period =
6473 				request->scan_plans[2].interval;
6474 			priv->scan_cfg.low_period_count =
6475 				request->scan_plans[2].iterations;
6476 		}
6477 	}
6478 #else
6479 	/* interval in miliseconds */
6480 	if (request->interval)
6481 		priv->scan_cfg.scan_interval = request->interval;
6482 #endif
6483 	priv->scan_cfg.report_condition =
6484 		BG_SCAN_SSID_MATCH | BG_SCAN_WAIT_ALL_CHAN_DONE;
6485 	priv->scan_cfg.bss_type = MLAN_BSS_MODE_INFRA;
6486 	priv->scan_cfg.action = BG_SCAN_ACT_SET;
6487 	priv->scan_cfg.enable = MTRUE;
6488 #ifdef WIFI_DIRECT_SUPPORT
6489 	if (priv->phandle->miracast_mode)
6490 		priv->scan_cfg.scan_chan_gap = priv->phandle->scan_chan_gap;
6491 	else
6492 		priv->scan_cfg.scan_chan_gap = 0;
6493 #endif
6494 
6495 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
6496 	if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
6497 		PRINTM(MIOCTL, "NL80211_SCAN_FLAG_RANDOM_ADDR is set\n");
6498 		get_random_bytes(buf, ETH_ALEN);
6499 		for (i = 0; i < ETH_ALEN; i++) {
6500 			buf[i] &= ~request->mac_addr_mask[i];
6501 			buf[i] |= request->mac_addr[i] &
6502 				  request->mac_addr_mask[i];
6503 		}
6504 		moal_memcpy_ext(priv->phandle, priv->scan_cfg.random_mac, buf,
6505 				ETH_ALEN, sizeof(priv->scan_cfg.random_mac));
6506 	} else
6507 #endif
6508 		moal_memcpy_ext(priv->phandle, priv->scan_cfg.random_mac,
6509 				priv->random_mac, ETH_ALEN,
6510 				sizeof(priv->scan_cfg.random_mac));
6511 
6512 	PRINTM(MCMND, "wlan:random_mac " MACSTR "\n",
6513 	       MAC2STR(priv->scan_cfg.random_mac));
6514 	if (MLAN_STATUS_SUCCESS ==
6515 	    woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &priv->scan_cfg)) {
6516 		PRINTM(MMSG, "wlan: sched scan start\n");
6517 		priv->sched_scanning = MTRUE;
6518 		priv->bg_scan_start = MTRUE;
6519 		priv->bg_scan_reported = MFALSE;
6520 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
6521 		priv->bg_scan_reqid = request->reqid;
6522 #endif
6523 	} else
6524 		ret = -EFAULT;
6525 done:
6526 	LEAVE();
6527 	return ret;
6528 }
6529 
6530 /**
6531  * @brief stop sched scan
6532  *
6533  * @param wiphy                 A pointer to wiphy structure
6534  * @param dev                   A pointer to net_device structure
6535  *
6536  * @return                      0 -- success, otherwise fail
6537  */
woal_cfg80211_sched_scan_stop(struct wiphy * wiphy,struct net_device * dev,u64 reqid)6538 int woal_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
6539 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
6540 				  ,
6541 				  u64 reqid
6542 #endif
6543 )
6544 {
6545 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
6546 	ENTER();
6547 	PRINTM(MMSG, "wlan: sched scan stop\n");
6548 	priv->sched_scanning = MFALSE;
6549 	woal_stop_bg_scan(priv, MOAL_NO_WAIT);
6550 	priv->bg_scan_start = MFALSE;
6551 	priv->bg_scan_reported = MFALSE;
6552 	LEAVE();
6553 	return 0;
6554 }
6555 #endif
6556 
6557 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
6558 /**
6559  * @brief cfg80211_resume handler
6560  *
6561  * @param wiphy                 A pointer to wiphy structure
6562  *
6563  * @return                      0 -- success, otherwise fail
6564  */
woal_cfg80211_resume(struct wiphy * wiphy)6565 int woal_cfg80211_resume(struct wiphy *wiphy)
6566 {
6567 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
6568 	moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
6569 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) && defined(CONFIG_PM)
6570 	struct cfg80211_wowlan_wakeup wakeup_report;
6571 #endif
6572 	mlan_ds_hs_wakeup_reason wakeup_reason;
6573 	int i;
6574 
6575 	PRINTM(MCMND, "<--- Enter woal_cfg80211_resume --->\n");
6576 
6577 	if (!priv) {
6578 		PRINTM(MERROR, "woal_cfg80211_resume: priv is NULL\n");
6579 		goto done;
6580 	}
6581 
6582 	for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
6583 		if (handle->priv[i] &&
6584 		    (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
6585 			if (handle->priv[i]->last_event &
6586 			    EVENT_BG_SCAN_REPORT) {
6587 				if (handle->priv[i]->sched_scanning) {
6588 					woal_inform_bss_from_scan_result(
6589 						handle->priv[i], NULL,
6590 						MOAL_IOCTL_WAIT);
6591 #if KERNEL_VERSION(3, 2, 0) <= CFG80211_VERSION_CODE
6592 					woal_report_sched_scan_result(
6593 						handle->priv[i]);
6594 #endif
6595 					handle->priv[i]->last_event = 0;
6596 					PRINTM(MCMND,
6597 					       "Report sched scan result in cfg80211 resume\n");
6598 				}
6599 				if (!moal_extflg_isset(handle, EXT_HW_TEST) &&
6600 				    handle->priv[i]->roaming_enabled) {
6601 					handle->priv[i]->roaming_required =
6602 						MTRUE;
6603 #ifdef ANDROID_KERNEL
6604 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
6605 					__pm_wakeup_event(
6606 						&handle->ws,
6607 						ROAMING_WAKE_LOCK_TIMEOUT);
6608 #else
6609 					wake_lock_timeout(
6610 						&handle->wake_lock,
6611 						msecs_to_jiffies(
6612 							ROAMING_WAKE_LOCK_TIMEOUT));
6613 #endif
6614 #endif
6615 #ifdef REASSOCIATION
6616 					wake_up_interruptible(
6617 						&handle->reassoc_thread.wait_q);
6618 #endif
6619 				}
6620 			}
6621 		}
6622 	}
6623 
6624 	memset((t_u8 *)&wakeup_reason, 0, sizeof(wakeup_reason));
6625 	if (MLAN_STATUS_SUCCESS !=
6626 	    woal_get_wakeup_reason(priv, &wakeup_reason)) {
6627 		PRINTM(MERROR, "%s: get_wakeup_reason failed \n", __func__);
6628 		goto done;
6629 	}
6630 #ifdef STA_CFG80211
6631 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
6632 	if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext))
6633 		woal_wake_reason_logger(priv, wakeup_reason);
6634 #endif
6635 #endif
6636 
6637 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) && defined(CONFIG_PM)
6638 	memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup));
6639 	wakeup_report.pattern_idx = -1;
6640 
6641 	switch (wakeup_reason.hs_wakeup_reason) {
6642 	case NO_HSWAKEUP_REASON:
6643 		break;
6644 	case BCAST_DATA_MATCHED:
6645 		break;
6646 	case MCAST_DATA_MATCHED:
6647 		break;
6648 	case UCAST_DATA_MATCHED:
6649 		break;
6650 	case MASKTABLE_EVENT_MATCHED:
6651 		break;
6652 	case NON_MASKABLE_EVENT_MATCHED:
6653 		break;
6654 	case NON_MASKABLE_CONDITION_MATCHED:
6655 		if (wiphy->wowlan_config && wiphy->wowlan_config->disconnect)
6656 			wakeup_report.disconnect = true;
6657 		break;
6658 	case MAGIC_PATTERN_MATCHED:
6659 		if (wiphy->wowlan_config && wiphy->wowlan_config->magic_pkt)
6660 			wakeup_report.magic_pkt = true;
6661 		if (wiphy->wowlan_config && wiphy->wowlan_config->n_patterns)
6662 			wakeup_report.pattern_idx = 1;
6663 		break;
6664 	case CONTROL_FRAME_MATCHED:
6665 		break;
6666 	case MANAGEMENT_FRAME_MATCHED:
6667 		break;
6668 	case GTK_REKEY_FAILURE:
6669 		if (wiphy->wowlan_config &&
6670 		    wiphy->wowlan_config->gtk_rekey_failure)
6671 			wakeup_report.gtk_rekey_failure = true;
6672 		break;
6673 	default:
6674 		break;
6675 	}
6676 
6677 	if ((wakeup_reason.hs_wakeup_reason > 0) &&
6678 	    (wakeup_reason.hs_wakeup_reason <= 10)) {
6679 		cfg80211_report_wowlan_wakeup(priv->wdev, &wakeup_report,
6680 					      GFP_KERNEL);
6681 	}
6682 #endif
6683 
6684 done:
6685 	handle->cfg80211_suspend = MFALSE;
6686 	queue_work(handle->rx_workqueue, &handle->rx_work);
6687 
6688 	PRINTM(MCMND, "<--- Leave woal_cfg80211_resume --->\n");
6689 	return 0;
6690 }
6691 
6692 /**
6693  * @brief is_wowlan_pattern_supported
6694  *
6695  * @param priv                 A pointer to moal_private
6696  * @param pat                 A pointer to wowlan pattern
6697  * @param byte_seq       A pointer to byte_seq
6698  *
6699  * @return                      1 -- support, 0 -- not support
6700  */
is_wowlan_pattern_supported(moal_private * priv,struct cfg80211_pkt_pattern * pat,s8 * byte_seq)6701 static t_bool is_wowlan_pattern_supported(moal_private *priv,
6702 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
6703 					  struct cfg80211_pkt_pattern *pat,
6704 #else
6705 					  struct cfg80211_wowlan_trig_pkt_pattern
6706 						  *pat,
6707 #endif
6708 					  s8 *byte_seq)
6709 {
6710 	int j, k, valid_byte_cnt = 0;
6711 	t_bool dont_care_byte = MFALSE;
6712 
6713 	for (j = 0; j < DIV_ROUND_UP(pat->pattern_len, 8); j++) {
6714 		for (k = 0; k < 8; k++) {
6715 			if (pat->mask[j] & 1 << k) {
6716 				moal_memcpy_ext(priv->phandle,
6717 						byte_seq + valid_byte_cnt,
6718 						&pat->pattern[j * 8 + k], 1, 1);
6719 				valid_byte_cnt++;
6720 				if (dont_care_byte)
6721 					return MFALSE;
6722 			} else {
6723 				if (valid_byte_cnt)
6724 					dont_care_byte = MTRUE;
6725 			}
6726 
6727 			if (valid_byte_cnt > MAX_NUM_BYTE_SEQ)
6728 				return MFALSE;
6729 		}
6730 	}
6731 
6732 	byte_seq[MAX_NUM_BYTE_SEQ] = valid_byte_cnt;
6733 
6734 	return MTRUE;
6735 }
6736 
6737 /**
6738  * @brief cfg80211_suspend handler
6739  *
6740  * @param wiphy                 A pointer to wiphy structure
6741  * @param wow                   A pointer to cfg80211_wowlan
6742  *
6743  * @return                      0 -- success, otherwise fail
6744  */
woal_cfg80211_suspend(struct wiphy * wiphy,struct cfg80211_wowlan * wow)6745 int woal_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
6746 {
6747 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
6748 	int i;
6749 	int ret = 0;
6750 	mlan_status status = MLAN_STATUS_SUCCESS;
6751 	mlan_ds_misc_mef_flt_cfg mef_cfg;
6752 	mef_entry_t *mef_entry = NULL;
6753 	int filt_num = 0;
6754 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
6755 	t_bool first_pat = MTRUE;
6756 #endif
6757 	t_u8 byte_seq[MAX_NUM_BYTE_SEQ + 1];
6758 	const t_u8 ipv4_mc_mac[] = {0x33, 0x33};
6759 	const t_u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
6760 	moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA);
6761 	mlan_ds_hs_cfg hscfg;
6762 
6763 	PRINTM(MCMND, "<--- Enter woal_cfg80211_suspend --->\n");
6764 	for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
6765 		if (handle->priv[i] &&
6766 		    (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
6767 			if (handle->scan_request) {
6768 				PRINTM(MIOCTL,
6769 				       "Cancel pending scan in woal_cfg80211_suspend\n");
6770 				woal_cancel_scan(handle->priv[i],
6771 						 MOAL_IOCTL_WAIT);
6772 			}
6773 			handle->priv[i]->last_event = 0;
6774 		}
6775 	}
6776 
6777 	handle->cfg80211_suspend = MTRUE;
6778 	if (!wow) {
6779 		PRINTM(MERROR, "None of the WOWLAN triggers enabled\n");
6780 		ret = 0;
6781 		goto done;
6782 	}
6783 
6784 	if (!priv || !priv->media_connected) {
6785 		PRINTM(MERROR,
6786 		       "Can not configure WOWLAN in disconnected state\n");
6787 		ret = 0;
6788 		goto done;
6789 	}
6790 
6791 	PRINTM(MCMND, "wow->n_patterns=%d\n", wow->n_patterns);
6792 	PRINTM(MCMND, "wow->any=%d\n", wow->any);
6793 	PRINTM(MCMND, "wow->disconnect=%d\n", wow->disconnect);
6794 	PRINTM(MCMND, "wow->magic_pkt=%d\n", wow->magic_pkt);
6795 	PRINTM(MCMND, "wow->gtk_rekey_failure=%d\n", wow->gtk_rekey_failure);
6796 	PRINTM(MCMND, "wow->eap_identity_req=%d\n", wow->eap_identity_req);
6797 	PRINTM(MCMND, "wow->four_way_handshake=%d\n", wow->four_way_handshake);
6798 	PRINTM(MCMND, "wow->rfkill_release=%d\n", wow->rfkill_release);
6799 
6800 	if (!(wow->n_patterns) && !(wow->magic_pkt)) {
6801 		PRINTM(MCMND, "No pattern or magic packet configured\n");
6802 		ret = 0;
6803 		goto done;
6804 	}
6805 
6806 	memset(&mef_cfg, 0, sizeof(mef_cfg));
6807 	mef_cfg.mef_act_type = MEF_ACT_WOWLAN;
6808 	mef_entry = &mef_cfg.mef_entry;
6809 
6810 	mef_entry->mode = MEF_MODE_HOST_SLEEP;
6811 	mef_entry->action = MEF_ACTION_ALLOW_AND_WAKEUP_HOST;
6812 
6813 	for (i = 0; i < wow->n_patterns; i++) {
6814 		memset(byte_seq, 0, sizeof(byte_seq));
6815 		if (!is_wowlan_pattern_supported(priv, &wow->patterns[i],
6816 						 byte_seq)) {
6817 			PRINTM(MERROR, "Pattern not supported\n");
6818 			ret = -EOPNOTSUPP;
6819 			goto done;
6820 		}
6821 
6822 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
6823 		if (!wow->patterns[i].pkt_offset) {
6824 #endif
6825 			if (!(byte_seq[0] & 0x01) &&
6826 			    (byte_seq[MAX_NUM_BYTE_SEQ] == 1)) {
6827 				mef_cfg.criteria |= CRITERIA_UNICAST;
6828 				continue;
6829 			} else if (is_broadcast_ether_addr(byte_seq)) {
6830 				mef_cfg.criteria |= CRITERIA_BROADCAST;
6831 				continue;
6832 			} else if ((!memcmp(byte_seq, ipv4_mc_mac, 2) &&
6833 				    (byte_seq[MAX_NUM_BYTE_SEQ] == 2)) ||
6834 				   (!memcmp(byte_seq, ipv6_mc_mac, 3) &&
6835 				    (byte_seq[MAX_NUM_BYTE_SEQ] == 3))) {
6836 				mef_cfg.criteria |= CRITERIA_MULTICAST;
6837 				continue;
6838 			}
6839 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
6840 		}
6841 
6842 		mef_entry->filter_item[filt_num].fill_flag =
6843 			(FILLING_TYPE | FILLING_REPEAT | FILLING_BYTE_SEQ |
6844 			 FILLING_OFFSET);
6845 		mef_entry->filter_item[filt_num].repeat = 1;
6846 		mef_entry->filter_item[filt_num].offset =
6847 			wow->patterns[i].pkt_offset;
6848 		moal_memcpy_ext(
6849 			priv->phandle,
6850 			mef_entry->filter_item[filt_num].byte_seq, byte_seq,
6851 			MAX_NUM_BYTE_SEQ,
6852 			sizeof(mef_entry->filter_item[filt_num].byte_seq));
6853 		mef_entry->filter_item[filt_num].num_byte_seq =
6854 			byte_seq[MAX_NUM_BYTE_SEQ];
6855 		mef_entry->filter_item[filt_num].type = TYPE_BYTE_EQ;
6856 
6857 		if (first_pat)
6858 			first_pat = MFALSE;
6859 		else
6860 			mef_entry->rpn[filt_num] = RPN_TYPE_OR;
6861 
6862 		filt_num++;
6863 #endif
6864 	}
6865 
6866 	if (wow->magic_pkt) {
6867 		mef_cfg.criteria |= CRITERIA_UNICAST | CRITERIA_BROADCAST |
6868 				    CRITERIA_MULTICAST;
6869 		mef_entry->filter_item[filt_num].fill_flag =
6870 			(FILLING_TYPE | FILLING_REPEAT | FILLING_BYTE_SEQ |
6871 			 FILLING_OFFSET);
6872 		mef_entry->filter_item[filt_num].repeat = 16;
6873 		moal_memcpy_ext(
6874 			priv->phandle,
6875 			mef_entry->filter_item[filt_num].byte_seq,
6876 			priv->current_addr, ETH_ALEN,
6877 			sizeof(mef_entry->filter_item[filt_num].byte_seq));
6878 		mef_entry->filter_item[filt_num].num_byte_seq = ETH_ALEN;
6879 		mef_entry->filter_item[filt_num].offset = 56;
6880 		mef_entry->filter_item[filt_num].type = TYPE_BYTE_EQ;
6881 		if (filt_num)
6882 			mef_entry->rpn[filt_num] = RPN_TYPE_OR;
6883 		filt_num++;
6884 		mef_entry->filter_item[filt_num].fill_flag =
6885 			(FILLING_TYPE | FILLING_REPEAT | FILLING_BYTE_SEQ |
6886 			 FILLING_OFFSET);
6887 		mef_entry->filter_item[filt_num].repeat = 16;
6888 		moal_memcpy_ext(
6889 			priv->phandle,
6890 			mef_entry->filter_item[filt_num].byte_seq,
6891 			priv->current_addr, ETH_ALEN,
6892 			sizeof(mef_entry->filter_item[filt_num].byte_seq));
6893 		mef_entry->filter_item[filt_num].num_byte_seq = ETH_ALEN;
6894 		mef_entry->filter_item[filt_num].offset = 28;
6895 		mef_entry->filter_item[filt_num].type = TYPE_BYTE_EQ;
6896 		if (filt_num)
6897 			mef_entry->rpn[filt_num] = RPN_TYPE_OR;
6898 		filt_num++;
6899 	}
6900 
6901 	mef_entry->filter_num = filt_num;
6902 
6903 	if (!mef_cfg.criteria)
6904 		mef_cfg.criteria = CRITERIA_BROADCAST | CRITERIA_UNICAST |
6905 				   CRITERIA_MULTICAST;
6906 
6907 	status = woal_set_get_wowlan_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
6908 					    &mef_cfg);
6909 	if (status != MLAN_STATUS_SUCCESS) {
6910 		PRINTM(MERROR, "woal_set_get_wowlan_config fail!\n");
6911 		ret = -EFAULT;
6912 		goto done;
6913 	}
6914 
6915 	memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
6916 	status = woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT,
6917 					&hscfg);
6918 	if (status != MLAN_STATUS_SUCCESS) {
6919 		PRINTM(MERROR,
6920 		       "Fail to get HS parameter in woal_cfg80211_suspend: 0x%x 0x%x 0x%x\n",
6921 		       hscfg.conditions, hscfg.gap, hscfg.gpio);
6922 		ret = -EFAULT;
6923 		goto done;
6924 	}
6925 	hscfg.is_invoke_hostcmd = MFALSE;
6926 	if (wow->n_patterns || wow->magic_pkt)
6927 		hscfg.conditions = 0;
6928 	status = woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
6929 					&hscfg);
6930 	if (status != MLAN_STATUS_SUCCESS) {
6931 		PRINTM(MERROR,
6932 		       "Fail to set HS parameter in woal_cfg80211_suspend: 0x%x 0x%x 0x%x\n",
6933 		       hscfg.conditions, hscfg.gap, hscfg.gpio);
6934 		ret = -EFAULT;
6935 		goto done;
6936 	}
6937 
6938 done:
6939 	PRINTM(MCMND, "<--- Leave woal_cfg80211_suspend --->\n");
6940 	return ret;
6941 }
6942 #endif
6943 
6944 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
woal_cfg80211_set_wakeup(struct wiphy * wiphy,bool enabled)6945 static void woal_cfg80211_set_wakeup(struct wiphy *wiphy, bool enabled)
6946 {
6947 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
6948 
6949 	device_set_wakeup_enable(handle->hotplug_device, enabled);
6950 }
6951 #endif
6952 
6953 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
6954 /**
6955  *  @brief TDLS operation ioctl handler
6956  *
6957  *  @param priv     A pointer to moal_private structure
6958  *  @param peer     A pointer to peer mac
6959  *  @apram action   action for TDLS
6960  *  @return         0 --success, otherwise fail
6961  */
woal_tdls_oper(moal_private * priv,u8 * peer,t_u8 action)6962 static int woal_tdls_oper(moal_private *priv, u8 *peer, t_u8 action)
6963 {
6964 	mlan_ioctl_req *ioctl_req = NULL;
6965 	mlan_ds_misc_cfg *misc = NULL;
6966 	int ret = 0;
6967 	mlan_status status = MLAN_STATUS_SUCCESS;
6968 
6969 	ENTER();
6970 
6971 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
6972 	if (ioctl_req == NULL) {
6973 		ret = -ENOMEM;
6974 		goto done;
6975 	}
6976 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
6977 	misc->sub_command = MLAN_OID_MISC_TDLS_OPER;
6978 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
6979 	ioctl_req->action = MLAN_ACT_SET;
6980 	misc->param.tdls_oper.tdls_action = action;
6981 	moal_memcpy_ext(priv->phandle, misc->param.tdls_oper.peer_mac, peer,
6982 			ETH_ALEN, sizeof(misc->param.tdls_oper.peer_mac));
6983 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
6984 	if (status != MLAN_STATUS_SUCCESS) {
6985 		ret = -EFAULT;
6986 		goto done;
6987 	}
6988 done:
6989 	if (status != MLAN_STATUS_PENDING)
6990 		kfree(ioctl_req);
6991 	LEAVE();
6992 	return ret;
6993 }
6994 
6995 /**
6996  *  @brief TDLS operation ioctl handler
6997  *
6998  *  @param priv         A pointer to moal_private structure
6999  *  @param peer         A pointer to peer mac
7000  *  @param tdls_ies     A pointer to mlan_ds_misc_tdls_ies structure
7001  *  @param flags        TDLS ie flags
7002  *
7003  *  @return         0 --success, otherwise fail
7004  */
woal_tdls_get_ies(moal_private * priv,u8 * peer,mlan_ds_misc_tdls_ies * tdls_ies,t_u16 flags)7005 static int woal_tdls_get_ies(moal_private *priv, u8 *peer,
7006 			     mlan_ds_misc_tdls_ies *tdls_ies, t_u16 flags)
7007 {
7008 	mlan_ioctl_req *ioctl_req = NULL;
7009 	mlan_ds_misc_cfg *misc = NULL;
7010 	int ret = 0;
7011 	mlan_status status = MLAN_STATUS_SUCCESS;
7012 
7013 	ENTER();
7014 
7015 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
7016 	if (ioctl_req == NULL) {
7017 		ret = -ENOMEM;
7018 		goto done;
7019 	}
7020 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
7021 	misc->sub_command = MLAN_OID_MISC_GET_TDLS_IES;
7022 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
7023 	ioctl_req->action = MLAN_ACT_GET;
7024 	misc->param.tdls_ies.flags = flags;
7025 	moal_memcpy_ext(priv->phandle, misc->param.tdls_ies.peer_mac, peer,
7026 			ETH_ALEN, sizeof(misc->param.tdls_ies.peer_mac));
7027 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
7028 	if (status != MLAN_STATUS_SUCCESS) {
7029 		ret = -EFAULT;
7030 		goto done;
7031 	}
7032 	if (tdls_ies)
7033 		moal_memcpy_ext(priv->phandle, tdls_ies, &misc->param.tdls_ies,
7034 				sizeof(mlan_ds_misc_tdls_ies),
7035 				sizeof(mlan_ds_misc_tdls_ies));
7036 done:
7037 	if (status != MLAN_STATUS_PENDING)
7038 		kfree(ioctl_req);
7039 	LEAVE();
7040 	return ret;
7041 }
7042 
7043 /**
7044  * @brief append tdls ext_capability
7045  *
7046  * @param skb                   A pointer to sk_buff structure
7047  *
7048  * @return                      N/A
7049  */
woal_tdls_add_ext_capab(moal_private * priv,struct sk_buff * skb,mlan_ds_misc_tdls_ies * tdls_ies)7050 static void woal_tdls_add_ext_capab(moal_private *priv, struct sk_buff *skb,
7051 				    mlan_ds_misc_tdls_ies *tdls_ies)
7052 {
7053 	u8 *pos = NULL;
7054 	if (tdls_ies->ext_cap[0] == WLAN_EID_EXT_CAPABILITY) {
7055 		pos = (void *)skb_put(skb, sizeof(IEEEtypes_ExtCap_t));
7056 		moal_memcpy_ext(priv->phandle, pos, tdls_ies->ext_cap,
7057 				sizeof(IEEEtypes_ExtCap_t),
7058 				sizeof(IEEEtypes_ExtCap_t));
7059 	} else {
7060 		PRINTM(MERROR, "Fail to append tdls ext_capability\n");
7061 	}
7062 }
7063 
7064 /**
7065  * @brief append supported rates
7066  *
7067  * @param priv                  A pointer to moal_private structure
7068  * @param skb                   A pointer to sk_buff structure
7069  * @param band                  AP's band
7070  *
7071  * @return                      N/A
7072  */
woal_add_supported_rates_ie(moal_private * priv,struct sk_buff * skb,enum ieee80211_band band)7073 static void woal_add_supported_rates_ie(moal_private *priv, struct sk_buff *skb,
7074 					enum ieee80211_band band)
7075 {
7076 	t_u8 basic_rates[] = {0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24};
7077 	t_u8 basic_rates_5G[] = {0x0c, 0x12, 0x18, 0x24,
7078 				 0x30, 0x48, 0x60, 0x6c};
7079 	t_u8 *pos;
7080 	t_u8 rate_num = 0;
7081 	if (band == IEEE80211_BAND_2GHZ)
7082 		rate_num = sizeof(basic_rates);
7083 	else
7084 		rate_num = sizeof(basic_rates_5G);
7085 
7086 	if (skb_tailroom(skb) < rate_num + 2)
7087 		return;
7088 
7089 	pos = skb_put(skb, rate_num + 2);
7090 	*pos++ = WLAN_EID_SUPP_RATES;
7091 	*pos++ = rate_num;
7092 	if (band == IEEE80211_BAND_2GHZ)
7093 		moal_memcpy_ext(priv->phandle, pos, basic_rates, rate_num,
7094 				rate_num);
7095 	else
7096 		moal_memcpy_ext(priv->phandle, pos, basic_rates_5G, rate_num,
7097 				rate_num);
7098 	return;
7099 }
7100 
7101 /**
7102  * @brief append ext_supported rates
7103  *
7104  * @param priv                  A pointer to moal_private structure
7105  * @param skb                   A pointer to sk_buff structure
7106  * @param band                  AP's band
7107  *
7108  * @return                      N/A
7109  */
woal_add_ext_supported_rates_ie(moal_private * priv,struct sk_buff * skb,enum ieee80211_band band)7110 static void woal_add_ext_supported_rates_ie(moal_private *priv,
7111 					    struct sk_buff *skb,
7112 					    enum ieee80211_band band)
7113 {
7114 	t_u8 ext_rates[] = {0x0c, 0x12, 0x18, 0x60};
7115 	t_u8 *pos;
7116 	t_u8 rate_num = sizeof(ext_rates);
7117 
7118 	if (band != IEEE80211_BAND_2GHZ)
7119 		return;
7120 
7121 	if (skb_tailroom(skb) < rate_num + 2)
7122 		return;
7123 
7124 	pos = skb_put(skb, rate_num + 2);
7125 	*pos++ = WLAN_EID_EXT_SUPP_RATES;
7126 	*pos++ = rate_num;
7127 	moal_memcpy_ext(priv->phandle, pos, ext_rates, rate_num, rate_num);
7128 	return;
7129 }
7130 
7131 /**
7132  * @brief append wmm ie
7133  *
7134  * @param priv                  A pointer to moal_private structure
7135  * @param skb                   A pointer to sk_buff structure
7136  * @param wmm_type         WMM_TYPE_INFO/WMM_TYPE_PARAMETER
7137  * @param pQosInfo           A pointer to qos info
7138  *
7139  * @return                      N/A
7140  */
woal_add_wmm_ie(moal_private * priv,struct sk_buff * skb,t_u8 wmm_type,t_u8 * pQosInfo)7141 static void woal_add_wmm_ie(moal_private *priv, struct sk_buff *skb,
7142 			    t_u8 wmm_type, t_u8 *pQosInfo)
7143 {
7144 	t_u8 wmmInfoElement[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
7145 	t_u8 wmmParamElement[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
7146 	t_u8 ac_vi[] = {0x42, 0x43, 0x5e, 0x00};
7147 	t_u8 ac_vo[] = {0x62, 0x32, 0x2f, 0x00};
7148 	t_u8 ac_be[] = {0x03, 0xa4, 0x00, 0x00};
7149 	t_u8 ac_bk[] = {0x27, 0xa4, 0x00, 0x00};
7150 	t_u8 qosInfo = 0x0;
7151 	t_u8 reserved = 0;
7152 	t_u8 wmm_id = 221;
7153 	t_u8 wmmParamIe_len = 25;
7154 	t_u8 wmmInfoIe_len = 7;
7155 	t_u8 len = 0;
7156 	t_u8 *pos;
7157 
7158 	qosInfo = (pQosInfo == NULL) ? 0xf : (*pQosInfo);
7159 	/*wmm parameter*/
7160 	if (wmm_type == WMM_TYPE_PARAMETER) {
7161 		if (skb_tailroom(skb) < (wmmParamIe_len + 2))
7162 			return;
7163 		pos = skb_put(skb, wmmParamIe_len + 2);
7164 		len = wmmParamIe_len;
7165 	} else {
7166 		if (skb_tailroom(skb) < (wmmInfoIe_len + 2))
7167 			return;
7168 		pos = skb_put(skb, wmmInfoIe_len + 2);
7169 		len = wmmInfoIe_len;
7170 	}
7171 
7172 	*pos++ = wmm_id;
7173 	*pos++ = len;
7174 	/*wmm parameter*/
7175 	if (wmm_type == WMM_TYPE_PARAMETER) {
7176 		moal_memcpy_ext(priv->phandle, pos, wmmParamElement,
7177 				sizeof(wmmParamElement),
7178 				sizeof(wmmParamElement));
7179 		pos += sizeof(wmmParamElement);
7180 	} else {
7181 		moal_memcpy_ext(priv->phandle, pos, wmmInfoElement,
7182 				sizeof(wmmInfoElement), sizeof(wmmInfoElement));
7183 		pos += sizeof(wmmInfoElement);
7184 	}
7185 	*pos++ = qosInfo;
7186 	/*wmm parameter*/
7187 	if (wmm_type == WMM_TYPE_PARAMETER) {
7188 		*pos++ = reserved;
7189 		moal_memcpy_ext(priv->phandle, pos, ac_be, sizeof(ac_be),
7190 				sizeof(ac_be));
7191 		pos += sizeof(ac_be);
7192 		moal_memcpy_ext(priv->phandle, pos, ac_bk, sizeof(ac_bk),
7193 				sizeof(ac_bk));
7194 		pos += sizeof(ac_bk);
7195 		moal_memcpy_ext(priv->phandle, pos, ac_vi, sizeof(ac_vi),
7196 				sizeof(ac_vi));
7197 		pos += sizeof(ac_vi);
7198 		moal_memcpy_ext(priv->phandle, pos, ac_vo, sizeof(ac_vo),
7199 				sizeof(ac_vo));
7200 	}
7201 	return;
7202 }
7203 
7204 /**
7205  * @brief update tdls peer status
7206  *
7207  * @param priv                  A pointer to moal_private structure
7208  * @param peer_addr             A point to peer mac address
7209  * @param link_status           link status
7210  *
7211  * @return                      N/A
7212  */
woal_updata_peer_status(moal_private * priv,t_u8 * peer_addr,tdlsStatus_e link_status)7213 static t_void woal_updata_peer_status(moal_private *priv, t_u8 *peer_addr,
7214 				      tdlsStatus_e link_status)
7215 {
7216 	struct tdls_peer *peer = NULL;
7217 	unsigned long flags;
7218 	if (priv && priv->enable_auto_tdls) {
7219 		spin_lock_irqsave(&priv->tdls_lock, flags);
7220 		list_for_each_entry (peer, &priv->tdls_list, link) {
7221 			if (!memcmp(peer->peer_addr, peer_addr, ETH_ALEN)) {
7222 				if ((link_status == TDLS_NOT_SETUP) &&
7223 				    (peer->link_status ==
7224 				     TDLS_SETUP_INPROGRESS))
7225 					peer->num_failure++;
7226 				else if (link_status == TDLS_SETUP_COMPLETE)
7227 					peer->num_failure = 0;
7228 				peer->link_status = link_status;
7229 				break;
7230 			}
7231 		}
7232 		spin_unlock_irqrestore(&priv->tdls_lock, flags);
7233 	}
7234 }
7235 
7236 /**
7237  * @brief add tdls peer
7238  *
7239  * @param priv                  A pointer to moal_private structure
7240  * @param peer                  A point to peer address
7241  *
7242  * @return                      N/A
7243  */
woal_add_tdls_peer(moal_private * priv,t_u8 * peer)7244 static t_void woal_add_tdls_peer(moal_private *priv, t_u8 *peer)
7245 {
7246 	struct tdls_peer *tdls_peer = NULL;
7247 	unsigned long flags;
7248 	t_u8 find_peer = MFALSE;
7249 	if (priv && priv->enable_auto_tdls) {
7250 		spin_lock_irqsave(&priv->tdls_lock, flags);
7251 		list_for_each_entry (tdls_peer, &priv->tdls_list, link) {
7252 			if (!memcmp(tdls_peer->peer_addr, peer, ETH_ALEN)) {
7253 				tdls_peer->link_status = TDLS_SETUP_INPROGRESS;
7254 				tdls_peer->rssi_jiffies = jiffies;
7255 				find_peer = MTRUE;
7256 				break;
7257 			}
7258 		}
7259 		if (!find_peer) {
7260 			/* create new TDLS peer */
7261 			tdls_peer =
7262 				kzalloc(sizeof(struct tdls_peer), GFP_ATOMIC);
7263 			if (tdls_peer) {
7264 				moal_memcpy_ext(priv->phandle,
7265 						tdls_peer->peer_addr, peer,
7266 						ETH_ALEN,
7267 						sizeof(tdls_peer->peer_addr));
7268 				tdls_peer->link_status = TDLS_SETUP_INPROGRESS;
7269 				tdls_peer->rssi_jiffies = jiffies;
7270 				INIT_LIST_HEAD(&tdls_peer->link);
7271 				list_add_tail(&tdls_peer->link,
7272 					      &priv->tdls_list);
7273 				PRINTM(MCMND,
7274 				       "Add to TDLS list: peer=" MACSTR "\n",
7275 				       MAC2STR(peer));
7276 			}
7277 		}
7278 		spin_unlock_irqrestore(&priv->tdls_lock, flags);
7279 	}
7280 }
7281 
7282 /**
7283  * @brief check auto tdls
7284  *
7285  * @param wiphy                 A pointer to wiphy structure
7286  * @param dev                   A pointer to net_device structure
7287  *
7288  * @return                      N/A
7289  */
woal_check_auto_tdls(struct wiphy * wiphy,struct net_device * dev)7290 void woal_check_auto_tdls(struct wiphy *wiphy, struct net_device *dev)
7291 {
7292 	t_u8 bcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
7293 	struct tdls_peer *tdls_peer = NULL;
7294 	unsigned long flags;
7295 	t_u8 tdls_discovery = MFALSE;
7296 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
7297 
7298 	ENTER();
7299 	if (priv && priv->enable_auto_tdls) {
7300 		priv->tdls_check_tx = MFALSE;
7301 		spin_lock_irqsave(&priv->tdls_lock, flags);
7302 		list_for_each_entry (tdls_peer, &priv->tdls_list, link) {
7303 			if ((jiffies - tdls_peer->rssi_jiffies) >
7304 			    TDLS_IDLE_TIME) {
7305 				tdls_peer->rssi = 0;
7306 				if (tdls_peer->num_failure <
7307 				    TDLS_MAX_FAILURE_COUNT)
7308 					tdls_discovery = MTRUE;
7309 			}
7310 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
7311 			if (tdls_peer->rssi &&
7312 			    (tdls_peer->rssi >= TDLS_RSSI_LOW_THRESHOLD)) {
7313 				if (tdls_peer->link_status ==
7314 				    TDLS_SETUP_COMPLETE) {
7315 					tdls_peer->link_status = TDLS_TEAR_DOWN;
7316 					PRINTM(MMSG,
7317 					       "Wlan: Tear down TDLS link, peer=" MACSTR
7318 					       " rssi=%d\n",
7319 					       MAC2STR(tdls_peer->peer_addr),
7320 					       -tdls_peer->rssi);
7321 					cfg80211_tdls_oper_request(
7322 						dev, tdls_peer->peer_addr,
7323 						NL80211_TDLS_TEARDOWN,
7324 						TDLS_TEARN_DOWN_REASON_UNSPECIFIC,
7325 						GFP_ATOMIC);
7326 				}
7327 			} else if (tdls_peer->rssi &&
7328 				   (tdls_peer->rssi <=
7329 				    TDLS_RSSI_HIGH_THRESHOLD)) {
7330 				if ((tdls_peer->link_status ==
7331 				     TDLS_NOT_SETUP) &&
7332 				    (tdls_peer->num_failure <
7333 				     TDLS_MAX_FAILURE_COUNT)) {
7334 					priv->tdls_check_tx = MTRUE;
7335 					PRINTM(MCMND,
7336 					       "Wlan: Find TDLS peer=" MACSTR
7337 					       " rssi=%d\n",
7338 					       MAC2STR(tdls_peer->peer_addr),
7339 					       -tdls_peer->rssi);
7340 				}
7341 			}
7342 #endif
7343 		}
7344 		spin_unlock_irqrestore(&priv->tdls_lock, flags);
7345 	}
7346 	if (tdls_discovery)
7347 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
7348 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
7349 		woal_cfg80211_tdls_mgmt(wiphy, dev, bcast_addr,
7350 					TDLS_DISCOVERY_REQUEST, 1, 0, 0, 0,
7351 					NULL, 0);
7352 #else
7353 		woal_cfg80211_tdls_mgmt(wiphy, dev, bcast_addr,
7354 					TDLS_DISCOVERY_REQUEST, 1, 0, 0, NULL,
7355 					0);
7356 #endif
7357 #else
7358 		woal_cfg80211_tdls_mgmt(wiphy, dev, bcast_addr,
7359 					TDLS_DISCOVERY_REQUEST, 1, 0, NULL, 0);
7360 #endif
7361 	LEAVE();
7362 }
7363 
7364 /**
7365  * @brief woal construct tdls data frame
7366  *
7367  * @param priv                  A pointer to moal_private structure
7368  * @param peer                  A pointer to peer mac
7369  * @param action_code           tdls action code
7370  * @param dialog_token          dialog_token
7371  * @param status_code           status_code
7372  * @param skb                   skb buffer
7373  *
7374  * @return                      0 -- success, otherwise fail
7375  */
woal_construct_tdls_data_frame(moal_private * priv,t_u8 * peer,t_u8 action_code,t_u8 dialog_token,t_u16 status_code,struct sk_buff * skb)7376 static int woal_construct_tdls_data_frame(moal_private *priv, t_u8 *peer,
7377 					  t_u8 action_code, t_u8 dialog_token,
7378 					  t_u16 status_code,
7379 					  struct sk_buff *skb)
7380 {
7381 	struct ieee80211_tdls_data *tdata;
7382 	t_u16 capability;
7383 	IEEEtypes_HTCap_t *HTcap;
7384 	IEEEtypes_HTInfo_t *HTInfo;
7385 	IEEEtypes_2040BSSCo_t *BSSCo;
7386 	IEEEtypes_VHTCap_t *VHTcap;
7387 	IEEEtypes_VHTOprat_t *vht_oprat;
7388 	IEEEtypes_AID_t *AidInfo;
7389 	IEEEtypes_Header_t *ieee_hdr;
7390 	t_u8 *skb_data;
7391 	t_u8 len = 0;
7392 	IEEEtypes_Generic_t *pSupp_chan = NULL, *pRegulatory_class = NULL;
7393 	mlan_ds_misc_tdls_ies *tdls_ies = NULL;
7394 	int ret = 0;
7395 	mlan_bss_info bss_info;
7396 	enum ieee80211_band band;
7397 	mlan_fw_info fw_info;
7398 	t_u16 setup_flag = 0;
7399 	t_u16 confirm_flag = 0;
7400 
7401 	ENTER();
7402 
7403 	memset(&bss_info, 0, sizeof(bss_info));
7404 	if (MLAN_STATUS_SUCCESS !=
7405 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
7406 		PRINTM(MERROR, "Fail to get bss info\n");
7407 		LEAVE();
7408 		return -EFAULT;
7409 	}
7410 	band = woal_band_cfg_to_ieee_band(bss_info.bss_band);
7411 	tdls_ies = kzalloc(sizeof(mlan_ds_misc_tdls_ies), GFP_KERNEL);
7412 	if (!tdls_ies) {
7413 		PRINTM(MERROR, "Fail to alloc memory for tdls_ies\n");
7414 		LEAVE();
7415 		return -ENOMEM;
7416 	}
7417 
7418 	capability = 0x2421;
7419 
7420 	memset(&fw_info, 0, sizeof(mlan_fw_info));
7421 	tdata = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
7422 	moal_memcpy_ext(priv->phandle, tdata->da, peer, ETH_ALEN,
7423 			sizeof(tdata->da));
7424 	moal_memcpy_ext(priv->phandle, tdata->sa, priv->current_addr, ETH_ALEN,
7425 			sizeof(tdata->sa));
7426 	tdata->ether_type = cpu_to_be16(MLAN_ETHER_PKT_TYPE_TDLS_ACTION);
7427 	tdata->payload_type = WLAN_TDLS_SNAP_RFTYPE;
7428 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
7429 
7430 	setup_flag = TDLS_IE_FLAGS_EXTCAP | TDLS_IE_FLAGS_HTCAP |
7431 		     TDLS_IE_FLAGS_SUPP_CS_IE;
7432 	confirm_flag = TDLS_IE_FLAGS_EXTCAP | TDLS_IE_FLAGS_HTINFO |
7433 		       TDLS_IE_FLAGS_QOS_INFO;
7434 	if (fw_info.fw_bands & BAND_AAC) {
7435 		setup_flag |= (TDLS_IE_FLAGS_VHTCAP | TDLS_IE_FLAGS_AID);
7436 		confirm_flag |= TDLS_IE_FLAGS_VHTOPRAT;
7437 	}
7438 	if (fw_info.fw_bands & BAND_AAX) {
7439 		setup_flag |= (TDLS_IE_FLAGS_VHTCAP | TDLS_IE_FLAGS_AID |
7440 			       TDLS_IE_FLAGS_HECAP);
7441 		confirm_flag |= (TDLS_IE_FLAGS_VHTOPRAT | TDLS_IE_FLAGS_HEOP);
7442 	}
7443 	if (fw_info.fw_bands & BAND_GAX) {
7444 		setup_flag |= TDLS_IE_FLAGS_HECAP;
7445 		confirm_flag |= TDLS_IE_FLAGS_HEOP;
7446 	}
7447 	switch (action_code) {
7448 	case WLAN_TDLS_SETUP_REQUEST:
7449 		setup_flag |= TDLS_IE_FLAGS_SETUP;
7450 		if (woal_tdls_get_ies(priv, peer, tdls_ies, setup_flag)) {
7451 			PRINTM(MERROR, "%s: woal_tdls_get_ies failed \n",
7452 			       __func__);
7453 			ret = -EFAULT;
7454 			goto done;
7455 		}
7456 		tdata->category = WLAN_CATEGORY_TDLS;
7457 		tdata->action_code = WLAN_TDLS_SETUP_REQUEST;
7458 		skb_put(skb, sizeof(tdata->u.setup_req));
7459 		tdata->u.setup_req.dialog_token = dialog_token;
7460 		tdata->u.setup_req.capability = cpu_to_le16(capability);
7461 		woal_add_supported_rates_ie(priv, skb, band);
7462 		woal_add_ext_supported_rates_ie(priv, skb, band);
7463 		break;
7464 	case WLAN_TDLS_SETUP_RESPONSE:
7465 		if (woal_tdls_get_ies(priv, peer, tdls_ies, setup_flag)) {
7466 			PRINTM(MERROR, "%s: woal_tdls_get_ies failed \n",
7467 			       __func__);
7468 			ret = -EFAULT;
7469 			goto done;
7470 		}
7471 		tdata->category = WLAN_CATEGORY_TDLS;
7472 		tdata->action_code = WLAN_TDLS_SETUP_RESPONSE;
7473 
7474 		skb_put(skb, sizeof(tdata->u.setup_resp));
7475 		tdata->u.setup_resp.status_code = cpu_to_le16(status_code);
7476 		tdata->u.setup_resp.dialog_token = dialog_token;
7477 		tdata->u.setup_resp.capability = cpu_to_le16(capability);
7478 
7479 		woal_add_supported_rates_ie(priv, skb, band);
7480 		woal_add_ext_supported_rates_ie(priv, skb, band);
7481 		break;
7482 	case WLAN_TDLS_SETUP_CONFIRM:
7483 		if (woal_tdls_get_ies(priv, peer, tdls_ies, confirm_flag)) {
7484 			PRINTM(MERROR, "%s: woal_tdls_get_ies failed \n",
7485 			       __func__);
7486 			ret = -EFAULT;
7487 			goto done;
7488 		}
7489 		tdata->category = WLAN_CATEGORY_TDLS;
7490 		tdata->action_code = WLAN_TDLS_SETUP_CONFIRM;
7491 
7492 		skb_put(skb, sizeof(tdata->u.setup_cfm));
7493 		tdata->u.setup_cfm.status_code = cpu_to_le16(status_code);
7494 		tdata->u.setup_cfm.dialog_token = dialog_token;
7495 
7496 		break;
7497 	case WLAN_TDLS_TEARDOWN:
7498 		tdata->category = WLAN_CATEGORY_TDLS;
7499 		tdata->action_code = WLAN_TDLS_TEARDOWN;
7500 
7501 		skb_put(skb, sizeof(tdata->u.teardown));
7502 		tdata->u.teardown.reason_code = cpu_to_le16(status_code);
7503 		break;
7504 	case WLAN_TDLS_DISCOVERY_REQUEST:
7505 		tdata->category = WLAN_CATEGORY_TDLS;
7506 		tdata->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
7507 
7508 		skb_put(skb, sizeof(tdata->u.discover_req));
7509 		tdata->u.discover_req.dialog_token = dialog_token;
7510 		break;
7511 	default:
7512 		ret = -EINVAL;
7513 		goto done;
7514 	}
7515 
7516 	if (action_code == WLAN_TDLS_SETUP_REQUEST ||
7517 	    action_code == WLAN_TDLS_SETUP_RESPONSE) {
7518 		/* supported chanel ie*/
7519 		if (tdls_ies->supp_chan[0] == SUPPORTED_CHANNELS) {
7520 			pSupp_chan = (void *)skb_put(
7521 				skb, sizeof(IEEEtypes_Header_t) +
7522 					     tdls_ies->supp_chan[1]);
7523 			memset(pSupp_chan, 0,
7524 			       sizeof(IEEEtypes_Header_t) +
7525 				       tdls_ies->supp_chan[1]);
7526 			moal_memcpy_ext(priv->phandle, pSupp_chan,
7527 					tdls_ies->supp_chan,
7528 					sizeof(IEEEtypes_Header_t) +
7529 						tdls_ies->supp_chan[1],
7530 					sizeof(IEEEtypes_Header_t) +
7531 						tdls_ies->supp_chan[1]);
7532 		}
7533 		/* supported regulatory class ie*/
7534 		if (tdls_ies->regulatory_class[0] == REGULATORY_CLASS) {
7535 			pRegulatory_class = (void *)skb_put(
7536 				skb, sizeof(IEEEtypes_Header_t) +
7537 					     tdls_ies->regulatory_class[1]);
7538 			memset(pRegulatory_class, 0,
7539 			       sizeof(IEEEtypes_Header_t) +
7540 				       tdls_ies->regulatory_class[1]);
7541 			moal_memcpy_ext(priv->phandle, pRegulatory_class,
7542 					tdls_ies->regulatory_class,
7543 					sizeof(IEEEtypes_Header_t) +
7544 						tdls_ies->regulatory_class[1],
7545 					sizeof(IEEEtypes_Header_t) +
7546 						tdls_ies->regulatory_class[1]);
7547 		}
7548 		woal_tdls_add_ext_capab(priv, skb, tdls_ies);
7549 	}
7550 
7551 	/* TODO we should fill in ht_cap and htinfo with correct value */
7552 	switch (action_code) {
7553 	case WLAN_TDLS_SETUP_REQUEST:
7554 	case WLAN_TDLS_SETUP_RESPONSE:
7555 		/*HT capability*/
7556 		if (tdls_ies->ht_cap[0] == HT_CAPABILITY) {
7557 			HTcap = (void *)skb_put(skb, sizeof(IEEEtypes_HTCap_t));
7558 			memset(HTcap, 0, sizeof(IEEEtypes_HTCap_t));
7559 			moal_memcpy_ext(priv->phandle, HTcap, tdls_ies->ht_cap,
7560 					sizeof(IEEEtypes_HTCap_t),
7561 					sizeof(IEEEtypes_HTCap_t));
7562 		} else {
7563 			PRINTM(MIOCTL, "No TDLS HT capability\n");
7564 		}
7565 
7566 		/*20_40_bss_coexist*/
7567 		BSSCo = (void *)skb_put(skb, sizeof(IEEEtypes_2040BSSCo_t));
7568 		memset(BSSCo, 0, sizeof(IEEEtypes_2040BSSCo_t));
7569 		BSSCo->ieee_hdr.element_id = BSSCO_2040;
7570 		BSSCo->ieee_hdr.len = sizeof(IEEEtypes_2040BSSCo_t) -
7571 				      sizeof(IEEEtypes_Header_t);
7572 		BSSCo->bss_co_2040.bss_co_2040_value = 0x01;
7573 
7574 		/* VHT capability */
7575 		if (tdls_ies->vht_cap[0] == VHT_CAPABILITY) {
7576 			VHTcap = (void *)skb_put(skb,
7577 						 sizeof(IEEEtypes_VHTCap_t));
7578 			memset(VHTcap, 0, sizeof(IEEEtypes_VHTCap_t));
7579 			moal_memcpy_ext(priv->phandle, VHTcap,
7580 					tdls_ies->vht_cap,
7581 					sizeof(IEEEtypes_VHTCap_t),
7582 					sizeof(IEEEtypes_VHTCap_t));
7583 		} else {
7584 			PRINTM(MIOCTL, "NO TDLS VHT capability\n");
7585 		}
7586 		/* AID info */
7587 		if (tdls_ies->aid_info[0] == AID_INFO) {
7588 			AidInfo = (void *)skb_put(skb, sizeof(IEEEtypes_AID_t));
7589 			memset(AidInfo, 0, sizeof(IEEEtypes_AID_t));
7590 			moal_memcpy_ext(priv->phandle, AidInfo,
7591 					tdls_ies->aid_info,
7592 					sizeof(IEEEtypes_AID_t),
7593 					sizeof(IEEEtypes_AID_t));
7594 		} else {
7595 			PRINTM(MIOCTL, "No TDLS AID info\n");
7596 		}
7597 		/* HE capability */
7598 		if (tdls_ies->he_cap[2] == HE_CAPABILITY) {
7599 			ieee_hdr = (IEEEtypes_Header_t *)tdls_ies->he_cap;
7600 			len = sizeof(IEEEtypes_Header_t) + ieee_hdr->len;
7601 			skb_data = (void *)skb_put(skb, len);
7602 			memset(skb_data, 0, len);
7603 			moal_memcpy_ext(priv->phandle, skb_data,
7604 					tdls_ies->he_cap, len, len);
7605 		} else {
7606 			PRINTM(MIOCTL, "NO TDLS HE Capability IE\n");
7607 		}
7608 		break;
7609 	case WLAN_TDLS_SETUP_CONFIRM:
7610 		/*HT information*/
7611 		if (tdls_ies->ht_info[0] == HT_OPERATION) {
7612 			HTInfo = (void *)skb_put(skb,
7613 						 sizeof(IEEEtypes_HTInfo_t));
7614 			memset(HTInfo, 0, sizeof(IEEEtypes_HTInfo_t));
7615 			moal_memcpy_ext(priv->phandle, HTInfo,
7616 					tdls_ies->ht_info,
7617 					sizeof(IEEEtypes_HTInfo_t),
7618 					sizeof(IEEEtypes_HTInfo_t));
7619 		} else
7620 			PRINTM(MIOCTL, "No TDLS HT information\n");
7621 		/** VHT operation */
7622 		if (tdls_ies->vht_oprat[0] == VHT_OPERATION) {
7623 			vht_oprat = (void *)skb_put(
7624 				skb, sizeof(IEEEtypes_VHTOprat_t));
7625 			memset(vht_oprat, 0, sizeof(IEEEtypes_VHTOprat_t));
7626 			moal_memcpy_ext(priv->phandle, vht_oprat,
7627 					tdls_ies->vht_oprat,
7628 					sizeof(IEEEtypes_VHTOprat_t),
7629 					sizeof(IEEEtypes_VHTOprat_t));
7630 		} else
7631 			PRINTM(MIOCTL, "NO TDLS VHT Operation IE\n");
7632 		/** HE operation */
7633 		if (tdls_ies->he_op[2] == HE_OPERATION) {
7634 			ieee_hdr = (IEEEtypes_Header_t *)tdls_ies->he_op;
7635 			len = sizeof(IEEEtypes_Header_t) + ieee_hdr->len;
7636 			skb_data = (void *)skb_put(skb, len);
7637 			memset(skb_data, 0, len);
7638 			moal_memcpy_ext(priv->phandle, skb_data,
7639 					tdls_ies->he_op, len, len);
7640 		} else
7641 			PRINTM(MIOCTL, "NO TDLS HE Operation IE\n");
7642 		break;
7643 	default:
7644 		break;
7645 	}
7646 
7647 	if (action_code == WLAN_TDLS_SETUP_REQUEST ||
7648 	    action_code == WLAN_TDLS_SETUP_RESPONSE) {
7649 		/*wmm info*/
7650 		woal_add_wmm_ie(priv, skb, WMM_TYPE_INFO, NULL);
7651 	} else if (action_code == WLAN_TDLS_SETUP_CONFIRM) {
7652 		/*wmm parameter*/
7653 		woal_add_wmm_ie(priv, skb, WMM_TYPE_PARAMETER,
7654 				&tdls_ies->QosInfo);
7655 	}
7656 
7657 done:
7658 	kfree(tdls_ies);
7659 	return ret;
7660 }
7661 
7662 /**
7663  * @brief woal construct tdls action frame
7664  *
7665  * @param priv                  A pointer to moal_private structure
7666  * @param peer                  A pointer to peer mac
7667  * @param action_code           tdls action code
7668  * @param dialog_token          dialog_token
7669  * @param status_code           status_code
7670  * @param skb                   skb buffer
7671  *
7672  * @return                      0 -- success, otherwise fail
7673  */
woal_construct_tdls_action_frame(moal_private * priv,t_u8 * peer,t_u8 action_code,t_u8 dialog_token,t_u16 status_code,struct sk_buff * skb)7674 static int woal_construct_tdls_action_frame(moal_private *priv, t_u8 *peer,
7675 					    t_u8 action_code, t_u8 dialog_token,
7676 					    t_u16 status_code,
7677 					    struct sk_buff *skb)
7678 {
7679 	struct ieee80211_mgmt *mgmt;
7680 	t_u8 addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
7681 	t_u16 capability;
7682 	t_u8 *pos = NULL;
7683 	mlan_ds_misc_tdls_ies *tdls_ies = NULL;
7684 	mlan_bss_info bss_info;
7685 	enum ieee80211_band band;
7686 	IEEEtypes_Generic_t *pSupp_chan = NULL, *pRegulatory_class = NULL;
7687 
7688 	int ret = 0;
7689 
7690 	ENTER();
7691 
7692 	memset(&bss_info, 0, sizeof(bss_info));
7693 	if (MLAN_STATUS_SUCCESS !=
7694 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
7695 		PRINTM(MERROR, "Fail to get bss info\n");
7696 		LEAVE();
7697 		return -EFAULT;
7698 	}
7699 	band = woal_band_cfg_to_ieee_band(bss_info.bss_band);
7700 
7701 	tdls_ies = kzalloc(sizeof(mlan_ds_misc_tdls_ies), GFP_KERNEL);
7702 	if (!tdls_ies) {
7703 		PRINTM(MERROR, "Fail to alloc memory for tdls_ies\n");
7704 		LEAVE();
7705 		return -ENOMEM;
7706 	}
7707 
7708 	mgmt = (void *)skb_put(skb, 24);
7709 	memset(mgmt, 0, 24);
7710 	moal_memcpy_ext(priv->phandle, mgmt->da, peer, ETH_ALEN,
7711 			sizeof(mgmt->da));
7712 	moal_memcpy_ext(priv->phandle, mgmt->sa, priv->current_addr, ETH_ALEN,
7713 			sizeof(mgmt->sa));
7714 	moal_memcpy_ext(priv->phandle, mgmt->bssid, priv->cfg_bssid, ETH_ALEN,
7715 			sizeof(mgmt->bssid));
7716 
7717 	mgmt->frame_control =
7718 		cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION);
7719 	/* add address 4*/
7720 	pos = skb_put(skb, ETH_ALEN);
7721 
7722 	capability = 0x2421;
7723 
7724 	switch (action_code) {
7725 	case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
7726 		if (woal_tdls_get_ies(priv, peer, tdls_ies,
7727 				      TDLS_IE_FLAGS_EXTCAP |
7728 					      TDLS_IE_FLAGS_SUPP_CS_IE)) {
7729 			PRINTM(MERROR, "%s: woal_tdls_get_ies failed \n",
7730 			       __func__);
7731 			if (tdls_ies)
7732 				kfree(tdls_ies);
7733 			LEAVE();
7734 			return -EFAULT;
7735 		}
7736 		skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
7737 		mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
7738 		mgmt->u.action.u.tdls_discover_resp.action_code =
7739 			WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
7740 		mgmt->u.action.u.tdls_discover_resp.dialog_token = dialog_token;
7741 		mgmt->u.action.u.tdls_discover_resp.capability =
7742 			cpu_to_le16(capability);
7743 		/* move back for addr4 */
7744 		memmove(pos + ETH_ALEN, &mgmt->u.action,
7745 			1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
7746 		/** init address 4 */
7747 		moal_memcpy_ext(priv->phandle, pos, addr, ETH_ALEN, ETH_ALEN);
7748 
7749 		woal_add_supported_rates_ie(priv, skb, band);
7750 		woal_add_ext_supported_rates_ie(priv, skb, band);
7751 		woal_tdls_add_ext_capab(priv, skb, tdls_ies);
7752 		/* supported chanel ie*/
7753 		if (tdls_ies->supp_chan[0] == SUPPORTED_CHANNELS) {
7754 			pSupp_chan = (void *)skb_put(
7755 				skb, sizeof(IEEEtypes_Header_t) +
7756 					     tdls_ies->supp_chan[1]);
7757 			memset(pSupp_chan, 0,
7758 			       sizeof(IEEEtypes_Header_t) +
7759 				       tdls_ies->supp_chan[1]);
7760 			moal_memcpy_ext(priv->phandle, pSupp_chan,
7761 					tdls_ies->supp_chan,
7762 					sizeof(IEEEtypes_Header_t) +
7763 						tdls_ies->supp_chan[1],
7764 					sizeof(IEEEtypes_Header_t) +
7765 						tdls_ies->supp_chan[1]);
7766 		}
7767 		/* supported regulatory class ie*/
7768 		if (tdls_ies->regulatory_class[0] == REGULATORY_CLASS) {
7769 			pRegulatory_class = (void *)skb_put(
7770 				skb, sizeof(IEEEtypes_Header_t) +
7771 					     tdls_ies->regulatory_class[1]);
7772 			memset(pRegulatory_class, 0,
7773 			       sizeof(IEEEtypes_Header_t) +
7774 				       tdls_ies->regulatory_class[1]);
7775 			moal_memcpy_ext(priv->phandle, pRegulatory_class,
7776 					tdls_ies->regulatory_class,
7777 					sizeof(IEEEtypes_Header_t) +
7778 						tdls_ies->regulatory_class[1],
7779 					sizeof(IEEEtypes_Header_t) +
7780 						tdls_ies->regulatory_class[1]);
7781 		}
7782 
7783 		break;
7784 	default:
7785 		ret = -EINVAL;
7786 		break;
7787 	}
7788 	if (tdls_ies)
7789 		kfree(tdls_ies);
7790 	return ret;
7791 }
7792 
7793 /**
7794  * @brief woal add tdls link identifier ie
7795  *
7796  * @param skb                   skb buffer
7797  * @param src_addr              source address
7798  * @param peer                  peer address
7799  * @param bssid                 AP's bssid
7800  *
7801  * @return                      NA
7802  */
woal_tdls_add_link_ie(moal_private * priv,struct sk_buff * skb,u8 * src_addr,u8 * peer,u8 * bssid)7803 static void woal_tdls_add_link_ie(moal_private *priv, struct sk_buff *skb,
7804 				  u8 *src_addr, u8 *peer, u8 *bssid)
7805 {
7806 	struct ieee80211_tdls_lnkie *lnkid;
7807 
7808 	lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
7809 
7810 	lnkid->ie_type = WLAN_EID_LINK_ID;
7811 	lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
7812 
7813 	moal_memcpy_ext(priv->phandle, lnkid->bssid, bssid, ETH_ALEN,
7814 			sizeof(lnkid->bssid));
7815 	moal_memcpy_ext(priv->phandle, lnkid->init_sta, src_addr, ETH_ALEN,
7816 			sizeof(lnkid->init_sta));
7817 	moal_memcpy_ext(priv->phandle, lnkid->resp_sta, peer, ETH_ALEN,
7818 			sizeof(lnkid->resp_sta));
7819 }
7820 
7821 /**
7822  * @brief woal send tdls action frame
7823  *
7824  * @param wiphy                 A pointer to wiphy structure
7825  * @param dev                   A pointer to net_device structure
7826  * @param peer                  A pointer to peer mac
7827  * @param action_code           tdls action code
7828  * @param dialog_token          dialog_token
7829  * @param status_code           status_code
7830  * @param extra_ies              A pointer to extra ie buffer
7831  * @param extra_ies_len          etra ie len
7832  * @param skb                   skb buffer
7833  *
7834  * @return                      0 -- success, otherwise fail
7835  */
woal_send_tdls_action_frame(struct wiphy * wiphy,struct net_device * dev,t_u8 * peer,u8 action_code,t_u8 dialog_token,t_u16 status_code,const t_u8 * extra_ies,size_t extra_ies_len)7836 static int woal_send_tdls_action_frame(struct wiphy *wiphy,
7837 				       struct net_device *dev, t_u8 *peer,
7838 				       u8 action_code, t_u8 dialog_token,
7839 				       t_u16 status_code, const t_u8 *extra_ies,
7840 				       size_t extra_ies_len)
7841 {
7842 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
7843 	pmlan_buffer pmbuf = NULL;
7844 	mlan_status status = MLAN_STATUS_SUCCESS;
7845 	struct sk_buff *skb = NULL;
7846 	t_u8 *pos;
7847 	t_u32 pkt_type;
7848 	t_u32 tx_control;
7849 	t_u16 pkt_len;
7850 	int ret = 0;
7851 
7852 	ENTER();
7853 
7854 #define HEADER_SIZE 8 /* pkt_type + tx_control */
7855 
7856 	pmbuf = woal_alloc_mlan_buffer(
7857 		priv->phandle,
7858 		MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE + sizeof(pkt_len) +
7859 			max(sizeof(struct ieee80211_mgmt),
7860 			    sizeof(struct ieee80211_tdls_data)) +
7861 			50 + /* supported rates */
7862 			sizeof(IEEEtypes_ExtCap_t) + /* ext capab */
7863 			extra_ies_len + sizeof(IEEEtypes_tdls_linkie));
7864 	if (!pmbuf) {
7865 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
7866 		ret = -ENOMEM;
7867 		goto done;
7868 	}
7869 
7870 	skb = (struct sk_buff *)pmbuf->pdesc;
7871 
7872 	skb_put(skb, MLAN_MIN_DATA_HEADER_LEN);
7873 
7874 	pos = skb_put(skb, HEADER_SIZE + sizeof(pkt_len));
7875 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
7876 	tx_control = 0;
7877 	memset(pos, 0, HEADER_SIZE + sizeof(pkt_len));
7878 	moal_memcpy_ext(priv->phandle, pos, &pkt_type, sizeof(pkt_type),
7879 			sizeof(pkt_type));
7880 	moal_memcpy_ext(priv->phandle, pos + sizeof(pkt_type), &tx_control,
7881 			sizeof(tx_control), sizeof(tx_control));
7882 
7883 	woal_construct_tdls_action_frame(priv, peer, action_code, dialog_token,
7884 					 status_code, skb);
7885 
7886 	if (extra_ies_len)
7887 		moal_memcpy_ext(priv->phandle, skb_put(skb, extra_ies_len),
7888 				extra_ies, extra_ies_len, extra_ies_len);
7889 
7890 	/* the TDLS link IE is always added last */
7891 	/* we are the responder */
7892 	woal_tdls_add_link_ie(priv, skb, peer, priv->current_addr,
7893 			      priv->cfg_bssid);
7894 
7895 	/*
7896 	 * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
7897 	 * we should default to AC_VI.
7898 	 */
7899 	skb_set_queue_mapping(skb, WMM_AC_VI);
7900 	skb->priority = 5;
7901 
7902 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
7903 	pmbuf->data_len = skb->len - pmbuf->data_offset;
7904 	pmbuf->priority = skb->priority;
7905 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
7906 	pmbuf->bss_index = priv->bss_index;
7907 
7908 	pkt_len = pmbuf->data_len - HEADER_SIZE - sizeof(pkt_len);
7909 	moal_memcpy_ext(priv->phandle,
7910 			pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE,
7911 			&pkt_len, sizeof(pkt_len), sizeof(pkt_len));
7912 
7913 	DBG_HEXDUMP(MDAT_D, "TDLS action:", pmbuf->pbuf + pmbuf->data_offset,
7914 		    pmbuf->data_len);
7915 
7916 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
7917 
7918 	switch (status) {
7919 	case MLAN_STATUS_PENDING:
7920 		atomic_inc(&priv->phandle->tx_pending);
7921 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
7922 		break;
7923 	case MLAN_STATUS_SUCCESS:
7924 		woal_free_mlan_buffer(priv->phandle, pmbuf);
7925 		break;
7926 	case MLAN_STATUS_FAILURE:
7927 	default:
7928 		woal_free_mlan_buffer(priv->phandle, pmbuf);
7929 		ret = -EFAULT;
7930 		break;
7931 	}
7932 
7933 done:
7934 	LEAVE();
7935 	return ret;
7936 }
7937 
7938 /**
7939  * @brief woal send tdls data frame
7940  *
7941  * @param wiphy                 A pointer to wiphy structure
7942  * @param dev                   A pointer to net_device structure
7943  * @param peer                  A pointer to peer mac
7944  * @param action_code           tdls action code
7945  * @param dialog_token          dialog_token
7946  * @param status_code           status_code
7947  * @param extra_ies              A pointer to extra ie buffer
7948  * @param extra_ies_len          etra ie len
7949  * @param skb                   skb buffer
7950  *
7951  * @return                      0 -- success, otherwise fail
7952  */
woal_send_tdls_data_frame(struct wiphy * wiphy,struct net_device * dev,t_u8 * peer,u8 action_code,t_u8 dialog_token,t_u16 status_code,const t_u8 * extra_ies,size_t extra_ies_len)7953 static int woal_send_tdls_data_frame(struct wiphy *wiphy,
7954 				     struct net_device *dev, t_u8 *peer,
7955 				     u8 action_code, t_u8 dialog_token,
7956 				     t_u16 status_code, const t_u8 *extra_ies,
7957 				     size_t extra_ies_len)
7958 {
7959 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
7960 	pmlan_buffer pmbuf = NULL;
7961 	mlan_status status = MLAN_STATUS_SUCCESS;
7962 	struct sk_buff *skb = NULL;
7963 	int ret = 0;
7964 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
7965 	t_u32 index = 0;
7966 #endif
7967 
7968 	ENTER();
7969 
7970 	skb = dev_alloc_skb(
7971 		priv->extra_tx_head_len + MLAN_MIN_DATA_HEADER_LEN +
7972 		sizeof(mlan_buffer) +
7973 		max(sizeof(struct ieee80211_mgmt),
7974 		    sizeof(struct ieee80211_tdls_data)) +
7975 		50 + /* supported rates */
7976 		sizeof(IEEEtypes_ExtCap_t) + /* ext capab */
7977 		3 + /* Qos Info */
7978 		sizeof(IEEEtypes_WmmParameter_t) + /*wmm ie*/
7979 		sizeof(IEEEtypes_HTCap_t) + sizeof(IEEEtypes_2040BSSCo_t) +
7980 		sizeof(IEEEtypes_HTInfo_t) + sizeof(IEEEtypes_VHTCap_t) +
7981 		sizeof(IEEEtypes_VHTOprat_t) + sizeof(IEEEtypes_AID_t) +
7982 		sizeof(IEEEtypes_HECap_t) + sizeof(IEEEtypes_HeOp_t) +
7983 		extra_ies_len + sizeof(IEEEtypes_tdls_linkie));
7984 	if (!skb)
7985 		return -ENOMEM;
7986 
7987 	skb_reserve(skb, MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
7988 				 priv->extra_tx_head_len);
7989 
7990 	woal_construct_tdls_data_frame(priv, peer, action_code, dialog_token,
7991 				       status_code, skb);
7992 
7993 	if (extra_ies_len)
7994 		moal_memcpy_ext(priv->phandle, skb_put(skb, extra_ies_len),
7995 				extra_ies, extra_ies_len, extra_ies_len);
7996 
7997 	/* the TDLS link IE is always added last */
7998 	switch (action_code) {
7999 	case WLAN_TDLS_SETUP_REQUEST:
8000 	case WLAN_TDLS_SETUP_CONFIRM:
8001 	case WLAN_TDLS_TEARDOWN:
8002 	case WLAN_TDLS_DISCOVERY_REQUEST:
8003 		/* we are the initiator */
8004 		woal_tdls_add_link_ie(priv, skb, priv->current_addr, peer,
8005 				      priv->cfg_bssid);
8006 		break;
8007 	case WLAN_TDLS_SETUP_RESPONSE:
8008 		/* we are the responder */
8009 		woal_tdls_add_link_ie(priv, skb, peer, priv->current_addr,
8010 				      priv->cfg_bssid);
8011 		break;
8012 	default:
8013 		ret = -ENOTSUPP;
8014 		goto fail;
8015 	}
8016 
8017 	/*
8018 	 * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
8019 	 * we should default to AC_VI.
8020 	 */
8021 	switch (action_code) {
8022 	case WLAN_TDLS_SETUP_REQUEST:
8023 	case WLAN_TDLS_SETUP_RESPONSE:
8024 		skb_set_queue_mapping(skb, WMM_AC_BK);
8025 		skb->priority = 2;
8026 		break;
8027 	default:
8028 		skb_set_queue_mapping(skb, WMM_AC_VI);
8029 		skb->priority = 5;
8030 		break;
8031 	}
8032 
8033 	pmbuf = (mlan_buffer *)skb->head;
8034 	memset((t_u8 *)pmbuf, 0, sizeof(mlan_buffer));
8035 	pmbuf->bss_index = priv->bss_index;
8036 	pmbuf->pdesc = skb;
8037 	pmbuf->pbuf = skb->head + sizeof(mlan_buffer);
8038 
8039 	pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer));
8040 	pmbuf->data_len = skb->len;
8041 	pmbuf->priority = skb->priority;
8042 	pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
8043 
8044 	DBG_HEXDUMP(MDAT_D, "TDLS data:", pmbuf->pbuf + pmbuf->data_offset,
8045 		    pmbuf->data_len);
8046 
8047 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
8048 	index = skb_get_queue_mapping(skb);
8049 #endif
8050 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
8051 
8052 	switch (status) {
8053 	case MLAN_STATUS_PENDING:
8054 		atomic_inc(&priv->phandle->tx_pending);
8055 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
8056 		atomic_inc(&priv->wmm_tx_pending[index]);
8057 #endif
8058 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
8059 		/*delay 10 ms to guarantee the teardown/confirm frame can be
8060 		 * sent out before disalbe/enable tdls link if we don't delay
8061 		 * and return immediately, wpa_supplicant will call
8062 		 * disalbe/enable tdls link this may cause tdls link
8063 		 * disabled/enabled before teardown/confirm frame sent out */
8064 		if (action_code == WLAN_TDLS_TEARDOWN ||
8065 		    action_code == WLAN_TDLS_SETUP_CONFIRM)
8066 			woal_sched_timeout(10);
8067 		break;
8068 	case MLAN_STATUS_SUCCESS:
8069 		dev_kfree_skb(skb);
8070 		break;
8071 	case MLAN_STATUS_FAILURE:
8072 	default:
8073 		dev_kfree_skb(skb);
8074 		ret = -ENOTSUPP;
8075 		break;
8076 	}
8077 
8078 	LEAVE();
8079 	return ret;
8080 fail:
8081 	dev_kfree_skb(skb);
8082 	return ret;
8083 }
8084 
8085 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
8086 /**
8087  * @brief Tx TDLS packet
8088  *
8089  * @param wiphy                 A pointer to wiphy structure
8090  * @param dev                   A pointer to net_device structure
8091  * @param peer                  A pointer to peer mac
8092  * @param action_code           tdls action code
8093  * @param dialog_token          dialog_token
8094  * @param status_code           status_code
8095  * @param peer_capability       peer capability
8096  * @param initiator             initiator
8097  * @param extra_ies              A pointer to extra ie buffer
8098  * @param extra_ies_len          etra ie len
8099  *
8100  * @return                      0 -- success, otherwise fail
8101  */
woal_cfg80211_tdls_mgmt(struct wiphy * wiphy,struct net_device * dev,const t_u8 * peer,u8 action_code,t_u8 dialog_token,t_u16 status_code,t_u32 peer_capability,bool initiator,const t_u8 * extra_ies,size_t extra_ies_len)8102 int woal_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
8103 			    const t_u8 *peer, u8 action_code, t_u8 dialog_token,
8104 			    t_u16 status_code, t_u32 peer_capability,
8105 			    bool initiator, const t_u8 *extra_ies,
8106 			    size_t extra_ies_len)
8107 #else
8108 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
8109 /**
8110  * @brief Tx TDLS packet
8111  *
8112  * @param wiphy                 A pointer to wiphy structure
8113  * @param dev                   A pointer to net_device structure
8114  * @param peer                  A pointer to peer mac
8115  * @param action_code           tdls action code
8116  * @param dialog_token          dialog_token
8117  * @param status_code           status_code
8118  * @param peer_capability       peer capability
8119  * @param extra_ies              A pointer to extra ie buffer
8120  * @param extra_ies_len          etra ie len
8121  *
8122  * @return                      0 -- success, otherwise fail
8123  */
8124 int woal_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
8125 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
8126 			    const t_u8 *peer,
8127 #else
8128 			    t_u8 *peer,
8129 #endif
8130 			    u8 action_code, t_u8 dialog_token,
8131 			    t_u16 status_code, t_u32 peer_capability,
8132 			    const t_u8 *extra_ies, size_t extra_ies_len)
8133 #else
8134 /**
8135  * @brief Tx TDLS packet
8136  *
8137  * @param wiphy                 A pointer to wiphy structure
8138  * @param dev                   A pointer to net_device structure
8139  * @param peer                  A pointer to peer mac
8140  * @param action_code           tdls action code
8141  * @param dialog_token          dialog_token
8142  * @param status_code           status_code
8143  * @param extra_ies              A pointer to extra ie buffer
8144  * @param extra_ies_len          etra ie len
8145  *
8146  * @return                      0 -- success, otherwise fail
8147  */
8148 int woal_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
8149 			    t_u8 *peer, u8 action_code, t_u8 dialog_token,
8150 			    t_u16 status_code, const t_u8 *extra_ies,
8151 			    size_t extra_ies_len)
8152 #endif
8153 #endif
8154 {
8155 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
8156 	int ret = 0;
8157 	mlan_bss_info bss_info;
8158 
8159 	ENTER();
8160 
8161 	if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) {
8162 		LEAVE();
8163 		return -ENOTSUPP;
8164 	}
8165 	/* make sure we are not in uAP mode and Go mode */
8166 	if (priv->bss_type != MLAN_BSS_TYPE_STA) {
8167 		LEAVE();
8168 		return -ENOTSUPP;
8169 	}
8170 
8171 	/* check if AP prohited TDLS */
8172 	memset(&bss_info, 0, sizeof(bss_info));
8173 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
8174 	if (IS_EXTCAP_TDLS_PROHIBITED(bss_info.ext_cap)) {
8175 		PRINTM(MMSG, "TDLS is prohibited by AP\n");
8176 		LEAVE();
8177 		return -ENOTSUPP;
8178 	}
8179 
8180 	switch (action_code) {
8181 	case TDLS_SETUP_REQUEST:
8182 		woal_add_tdls_peer(priv, (t_u8 *)peer);
8183 		PRINTM(MMSG,
8184 		       "wlan: Send TDLS Setup Request to " MACSTR
8185 		       " status_code=%d\n",
8186 		       MAC2STR(peer), status_code);
8187 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
8188 						action_code, dialog_token,
8189 						status_code, extra_ies,
8190 						extra_ies_len);
8191 		break;
8192 	case TDLS_SETUP_RESPONSE:
8193 		PRINTM(MMSG,
8194 		       "wlan: Send TDLS Setup Response to " MACSTR
8195 		       " status_code=%d\n",
8196 		       MAC2STR(peer), status_code);
8197 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
8198 						action_code, dialog_token,
8199 						status_code, extra_ies,
8200 						extra_ies_len);
8201 		break;
8202 	case TDLS_SETUP_CONFIRM:
8203 		PRINTM(MMSG,
8204 		       "wlan: Send TDLS Confirm to " MACSTR " status_code=%d\n",
8205 		       MAC2STR(peer), status_code);
8206 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
8207 						action_code, dialog_token,
8208 						status_code, extra_ies,
8209 						extra_ies_len);
8210 		break;
8211 	case TDLS_TEARDOWN:
8212 		PRINTM(MMSG, "wlan: Send TDLS Tear down to " MACSTR "\n",
8213 		       MAC2STR(peer));
8214 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
8215 						action_code, dialog_token,
8216 						status_code, extra_ies,
8217 						extra_ies_len);
8218 		break;
8219 	case TDLS_DISCOVERY_REQUEST:
8220 		PRINTM(MMSG,
8221 		       "wlan: Send TDLS Discovery Request to " MACSTR "\n",
8222 		       MAC2STR(peer));
8223 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
8224 						action_code, dialog_token,
8225 						status_code, extra_ies,
8226 						extra_ies_len);
8227 		break;
8228 	case TDLS_DISCOVERY_RESPONSE:
8229 		PRINTM(MMSG,
8230 		       "wlan: Send TDLS Discovery Response to " MACSTR "\n",
8231 		       MAC2STR(peer));
8232 		ret = woal_send_tdls_action_frame(wiphy, dev, (t_u8 *)peer,
8233 						  action_code, dialog_token,
8234 						  status_code, extra_ies,
8235 						  extra_ies_len);
8236 		break;
8237 	default:
8238 		break;
8239 	}
8240 
8241 	LEAVE();
8242 	return ret;
8243 }
8244 
8245 /**
8246  * @brief cfg80211_tdls_oper handler
8247  *
8248  * @param wiphy                 A pointer to wiphy structure
8249  * @param dev                   A pointer to net_device structure
8250  * @param peer                  tdls peer mac
8251  * @param oper                  tdls operation code
8252  *
8253  * @return                  	0 -- success, otherwise fail
8254  */
woal_cfg80211_tdls_oper(struct wiphy * wiphy,struct net_device * dev,const u8 * peer,enum nl80211_tdls_operation oper)8255 int woal_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
8256 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
8257 			    const u8 *peer,
8258 #else
8259 			    u8 *peer,
8260 #endif
8261 			    enum nl80211_tdls_operation oper)
8262 {
8263 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
8264 	t_u8 action;
8265 	int ret = 0;
8266 	t_u8 event_buf[32];
8267 	int custom_len = 0;
8268 
8269 	ENTER();
8270 
8271 	if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
8272 		return -ENOTSUPP;
8273 
8274 	if (!(wiphy->flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
8275 		return -ENOTSUPP;
8276 	/* make sure we are in managed mode, and associated */
8277 	if (priv->bss_type != MLAN_BSS_TYPE_STA)
8278 		return -ENOTSUPP;
8279 
8280 	PRINTM(MIOCTL, "wlan: TDLS peer=" MACSTR ", oper=%d\n", MAC2STR(peer),
8281 	       oper);
8282 	switch (oper) {
8283 	case NL80211_TDLS_ENABLE_LINK:
8284 		/*Configure TDLS link first*/
8285 		woal_tdls_oper(priv, (u8 *)peer, WLAN_TDLS_CONFIG_LINK);
8286 		woal_updata_peer_status(priv, (t_u8 *)peer,
8287 					TDLS_SETUP_COMPLETE);
8288 		PRINTM(MMSG, "wlan: TDLS_ENABLE_LINK: peer=" MACSTR "\n",
8289 		       MAC2STR(peer));
8290 		action = WLAN_TDLS_ENABLE_LINK;
8291 		memset(event_buf, 0, sizeof(event_buf));
8292 		custom_len = strlen(CUS_EVT_TDLS_CONNECTED);
8293 		moal_memcpy_ext(priv->phandle, event_buf,
8294 				CUS_EVT_TDLS_CONNECTED, custom_len,
8295 				sizeof(event_buf));
8296 		moal_memcpy_ext(priv->phandle, event_buf + custom_len, peer,
8297 				ETH_ALEN, sizeof(event_buf) - custom_len);
8298 		woal_broadcast_event(priv, event_buf, custom_len + ETH_ALEN);
8299 		break;
8300 	case NL80211_TDLS_DISABLE_LINK:
8301 		woal_updata_peer_status(priv, (t_u8 *)peer, TDLS_NOT_SETUP);
8302 		PRINTM(MMSG, "wlan: TDLS_DISABLE_LINK: peer=" MACSTR "\n",
8303 		       MAC2STR(peer));
8304 		action = WLAN_TDLS_DISABLE_LINK;
8305 		memset(event_buf, 0, sizeof(event_buf));
8306 		custom_len = strlen(CUS_EVT_TDLS_TEARDOWN);
8307 		moal_memcpy_ext(priv->phandle, event_buf, CUS_EVT_TDLS_TEARDOWN,
8308 				custom_len, sizeof(event_buf));
8309 		moal_memcpy_ext(priv->phandle, event_buf + custom_len, peer,
8310 				ETH_ALEN, sizeof(event_buf) - custom_len);
8311 		woal_broadcast_event(priv, event_buf, custom_len + ETH_ALEN);
8312 		break;
8313 	case NL80211_TDLS_TEARDOWN:
8314 	case NL80211_TDLS_SETUP:
8315 	case NL80211_TDLS_DISCOVERY_REQ:
8316 		return 0;
8317 
8318 	default:
8319 		return -ENOTSUPP;
8320 	}
8321 	ret = woal_tdls_oper(priv, (u8 *)peer, action);
8322 
8323 	LEAVE();
8324 	return ret;
8325 }
8326 
8327 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
8328 /**
8329  * @brief tdls channel switch
8330  *
8331  * @param wiphy                 A pointer to wiphy structure
8332  * @param dev                   A pointer to net_device structure
8333  * @param addr                  A pointer to peer addr
8334  * @param oper_class            The operating class
8335  * @param chandef               A pointer to cfg80211_chan_def structure
8336  *
8337  * @return                      0 -- success, otherwise fail
8338  */
woal_cfg80211_tdls_channel_switch(struct wiphy * wiphy,struct net_device * dev,const u8 * addr,u8 oper_class,struct cfg80211_chan_def * chandef)8339 static int woal_cfg80211_tdls_channel_switch(struct wiphy *wiphy,
8340 					     struct net_device *dev,
8341 					     const u8 *addr, u8 oper_class,
8342 					     struct cfg80211_chan_def *chandef)
8343 {
8344 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
8345 	mlan_ioctl_req *ioctl_req = NULL;
8346 	mlan_ds_misc_cfg *misc = NULL;
8347 	mlan_ds_misc_tdls_config *tdls_data = NULL;
8348 	tdls_all_config *tdls_all_cfg = NULL;
8349 	int ret = 0;
8350 	mlan_status status = MLAN_STATUS_SUCCESS;
8351 	mlan_bss_info bss_info;
8352 
8353 	ENTER();
8354 
8355 	/* check if AP prohited TDLS channel switch */
8356 	memset(&bss_info, 0, sizeof(bss_info));
8357 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
8358 	if (IS_EXTCAP_TDLS_CHLSWITCHPROHIB(bss_info.ext_cap)) {
8359 		PRINTM(MMSG, "TDLS Channel Switching is prohibited by AP\n");
8360 		LEAVE();
8361 		return -ENOTSUPP;
8362 	}
8363 
8364 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8365 	if (ioctl_req == NULL) {
8366 		ret = -ENOMEM;
8367 		goto done;
8368 	}
8369 
8370 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
8371 	misc->sub_command = MLAN_OID_MISC_TDLS_OPER;
8372 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
8373 	ioctl_req->action = MLAN_ACT_SET;
8374 
8375 	tdls_data = &misc->param.tdls_config;
8376 	tdls_data->tdls_action = WLAN_TDLS_INIT_CHAN_SWITCH;
8377 
8378 	tdls_all_cfg = (tdls_all_config *)tdls_data->tdls_data;
8379 	moal_memcpy_ext(priv->phandle,
8380 			tdls_all_cfg->u.tdls_chan_switch.peer_mac_addr, addr,
8381 			ETH_ALEN,
8382 			sizeof(tdls_all_cfg->u.tdls_chan_switch.peer_mac_addr));
8383 	tdls_all_cfg->u.tdls_chan_switch.primary_channel =
8384 		chandef->chan->hw_value;
8385 	tdls_all_cfg->u.tdls_chan_switch.band = chandef->chan->band;
8386 	tdls_all_cfg->u.tdls_chan_switch.regulatory_class = oper_class;
8387 
8388 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
8389 	if (status != MLAN_STATUS_SUCCESS) {
8390 		PRINTM(MERROR, "TDLS channel switch request failed.\n");
8391 		ret = -EFAULT;
8392 		goto done;
8393 	}
8394 
8395 done:
8396 	if (status != MLAN_STATUS_PENDING)
8397 		kfree(ioctl_req);
8398 	LEAVE();
8399 	return ret;
8400 }
8401 
8402 /**
8403  * @brief tdls cancel channel switch
8404  *
8405  * @param wiphy                 A pointer to wiphy structure
8406  * @param dev                   A pointer to net_device structure
8407  * @param addr                  A pointer to peer addr
8408  *
8409  */
woal_cfg80211_tdls_cancel_channel_switch(struct wiphy * wiphy,struct net_device * dev,const u8 * addr)8410 void woal_cfg80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
8411 					      struct net_device *dev,
8412 					      const u8 *addr)
8413 {
8414 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
8415 	mlan_ioctl_req *ioctl_req = NULL;
8416 	mlan_ds_misc_cfg *misc = NULL;
8417 	mlan_ds_misc_tdls_config *tdls_data = NULL;
8418 	mlan_status status = MLAN_STATUS_SUCCESS;
8419 
8420 	ENTER();
8421 
8422 	if (!priv || !priv->phandle) {
8423 		PRINTM(MERROR, "priv or handle is null\n");
8424 		status = MLAN_STATUS_FAILURE;
8425 		goto done;
8426 	}
8427 
8428 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
8429 	if (ioctl_req == NULL) {
8430 		status = MLAN_STATUS_FAILURE;
8431 		goto done;
8432 	}
8433 
8434 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
8435 	misc->sub_command = MLAN_OID_MISC_TDLS_CONFIG;
8436 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
8437 	ioctl_req->action = MLAN_ACT_SET;
8438 
8439 	tdls_data = &misc->param.tdls_config;
8440 	tdls_data->tdls_action = WLAN_TDLS_STOP_CHAN_SWITCH;
8441 	moal_memcpy_ext(priv->phandle, tdls_data->tdls_data, addr, ETH_ALEN,
8442 			sizeof(tdls_data->tdls_data));
8443 
8444 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
8445 	if (status != MLAN_STATUS_SUCCESS)
8446 		goto done;
8447 
8448 	PRINTM(MIOCTL, "Tdls channel switch stop!\n");
8449 done:
8450 	if (status != MLAN_STATUS_PENDING)
8451 		kfree(ioctl_req);
8452 
8453 	LEAVE();
8454 }
8455 #endif
8456 #endif
8457 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
8458 /**
8459  * @brief change station info
8460  *
8461  * @param wiphy                 A pointer to wiphy structure
8462  * @param dev                   A pointer to net_device structure
8463  * @param mac                   A pointer to peer mac
8464  * @param params                station parameters
8465  *
8466  * @return                      0 -- success, otherwise fail
8467  */
woal_cfg80211_change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)8468 static int woal_cfg80211_change_station(struct wiphy *wiphy,
8469 					struct net_device *dev,
8470 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
8471 					const u8 *mac,
8472 #else
8473 					u8 *mac,
8474 #endif
8475 					struct station_parameters *params)
8476 {
8477 	int ret = 0;
8478 
8479 	ENTER();
8480 	/**do nothing*/
8481 
8482 	LEAVE();
8483 	return ret;
8484 }
8485 #endif
8486 
8487 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
8488 #ifdef UAP_SUPPORT
8489 /**
8490  * @brief add station
8491  *
8492  * @param wiphy                 A pointer to wiphy structure
8493  * @param dev                   A pointer to net_device structure
8494  * @param mac                  A pointer to peer mac
8495  * @param params           	station parameters
8496  *
8497  * @return                  	0 -- success, otherwise fail
8498  */
woal_cfg80211_add_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)8499 static int woal_cfg80211_add_station(struct wiphy *wiphy,
8500 				     struct net_device *dev,
8501 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
8502 				     const u8 *mac,
8503 #else
8504 				     u8 *mac,
8505 #endif
8506 				     struct station_parameters *params)
8507 {
8508 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
8509 	int ret = 0;
8510 
8511 	ENTER();
8512 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
8513 #ifdef UAP_SUPPORT
8514 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME) &&
8515 	    (priv->bss_role == MLAN_BSS_ROLE_UAP)) {
8516 		ret = woal_cfg80211_uap_add_station(wiphy, dev, (u8 *)mac,
8517 						    params);
8518 		LEAVE();
8519 		return ret;
8520 	}
8521 #endif
8522 #endif
8523 	if (!(params->sta_flags_set & MBIT(NL80211_STA_FLAG_TDLS_PEER)))
8524 		goto done;
8525 	/* make sure we are in connected mode */
8526 	if ((priv->bss_type != MLAN_BSS_TYPE_STA) ||
8527 	    (priv->media_connected == MFALSE)) {
8528 		ret = -ENOTSUPP;
8529 		goto done;
8530 	}
8531 	PRINTM(MMSG, "wlan: TDLS add peer station, address =" MACSTR "\n",
8532 	       MAC2STR(mac));
8533 	ret = woal_tdls_oper(priv, (u8 *)mac, WLAN_TDLS_CREATE_LINK);
8534 done:
8535 	LEAVE();
8536 	return ret;
8537 }
8538 #endif
8539 #endif
8540 
8541 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
8542 /**
8543  * @brief Update ft ie for Fast BSS Transition
8544  *
8545  * @param wiphy           A pointer to wiphy structure
8546  * @param dev             A pointer to net_device structure
8547  * @param ftie           A pointer to cfg80211_update_ft_ies_params structure
8548  *
8549  * @return                0 success , other failure
8550  */
woal_cfg80211_update_ft_ies(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_update_ft_ies_params * ftie)8551 int woal_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
8552 				struct cfg80211_update_ft_ies_params *ftie)
8553 {
8554 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
8555 	IEEEtypes_MobilityDomain_t *md_ie = NULL;
8556 	int ret = 0;
8557 	mlan_ds_misc_assoc_rsp *assoc_rsp = NULL;
8558 	IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
8559 	mlan_bss_info bss_info;
8560 
8561 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
8562 	struct cfg80211_roam_info roam_info = {};
8563 #endif
8564 
8565 	ENTER();
8566 
8567 	if (!ftie) {
8568 		LEAVE();
8569 		return ret;
8570 	}
8571 	assoc_rsp = kmalloc(sizeof(mlan_ds_misc_assoc_rsp), GFP_KERNEL);
8572 	if (!assoc_rsp) {
8573 		LEAVE();
8574 		return ret;
8575 	}
8576 #ifdef MLAN_64BIT
8577 	PRINTM(MINFO, "==>woal_cfg80211_update_ft_ies %lx \n", ftie->ie_len);
8578 #else
8579 	PRINTM(MINFO, "==>woal_cfg80211_update_ft_ies %x \n", ftie->ie_len);
8580 #endif
8581 	md_ie = (IEEEtypes_MobilityDomain_t *)woal_parse_ie_tlv(
8582 		ftie->ie, ftie->ie_len, MOBILITY_DOMAIN);
8583 	if (!md_ie) {
8584 		PRINTM(MERROR, "No Mobility domain IE\n");
8585 		kfree(assoc_rsp);
8586 		LEAVE();
8587 		return ret;
8588 	}
8589 	priv->ft_cap = md_ie->ft_cap;
8590 	if (priv->ft_ie_len) {
8591 		priv->pre_ft_ie_len = priv->ft_ie_len;
8592 		moal_memcpy_ext(priv->phandle, priv->pre_ft_ie, priv->ft_ie,
8593 				priv->ft_ie_len, MAX_IE_SIZE);
8594 	}
8595 	memset(priv->ft_ie, 0, MAX_IE_SIZE);
8596 	moal_memcpy_ext(priv->phandle, priv->ft_ie, ftie->ie,
8597 			MIN(ftie->ie_len, MAX_IE_SIZE), sizeof(priv->ft_ie));
8598 	priv->ft_ie_len = ftie->ie_len;
8599 	priv->ft_md = ftie->md;
8600 
8601 	if (!priv->ft_pre_connect) {
8602 		kfree(assoc_rsp);
8603 		LEAVE();
8604 		return ret;
8605 	}
8606 	/* check if is different AP */
8607 	if (!memcmp(&priv->target_ap_bssid, priv->cfg_bssid,
8608 		    MLAN_MAC_ADDR_LENGTH)) {
8609 		PRINTM(MMSG, "This is the same AP, no Fast bss transition\n");
8610 		kfree(assoc_rsp);
8611 		priv->ft_pre_connect = MFALSE;
8612 		priv->ft_ie_len = 0;
8613 		LEAVE();
8614 		return 0;
8615 	}
8616 
8617 	/* start fast BSS transition to target AP */
8618 	priv->assoc_status = 0;
8619 	priv->sme_current.bssid = priv->conn_bssid;
8620 	moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.bssid,
8621 			&priv->target_ap_bssid, MLAN_MAC_ADDR_LENGTH,
8622 			sizeof(priv->conn_bssid));
8623 	memset(assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
8624 	ret = woal_cfg80211_assoc(priv, (void *)&priv->sme_current,
8625 				  MOAL_IOCTL_WAIT, assoc_rsp);
8626 
8627 	if ((priv->ft_cap & MBIT(0)) || priv->ft_roaming_triggered_by_driver) {
8628 		if (!ret) {
8629 			woal_inform_bss_from_scan_result(priv, NULL,
8630 							 MOAL_IOCTL_WAIT);
8631 			passoc_rsp = (IEEEtypes_AssocRsp_t *)
8632 					     assoc_rsp->assoc_resp_buf;
8633 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
8634 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) || IMX_ANDROID_13)
8635 			roam_info.links[0].bssid = priv->cfg_bssid;
8636 #else
8637 			roam_info.bssid = priv->cfg_bssid;
8638 #endif
8639 			roam_info.req_ie = priv->sme_current.ie;
8640 			roam_info.req_ie_len = priv->sme_current.ie_len;
8641 			roam_info.resp_ie = passoc_rsp->ie_buffer;
8642 			roam_info.resp_ie_len = assoc_rsp->assoc_resp_len -
8643 						ASSOC_RESP_FIXED_SIZE;
8644 			cfg80211_roamed(priv->netdev, &roam_info, GFP_KERNEL);
8645 #else
8646 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
8647 			cfg80211_roamed(priv->netdev, NULL, priv->cfg_bssid,
8648 					priv->sme_current.ie,
8649 					priv->sme_current.ie_len,
8650 					passoc_rsp->ie_buffer,
8651 					assoc_rsp->assoc_resp_len -
8652 						ASSOC_RESP_FIXED_SIZE,
8653 					GFP_KERNEL);
8654 #else
8655 			cfg80211_roamed(priv->netdev, priv->cfg_bssid,
8656 					priv->sme_current.ie,
8657 					priv->sme_current.ie_len,
8658 					passoc_rsp->ie_buffer,
8659 					assoc_rsp->assoc_resp_len -
8660 						ASSOC_RESP_FIXED_SIZE,
8661 					GFP_KERNEL);
8662 #endif
8663 #endif
8664 			PRINTM(MMSG,
8665 			       "Fast BSS transition to bssid " MACSTR
8666 			       " successfully\n",
8667 			       MAC2STR(priv->cfg_bssid));
8668 		} else {
8669 			PRINTM(MMSG,
8670 			       "Fast BSS transition failed, keep connect to " MACSTR
8671 			       " \n",
8672 			       MAC2STR(priv->cfg_bssid));
8673 			moal_memcpy_ext(priv->phandle,
8674 					(void *)priv->sme_current.bssid,
8675 					&priv->cfg_bssid, MLAN_MAC_ADDR_LENGTH,
8676 					sizeof(priv->conn_bssid));
8677 			priv->ft_ie_len = priv->pre_ft_ie_len;
8678 			moal_memcpy_ext(priv->phandle, priv->ft_ie,
8679 					priv->pre_ft_ie, priv->pre_ft_ie_len,
8680 					MAX_IE_SIZE);
8681 		}
8682 		priv->ft_roaming_triggered_by_driver = MFALSE;
8683 
8684 	} else {
8685 		if (!ret) {
8686 			memset(assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
8687 			woal_get_assoc_rsp(priv, assoc_rsp, MOAL_IOCTL_WAIT);
8688 			passoc_rsp = (IEEEtypes_AssocRsp_t *)
8689 					     assoc_rsp->assoc_resp_buf;
8690 			cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
8691 						NULL, 0, passoc_rsp->ie_buffer,
8692 						assoc_rsp->assoc_resp_len -
8693 							ASSOC_RESP_FIXED_SIZE,
8694 						WLAN_STATUS_SUCCESS,
8695 						GFP_KERNEL);
8696 			PRINTM(MMSG,
8697 			       "wlan: Fast Bss transition to bssid " MACSTR
8698 			       " successfully\n",
8699 			       MAC2STR(priv->cfg_bssid));
8700 
8701 			memset(&bss_info, 0, sizeof(bss_info));
8702 			woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
8703 			priv->channel = bss_info.bss_chan;
8704 		} else {
8705 			PRINTM(MMSG,
8706 			       "wlan: Failed to connect to bssid " MACSTR "\n",
8707 			       MAC2STR(priv->target_ap_bssid));
8708 			cfg80211_connect_result(priv->netdev,
8709 						priv->target_ap_bssid, NULL, 0,
8710 						NULL, 0,
8711 						woal_get_assoc_status(priv),
8712 						GFP_KERNEL);
8713 			moal_memcpy_ext(priv->phandle,
8714 					(void *)priv->sme_current.bssid,
8715 					&priv->cfg_bssid, MLAN_MAC_ADDR_LENGTH,
8716 					sizeof(priv->conn_bssid));
8717 			memset(priv->target_ap_bssid, 0, ETH_ALEN);
8718 			priv->ft_ie_len = priv->pre_ft_ie_len;
8719 			moal_memcpy_ext(priv->phandle, priv->ft_ie,
8720 					priv->pre_ft_ie, priv->pre_ft_ie_len,
8721 					MAX_IE_SIZE);
8722 			// priv->ft_ie_len = 0;
8723 		}
8724 	}
8725 	kfree(assoc_rsp);
8726 	priv->ft_pre_connect = MFALSE;
8727 	LEAVE();
8728 	return 0;
8729 }
8730 #endif
8731 
8732 /**
8733  * @brief Save connect parameters for roaming
8734  *
8735  * @param priv            A pointer to moal_private
8736  * @param sme             A pointer to cfg80211_connect_params structure
8737  */
woal_save_conn_params(moal_private * priv,struct cfg80211_connect_params * sme)8738 void woal_save_conn_params(moal_private *priv,
8739 			   struct cfg80211_connect_params *sme)
8740 {
8741 	ENTER();
8742 	woal_clear_conn_params(priv);
8743 	moal_memcpy_ext(priv->phandle, &priv->sme_current, sme,
8744 			sizeof(struct cfg80211_connect_params),
8745 			sizeof(priv->sme_current));
8746 	if (sme->channel) {
8747 		priv->sme_current.channel = &priv->conn_chan;
8748 		moal_memcpy_ext(priv->phandle, priv->sme_current.channel,
8749 				sme->channel, sizeof(struct ieee80211_channel),
8750 				sizeof(priv->conn_chan));
8751 	}
8752 	if (sme->bssid) {
8753 		priv->sme_current.bssid = priv->conn_bssid;
8754 		moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.bssid,
8755 				sme->bssid, MLAN_MAC_ADDR_LENGTH,
8756 				sizeof(priv->conn_bssid));
8757 	}
8758 	if (sme->ssid && sme->ssid_len) {
8759 		priv->sme_current.ssid = priv->conn_ssid;
8760 		memset(priv->conn_ssid, 0, MLAN_MAX_SSID_LENGTH);
8761 		moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ssid,
8762 				sme->ssid, sme->ssid_len,
8763 				sizeof(priv->conn_ssid));
8764 	}
8765 	if (sme->ie && sme->ie_len) {
8766 		priv->sme_current.ie = kzalloc(sme->ie_len, GFP_KERNEL);
8767 		moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.ie,
8768 				sme->ie, sme->ie_len, sme->ie_len);
8769 	}
8770 	if (sme->key && sme->key_len && (sme->key_len <= MAX_WEP_KEY_SIZE)) {
8771 		priv->sme_current.key = priv->conn_wep_key;
8772 		moal_memcpy_ext(priv->phandle, (t_u8 *)priv->sme_current.key,
8773 				sme->key, sme->key_len,
8774 				sizeof(priv->conn_wep_key));
8775 	}
8776 	if (priv->sinfo)
8777 		memset(priv->sinfo, 0, sizeof(struct station_info));
8778 	else
8779 		priv->sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
8780 }
8781 
8782 /**
8783  * @brief clear connect parameters for ing
8784  *
8785  * @param priv            A pointer to moal_private
8786  */
woal_clear_conn_params(moal_private * priv)8787 void woal_clear_conn_params(moal_private *priv)
8788 {
8789 	ENTER();
8790 	if (priv->sme_current.ie_len)
8791 		kfree(priv->sme_current.ie);
8792 	memset(&priv->sme_current, 0, sizeof(struct cfg80211_connect_params));
8793 	priv->roaming_required = MFALSE;
8794 	priv->assoc_bss = NULL;
8795 	if (priv->sinfo) {
8796 		kfree(priv->sinfo);
8797 		priv->sinfo = NULL;
8798 	}
8799 	LEAVE();
8800 }
8801 
8802 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
8803 /**
8804  * @brief Build new roaming connect ie for okc
8805  *
8806  * @param priv            A pointer to moal_private
8807  * @param entry           A pointer to pmksa_entry
8808  **/
woal_update_okc_roaming_ie(moal_private * priv,struct pmksa_entry * entry)8809 static int woal_update_okc_roaming_ie(moal_private *priv,
8810 				      struct pmksa_entry *entry)
8811 {
8812 	struct cfg80211_connect_params *sme = &priv->sme_current;
8813 	int ret = MLAN_STATUS_SUCCESS;
8814 	const t_u8 *sme_pos, *sme_ptr;
8815 	t_u8 *okc_ie_pos;
8816 	t_u8 id, ie_len;
8817 	int left_len;
8818 
8819 	ENTER();
8820 
8821 	if (!sme->ie || !sme->ie_len) {
8822 		PRINTM(MERROR, "No connect ie saved in driver\n");
8823 		ret = MLAN_STATUS_FAILURE;
8824 		goto done;
8825 	}
8826 
8827 	if (!entry) {
8828 		PRINTM(MERROR, "No roaming ap pmkid\n");
8829 		ret = MLAN_STATUS_FAILURE;
8830 		goto done;
8831 	}
8832 
8833 	if (!priv->okc_roaming_ie) {
8834 		int okc_ie_len = sme->ie_len + sizeof(t_u16) + PMKID_LEN;
8835 
8836 		/** Alloc new buffer for okc roaming ie */
8837 		priv->okc_roaming_ie = kzalloc(okc_ie_len, GFP_KERNEL);
8838 		if (!priv->okc_roaming_ie) {
8839 			PRINTM(MERROR, "Fail to allocate assoc req ie\n");
8840 			ret = MLAN_STATUS_FAILURE;
8841 			goto done;
8842 		}
8843 	}
8844 
8845 	/* Build OKC RSN IE with PMKID list
8846 	 * Format of RSN IE: length(bytes) and container
8847 	 * | 1| 1 |   2   |          4            |           2               |
8848 	 * |id|len|version|group data cipher suite|pairwise cipher suite count|
8849 	 * |          4 * m           |       2       |    4 * n     |   2    |
8850 	 * |pairwise cipher suite list|AKM suite count|AKM suite list|RSN Cap |
8851 	 * |    2     |  16 * s  |              4              |
8852 	 * |PMKIDCount|PMKID List|Group Management Cipher Suite|
8853 	 */
8854 #define PAIRWISE_CIPHER_COUNT_OFFSET 8
8855 #define AKM_SUITE_COUNT_OFFSET(n) (10 + (n)*4)
8856 #define PMKID_COUNT_OFFSET(n) (14 + (n)*4)
8857 
8858 	sme_pos = sme->ie;
8859 	left_len = sme->ie_len;
8860 	okc_ie_pos = priv->okc_roaming_ie;
8861 	priv->okc_ie_len = 0;
8862 
8863 	while (left_len >= 2) {
8864 		id = *sme_pos;
8865 		ie_len = *(sme_pos + 1);
8866 		if ((ie_len + 2) > left_len) {
8867 			PRINTM(MERROR, "Invalid ie len %d\n", ie_len);
8868 			ret = MLAN_STATUS_FAILURE;
8869 			goto done;
8870 		}
8871 
8872 		if (id == RSN_IE) {
8873 			t_u16 pairwise_count, akm_count;
8874 			t_u8 *rsn_ie_len;
8875 			int rsn_offset;
8876 
8877 			pairwise_count =
8878 				*(t_u16 *)(sme_pos +
8879 					   PAIRWISE_CIPHER_COUNT_OFFSET);
8880 			akm_count =
8881 				*(t_u16 *)(sme_pos + AKM_SUITE_COUNT_OFFSET(
8882 							     pairwise_count));
8883 			rsn_offset =
8884 				PMKID_COUNT_OFFSET(pairwise_count + akm_count);
8885 			sme_ptr = (t_u8 *)(sme_pos + rsn_offset);
8886 
8887 			moal_memcpy_ext(priv->phandle, okc_ie_pos, sme_pos,
8888 					rsn_offset, rsn_offset);
8889 			rsn_ie_len = okc_ie_pos + 1;
8890 			okc_ie_pos += rsn_offset;
8891 			*(t_u16 *)okc_ie_pos = 1;
8892 			okc_ie_pos += sizeof(t_u16);
8893 			moal_memcpy_ext(priv->phandle, okc_ie_pos, entry->pmkid,
8894 					PMKID_LEN, PMKID_LEN);
8895 			okc_ie_pos += PMKID_LEN;
8896 			priv->okc_ie_len +=
8897 				rsn_offset + sizeof(t_u16) + PMKID_LEN;
8898 			*rsn_ie_len =
8899 				rsn_offset - 2 + sizeof(t_u16) + PMKID_LEN;
8900 
8901 			if ((ie_len + 2) > rsn_offset) {
8902 				/** Previous conn ie include pmkid list */
8903 				u16 pmkid_count = *(t_u16 *)sme_ptr;
8904 				rsn_offset += (sizeof(t_u16) +
8905 					       PMKID_LEN * pmkid_count);
8906 				if ((ie_len + 2) > rsn_offset) {
8907 					sme_ptr += (sizeof(t_u16) +
8908 						    PMKID_LEN * pmkid_count);
8909 					moal_memcpy_ext(
8910 						priv->phandle, okc_ie_pos,
8911 						sme_ptr,
8912 						(ie_len + 2 - rsn_offset),
8913 						(ie_len + 2 - rsn_offset));
8914 					okc_ie_pos += (ie_len + 2 - rsn_offset);
8915 					priv->okc_ie_len +=
8916 						(ie_len + 2 - rsn_offset);
8917 					*rsn_ie_len +=
8918 						(ie_len + 2 - rsn_offset);
8919 				}
8920 			}
8921 		} else {
8922 			moal_memcpy_ext(priv->phandle, okc_ie_pos, sme_pos,
8923 					ie_len + 2, ie_len + 2);
8924 			okc_ie_pos += ie_len + 2;
8925 			priv->okc_ie_len += ie_len + 2;
8926 		}
8927 
8928 		sme_pos += (ie_len + 2);
8929 		left_len -= (ie_len + 2);
8930 	}
8931 
8932 done:
8933 	if (ret != MLAN_STATUS_SUCCESS) {
8934 		if (priv->okc_roaming_ie) {
8935 			kfree(priv->okc_roaming_ie);
8936 			priv->okc_roaming_ie = NULL;
8937 			priv->okc_ie_len = 0;
8938 		}
8939 	}
8940 
8941 	LEAVE();
8942 	return ret;
8943 }
8944 #endif
8945 
8946 /**
8947  * @brief Start roaming: driver handle roaming
8948  *
8949  * @param priv      A pointer to moal_private structure
8950  *
8951  * @return          N/A
8952  */
woal_start_roaming(moal_private * priv)8953 void woal_start_roaming(moal_private *priv)
8954 {
8955 	mlan_ds_get_signal signal;
8956 	mlan_ssid_bssid *ssid_bssid = NULL;
8957 	char rssi_low[10];
8958 	int ret = 0;
8959 	mlan_ds_misc_assoc_rsp *assoc_rsp = NULL;
8960 	IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
8961 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
8962 	struct cfg80211_roam_info roam_info = {};
8963 #endif
8964 
8965 	ENTER();
8966 	if (priv->ft_roaming_triggered_by_driver) {
8967 		PRINTM(MIOCTL, "FT roaming is in processing ...... \n");
8968 		LEAVE();
8969 		return;
8970 	}
8971 	ssid_bssid = kmalloc(sizeof(mlan_ssid_bssid), GFP_KERNEL);
8972 	if (!ssid_bssid) {
8973 		LEAVE();
8974 		return;
8975 	}
8976 
8977 	if (priv->last_event & EVENT_BG_SCAN_REPORT) {
8978 		woal_inform_bss_from_scan_result(priv, NULL, MOAL_IOCTL_WAIT);
8979 		PRINTM(MIOCTL, "Report bgscan result\n");
8980 	}
8981 	if (priv->media_connected == MFALSE || !priv->sme_current.ssid_len) {
8982 		PRINTM(MIOCTL, "Not connected, ignore roaming\n");
8983 		kfree(ssid_bssid);
8984 		LEAVE();
8985 		return;
8986 	}
8987 
8988 	/* Get signal information from the firmware */
8989 	memset(&signal, 0, sizeof(mlan_ds_get_signal));
8990 	if (MLAN_STATUS_SUCCESS !=
8991 	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
8992 		PRINTM(MERROR, "Error getting signal information\n");
8993 		ret = -EFAULT;
8994 		goto done;
8995 	}
8996 	memset(ssid_bssid, 0, sizeof(mlan_ssid_bssid));
8997 	ssid_bssid->ssid.ssid_len = priv->sme_current.ssid_len;
8998 	moal_memcpy_ext(priv->phandle, ssid_bssid->ssid.ssid,
8999 			priv->sme_current.ssid, priv->sme_current.ssid_len,
9000 			sizeof(ssid_bssid->ssid.ssid));
9001 	if (MLAN_STATUS_SUCCESS !=
9002 	    woal_find_best_network(priv, MOAL_IOCTL_WAIT, ssid_bssid)) {
9003 		PRINTM(MIOCTL, "Can not find better network\n");
9004 		ret = -EFAULT;
9005 		goto done;
9006 	}
9007 	/* check if we found different AP */
9008 	if (!memcmp(&ssid_bssid->bssid, priv->cfg_bssid,
9009 		    MLAN_MAC_ADDR_LENGTH)) {
9010 		PRINTM(MIOCTL, "This is the same AP, no roaming\n");
9011 		ret = -EFAULT;
9012 		goto done;
9013 	}
9014 	PRINTM(MIOCTL, "Find AP: bssid=" MACSTR ", signal=%d\n",
9015 	       MAC2STR(ssid_bssid->bssid), ssid_bssid->rssi);
9016 	/* check signal */
9017 	if (!(priv->last_event & EVENT_PRE_BCN_LOST)) {
9018 		if ((abs(signal.bcn_rssi_avg) - abs(ssid_bssid->rssi)) <
9019 		    DELTA_RSSI) {
9020 			PRINTM(MERROR, "New AP's signal is not good too.\n");
9021 			ret = -EFAULT;
9022 			goto done;
9023 		}
9024 	}
9025 	/**check if need start FT Roaming*/
9026 	if (priv->ft_ie_len && (priv->ft_md == ssid_bssid->ft_md) &&
9027 	    (priv->ft_cap == ssid_bssid->ft_cap)) {
9028 		priv->ft_roaming_triggered_by_driver = MTRUE;
9029 		woal_start_ft_roaming(priv, ssid_bssid);
9030 		goto done;
9031 	}
9032 	/* start roaming to new AP */
9033 	priv->sme_current.bssid = priv->conn_bssid;
9034 	moal_memcpy_ext(priv->phandle, (void *)priv->sme_current.bssid,
9035 			&ssid_bssid->bssid, MLAN_MAC_ADDR_LENGTH,
9036 			sizeof(priv->conn_bssid));
9037 
9038 #ifdef STA_CFG80211
9039 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
9040 	if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
9041 		/** Check if current roaming support OKC offload roaming */
9042 		if (priv->sme_current.crypto.n_akm_suites &&
9043 		    priv->sme_current.crypto.akm_suites[0] ==
9044 			    WLAN_AKM_SUITE_8021X) {
9045 			struct pmksa_entry *entry = NULL;
9046 
9047 			/** Get OKC PMK Cache entry
9048 			 *  Firstly try to get pmksa from cfg80211
9049 			 */
9050 			priv->wait_target_ap_pmkid = MTRUE;
9051 			cfg80211_pmksa_candidate_notify(priv->netdev, 0,
9052 							priv->sme_current.bssid,
9053 							MTRUE, GFP_ATOMIC);
9054 			if (wait_event_interruptible_timeout(
9055 				    priv->okc_wait_q,
9056 				    !priv->wait_target_ap_pmkid,
9057 				    OKC_WAIT_TARGET_PMKSA_TIMEOUT)) {
9058 				PRINTM(MIOCTL, "OKC Roaming is ready\n");
9059 				entry = priv->target_ap_pmksa;
9060 			} else {
9061 				/** Try to get pmksa from pmksa list */
9062 				priv->wait_target_ap_pmkid = MFALSE;
9063 				entry = woal_get_pmksa_entry(
9064 					priv, priv->sme_current.bssid);
9065 			}
9066 			/** Build okc roaming ie */
9067 			woal_update_okc_roaming_ie(priv, entry);
9068 			priv->target_ap_pmksa = NULL;
9069 		}
9070 	}
9071 #endif
9072 #endif
9073 	assoc_rsp = kzalloc(sizeof(mlan_ds_misc_assoc_rsp), GFP_ATOMIC);
9074 	if (!assoc_rsp) {
9075 		PRINTM(MERROR, "Failed to allocate memory for assoc_rsp\n");
9076 		ret = -ENOMEM;
9077 		goto done;
9078 	}
9079 	ret = woal_cfg80211_assoc(priv, (void *)&priv->sme_current,
9080 				  MOAL_IOCTL_WAIT, assoc_rsp);
9081 	if (!ret) {
9082 		const t_u8 *ie;
9083 		int ie_len;
9084 
9085 		woal_inform_bss_from_scan_result(priv, NULL, MOAL_IOCTL_WAIT);
9086 		passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp->assoc_resp_buf;
9087 
9088 		/** Update connect ie in roam event */
9089 		ie = priv->sme_current.ie;
9090 		ie_len = priv->sme_current.ie_len;
9091 #ifdef STA_CFG80211
9092 		if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) {
9093 			/** Check if current roaming support OKC offload roaming
9094 			 */
9095 			if (priv->sme_current.crypto.n_akm_suites &&
9096 			    priv->sme_current.crypto.akm_suites[0] ==
9097 				    WLAN_AKM_SUITE_8021X) {
9098 				if (priv->okc_roaming_ie && priv->okc_ie_len) {
9099 					ie = priv->okc_roaming_ie;
9100 					ie_len = priv->okc_ie_len;
9101 				}
9102 			}
9103 		}
9104 #endif
9105 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
9106 #if ((CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) || IMX_ANDROID_13)
9107 		roam_info.links[0].bssid = priv->cfg_bssid;
9108 #else
9109 		roam_info.bssid = priv->cfg_bssid;
9110 #endif
9111 		roam_info.req_ie = ie;
9112 		roam_info.req_ie_len = ie_len;
9113 		roam_info.resp_ie = passoc_rsp->ie_buffer;
9114 		roam_info.resp_ie_len =
9115 			assoc_rsp->assoc_resp_len - ASSOC_RESP_FIXED_SIZE;
9116 		cfg80211_roamed(priv->netdev, &roam_info, GFP_KERNEL);
9117 #else
9118 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
9119 		cfg80211_roamed(priv->netdev, NULL, priv->cfg_bssid, ie, ie_len,
9120 				passoc_rsp->ie_buffer,
9121 				assoc_rsp->assoc_resp_len -
9122 					ASSOC_RESP_FIXED_SIZE,
9123 				GFP_KERNEL);
9124 #else
9125 		cfg80211_roamed(priv->netdev, priv->cfg_bssid, ie, ie_len,
9126 				passoc_rsp->ie_buffer,
9127 				assoc_rsp->assoc_resp_len -
9128 					ASSOC_RESP_FIXED_SIZE,
9129 				GFP_KERNEL);
9130 #endif
9131 #endif
9132 		PRINTM(MMSG, "Roamed to bssid " MACSTR " successfully\n",
9133 		       MAC2STR(priv->cfg_bssid));
9134 	} else {
9135 		PRINTM(MIOCTL, "Roaming to bssid " MACSTR " failed\n",
9136 		       MAC2STR(ssid_bssid->bssid));
9137 	}
9138 	kfree(assoc_rsp);
9139 done:
9140 	kfree(ssid_bssid);
9141 	/* config rssi low threshold again */
9142 	priv->last_event = 0;
9143 	priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD;
9144 	sprintf(rssi_low, "%d", priv->rssi_low);
9145 	if (MLAN_STATUS_FAILURE ==
9146 	    woal_set_rssi_low_threshold(priv, rssi_low, MOAL_IOCTL_WAIT))
9147 		PRINTM(MERROR, "set_rssi_low_threshold fail\n");
9148 	LEAVE();
9149 	return;
9150 }
9151 
9152 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
9153 #ifdef UAP_SUPPORT
9154 /**
9155  * @brief add uap station
9156  *
9157  * @param wiphy                 A pointer to wiphy structure
9158  * @param dev                   A pointer to net_device structure
9159  * @param mac                  A pointer to peer mac
9160  * @param params           	station parameters
9161  *
9162  * @return                  	0 -- success, otherwise fail
9163  */
woal_cfg80211_uap_add_station(struct wiphy * wiphy,struct net_device * dev,u8 * mac,struct station_parameters * params)9164 int woal_cfg80211_uap_add_station(struct wiphy *wiphy, struct net_device *dev,
9165 				  u8 *mac, struct station_parameters *params)
9166 {
9167 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
9168 	mlan_ioctl_req *req = NULL;
9169 	t_u32 req_len = 0;
9170 	mlan_ds_bss *bss = NULL;
9171 	t_u8 *pos;
9172 	t_u8 qosinfo;
9173 	MrvlIEtypes_Data_t *tlv;
9174 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
9175 	MrvlExtIEtypes_Data_t *ext_tlv;
9176 #endif
9177 	mlan_status status;
9178 	int ret = 0;
9179 
9180 	ENTER();
9181 
9182 	req_len = sizeof(mlan_ds_bss);
9183 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
9184 	if (params->ext_capab_len)
9185 		req_len += sizeof(MrvlIEtypesHeader_t) + params->ext_capab_len;
9186 #endif
9187 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9188 	if (params->link_sta_params.supported_rates_len)
9189 		req_len += sizeof(MrvlIEtypesHeader_t) +
9190 			   params->link_sta_params.supported_rates_len;
9191 #else
9192 	if (params->supported_rates_len)
9193 		req_len += sizeof(MrvlIEtypesHeader_t) +
9194 			   params->supported_rates_len;
9195 #endif
9196 	if (params->uapsd_queues || params->max_sp)
9197 		req_len += sizeof(MrvlIEtypesHeader_t) + sizeof(qosinfo);
9198 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9199 	if (params->link_sta_params.ht_capa)
9200 #else
9201 	if (params->ht_capa)
9202 #endif
9203 		req_len += sizeof(MrvlIEtypesHeader_t) +
9204 			   sizeof(struct ieee80211_ht_cap);
9205 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9206 	if (params->link_sta_params.vht_capa)
9207 #else
9208 	if (params->vht_capa)
9209 #endif
9210 		req_len += sizeof(MrvlIEtypesHeader_t) +
9211 			   sizeof(struct ieee80211_vht_cap);
9212 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
9213 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9214 	if (params->link_sta_params.opmode_notif_used)
9215 		req_len += sizeof(MrvlIEtypesHeader_t) + sizeof(u8);
9216 #else
9217 	if (params->opmode_notif_used)
9218 		req_len += sizeof(MrvlIEtypesHeader_t) + sizeof(u8);
9219 #endif
9220 #endif
9221 
9222 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
9223 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9224 	if (params->link_sta_params.he_capa_len)
9225 		req_len += sizeof(MrvlExtIEtypesHeader_t) +
9226 			   params->link_sta_params.he_capa_len;
9227 #else
9228 	if (params->he_capa_len)
9229 		req_len += sizeof(MrvlExtIEtypesHeader_t) + params->he_capa_len;
9230 #endif
9231 #endif
9232 	req = woal_alloc_mlan_ioctl_req(req_len);
9233 	if (req == NULL) {
9234 		ret = -ENOMEM;
9235 		goto done;
9236 	}
9237 	bss = (mlan_ds_bss *)req->pbuf;
9238 	bss->sub_command = MLAN_OID_UAP_ADD_STATION;
9239 	req->req_id = MLAN_IOCTL_BSS;
9240 	req->action = MLAN_ACT_SET;
9241 	bss->param.sta_info.listen_interval = params->listen_interval;
9242 	bss->param.sta_info.aid = params->aid;
9243 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
9244 	bss->param.sta_info.cap_info = params->capability;
9245 #else
9246 	bss->param.sta_info.cap_info = 0;
9247 #endif
9248 	bss->param.sta_info.tlv_len = 0;
9249 	bss->param.sta_info.sta_flags = params->sta_flags_set;
9250 	moal_memcpy_ext(priv->phandle, bss->param.sta_info.peer_mac, mac,
9251 			MLAN_MAC_ADDR_LENGTH,
9252 			sizeof(bss->param.sta_info.peer_mac));
9253 	PRINTM(MMSG, "wlan: UAP/GO add peer station, address =" MACSTR "\n",
9254 	       MAC2STR(mac));
9255 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
9256 	PRINTM(MCMND,
9257 	       "sta_flags=0x%x listen_interval=%d aid=%d cap_info=0x%x\n",
9258 	       params->sta_flags_set, params->listen_interval, params->aid,
9259 	       params->capability);
9260 #else
9261 	PRINTM(MCMND, "sta_flags=0x%x listen_interval=%d aid=%d\n",
9262 	       params->sta_flags_set, params->listen_interval, params->aid);
9263 #endif
9264 	pos = &bss->param.sta_info.tlv[0];
9265 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
9266 	if (params->ext_capab_len) {
9267 		tlv = (MrvlIEtypes_Data_t *)pos;
9268 		tlv->header.type = EXT_CAPABILITY;
9269 		tlv->header.len = params->ext_capab_len;
9270 		moal_memcpy_ext(priv->phandle, tlv->data, params->ext_capab,
9271 				tlv->header.len, tlv->header.len);
9272 		pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9273 		bss->param.sta_info.tlv_len +=
9274 			sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9275 		tlv = (MrvlIEtypes_Data_t *)pos;
9276 	}
9277 #endif
9278 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9279 	if (params->link_sta_params.supported_rates_len) {
9280 #else
9281 	if (params->supported_rates_len) {
9282 #endif
9283 		tlv = (MrvlIEtypes_Data_t *)pos;
9284 		tlv->header.type = SUPPORTED_RATES;
9285 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9286 		tlv->header.len = params->link_sta_params.supported_rates_len;
9287 #else
9288 		tlv->header.len = params->supported_rates_len;
9289 #endif
9290 		moal_memcpy_ext(priv->phandle, tlv->data,
9291 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9292 				params->link_sta_params.supported_rates,
9293 				tlv->header.len,
9294 #else
9295 				params->supported_rates, tlv->header.len,
9296 #endif
9297 				tlv->header.len);
9298 		pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9299 		bss->param.sta_info.tlv_len +=
9300 			sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9301 		tlv = (MrvlIEtypes_Data_t *)pos;
9302 	}
9303 	if (params->uapsd_queues || params->max_sp) {
9304 		tlv = (MrvlIEtypes_Data_t *)pos;
9305 		tlv->header.type = QOS_INFO;
9306 		tlv->header.len = sizeof(qosinfo);
9307 		qosinfo = params->uapsd_queues | (params->max_sp << 5);
9308 		moal_memcpy_ext(priv->phandle, tlv->data, &qosinfo,
9309 				tlv->header.len, tlv->header.len);
9310 		pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9311 		bss->param.sta_info.tlv_len +=
9312 			sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9313 		tlv = (MrvlIEtypes_Data_t *)pos;
9314 	}
9315 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9316 	if (params->link_sta_params.ht_capa) {
9317 #else
9318 	if (params->ht_capa) {
9319 #endif
9320 		tlv = (MrvlIEtypes_Data_t *)pos;
9321 		tlv->header.type = HT_CAPABILITY;
9322 		tlv->header.len = sizeof(struct ieee80211_ht_cap);
9323 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9324 		moal_memcpy_ext(priv->phandle, tlv->data,
9325 				params->link_sta_params.ht_capa,
9326 #else
9327 		moal_memcpy_ext(priv->phandle, tlv->data, params->ht_capa,
9328 #endif
9329 				tlv->header.len, tlv->header.len);
9330 		pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9331 		bss->param.sta_info.tlv_len +=
9332 			sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9333 		tlv = (MrvlIEtypes_Data_t *)pos;
9334 	}
9335 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9336 	if (params->link_sta_params.vht_capa) {
9337 #else
9338 	if (params->vht_capa) {
9339 #endif
9340 		tlv = (MrvlIEtypes_Data_t *)pos;
9341 		tlv->header.type = VHT_CAPABILITY;
9342 		tlv->header.len = sizeof(struct ieee80211_vht_cap);
9343 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9344 		moal_memcpy_ext(priv->phandle, tlv->data,
9345 				params->link_sta_params.vht_capa,
9346 #else
9347 		moal_memcpy_ext(priv->phandle, tlv->data, params->vht_capa,
9348 #endif
9349 				tlv->header.len, tlv->header.len);
9350 		pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9351 		bss->param.sta_info.tlv_len +=
9352 			sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9353 		tlv = (MrvlIEtypes_Data_t *)pos;
9354 	}
9355 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
9356 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9357 	if (params->link_sta_params.opmode_notif_used) {
9358 #else
9359 	if (params->opmode_notif_used) {
9360 #endif
9361 		tlv = (MrvlIEtypes_Data_t *)pos;
9362 		tlv->header.type = OPER_MODE_NTF;
9363 		tlv->header.len = sizeof(u8);
9364 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9365 		moal_memcpy_ext(priv->phandle, tlv->data,
9366 				&params->link_sta_params.opmode_notif,
9367 #else
9368 		moal_memcpy_ext(priv->phandle, tlv->data, &params->opmode_notif,
9369 #endif
9370 				tlv->header.len, tlv->header.len);
9371 		pos += sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9372 		bss->param.sta_info.tlv_len +=
9373 			sizeof(MrvlIEtypesHeader_t) + tlv->header.len;
9374 		tlv = (MrvlIEtypes_Data_t *)pos;
9375 	}
9376 #endif
9377 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
9378 	if (params->link_sta_params.he_capa_len) {
9379 		ext_tlv = (MrvlExtIEtypes_Data_t *)pos;
9380 		ext_tlv->header.type = EXTENSION;
9381 		ext_tlv->header.len =
9382 			params->link_sta_params.he_capa_len + sizeof(u8);
9383 		ext_tlv->header.ext_id = HE_CAPABILITY;
9384 		moal_memcpy_ext(priv->phandle, ext_tlv->data,
9385 				(u8 *)params->link_sta_params.he_capa,
9386 				params->link_sta_params.he_capa_len,
9387 				params->link_sta_params.he_capa_len);
9388 		pos += sizeof(MrvlExtIEtypesHeader_t) +
9389 		       params->link_sta_params.he_capa_len;
9390 		bss->param.sta_info.tlv_len +=
9391 			sizeof(MrvlExtIEtypesHeader_t) +
9392 			params->link_sta_params.he_capa_len;
9393 		tlv = (MrvlIEtypes_Data_t *)pos;
9394 	}
9395 #elif CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
9396 	if (params->he_capa_len) {
9397 		ext_tlv = (MrvlExtIEtypes_Data_t *)pos;
9398 		ext_tlv->header.type = EXTENSION;
9399 		ext_tlv->header.len = params->he_capa_len + sizeof(u8);
9400 		ext_tlv->header.ext_id = HE_CAPABILITY;
9401 		moal_memcpy_ext(priv->phandle, ext_tlv->data,
9402 				(u8 *)params->he_capa, params->he_capa_len,
9403 				params->he_capa_len);
9404 		pos += sizeof(MrvlExtIEtypesHeader_t) + params->he_capa_len;
9405 		bss->param.sta_info.tlv_len +=
9406 			sizeof(MrvlExtIEtypesHeader_t) + params->he_capa_len;
9407 		tlv = (MrvlIEtypes_Data_t *)pos;
9408 	}
9409 #endif
9410 	DBG_HEXDUMP(MCMD_D, "sta tlv", &bss->param.sta_info.tlv[0],
9411 		    bss->param.sta_info.tlv_len);
9412 	/* Send IOCTL request to MLAN */
9413 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
9414 	if (status != MLAN_STATUS_PENDING)
9415 		kfree(req);
9416 #if KERNEL_VERSION(3, 8, 0) <= CFG80211_VERSION_CODE
9417 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
9418 		struct station_info *sinfo = NULL;
9419 		sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
9420 		if (sinfo) {
9421 			cfg80211_new_sta(dev, mac, sinfo, GFP_KERNEL);
9422 			kfree(sinfo);
9423 		}
9424 	}
9425 #endif
9426 done:
9427 	LEAVE();
9428 	return ret;
9429 }
9430 
9431 /**
9432  *  @brief This function is probe client handle.
9433  *
9434  *  @param wiphy       A pointer to wiphy.
9435  *
9436  *  @param dev         A pointer to net_device
9437  *
9438  *  @param peer        A pointer to peer
9439  *
9440  *  @param cookie      A pointer to cookie
9441  *
9442  *  @return            0 -- success, otherwise fail
9443  */
9444 static int woal_cfg80211_probe_client(struct wiphy *wiphy,
9445 				      struct net_device *dev, const u8 *peer,
9446 				      u64 *cookie)
9447 {
9448 	return -1;
9449 }
9450 #endif
9451 
9452 /**
9453  *  @brief Sends deauth packet to kernel
9454  *
9455  *  @param priv A pointer to moal_private struct
9456  *  @param sa   A pointer to source address
9457  *  @param reason_code  disconnect reason code
9458  *  @return     N/A
9459  */
9460 void woal_host_mlme_disconnect(moal_private *priv, u16 reason_code, u8 *sa)
9461 {
9462 	t_u8 broadcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
9463 	t_u8 frame_buf[26];
9464 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)frame_buf;
9465 	ENTER();
9466 
9467 	mgmt->frame_control = (__force __le16)IEEE80211_STYPE_DEAUTH;
9468 	mgmt->duration = 0;
9469 	mgmt->seq_ctrl = 0;
9470 	mgmt->u.deauth.reason_code = (__force __le16)reason_code;
9471 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
9472 		moal_memcpy_ext(priv->phandle, mgmt->da, broadcast_addr,
9473 				ETH_ALEN, sizeof(mgmt->da));
9474 		moal_memcpy_ext(priv->phandle, mgmt->sa,
9475 				priv->sme_current.bssid, ETH_ALEN,
9476 				sizeof(mgmt->sa));
9477 		moal_memcpy_ext(priv->phandle, mgmt->bssid, priv->cfg_bssid,
9478 				ETH_ALEN, sizeof(mgmt->bssid));
9479 		priv->host_mlme = MFALSE;
9480 		priv->auth_flag = 0;
9481 	} else {
9482 		moal_memcpy_ext(priv->phandle, mgmt->da, priv->current_addr,
9483 				ETH_ALEN, sizeof(mgmt->da));
9484 		moal_memcpy_ext(priv->phandle, mgmt->sa, sa, ETH_ALEN,
9485 				sizeof(mgmt->sa));
9486 		moal_memcpy_ext(priv->phandle, mgmt->bssid, priv->current_addr,
9487 				ETH_ALEN, sizeof(mgmt->bssid));
9488 		PRINTM(MMSG,
9489 		       "wlan: hostmlme notify deauth station " MACSTR "\n",
9490 		       MAC2STR(sa));
9491 	}
9492 
9493 	if (GET_BSS_ROLE(priv) != MLAN_BSS_ROLE_UAP) {
9494 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
9495 		mutex_lock(&priv->wdev->mtx);
9496 		cfg80211_rx_mlme_mgmt(priv->netdev, frame_buf, 26);
9497 		mutex_unlock(&priv->wdev->mtx);
9498 #else
9499 		cfg80211_send_deauth(priv->netdev, frame_buf, 26);
9500 #endif
9501 
9502 	} else {
9503 		int freq = ieee80211_channel_to_frequency(
9504 			priv->channel
9505 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
9506 			,
9507 			(priv->channel <= 14 ? IEEE80211_BAND_2GHZ :
9508 					       IEEE80211_BAND_5GHZ)
9509 #endif
9510 		);
9511 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
9512 		cfg80211_rx_mgmt(
9513 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
9514 			priv->wdev,
9515 #else
9516 			priv->netdev,
9517 #endif
9518 			freq, 0, frame_buf, 26
9519 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
9520 			,
9521 			0
9522 #endif
9523 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
9524 			,
9525 			GFP_ATOMIC
9526 #endif
9527 		);
9528 #else
9529 		cfg80211_rx_mgmt(priv->netdev, freq, frame_buf, 26, GFP_ATOMIC);
9530 #endif
9531 	}
9532 
9533 	LEAVE();
9534 	return;
9535 }
9536 #endif
9537 
9538 /**
9539  * @brief Register the device with cfg80211
9540  *
9541  * @param dev       A pointer to net_device structure
9542  * @param bss_type  BSS type
9543  *
9544  * @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
9545  */
9546 mlan_status woal_register_sta_cfg80211(struct net_device *dev, t_u8 bss_type)
9547 {
9548 	mlan_status ret = MLAN_STATUS_SUCCESS;
9549 	moal_private *priv = (moal_private *)netdev_priv(dev);
9550 	struct wireless_dev *wdev = NULL;
9551 	int psmode = 0;
9552 	enum ieee80211_band band;
9553 
9554 	ENTER();
9555 
9556 	wdev = (struct wireless_dev *)&priv->w_dev;
9557 	memset(wdev, 0, sizeof(struct wireless_dev));
9558 	wdev->wiphy = priv->phandle->wiphy;
9559 	if (!wdev->wiphy) {
9560 		LEAVE();
9561 		return MLAN_STATUS_FAILURE;
9562 	}
9563 	if (bss_type == MLAN_BSS_TYPE_STA) {
9564 		wdev->iftype = NL80211_IFTYPE_STATION;
9565 		priv->roaming_enabled = MFALSE;
9566 		priv->roaming_required = MFALSE;
9567 	}
9568 #ifdef WIFI_DIRECT_SUPPORT
9569 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
9570 	if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
9571 		wdev->iftype = NL80211_IFTYPE_STATION;
9572 #endif
9573 #endif
9574 	dev_net_set(dev, wiphy_net(wdev->wiphy));
9575 	dev->ieee80211_ptr = wdev;
9576 	SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
9577 	priv->wdev = wdev;
9578 	/* Get IEEE power save mode */
9579 	if (MLAN_STATUS_SUCCESS == woal_set_get_power_mgmt(priv, MLAN_ACT_GET,
9580 							   &psmode, 0,
9581 							   MOAL_IOCTL_WAIT)) {
9582 		/* Save the IEEE power save mode to wiphy, because after
9583 		 * warmreset wiphy power save should be updated instead
9584 		 * of using the last saved configuration */
9585 		if (psmode)
9586 			priv->wdev->ps = MTRUE;
9587 		else
9588 			priv->wdev->ps = MFALSE;
9589 	}
9590 	if (priv->phandle->country_code[0] && priv->phandle->country_code[1]) {
9591 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
9592 		if (priv->phandle->params.cntry_txpwr == CNTRY_RGPOWER_MODE &&
9593 		    !priv->phandle->params.txpwrlimit_cfg)
9594 			queue_work(priv->phandle->evt_workqueue,
9595 				   &priv->phandle->regulatory_work);
9596 #endif
9597 		band = priv->phandle->band;
9598 		priv->phandle->band = IEEE80211_BAND_2GHZ;
9599 		woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
9600 		if (priv->phandle->fw_bands & BAND_A) {
9601 			priv->phandle->band = IEEE80211_BAND_5GHZ;
9602 			woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
9603 		}
9604 		priv->phandle->band = band;
9605 	}
9606 	LEAVE();
9607 	return ret;
9608 }
9609 
9610 /**
9611  * @brief Initialize the wiphy
9612  *
9613  * @param priv            A pointer to moal_private structure
9614  * @param wiphy 		  A pointer to structure wiphy
9615  * @param wait_option     Wait option
9616  * @return                MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
9617  */
9618 static mlan_status woal_cfg80211_init_wiphy(moal_private *priv,
9619 					    struct wiphy *wiphy,
9620 					    t_u8 wait_option)
9621 {
9622 	mlan_status ret = MLAN_STATUS_SUCCESS;
9623 	int retry_count, rts_thr, frag_thr;
9624 	mlan_ioctl_req *req = NULL;
9625 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
9626 	mlan_ds_radio_cfg *radio = NULL;
9627 #endif
9628 	pmlan_ds_11n_cfg cfg_11n = NULL;
9629 	t_u32 hw_dev_cap;
9630 #ifdef UAP_SUPPORT
9631 	pmlan_uap_bss_param sys_cfg = NULL;
9632 #endif
9633 	int mcs_supp = 0;
9634 
9635 	ENTER();
9636 	/* Get 11n tx parameters from MLAN */
9637 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
9638 	if (req == NULL) {
9639 		ret = MLAN_STATUS_FAILURE;
9640 		goto done;
9641 	}
9642 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
9643 	cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
9644 	req->req_id = MLAN_IOCTL_11N_CFG;
9645 	req->action = MLAN_ACT_GET;
9646 	cfg_11n->param.htcap_cfg.hw_cap_req = MTRUE;
9647 
9648 	ret = woal_request_ioctl(priv, req, wait_option);
9649 	if (ret != MLAN_STATUS_SUCCESS)
9650 		goto done;
9651 	hw_dev_cap = cfg_11n->param.htcap_cfg.htcap;
9652 
9653 	/* Get supported MCS sets */
9654 	memset(req->pbuf, 0, sizeof(mlan_ds_11n_cfg));
9655 	cfg_11n->sub_command = MLAN_OID_11N_CFG_SUPPORTED_MCS_SET;
9656 	req->req_id = MLAN_IOCTL_11N_CFG;
9657 	req->action = MLAN_ACT_GET;
9658 
9659 	ret = woal_request_ioctl(priv, req, wait_option);
9660 	if (ret != MLAN_STATUS_SUCCESS)
9661 		goto done;
9662 
9663 	/* Initialize parameters for 2GHz and 5GHz bands */
9664 	if (wiphy->bands[IEEE80211_BAND_2GHZ]) {
9665 		if (IS_CARD9098(priv->phandle->card_type) ||
9666 		    IS_CARD9097(priv->phandle->card_type)) {
9667 			mcs_supp = priv->phandle->params.antcfg & 0xf;
9668 			if (mcs_supp != 3 && mcs_supp != 0)
9669 				cfg_11n->param.supported_mcs_set[1] = 0;
9670 		}
9671 		woal_cfg80211_setup_ht_cap(
9672 			&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, hw_dev_cap,
9673 			cfg_11n->param.supported_mcs_set);
9674 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
9675 		woal_cfg80211_setup_vht_cap(
9676 			priv, &wiphy->bands[IEEE80211_BAND_2GHZ]->vht_cap);
9677 #endif
9678 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
9679 		woal_cfg80211_setup_he_cap(priv,
9680 					   wiphy->bands[IEEE80211_BAND_2GHZ]);
9681 #endif
9682 	}
9683 	/* For 2.4G band only card, this shouldn't be set */
9684 	if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
9685 		if (IS_CARD9098(priv->phandle->card_type) ||
9686 		    IS_CARD9097(priv->phandle->card_type)) {
9687 			mcs_supp = (priv->phandle->params.antcfg & 0xf00) >> 8;
9688 			if (mcs_supp != 3 && mcs_supp != 0)
9689 				cfg_11n->param.supported_mcs_set[1] = 0;
9690 		}
9691 		woal_cfg80211_setup_ht_cap(
9692 			&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, hw_dev_cap,
9693 			cfg_11n->param.supported_mcs_set);
9694 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
9695 		woal_cfg80211_setup_vht_cap(
9696 			priv, &wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap);
9697 #endif
9698 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
9699 		woal_cfg80211_setup_he_cap(priv,
9700 					   wiphy->bands[IEEE80211_BAND_5GHZ]);
9701 #endif
9702 	}
9703 
9704 	kfree(req);
9705 
9706 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
9707 	/* Get antenna modes */
9708 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
9709 	if (req == NULL) {
9710 		ret = MLAN_STATUS_FAILURE;
9711 		goto done;
9712 	}
9713 	radio = (mlan_ds_radio_cfg *)req->pbuf;
9714 	radio->sub_command = MLAN_OID_ANT_CFG;
9715 	req->req_id = MLAN_IOCTL_RADIO_CFG;
9716 	req->action = MLAN_ACT_GET;
9717 
9718 	ret = woal_request_ioctl(priv, req, wait_option);
9719 	if (ret != MLAN_STATUS_SUCCESS)
9720 		goto done;
9721 		/* Set available antennas to wiphy */
9722 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
9723 	if (priv->phandle->params.drv_mode & DRV_MODE_DFS) {
9724 		radio->param.ant_cfg.tx_antenna = 0x101;
9725 		radio->param.ant_cfg.rx_antenna = 0x101;
9726 	}
9727 #endif
9728 	if (IS_CARD9098(priv->phandle->card_type) ||
9729 	    IS_CARD9097(priv->phandle->card_type)) {
9730 		woal_cfg80211_notify_antcfg(priv, wiphy, radio);
9731 	}
9732 	wiphy->available_antennas_tx = radio->param.ant_cfg.tx_antenna;
9733 	wiphy->available_antennas_rx = radio->param.ant_cfg.rx_antenna;
9734 #endif /* CFG80211_VERSION_CODE */
9735 
9736 	/* Set retry limit count to wiphy */
9737 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
9738 		if (MLAN_STATUS_SUCCESS !=
9739 		    woal_set_get_retry(priv, MLAN_ACT_GET, wait_option,
9740 				       &retry_count)) {
9741 			ret = MLAN_STATUS_FAILURE;
9742 			goto done;
9743 		}
9744 	}
9745 #ifdef UAP_SUPPORT
9746 	else {
9747 		sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
9748 		if (!sys_cfg) {
9749 			PRINTM(MERROR,
9750 			       "Fail to alloc memory for mlan_uap_bss_param\n");
9751 			ret = MLAN_STATUS_FAILURE;
9752 			kfree(sys_cfg);
9753 			goto done;
9754 		}
9755 		if (MLAN_STATUS_SUCCESS !=
9756 		    woal_set_get_sys_config(priv, MLAN_ACT_GET, wait_option,
9757 					    sys_cfg)) {
9758 			ret = MLAN_STATUS_FAILURE;
9759 			kfree(sys_cfg);
9760 			goto done;
9761 		}
9762 		retry_count = sys_cfg->retry_limit;
9763 		kfree(sys_cfg);
9764 	}
9765 #endif
9766 	wiphy->retry_long = (t_u8)retry_count;
9767 	wiphy->retry_short = (t_u8)retry_count;
9768 	wiphy->max_scan_ie_len = MAX_IE_SIZE;
9769 
9770 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
9771 	wiphy->mgmt_stypes = ieee80211_mgmt_stypes;
9772 #endif
9773 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
9774 	wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION;
9775 #endif /* KERNEL_VERSION */
9776 
9777 	/* Set RTS threshold to wiphy */
9778 	if (MLAN_STATUS_SUCCESS !=
9779 	    woal_set_get_rts(priv, MLAN_ACT_GET, wait_option, &rts_thr)) {
9780 		ret = MLAN_STATUS_FAILURE;
9781 		goto done;
9782 	}
9783 	if (rts_thr < MLAN_RTS_MIN_VALUE || rts_thr > MLAN_RTS_MAX_VALUE)
9784 		rts_thr = MLAN_FRAG_RTS_DISABLED;
9785 	wiphy->rts_threshold = (t_u32)rts_thr;
9786 
9787 	/* Set fragment threshold to wiphy */
9788 	if (MLAN_STATUS_SUCCESS !=
9789 	    woal_set_get_frag(priv, MLAN_ACT_GET, wait_option, &frag_thr)) {
9790 		ret = MLAN_STATUS_FAILURE;
9791 		goto done;
9792 	}
9793 	if (frag_thr < MLAN_RTS_MIN_VALUE || frag_thr > MLAN_RTS_MAX_VALUE)
9794 		frag_thr = MLAN_FRAG_RTS_DISABLED;
9795 	wiphy->frag_threshold = (t_u32)frag_thr;
9796 
9797 done:
9798 	LEAVE();
9799 	if (ret != MLAN_STATUS_PENDING)
9800 		kfree(req);
9801 	return ret;
9802 }
9803 
9804 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
9805 /**
9806  * @brief Update channel flag
9807  *
9808  * @param wiphy          A pointer to wiphy structure
9809  *
9810  * @return                N/A
9811  */
9812 static void woal_update_channel_flag(struct wiphy *wiphy, mlan_fw_info *fw_info)
9813 {
9814 	enum ieee80211_band band;
9815 	struct ieee80211_supported_band *sband;
9816 	int i;
9817 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
9818 		sband = wiphy->bands[band];
9819 		if (!sband)
9820 			continue;
9821 		if (sband->band == IEEE80211_BAND_5GHZ &&
9822 		    fw_info->prohibit_80mhz) {
9823 			for (i = 0; i < sband->n_channels; i++) {
9824 				sband->channels[i].flags |=
9825 					IEEE80211_CHAN_NO_80MHZ;
9826 				PRINTM(MCMND, "hw_value=%d channel flag %x\n",
9827 				       sband->channels[i].hw_value,
9828 				       sband->channels[i].flags);
9829 			}
9830 		}
9831 	}
9832 }
9833 #endif
9834 
9835 /*
9836  * This function registers the device with CFG802.11 subsystem.
9837  *
9838  * @param priv       A pointer to moal_private
9839  *
9840  */
9841 mlan_status woal_register_cfg80211(moal_private *priv)
9842 {
9843 	mlan_status ret = MLAN_STATUS_SUCCESS;
9844 	struct wiphy *wiphy;
9845 	void *wdev_priv = NULL;
9846 	mlan_fw_info fw_info;
9847 	char *country = NULL, *reg_alpha2 = NULL;
9848 	int index = 0;
9849 
9850 	ENTER();
9851 
9852 	memset(&fw_info, 0, sizeof(mlan_fw_info));
9853 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
9854 	reg_alpha2 = priv->phandle->params.reg_alpha2;
9855 	wiphy = wiphy_new(&woal_cfg80211_ops, sizeof(moal_handle *));
9856 	if (!wiphy) {
9857 		PRINTM(MERROR, "Could not allocate wiphy device\n");
9858 		ret = MLAN_STATUS_FAILURE;
9859 		goto err_wiphy;
9860 	}
9861 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
9862 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) {
9863 		woal_cfg80211_ops.auth = woal_cfg80211_authenticate;
9864 		woal_cfg80211_ops.assoc = woal_cfg80211_associate;
9865 		woal_cfg80211_ops.disconnect = NULL;
9866 		woal_cfg80211_ops.connect = NULL;
9867 #ifdef UAP_SUPPORT
9868 		woal_cfg80211_ops.probe_client = woal_cfg80211_probe_client;
9869 #endif
9870 	}
9871 #endif
9872 #ifdef CONFIG_PM
9873 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
9874 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
9875 	if (fw_info.fw_supplicant_support)
9876 		wiphy->wowlan = &wowlan_support_with_gtk;
9877 	else
9878 		wiphy->wowlan = &wowlan_support;
9879 #else
9880 	wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT;
9881 	if (fw_info.fw_supplicant_support) {
9882 		wiphy->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
9883 				       WIPHY_WOWLAN_GTK_REKEY_FAILURE;
9884 	}
9885 	wiphy->wowlan.n_patterns = MAX_NUM_FILTERS;
9886 	wiphy->wowlan.pattern_min_len = 1;
9887 	wiphy->wowlan.pattern_max_len = WOWLAN_MAX_PATTERN_LEN;
9888 	wiphy->wowlan.max_pkt_offset = WOWLAN_MAX_OFFSET_LEN;
9889 #endif
9890 #endif
9891 #endif
9892 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
9893 	wiphy->coalesce = &coalesce_support;
9894 #endif
9895 	wiphy->max_scan_ssids = MRVDRV_MAX_SSID_LIST_LENGTH;
9896 	wiphy->max_scan_ie_len = MAX_IE_SIZE;
9897 	wiphy->interface_modes = 0;
9898 	wiphy->interface_modes =
9899 		MBIT(NL80211_IFTYPE_STATION) | MBIT(NL80211_IFTYPE_AP);
9900 	wiphy->interface_modes |= MBIT(NL80211_IFTYPE_MONITOR);
9901 
9902 #ifdef WIFI_DIRECT_SUPPORT
9903 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
9904 	wiphy->interface_modes |=
9905 		MBIT(NL80211_IFTYPE_P2P_GO) | MBIT(NL80211_IFTYPE_P2P_CLIENT);
9906 #endif
9907 #endif
9908 
9909 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
9910 	woal_register_cfg80211_vendor_command(wiphy);
9911 #endif
9912 	/* Make this wiphy known to this driver only */
9913 	wiphy->privid = mrvl_wiphy_privid;
9914 
9915 	if (!fw_info.fw_bands)
9916 		fw_info.fw_bands = BAND_B | BAND_G;
9917 	if (fw_info.fw_bands & BAND_A) {
9918 		wiphy->bands[IEEE80211_BAND_5GHZ] =
9919 			woal_setup_wiphy_bands(IEEE80211_BAND_5GHZ);
9920 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
9921 		woal_update_channel_flag(wiphy, &fw_info);
9922 #endif
9923 		priv->phandle->band = IEEE80211_BAND_5GHZ;
9924 	}
9925 
9926 	/* Supported bands */
9927 	if (fw_info.fw_bands & (BAND_B | BAND_G | BAND_GN | BAND_GAC)) {
9928 		wiphy->bands[IEEE80211_BAND_2GHZ] =
9929 			woal_setup_wiphy_bands(IEEE80211_BAND_2GHZ);
9930 		/* If 2.4G enable, it will overwrite default to 2.4G*/
9931 		priv->phandle->band = IEEE80211_BAND_2GHZ;
9932 	}
9933 
9934 	if (fw_info.fw_bands & BAND_A) {
9935 		/** reduce scan time from 110ms to 80ms */
9936 		woal_set_scan_time(priv, INIT_ACTIVE_SCAN_CHAN_TIME,
9937 				   INIT_PASSIVE_SCAN_CHAN_TIME,
9938 				   INIT_SPECIFIC_SCAN_CHAN_TIME);
9939 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
9940 		cfg80211_iface_comb_ap_sta.radar_detect_widths |=
9941 			MBIT(NL80211_CHAN_WIDTH_40);
9942 		if (fw_info.fw_bands & BAND_AAC)
9943 			cfg80211_iface_comb_ap_sta.radar_detect_widths |=
9944 				MBIT(NL80211_CHAN_WIDTH_80);
9945 #endif
9946 	} else
9947 		woal_set_scan_time(priv, ACTIVE_SCAN_CHAN_TIME,
9948 				   PASSIVE_SCAN_CHAN_TIME,
9949 				   SPECIFIC_SCAN_CHAN_TIME);
9950 
9951 	/* Initialize cipher suits */
9952 	wiphy->cipher_suites = cfg80211_cipher_suites;
9953 	wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites);
9954 #ifdef UAP_CFG80211
9955 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
9956 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
9957 	if (!moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
9958 #endif
9959 		wiphy->max_acl_mac_addrs = MAX_MAC_FILTER_NUM;
9960 #endif
9961 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
9962 	if (fw_info.max_ap_assoc_sta) {
9963 		wiphy->max_ap_assoc_sta = fw_info.max_ap_assoc_sta;
9964 		PRINTM(MCMND, "Set wiphy max_ap_assoc_sta=%d\n",
9965 		       wiphy->max_ap_assoc_sta);
9966 	}
9967 #endif
9968 #endif
9969 
9970 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
9971 	/* Initialize interface combinations */
9972 	wiphy->iface_combinations = &cfg80211_iface_comb_ap_sta;
9973 	wiphy->n_iface_combinations = 1;
9974 #endif
9975 
9976 	moal_memcpy_ext(priv->phandle, wiphy->perm_addr, priv->current_addr,
9977 			ETH_ALEN, sizeof(wiphy->perm_addr));
9978 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
9979 
9980 	wiphy->flags = 0;
9981 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
9982 	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
9983 	wiphy->flags |= WIPHY_FLAG_NETNS_OK;
9984 #endif
9985 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
9986 	wiphy->flags |=
9987 		WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_OFFCHAN_TX;
9988 	wiphy->flags |= WIPHY_FLAG_AP_UAPSD | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
9989 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
9990 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
9991 		wiphy->flags |= WIPHY_FLAG_REPORTS_OBSS;
9992 	else
9993 #endif
9994 		wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
9995 #endif
9996 #ifdef ANDROID_KERNEL
9997 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
9998 	if (!moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
9999 #endif
10000 		wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
10001 #endif
10002 
10003 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
10004 	if (priv->phandle->params.sched_scan) {
10005 #if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
10006 		wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
10007 #else
10008 		wiphy->max_sched_scan_reqs = 1;
10009 #endif
10010 		wiphy->max_sched_scan_ssids = MRVDRV_MAX_SSID_LIST_LENGTH;
10011 		wiphy->max_sched_scan_ie_len = MAX_IE_SIZE;
10012 		wiphy->max_match_sets = MRVDRV_MAX_SSID_LIST_LENGTH;
10013 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
10014 		wiphy->max_sched_scan_plans = 3;
10015 		wiphy->max_sched_scan_plan_iterations = 100;
10016 #endif
10017 	}
10018 #endif
10019 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
10020 	wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION;
10021 #endif
10022 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
10023 	wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER;
10024 #endif
10025 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
10026 	wiphy->flags |=
10027 		WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
10028 #endif
10029 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
10030 	wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
10031 #endif
10032 
10033 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
10034 #define WLAN_EXT_FEATURE_DFS_OFFLOAD 25
10035 	if (moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD)) {
10036 		if (NUM_NL80211_EXT_FEATURES > WLAN_EXT_FEATURE_DFS_OFFLOAD) {
10037 			PRINTM(MCMND,
10038 			       "wlan: Set NL80211_EXT_FEATURE_DFS_OFFLOAD\n");
10039 			wiphy_ext_feature_set(wiphy,
10040 					      WLAN_EXT_FEATURE_DFS_OFFLOAD);
10041 		}
10042 	}
10043 #endif
10044 
10045 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
10046 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
10047 		wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RRM);
10048 #endif
10049 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
10050 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
10051 		wiphy->features |= NL80211_FEATURE_SAE;
10052 #endif
10053 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
10054 	wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN;
10055 #endif
10056 
10057 	wiphy->reg_notifier = woal_cfg80211_reg_notifier;
10058 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
10059 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
10060 #endif
10061 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
10062 	/* Indicate to cfg80211 that the driver can support
10063 	 * CSA and ESCA,i.e., both types of channel switch
10064 	 * Applications like hostapd 2.6 will append CSA IE
10065 	 * and ECSA IE and expect the driver to advertise 2
10066 	 * in max_num_csa_counters to successfully issue a
10067 	 * channel switch
10068 	 */
10069 	wiphy->max_num_csa_counters = MAX_CSA_COUNTERS_NUM;
10070 #endif
10071 	wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
10072 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
10073 	wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR;
10074 	wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
10075 #endif
10076 
10077 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
10078 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA);
10079 	wiphy_ext_feature_set(wiphy,
10080 			      NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED);
10081 #endif
10082 
10083 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
10084 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
10085 #endif
10086 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
10087 	if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME))
10088 		wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
10089 #endif
10090 
10091 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
10092 	if (fw_info.fw_beacon_prot) {
10093 		wiphy_ext_feature_set(wiphy,
10094 				      NL80211_EXT_FEATURE_BEACON_PROTECTION);
10095 		wiphy_ext_feature_set(
10096 			wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT);
10097 	}
10098 #endif
10099 #ifdef UAP_CFG80211
10100 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
10101 	if (priv->phandle->params.drv_mode & DRV_MODE_DFS) {
10102 		wiphy_ext_feature_set(wiphy,
10103 				      NL80211_EXT_FEATURE_RADAR_BACKGROUND);
10104 		woal_cfg80211_ops.set_radar_background =
10105 			woal_cfg80211_set_radar_background;
10106 	}
10107 #endif
10108 #endif
10109 	/* Set struct moal_handle pointer in wiphy_priv */
10110 	wdev_priv = wiphy_priv(wiphy);
10111 	*(unsigned long *)wdev_priv = (unsigned long)priv->phandle;
10112 
10113 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
10114 	set_wiphy_dev(wiphy, (struct device *)priv->phandle->hotplug_device);
10115 #endif
10116 	/* Set phy name*/
10117 	for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
10118 		if (m_handle[index] == priv->phandle) {
10119 			dev_set_name(&wiphy->dev, mwiphy_name, index);
10120 			break;
10121 		}
10122 	}
10123 
10124 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
10125 	if (moal_extflg_isset(priv->phandle, EXT_BEACON_HINTS)) {
10126 		/* REGULATORY_DISABLE_BEACON_HINTS: NO-IR flag won't be removed
10127 		 * on chn where an AP is visible! */
10128 		wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
10129 	}
10130 	if (moal_extflg_isset(priv->phandle, EXT_COUNTRY_IE_IGNORE)) {
10131 		PRINTM(MIOCTL, "Don't follow countryIE provided by AP.\n");
10132 		wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
10133 	} else {
10134 		PRINTM(MIOCTL, "Follow countryIE provided by AP.\n");
10135 	}
10136 #endif
10137 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
10138 	/*REGULATORY_IGNORE_STALE_KICKOFF: the regulatory core will _not_ make
10139 	 * sure all interfaces on this wiphy reside on allowed channels. If this
10140 	 * flag is not set, upon a regdomain change, the interfaces are given a
10141 	 * grace period (currently 60 seconds) to disconnect or move to an
10142 	 * allowed channel.*/
10143 	wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
10144 #endif
10145 
10146 	memset(&priv->phandle->country_code, 0,
10147 	       sizeof(priv->phandle->country_code));
10148 	priv->phandle->dfs_region = NXP_DFS_UNKNOWN;
10149 
10150 	if (reg_alpha2 && !strncmp(reg_alpha2, "99", strlen("99"))) {
10151 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
10152 		wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
10153 					   REGULATORY_DISABLE_BEACON_HINTS |
10154 					   REGULATORY_COUNTRY_IE_IGNORE;
10155 #else
10156 		wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
10157 #endif
10158 		wiphy_apply_custom_regulatory(wiphy, &mrvl_regdom);
10159 	}
10160 
10161 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
10162 	if (woal_request_extcap(priv, (t_u8 *)&priv->extended_capabilities,
10163 				sizeof(priv->extended_capabilities)) < 0)
10164 		PRINTM(MERROR,
10165 		       "Failed to get driver extended capability, use default\n");
10166 	DBG_HEXDUMP(MCMD_D, "wiphy ext cap",
10167 		    (t_u8 *)&priv->extended_capabilities,
10168 		    sizeof(priv->extended_capabilities));
10169 	wiphy->extended_capabilities = (t_u8 *)&priv->extended_capabilities;
10170 	wiphy->extended_capabilities_mask =
10171 		(t_u8 *)&priv->extended_capabilities;
10172 	wiphy->extended_capabilities_len = sizeof(priv->extended_capabilities);
10173 #endif
10174 	woal_cfg80211_init_wiphy(priv, wiphy, MOAL_IOCTL_WAIT);
10175 	if (wiphy_register(wiphy) < 0) {
10176 		PRINTM(MERROR, "Wiphy device registration failed!\n");
10177 		ret = MLAN_STATUS_FAILURE;
10178 		goto err_wiphy;
10179 	}
10180 
10181 	wiphy->interface_modes &= ~(MBIT(NL80211_IFTYPE_MONITOR));
10182 
10183 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
10184 	if (fw_info.force_reg) {
10185 		PRINTM(MCMND, "FW region_code=%d force_reg=%d\n",
10186 		       fw_info.region_code, fw_info.force_reg);
10187 		country = region_code_2_string(fw_info.region_code);
10188 		if (country) {
10189 			moal_memcpy_ext(priv->phandle,
10190 					priv->phandle->country_code, country, 2,
10191 					2);
10192 			queue_work(priv->phandle->evt_workqueue,
10193 				   &priv->phandle->regulatory_work);
10194 		}
10195 	}
10196 #endif
10197 	if ((!reg_alpha2 || strncmp(reg_alpha2, "99", strlen("99")))
10198 
10199 	) {
10200 		/** we will try driver parameter first */
10201 		if (reg_alpha2 && woal_is_valid_alpha2(reg_alpha2)) {
10202 			PRINTM(MIOCTL, "Notify reg_alpha2 %c%c\n",
10203 			       reg_alpha2[0], reg_alpha2[1]);
10204 			if (!moal_extflg_isset(priv->phandle,
10205 					       EXT_DISABLE_REGD_BY_DRIVER))
10206 				regulatory_hint(wiphy, reg_alpha2);
10207 		} else {
10208 			country = region_code_2_string(fw_info.region_code);
10209 			if (country) {
10210 				if (fw_info.region_code != 0) {
10211 					PRINTM(MIOCTL,
10212 					       "Notify hw region code=%d %c%c\n",
10213 					       fw_info.region_code, country[0],
10214 					       country[1]);
10215 					if (!moal_extflg_isset(
10216 						    priv->phandle,
10217 						    EXT_DISABLE_REGD_BY_DRIVER))
10218 						regulatory_hint(wiphy, country);
10219 				}
10220 			} else
10221 				PRINTM(MCMND,
10222 				       "hw region code=%d not supported\n",
10223 				       fw_info.region_code);
10224 		}
10225 	}
10226 	priv->phandle->wiphy = wiphy;
10227 	return ret;
10228 err_wiphy:
10229 	if (wiphy) {
10230 		woal_cfg80211_free_bands(wiphy);
10231 		wiphy_free(wiphy);
10232 	}
10233 	LEAVE();
10234 	return ret;
10235 }
10236