xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/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   * Copyright (C) 2011-2017, Marvell International Ltd.
6   *
7   * This software file (the "File") is distributed by Marvell International
8   * Ltd. under the terms of the GNU General Public License Version 2, June 1991
9   * (the "License").  You may use, redistribute and/or modify this File in
10   * accordance with the terms and conditions of the License, a copy of which
11   * is available by writing to the Free Software Foundation, Inc.,
12   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
13   * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
14   *
15   * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
16   * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
17   * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
18   * this warranty disclaimer.
19   *
20   */
21 
22 #include "moal_cfg80211.h"
23 #include "moal_cfgvendor.h"
24 #include "moal_sta_cfg80211.h"
25 #include "moal_eth_ioctl.h"
26 #ifdef UAP_SUPPORT
27 #include    "moal_uap.h"
28 #endif
29 
30 extern int cfg80211_wext;
31 
32 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
33 extern int fw_region;
34 #endif
35 
36 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
37 extern int dfs_offload;
38 #endif
39 
40 extern int cntry_txpwr;
41 
42 /* Supported crypto cipher suits to be advertised to cfg80211 */
43 const u32 cfg80211_cipher_suites[] = {
44 	WLAN_CIPHER_SUITE_WEP40,
45 	WLAN_CIPHER_SUITE_WEP104,
46 	WLAN_CIPHER_SUITE_TKIP,
47 	WLAN_CIPHER_SUITE_CCMP,
48 	WLAN_CIPHER_SUITE_SMS4,
49 	WLAN_CIPHER_SUITE_AES_CMAC,
50 };
51 
52 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
53 static int woal_cfg80211_set_monitor_channel(struct wiphy *wiphy,
54 					     struct cfg80211_chan_def *chandef);
55 #endif
56 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
57 static void
58 #else
59 static int
60 #endif
61 
62 woal_cfg80211_reg_notifier(struct wiphy *wiphy,
63 			   struct regulatory_request *request);
64 
65 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
66 static int woal_cfg80211_scan(struct wiphy *wiphy,
67 			      struct cfg80211_scan_request *request);
68 #else
69 static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
70 			      struct cfg80211_scan_request *request);
71 #endif
72 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4,5,0)
73 static void woal_cfg80211_abort_scan(struct wiphy *wiphy,
74 				     struct wireless_dev *wdev);
75 #endif
76 static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
77 				 struct cfg80211_connect_params *sme);
78 
79 static int woal_cfg80211_disconnect(struct wiphy *wiphy,
80 				    struct net_device *dev, t_u16 reason_code);
81 
82 static int woal_cfg80211_get_station(struct wiphy *wiphy,
83 				     struct net_device *dev,
84 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
85 				     const t_u8 *mac,
86 #else
87 				     t_u8 *mac,
88 #endif
89 				     struct station_info *sinfo);
90 
91 static int woal_cfg80211_dump_station(struct wiphy *wiphy,
92 				      struct net_device *dev, int idx,
93 				      t_u8 *mac, struct station_info *sinfo);
94 
95 static int woal_cfg80211_dump_survey(struct wiphy *wiphy,
96 				     struct net_device *dev, int idx,
97 				     struct survey_info *survey);
98 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
99 static int woal_cfg80211_get_channel(struct wiphy *wiphy,
100 				     struct wireless_dev *wdev,
101 				     struct cfg80211_chan_def *chandef);
102 #endif
103 static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
104 					struct net_device *dev, bool enabled,
105 					int timeout);
106 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
107 static int woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
108 					     struct net_device *dev,
109 					     s32 rssi_thold, u32 rssi_hyst);
110 #endif
111 
112 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
113 static int woal_cfg80211_get_tx_power(struct wiphy *wiphy,
114 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
115 				      struct wireless_dev *wdev,
116 #endif
117 				      int *dbm);
118 
119 static int woal_cfg80211_set_tx_power(struct wiphy *wiphy,
120 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
121 				      struct wireless_dev *wdev,
122 #endif
123 #if CFG80211_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
124 				      enum tx_power_setting type,
125 #else
126 				      enum nl80211_tx_power_setting type,
127 #endif
128 				      int dbm);
129 #endif
130 
131 static int woal_cfg80211_join_ibss(struct wiphy *wiphy,
132 				   struct net_device *dev,
133 				   struct cfg80211_ibss_params *params);
134 
135 static int woal_cfg80211_leave_ibss(struct wiphy *wiphy,
136 				    struct net_device *dev);
137 
138 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
139 static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
140 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
141 					     struct wireless_dev *wdev,
142 #else
143 					     struct net_device *dev,
144 #endif
145 					     u64 cookie);
146 
147 static int woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
148 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
149 					   struct wireless_dev *wdev,
150 #else
151 					   struct net_device *dev,
152 #endif
153 					   struct ieee80211_channel *chan,
154 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
155 					   enum nl80211_channel_type
156 					   channel_type,
157 #endif
158 					   unsigned int duration, u64 * cookie);
159 
160 static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
161 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
162 						  struct wireless_dev *wdev,
163 #else
164 						  struct net_device *dev,
165 #endif
166 						  u64 cookie);
167 #endif /* KERNEL_VERSION */
168 
169 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
170 int woal_cfg80211_sched_scan_start(struct wiphy *wiphy,
171 				   struct net_device *dev,
172 				   struct cfg80211_sched_scan_request *request);
173 int woal_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
174 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
175 				  , u64 reqid
176 #endif
177 	);
178 #endif
179 
180 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
181 int woal_cfg80211_resume(struct wiphy *wiphy);
182 int woal_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
183 #endif
184 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
185 static void woal_cfg80211_set_wakeup(struct wiphy *wiphy, bool enabled);
186 #endif
187 
188 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,2,0)
189 void woal_check_auto_tdls(struct wiphy *wiphy, struct net_device *dev);
190 int woal_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
191 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
192 			    const u8 *peer,
193 #else
194 			    u8 *peer,
195 #endif
196 			    enum nl80211_tdls_operation oper);
197 int woal_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
198 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
199 			    const u8 *peer,
200 #else
201 			    u8 *peer,
202 #endif
203 			    u8 action_code, u8 dialog_token, u16 status_code,
204 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
205 			    u32 peer_capability,
206 #endif
207 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
208 			    bool initiator,
209 #endif
210 			    const u8 *extra_ies, size_t extra_ies_len);
211 static int
212  woal_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
213 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
214 			   const u8 *mac,
215 #else
216 			   u8 *mac,
217 #endif
218 			   struct station_parameters *params);
219 static int
220  woal_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev,
221 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
222 			      const u8 *mac,
223 #else
224 			      u8 *mac,
225 #endif
226 			      struct station_parameters *params);
227 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
228 static int
229 
230 woal_cfg80211_tdls_channel_switch(struct wiphy *wiphy,
231 				  struct net_device *dev,
232 				  const u8 *addr, u8 oper_class,
233 				  struct cfg80211_chan_def *chandef);
234 
235 void woal_cfg80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
236 					      struct net_device *dev,
237 					      const u8 *addr);
238 #endif
239 #endif
240 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,10,0)
241 int woal_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
242 				struct cfg80211_update_ft_ies_params *ftie);
243 #endif
244 /** cfg80211 operations */
245 static struct cfg80211_ops woal_cfg80211_ops = {
246 	.change_virtual_intf = woal_cfg80211_change_virtual_intf,
247 	.scan = woal_cfg80211_scan,
248 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4,5,0)
249 	.abort_scan = woal_cfg80211_abort_scan,
250 #endif
251 	.connect = woal_cfg80211_connect,
252 	.disconnect = woal_cfg80211_disconnect,
253 	.get_station = woal_cfg80211_get_station,
254 	.dump_station = woal_cfg80211_dump_station,
255 	.dump_survey = woal_cfg80211_dump_survey,
256 	.set_wiphy_params = woal_cfg80211_set_wiphy_params,
257 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
258 	.set_channel = woal_cfg80211_set_channel,
259 #endif
260 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
261 	.get_channel = woal_cfg80211_get_channel,
262 #endif
263 	.join_ibss = woal_cfg80211_join_ibss,
264 	.leave_ibss = woal_cfg80211_leave_ibss,
265 	.add_key = woal_cfg80211_add_key,
266 	.del_key = woal_cfg80211_del_key,
267 	.set_default_key = woal_cfg80211_set_default_key,
268 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
269 	.set_default_mgmt_key = woal_cfg80211_set_default_mgmt_key,
270 #endif
271 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
272 	.set_rekey_data = woal_cfg80211_set_rekey_data,
273 #endif
274 	.set_pmksa = woal_cfg80211_set_pmksa,
275 	.del_pmksa = woal_cfg80211_del_pmksa,
276 	.flush_pmksa = woal_cfg80211_flush_pmksa,
277 	.set_power_mgmt = woal_cfg80211_set_power_mgmt,
278 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
279 	.set_tx_power = woal_cfg80211_set_tx_power,
280 	.get_tx_power = woal_cfg80211_get_tx_power,
281 #endif
282 	.set_bitrate_mask = woal_cfg80211_set_bitrate_mask,
283 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
284 	.sched_scan_start = woal_cfg80211_sched_scan_start,
285 	.sched_scan_stop = woal_cfg80211_sched_scan_stop,
286 #endif
287 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
288 	.suspend = woal_cfg80211_suspend,
289 	.resume = woal_cfg80211_resume,
290 #endif
291 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
292 	.set_wakeup = woal_cfg80211_set_wakeup,
293 #endif
294 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
295 	.set_antenna = woal_cfg80211_set_antenna,
296 	.get_antenna = woal_cfg80211_get_antenna,
297 #endif
298 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
299 	.set_cqm_rssi_config = woal_cfg80211_set_cqm_rssi_config,
300 #endif
301 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,2,0)
302 	.tdls_oper = woal_cfg80211_tdls_oper,
303 	.tdls_mgmt = woal_cfg80211_tdls_mgmt,
304 	.add_station = woal_cfg80211_add_station,
305 	.change_station = woal_cfg80211_change_station,
306 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
307 	.tdls_channel_switch =
308 		woal_cfg80211_tdls_channel_switch,.tdls_cancel_channel_switch =
309 		woal_cfg80211_tdls_cancel_channel_switch,
310 #endif
311 #endif
312 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,10,0)
313 		.update_ft_ies = woal_cfg80211_update_ft_ies,
314 #endif
315 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,14,0)
316 		.set_qos_map = woal_cfg80211_set_qos_map,
317 #endif
318 #ifdef UAP_CFG80211
319 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
320 		.set_coalesce = woal_cfg80211_set_coalesce,
321 #endif
322 		.add_virtual_intf =
323 		woal_cfg80211_add_virtual_intf,.del_virtual_intf =
324 		woal_cfg80211_del_virtual_intf,
325 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
326 		.start_ap = woal_cfg80211_add_beacon,.change_beacon =
327 		woal_cfg80211_set_beacon,.stop_ap = woal_cfg80211_del_beacon,
328 #else
329 		.add_beacon = woal_cfg80211_add_beacon,.set_beacon =
330 		woal_cfg80211_set_beacon,.del_beacon = woal_cfg80211_del_beacon,
331 #endif
332 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
333 		.change_bss = woal_cfg80211_change_bss,
334 #endif
335 		.del_station = woal_cfg80211_del_station,
336 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
337 		.set_txq_params = woal_cfg80211_set_txq_params,
338 #endif
339 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
340 		.set_mac_acl = woal_cfg80211_set_mac_acl,
341 #endif
342 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
343 		.start_radar_detection =
344 		woal_cfg80211_start_radar_detection,.channel_switch =
345 		woal_cfg80211_channel_switch,
346 #endif
347 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
348 		.mgmt_frame_register =
349 		woal_cfg80211_mgmt_frame_register,.mgmt_tx =
350 		woal_cfg80211_mgmt_tx,
351 #endif
352 #endif
353 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
354 		.mgmt_tx_cancel_wait =
355 		woal_cfg80211_mgmt_tx_cancel_wait,.remain_on_channel =
356 		woal_cfg80211_remain_on_channel,.cancel_remain_on_channel =
357 		woal_cfg80211_cancel_remain_on_channel,
358 #endif
359 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
360 		.set_monitor_channel = woal_cfg80211_set_monitor_channel,
361 #endif
362 };
363 
364 /** Region code mapping */
365 typedef struct _region_code_t {
366     /** Region */
367 	t_u8 region[COUNTRY_CODE_LEN];
368 } region_code_t;
369 
370 static const struct ieee80211_regdomain mrvl_regdom = {
371 	.n_reg_rules = 4,
372 	.alpha2 = "99",
373 	.reg_rules = {
374 		      /* IEEE 802.11b/g, channels 1..11 */
375 		      REG_RULE(2412 - 10, 2472 + 10, 40, 6, 20, 0),
376 		      /* If any */
377 		      /* IEEE 802.11 channel 14 - Only JP enables
378 		       * this and for 802.11b only
379 		       */
380 		      REG_RULE(2484 - 10, 2484 + 10, 20, 6, 20, 0),
381 		      /* IEEE 802.11a, channel 36..64 */
382 		      REG_RULE(5150 - 10, 5350 + 10, 80, 6, 20, 0),
383 		      /* IEEE 802.11a, channel 100..165 */
384 		      REG_RULE(5470 - 10, 5850 + 10, 80, 6, 20, 0),}
385 };
386 
387 /********************************************************
388 				Local Variables
389 ********************************************************/
390 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
391 static const struct ieee80211_txrx_stypes
392  ieee80211_mgmt_stypes[NUM_NL80211_IFTYPES] = {
393 	[NL80211_IFTYPE_ADHOC] = {
394 				  .tx = BIT(IEEE80211_STYPE_ACTION >> 4),
395 				  .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
396 				  },
397 	[NL80211_IFTYPE_STATION] = {
398 				    .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
399 				    BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
400 				    .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
401 				    BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
402 				    },
403 	[NL80211_IFTYPE_AP] = {
404 			       .tx = 0xffff,
405 			       .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
406 			       BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
407 			       BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
408 			       BIT(IEEE80211_STYPE_DISASSOC >> 4) |
409 			       BIT(IEEE80211_STYPE_AUTH >> 4) |
410 			       BIT(IEEE80211_STYPE_DEAUTH >> 4) |
411 			       BIT(IEEE80211_STYPE_ACTION >> 4),
412 			       },
413 	[NL80211_IFTYPE_AP_VLAN] = {
414 				    .tx = 0x0000,
415 				    .rx = 0x0000,
416 				    },
417 #if defined(WIFI_DIRECT_SUPPORT)
418 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
419 	[NL80211_IFTYPE_P2P_CLIENT] = {
420 				       .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
421 				       BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
422 				       .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
423 				       BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
424 				       },
425 	[NL80211_IFTYPE_P2P_GO] = {
426 				   .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
427 				   BIT(IEEE80211_STYPE_PROBE_RESP >> 4),
428 				   .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
429 				   BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
430 				   BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
431 				   BIT(IEEE80211_STYPE_DISASSOC >> 4) |
432 				   BIT(IEEE80211_STYPE_AUTH >> 4) |
433 				   BIT(IEEE80211_STYPE_DEAUTH >> 4) |
434 				   BIT(IEEE80211_STYPE_ACTION >> 4),
435 				   },
436 #endif
437 #endif
438 	[NL80211_IFTYPE_MESH_POINT] = {
439 				       .tx = 0x0000,
440 				       .rx = 0x0000,
441 				       },
442 
443 };
444 #endif
445 
446 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 0, 0)
447 /**
448  * NOTE: types in all the sets must be equals to the
449  * initial value of wiphy->interface_modes
450  */
451 static const struct ieee80211_iface_limit cfg80211_ap_sta_limits[] = {
452 	{
453 	 .max = 4,
454 	 .types = MBIT(NL80211_IFTYPE_STATION) |
455 #ifdef UAP_CFG80211
456 	 MBIT(NL80211_IFTYPE_AP) | MBIT(NL80211_IFTYPE_MONITOR) |
457 #endif
458 #if defined(WIFI_DIRECT_SUPPORT)
459 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
460 	 MBIT(NL80211_IFTYPE_P2P_GO) | MBIT(NL80211_IFTYPE_P2P_CLIENT) |
461 #endif
462 #endif
463 	 MBIT(NL80211_IFTYPE_ADHOC)
464 	 }
465 };
466 
467 static struct ieee80211_iface_combination cfg80211_iface_comb_ap_sta = {
468 	.limits = cfg80211_ap_sta_limits,
469 	.num_different_channels = 1,
470 	.n_limits = ARRAY_SIZE(cfg80211_ap_sta_limits),
471 	.max_interfaces = 4,
472 	.beacon_int_infra_match = MTRUE,
473 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
474 	.radar_detect_widths = MBIT(NL80211_CHAN_WIDTH_20_NOHT)
475 		| MBIT(NL80211_CHAN_WIDTH_20),
476 #endif
477 };
478 #endif
479 
480 extern moal_handle *m_handle[];
481 extern int hw_test;
482 extern int ps_mode;
483 /** Region alpha2 string */
484 char *reg_alpha2;
485 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
486 int country_ie_ignore = 0;
487 int beacon_hints = 0;
488 #endif
489 
490 #if defined(WIFI_DIRECT_SUPPORT)
491 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
492 extern int p2p_enh;
493 #endif
494 #endif
495 
496 int cfg80211_drcs = 0;
497 
498 #ifdef CONFIG_PM
499 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
500 static const struct wiphy_wowlan_support wowlan_support = {
501 	.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT,
502 	.n_patterns = MAX_NUM_FILTERS,
503 	.pattern_min_len = 1,
504 	.pattern_max_len = WOWLAN_MAX_PATTERN_LEN,
505 	.max_pkt_offset = WOWLAN_MAX_OFFSET_LEN,
506 };
507 
508 static const struct wiphy_wowlan_support wowlan_support_with_gtk = {
509 	.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT
510 		| WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
511 		WIPHY_WOWLAN_GTK_REKEY_FAILURE,
512 	.n_patterns = MAX_NUM_FILTERS,
513 	.pattern_min_len = 1,
514 	.pattern_max_len = WOWLAN_MAX_PATTERN_LEN,
515 	.max_pkt_offset = WOWLAN_MAX_OFFSET_LEN,
516 };
517 #endif
518 #endif
519 
520 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
521 static const struct wiphy_coalesce_support coalesce_support = {
522 	.n_rules = COALESCE_MAX_RULES,
523 	.max_delay = MAX_COALESCING_DELAY,
524 	.n_patterns = COALESCE_MAX_FILTERS,
525 	.pattern_min_len = 1,
526 	.pattern_max_len = MAX_PATTERN_LEN,
527 	.max_pkt_offset = MAX_OFFSET_LEN,
528 };
529 #endif
530 
531 /********************************************************
532 				Global Variables
533 ********************************************************/
534 
535 /********************************************************
536 				Local Functions
537 ********************************************************/
538 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
539 static int
woal_cfg80211_set_monitor_channel(struct wiphy * wiphy,struct cfg80211_chan_def * chandef)540 woal_cfg80211_set_monitor_channel(struct wiphy *wiphy,
541 				  struct cfg80211_chan_def *chandef)
542 {
543 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
544 	moal_private *priv =
545 		(moal_private *)woal_get_priv(handle, MLAN_BSS_ROLE_STA);
546 	netmon_band_chan_cfg band_chan_cfg;
547 	t_u32 bandwidth = 0;
548 	int ret = -EFAULT;
549 
550 	ENTER();
551 
552 	if (handle->mon_if) {
553 		if (cfg80211_chandef_identical
554 		    (&handle->mon_if->chandef, chandef)) {
555 			ret = 0;
556 			goto done;
557 		}
558 
559 		memset(&band_chan_cfg, 0x00, sizeof(band_chan_cfg));
560 		/* Set channel */
561 		band_chan_cfg.channel =
562 			ieee80211_frequency_to_channel(chandef->chan->
563 						       center_freq);
564 		/* Set band */
565 		if (chandef->chan->band == IEEE80211_BAND_2GHZ)
566 			band_chan_cfg.band |= (BAND_B | BAND_G);
567 		if (chandef->chan->band == IEEE80211_BAND_5GHZ)
568 			band_chan_cfg.band |= BAND_A;
569 		if (chandef->chan->band == IEEE80211_BAND_2GHZ)
570 			band_chan_cfg.band |= BAND_GN;
571 		if (chandef->chan->band == IEEE80211_BAND_5GHZ)
572 			band_chan_cfg.band |= BAND_AN;
573 		/* Set bandwidth */
574 		if (chandef->width == NL80211_CHAN_WIDTH_20)
575 			bandwidth = CHANNEL_BW_20MHZ;
576 		else if (chandef->width == NL80211_CHAN_WIDTH_40)
577 			bandwidth =
578 				chandef->center_freq1 >
579 				chandef->chan->
580 				center_freq ? CHANNEL_BW_40MHZ_ABOVE :
581 				CHANNEL_BW_40MHZ_BELOW;
582 		band_chan_cfg.chan_bandwidth = bandwidth;
583 
584 		if (MLAN_STATUS_SUCCESS !=
585 		    woal_set_net_monitor(priv, MOAL_IOCTL_WAIT,
586 					 CHANNEL_SPEC_SNIFFER_MODE, 0x7,
587 					 &band_chan_cfg)) {
588 			PRINTM(MERROR, "%s: woal_set_net_monitor fail\n",
589 			       __func__);
590 			ret = -EFAULT;
591 			goto done;
592 		}
593 
594 		memcpy(&handle->mon_if->band_chan_cfg, &band_chan_cfg,
595 		       sizeof(handle->mon_if->band_chan_cfg));
596 		handle->mon_if->chandef = *chandef;
597 
598 		if (handle->mon_if->chandef.chan)
599 			PRINTM(MINFO,
600 			       "set_monitor_channel+++ chan[band=%d center_freq=%d hw_value=%d] width=%d center_freq1=%d center_freq2=%d\n",
601 			       handle->mon_if->chandef.chan->band,
602 			       handle->mon_if->chandef.chan->center_freq,
603 			       handle->mon_if->chandef.chan->hw_value,
604 			       handle->mon_if->chandef.width,
605 			       handle->mon_if->chandef.center_freq1,
606 			       handle->mon_if->chandef.center_freq2);
607 		PRINTM(MINFO,
608 		       "set_monitor_channel+++ band=%x channel=%d bandwidth=%d\n",
609 		       handle->mon_if->band_chan_cfg.band,
610 		       handle->mon_if->band_chan_cfg.channel,
611 		       handle->mon_if->band_chan_cfg.chan_bandwidth);
612 		ret = 0;
613 	}
614 
615 done:
616 	LEAVE();
617 	return ret;
618 }
619 #endif
620 
621 /**
622  *  @brief This function check cfg80211 special region code.
623  *
624  *  @param region_string         Region string
625  *
626  *  @return     MTRUE/MFALSE
627  */
628 t_u8
is_cfg80211_special_region_code(char * region_string)629 is_cfg80211_special_region_code(char *region_string)
630 {
631 	t_u8 i;
632 	region_code_t cfg80211_special_region_code[] = {
633 		{"00 "}, {"99 "}, {"98 "}, {"97 "}
634 	};
635 
636 	for (i = 0; i < COUNTRY_CODE_LEN && region_string[i]; i++)
637 		region_string[i] = toupper(region_string[i]);
638 
639 	for (i = 0; i < ARRAY_SIZE(cfg80211_special_region_code); i++) {
640 		if (!memcmp(region_string,
641 			    cfg80211_special_region_code[i].region,
642 			    COUNTRY_CODE_LEN)) {
643 			PRINTM(MIOCTL, "special region code=%s\n",
644 			       region_string);
645 			return MTRUE;
646 		}
647 	}
648 	return MFALSE;
649 }
650 
651 /**
652  * @brief Get the encryption mode from cipher
653  *
654  * @param cipher        Cipher cuite
655  * @param wpa_enabled   WPA enable or disable
656  *
657  * @return              MLAN_ENCRYPTION_MODE_*
658  */
659 static int
woal_cfg80211_get_encryption_mode(t_u32 cipher,int * wpa_enabled)660 woal_cfg80211_get_encryption_mode(t_u32 cipher, int *wpa_enabled)
661 {
662 	int encrypt_mode;
663 
664 	ENTER();
665 
666 	*wpa_enabled = 0;
667 	switch (cipher) {
668 	case MW_AUTH_CIPHER_NONE:
669 		encrypt_mode = MLAN_ENCRYPTION_MODE_NONE;
670 		break;
671 	case WLAN_CIPHER_SUITE_WEP40:
672 		encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40;
673 		break;
674 	case WLAN_CIPHER_SUITE_WEP104:
675 		encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104;
676 		break;
677 	case WLAN_CIPHER_SUITE_TKIP:
678 		encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP;
679 		*wpa_enabled = 1;
680 		break;
681 	case WLAN_CIPHER_SUITE_CCMP:
682 		encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP;
683 		*wpa_enabled = 1;
684 		break;
685 	default:
686 		encrypt_mode = -1;
687 	}
688 
689 	LEAVE();
690 	return encrypt_mode;
691 }
692 
693 /**
694  *  @brief get associate failure status code
695  *
696  *  @param priv     Pointer to the moal_private driver data struct
697  *
698  *  @return         IEEE status code
699  */
700 static int
woal_get_assoc_status(moal_private * priv)701 woal_get_assoc_status(moal_private *priv)
702 {
703 	int ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
704 	t_u16 status = (t_u16)(priv->assoc_status & 0xffff);
705 	t_u16 cap = (t_u16)(priv->assoc_status >> 16);
706 
707 	switch (cap) {
708 	case 0xfffd:
709 	case 0xfffe:
710 		ret = status;
711 		break;
712 	case 0xfffc:
713 		ret = WLAN_STATUS_AUTH_TIMEOUT;
714 		break;
715 	default:
716 		break;
717 	}
718 	PRINTM(MCMND, "Assoc fail: status=%d, cap=0x%x, IEEE status=%d\n",
719 	       status, cap, ret);
720 	return ret;
721 }
722 
723 /**
724  *  @brief Check the pairwise or group cipher for
725  *  WEP enabled or not
726  *
727  *  @param cipher       MLAN Cipher cuite
728  *
729  *  @return             1 -- enable or 0 -- disable
730  */
731 static int
woal_cfg80211_is_alg_wep(t_u32 cipher)732 woal_cfg80211_is_alg_wep(t_u32 cipher)
733 {
734 	int alg = 0;
735 	ENTER();
736 
737 	if (cipher == MLAN_ENCRYPTION_MODE_WEP40 ||
738 	    cipher == MLAN_ENCRYPTION_MODE_WEP104)
739 		alg = 1;
740 
741 	LEAVE();
742 	return alg;
743 }
744 
745 /**
746  *  @brief Convert NL802.11 channel type into driver channel type
747  *
748  * The mapping is as follows -
749  *      NL80211_CHAN_NO_HT     -> CHANNEL_BW_20MHZ
750  *      NL80211_CHAN_HT20      -> CHANNEL_BW_20MHZ
751  *      NL80211_CHAN_HT40PLUS  -> CHANNEL_BW_40MHZ_ABOVE
752  *      NL80211_CHAN_HT40MINUS -> CHANNEL_BW_40MHZ_BELOW
753  *      Others                 -> CHANNEL_BW_20MHZ
754  *
755  *  @param channel_type     Channel type
756  *
757  *  @return                 Driver channel type
758  */
759 static int
woal_cfg80211_channel_type_to_channel(enum nl80211_channel_type channel_type)760 woal_cfg80211_channel_type_to_channel(enum nl80211_channel_type channel_type)
761 {
762 	int channel;
763 
764 	ENTER();
765 
766 	switch (channel_type) {
767 	case NL80211_CHAN_NO_HT:
768 	case NL80211_CHAN_HT20:
769 		channel = CHANNEL_BW_20MHZ;
770 		break;
771 	case NL80211_CHAN_HT40PLUS:
772 		channel = CHANNEL_BW_40MHZ_ABOVE;
773 		break;
774 	case NL80211_CHAN_HT40MINUS:
775 		channel = CHANNEL_BW_40MHZ_BELOW;
776 		break;
777 	default:
778 		channel = CHANNEL_BW_20MHZ;
779 	}
780 	LEAVE();
781 	return channel;
782 }
783 
784 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
785 /**
786  *  @brief get nl80211_channel_type from cfg80211_chan_def
787  *
788  *  @param chan_def     struct cfg80211_chan_def
789  *
790  *  @return                 nl80211_channel_type type
791  */
792 static enum nl80211_channel_type
woal_channel_to_nl80211_channel_type(struct cfg80211_chan_def * chan_def)793 woal_channel_to_nl80211_channel_type(struct cfg80211_chan_def *chan_def)
794 {
795 	enum nl80211_channel_type channel_type = 0;
796 
797 	ENTER();
798 
799 	switch (chan_def->width) {
800 	case NL80211_CHAN_WIDTH_20:
801 		/** Channel width 20MHz**/
802 		channel_type = NL80211_CHAN_HT20;
803 		break;
804 	case NL80211_CHAN_WIDTH_40:
805 		/** Channel width 40MHz**/
806 		if (chan_def->center_freq1 < chan_def->chan->center_freq)
807 			channel_type = NL80211_CHAN_HT40MINUS;
808 		else if (chan_def->center_freq1 > chan_def->chan->center_freq)
809 			channel_type = NL80211_CHAN_HT40PLUS;
810 		break;
811 	default:
812 		channel_type = NL80211_CHAN_HT20;
813 		break;
814 	}
815 	LEAVE();
816 	return channel_type;
817 }
818 #endif
819 
820 /**
821  *  @brief Convert NL80211 interface type to MLAN_BSS_MODE_*
822  *
823  *  @param iftype   Interface type of NL80211
824  *
825  *  @return         Driver bss mode
826  */
827 static t_u32
woal_nl80211_iftype_to_mode(enum nl80211_iftype iftype)828 woal_nl80211_iftype_to_mode(enum nl80211_iftype iftype)
829 {
830 	switch (iftype) {
831 	case NL80211_IFTYPE_ADHOC:
832 		return MLAN_BSS_MODE_IBSS;
833 	case NL80211_IFTYPE_STATION:
834 		return MLAN_BSS_MODE_INFRA;
835 	case NL80211_IFTYPE_UNSPECIFIED:
836 	default:
837 		return MLAN_BSS_MODE_AUTO;
838 	}
839 }
840 
841 /**
842  *  @brief Control WPS Session Enable/Disable
843  *
844  *  @param priv     Pointer to the moal_private driver data struct
845  *  @param enable   enable/disable flag
846  *
847  *  @return          0 --success, otherwise fail
848  */
849 static int
woal_wps_cfg(moal_private * priv,int enable)850 woal_wps_cfg(moal_private *priv, int enable)
851 {
852 	int ret = 0;
853 	mlan_ds_wps_cfg *pwps = NULL;
854 	mlan_ioctl_req *req = NULL;
855 	mlan_status status = MLAN_STATUS_SUCCESS;
856 
857 	ENTER();
858 
859 	PRINTM(MINFO, "WOAL_WPS_SESSION\n");
860 
861 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg));
862 	if (req == NULL) {
863 		ret = -ENOMEM;
864 		goto done;
865 	}
866 
867 	pwps = (mlan_ds_wps_cfg *)req->pbuf;
868 	req->req_id = MLAN_IOCTL_WPS_CFG;
869 	req->action = MLAN_ACT_SET;
870 	pwps->sub_command = MLAN_OID_WPS_CFG_SESSION;
871 	if (enable)
872 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START;
873 	else
874 		pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END;
875 
876 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
877 	if (status != MLAN_STATUS_SUCCESS) {
878 		ret = -EFAULT;
879 		goto done;
880 	}
881 
882 done:
883 	if (status != MLAN_STATUS_PENDING)
884 		kfree(req);
885 	LEAVE();
886 	return ret;
887 }
888 
889 /**
890  * @brief configure ASSOC IE
891  *
892  * @param priv				A pointer to moal private structure
893  * @param ie				A pointer to ie data
894  * @param ie_len			The length of ie data
895  * @param wait_option       wait option
896  *
897  * @return                  0 -- success, otherwise fail
898  */
899 static int
woal_cfg80211_assoc_ies_cfg(moal_private * priv,t_u8 * ie,int ie_len,t_u8 wait_option)900 woal_cfg80211_assoc_ies_cfg(moal_private *priv, t_u8 *ie, int ie_len,
901 			    t_u8 wait_option)
902 {
903 	int bytes_left = ie_len;
904 	t_u8 *pcurrent_ptr = ie;
905 	int total_ie_len;
906 	t_u8 element_len;
907 	int ret = MLAN_STATUS_SUCCESS;
908 	IEEEtypes_ElementId_e element_id;
909 	IEEEtypes_VendorSpecific_t *pvendor_ie;
910 	t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
911 
912 	while (bytes_left >= 2) {
913 		element_id = (IEEEtypes_ElementId_e)(*((t_u8 *)pcurrent_ptr));
914 		element_len = *((t_u8 *)pcurrent_ptr + 1);
915 		total_ie_len = element_len + sizeof(IEEEtypes_Header_t);
916 		if (bytes_left < total_ie_len) {
917 			PRINTM(MERROR,
918 			       "InterpretIE: Error in processing IE, bytes left < IE length\n");
919 			bytes_left = 0;
920 			continue;
921 		}
922 		switch (element_id) {
923 		case RSN_IE:
924 			if (MLAN_STATUS_SUCCESS !=
925 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
926 						pcurrent_ptr, &total_ie_len,
927 						wait_option)) {
928 				PRINTM(MERROR, "Fail to set RSN IE\n");
929 				ret = -EFAULT;
930 				goto done;
931 			}
932 			PRINTM(MIOCTL, "Set RSN IE\n");
933 			break;
934 		case VENDOR_SPECIFIC_221:
935 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pcurrent_ptr;
936 			if (!memcmp
937 			    (pvendor_ie->vend_hdr.oui, wps_oui,
938 			     sizeof(pvendor_ie->vend_hdr.oui)) &&
939 			    (pvendor_ie->vend_hdr.oui_type == wps_oui[3])) {
940 				PRINTM(MIOCTL, "Enable WPS session\n");
941 				woal_wps_cfg(priv, MTRUE);
942 			}
943 			if (MLAN_STATUS_SUCCESS !=
944 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
945 						pcurrent_ptr, &total_ie_len,
946 						wait_option)) {
947 				PRINTM(MERROR,
948 				       "Fail to Set VENDOR SPECIFIC IE\n");
949 				ret = -EFAULT;
950 				goto done;
951 			}
952 			PRINTM(MIOCTL,
953 			       "Set VENDOR SPECIFIC IE, OUI: %02x:%02x:%02x:%02x\n",
954 			       pvendor_ie->vend_hdr.oui[0],
955 			       pvendor_ie->vend_hdr.oui[1],
956 			       pvendor_ie->vend_hdr.oui[2],
957 			       pvendor_ie->vend_hdr.oui_type);
958 			break;
959 		case MOBILITY_DOMAIN:
960 			break;
961 		case FAST_BSS_TRANSITION:
962 			if (MLAN_STATUS_SUCCESS !=
963 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
964 						pcurrent_ptr, &total_ie_len,
965 						wait_option)) {
966 				PRINTM(MERROR,
967 				       "Fail to set"
968 				       "FAST_BSS_TRANSITION IE\n");
969 				ret = -EFAULT;
970 				goto done;
971 			}
972 			PRINTM(MIOCTL, "Set FAST_BSS_TRANSITION IE\n");
973 			break;
974 		case RIC:
975 			if (MLAN_STATUS_SUCCESS !=
976 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
977 						pcurrent_ptr, &total_ie_len,
978 						wait_option)) {
979 				PRINTM(MERROR,
980 				       "Fail to set"
981 				       "RESOURCE INFORMATION CONTAINER IE\n");
982 				ret = -EFAULT;
983 				goto done;
984 			}
985 			PRINTM(MIOCTL,
986 			       "Set RESOURCE INFORMATION CONTAINER IE\n");
987 			break;
988 		case EXT_CAPABILITY:
989 			if (MLAN_STATUS_SUCCESS !=
990 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
991 						pcurrent_ptr, &total_ie_len,
992 						wait_option)) {
993 				PRINTM(MERROR,
994 				       "Fail to set Extended Capabilites IE\n");
995 				ret = -EFAULT;
996 				goto done;
997 			}
998 			PRINTM(MIOCTL, "Set Extended Capabilities IE\n");
999 			break;
1000 		default:
1001 			if (MLAN_STATUS_SUCCESS !=
1002 			    woal_set_get_gen_ie(priv, MLAN_ACT_SET,
1003 						pcurrent_ptr, &total_ie_len,
1004 						wait_option)) {
1005 				PRINTM(MERROR, "Fail to set GEN IE\n");
1006 				ret = -EFAULT;
1007 				goto done;
1008 			}
1009 			PRINTM(MIOCTL, "Set GEN IE\n");
1010 			break;
1011 		}
1012 		pcurrent_ptr += element_len + 2;
1013 		/* Need to account for IE ID and IE Len */
1014 		bytes_left -= (element_len + 2);
1015 	}
1016 done:
1017 	return ret;
1018 }
1019 
1020 /**
1021  * @brief Send domain info command to FW
1022  *
1023  * @param priv      A pointer to moal_private structure
1024  * @param wait_option  wait option
1025  *
1026  * @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1027  */
1028 static mlan_status
woal_send_domain_info_cmd_fw(moal_private * priv,t_u8 wait_option)1029 woal_send_domain_info_cmd_fw(moal_private *priv, t_u8 wait_option)
1030 {
1031 	mlan_status ret = MLAN_STATUS_SUCCESS;
1032 	enum ieee80211_band band;
1033 	struct ieee80211_supported_band *sband = NULL;
1034 	struct ieee80211_channel *channel = NULL;
1035 	t_u8 no_of_sub_band = 0;
1036 	t_u8 no_of_parsed_chan = 0;
1037 	t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
1038 	t_u8 i, flag = 0;
1039 	mlan_ds_11d_cfg *cfg_11d = NULL;
1040 	mlan_ioctl_req *req = NULL;
1041 	mlan_status status = MLAN_STATUS_SUCCESS;
1042 
1043 	ENTER();
1044 
1045 	if (!priv->wdev || !priv->wdev->wiphy) {
1046 		PRINTM(MERROR, "No wdev or wiphy in priv\n");
1047 		ret = MLAN_STATUS_FAILURE;
1048 		goto done;
1049 	}
1050 	band = priv->phandle->band;
1051 	if (!priv->wdev->wiphy->bands[band]) {
1052 		PRINTM(MERROR, "11D: setting domain info in FW failed band=%d",
1053 		       band);
1054 		ret = MLAN_STATUS_FAILURE;
1055 		goto done;
1056 	}
1057 
1058 	if (MTRUE ==
1059 	    is_cfg80211_special_region_code(priv->phandle->country_code)) {
1060 		PRINTM(MIOCTL,
1061 		       "skip region code config, cfg80211 special region code: %s\n",
1062 		       priv->phandle->country_code);
1063 		goto done;
1064 	}
1065 	PRINTM(MIOCTL, "Send domain info: country=%c%c band=%d\n",
1066 	       priv->phandle->country_code[0], priv->phandle->country_code[1],
1067 	       band);
1068 	/* Allocate an IOCTL request buffer */
1069 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
1070 	if (req == NULL) {
1071 		ret = MLAN_STATUS_FAILURE;
1072 		goto done;
1073 	}
1074 	cfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
1075 	cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
1076 	req->req_id = MLAN_IOCTL_11D_CFG;
1077 	req->action = MLAN_ACT_SET;
1078 
1079 	/* Set country code */
1080 	cfg_11d->param.domain_info.country_code[0] =
1081 		priv->phandle->country_code[0];
1082 	cfg_11d->param.domain_info.country_code[1] =
1083 		priv->phandle->country_code[1];
1084 	cfg_11d->param.domain_info.country_code[2] = ' ';
1085 	cfg_11d->param.domain_info.band = band;
1086 
1087 	sband = priv->wdev->wiphy->bands[band];
1088 	for (i = 0; (i < sband->n_channels) &&
1089 	     (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D); i++) {
1090 		channel = &sband->channels[i];
1091 		if (channel->flags & IEEE80211_CHAN_DISABLED)
1092 			continue;
1093 
1094 		if (!flag) {
1095 			flag = 1;
1096 			next_chan = first_chan = (t_u32)channel->hw_value;
1097 			max_pwr = channel->max_power;
1098 			no_of_parsed_chan = 1;
1099 			continue;
1100 		}
1101 
1102 		if (channel->hw_value == next_chan + 1 &&
1103 		    channel->max_power == max_pwr) {
1104 			next_chan++;
1105 			no_of_parsed_chan++;
1106 		} else {
1107 			cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1108 				.first_chan = first_chan;
1109 			cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1110 				.no_of_chan = no_of_parsed_chan;
1111 			cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1112 				.max_tx_pwr = max_pwr;
1113 			no_of_sub_band++;
1114 			next_chan = first_chan = (t_u32)channel->hw_value;
1115 			max_pwr = channel->max_power;
1116 			no_of_parsed_chan = 1;
1117 		}
1118 	}
1119 
1120 	if (flag && (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D)) {
1121 		cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1122 			.first_chan = first_chan;
1123 		cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1124 			.no_of_chan = no_of_parsed_chan;
1125 		cfg_11d->param.domain_info.sub_band[no_of_sub_band]
1126 			.max_tx_pwr = max_pwr;
1127 		no_of_sub_band++;
1128 	}
1129 	cfg_11d->param.domain_info.no_of_sub_band = no_of_sub_band;
1130 
1131 	/* Send domain info command to FW */
1132 	status = woal_request_ioctl(priv, req, wait_option);
1133 	if (status != MLAN_STATUS_SUCCESS) {
1134 		ret = MLAN_STATUS_FAILURE;
1135 		PRINTM(MERROR, "11D: Error setting domain info in FW\n");
1136 		goto done;
1137 	}
1138 
1139 done:
1140 	if (status != MLAN_STATUS_PENDING)
1141 		kfree(req);
1142 	LEAVE();
1143 	return ret;
1144 }
1145 
1146 /**
1147  * @brief Request the driver to change the channel and
1148  * change domain info according to that channel
1149  *
1150  * @param priv            A pointer to moal_private structure
1151  * @param chan            A pointer to ieee80211_channel structure
1152  * @param channel_type    Channel type of nl80211_channel_type
1153  * @param wait_option     wait option
1154  *
1155  * @return                0 -- success, otherwise fail
1156  */
1157 int
woal_set_rf_channel(moal_private * priv,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type,t_u8 wait_option)1158 woal_set_rf_channel(moal_private *priv,
1159 		    struct ieee80211_channel *chan,
1160 		    enum nl80211_channel_type channel_type, t_u8 wait_option)
1161 {
1162 	int ret = 0;
1163 	t_u32 mode, config_bands = 0;
1164 	mlan_ioctl_req *req = NULL;
1165 	mlan_ds_radio_cfg *radio_cfg = NULL;
1166 	mlan_status status = MLAN_STATUS_SUCCESS;
1167 	int chan_width = 0;
1168 
1169 	ENTER();
1170 
1171 	if (!chan) {
1172 		LEAVE();
1173 		return -EINVAL;
1174 	}
1175 	mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
1176 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
1177 	if (req == NULL) {
1178 		ret = -ENOMEM;
1179 		goto done;
1180 	}
1181 	radio_cfg = (mlan_ds_radio_cfg *)req->pbuf;
1182 	radio_cfg->sub_command = MLAN_OID_BAND_CFG;
1183 	req->req_id = MLAN_IOCTL_RADIO_CFG;
1184 	/* Get config_bands, adhoc_start_band and adhoc_channel values from MLAN */
1185 	req->action = MLAN_ACT_GET;
1186 	status = woal_request_ioctl(priv, req, wait_option);
1187 	if (status != MLAN_STATUS_SUCCESS) {
1188 		ret = -EFAULT;
1189 		goto done;
1190 	}
1191 	req->action = MLAN_ACT_SET;
1192 	priv->phandle->band = chan->band;
1193 	chan_width = woal_cfg80211_channel_type_to_channel(channel_type);
1194 	/* Set appropriate bands */
1195 	if (chan->band == IEEE80211_BAND_2GHZ)
1196 		config_bands = BAND_B | BAND_G | BAND_GN;
1197 	else {
1198 		config_bands = BAND_AN | BAND_A;
1199 	}
1200 	if (mode == MLAN_BSS_MODE_IBSS) {
1201 		radio_cfg->param.band_cfg.adhoc_start_band = config_bands;
1202 		radio_cfg->param.band_cfg.adhoc_channel =
1203 			ieee80211_frequency_to_channel(chan->center_freq);
1204 	}
1205 	/* Set channel offset */
1206 	radio_cfg->param.band_cfg.adhoc_chan_bandwidth = chan_width;
1207 
1208 	status = woal_request_ioctl(priv, req, wait_option);
1209 	if (status != MLAN_STATUS_SUCCESS) {
1210 		ret = -EFAULT;
1211 		goto done;
1212 	}
1213 	woal_send_domain_info_cmd_fw(priv, wait_option);
1214 
1215 	PRINTM(MINFO,
1216 	       "Setting band %d, channel bandwidth %d and mode = %d channel=%d\n",
1217 	       config_bands, radio_cfg->param.band_cfg.adhoc_chan_bandwidth,
1218 	       mode, ieee80211_frequency_to_channel(chan->center_freq));
1219 
1220 	if (MLAN_STATUS_SUCCESS !=
1221 	    woal_change_adhoc_chan(priv,
1222 				   ieee80211_frequency_to_channel(chan->
1223 								  center_freq),
1224 				   wait_option)) {
1225 		ret = -EFAULT;
1226 		goto done;
1227 	}
1228 
1229 done:
1230 	if (status != MLAN_STATUS_PENDING)
1231 		kfree(req);
1232 	LEAVE();
1233 	return ret;
1234 }
1235 
1236 /**
1237  *  @brief Set ewpa mode
1238  *
1239  *  @param priv                 A pointer to moal_private structure
1240  *  @param wait_option          Wait option
1241  *  @param ssid_bssid           A pointer to mlan_ssid_bssid structure
1242  *
1243  *  @return                     MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
1244  */
1245 mlan_status
woal_set_ewpa_mode(moal_private * priv,t_u8 wait_option,mlan_ssid_bssid * ssid_bssid)1246 woal_set_ewpa_mode(moal_private *priv, t_u8 wait_option,
1247 		   mlan_ssid_bssid *ssid_bssid)
1248 {
1249 	int ret = 0;
1250 	mlan_ioctl_req *req = NULL;
1251 	mlan_ds_sec_cfg *sec = NULL;
1252 	mlan_status status = MLAN_STATUS_SUCCESS;
1253 
1254 	ENTER();
1255 
1256 	/* Allocate an IOCTL request buffer */
1257 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
1258 	if (req == NULL) {
1259 		ret = -ENOMEM;
1260 		goto error;
1261 	}
1262 	/* Fill request buffer */
1263 	sec = (mlan_ds_sec_cfg *)req->pbuf;
1264 	sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE;
1265 	req->req_id = MLAN_IOCTL_SEC_CFG;
1266 	req->action = MLAN_ACT_GET;
1267 
1268 	/* Try Get All */
1269 	memset(&sec->param.passphrase, 0, sizeof(mlan_ds_passphrase));
1270 	memcpy(&sec->param.passphrase.ssid, &ssid_bssid->ssid,
1271 	       sizeof(sec->param.passphrase.ssid));
1272 	memcpy(&sec->param.passphrase.bssid, &ssid_bssid->bssid,
1273 	       MLAN_MAC_ADDR_LENGTH);
1274 	sec->param.passphrase.psk_type = MLAN_PSK_QUERY;
1275 
1276 	/* Send IOCTL request to MLAN */
1277 	status = woal_request_ioctl(priv, req, wait_option);
1278 	if (status != MLAN_STATUS_SUCCESS)
1279 		goto error;
1280 	sec->param.ewpa_enabled = MFALSE;
1281 	if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) {
1282 		if (sec->param.passphrase.psk.passphrase.passphrase_len > 0)
1283 			sec->param.ewpa_enabled = MTRUE;
1284 	} else if (sec->param.passphrase.psk_type == MLAN_PSK_PMK)
1285 		sec->param.ewpa_enabled = MTRUE;
1286 
1287 	sec->sub_command = MLAN_OID_SEC_CFG_EWPA_ENABLED;
1288 	req->action = MLAN_ACT_SET;
1289 
1290 	/* Send IOCTL request to MLAN */
1291 	status = woal_request_ioctl(priv, req, wait_option);
1292 
1293 error:
1294 	if (status != MLAN_STATUS_PENDING)
1295 		kfree(req);
1296 	LEAVE();
1297 	return status;
1298 }
1299 
1300 /**
1301  * @brief Set encryption mode and enable WPA
1302  *
1303  * @param priv          A pointer to moal_private structure
1304  * @param encrypt_mode  Encryption mode
1305  * @param wpa_enabled   WPA enable or not
1306  * @param wait_option   wait option
1307  *
1308  * @return              0 -- success, otherwise fail
1309  */
1310 static int
woal_cfg80211_set_auth(moal_private * priv,int encrypt_mode,int wpa_enabled,t_u8 wait_option)1311 woal_cfg80211_set_auth(moal_private *priv, int encrypt_mode,
1312 		       int wpa_enabled, t_u8 wait_option)
1313 {
1314 	int ret = 0;
1315 
1316 	ENTER();
1317 
1318 	if (MLAN_STATUS_SUCCESS !=
1319 	    woal_set_encrypt_mode(priv, wait_option, encrypt_mode))
1320 		ret = -EFAULT;
1321 
1322 	if (wpa_enabled) {
1323 		if (MLAN_STATUS_SUCCESS !=
1324 		    woal_set_wpa_enable(priv, wait_option, 1))
1325 			ret = -EFAULT;
1326 	}
1327 
1328 	LEAVE();
1329 	return ret;
1330 }
1331 
1332 /**
1333  * @brief Informs the CFG802.11 subsystem of a new BSS connection.
1334  *
1335  * The following information are sent to the CFG802.11 subsystem
1336  * to register the new BSS connection. If we do not register the new BSS,
1337  * a kernel panic will result.
1338  *      - MAC address
1339  *      - Capabilities
1340  *      - Beacon period
1341  *      - RSSI value
1342  *      - Channel
1343  *      - Supported rates IE
1344  *      - Extended capabilities IE
1345  *      - DS parameter set IE
1346  *      - HT Capability IE
1347  *      - Vendor Specific IE (221)
1348  *      - WPA IE
1349  *      - RSN IE
1350  *
1351  * @param priv            A pointer to moal_private structure
1352  * @param ssid_bssid      A pointer to A pointer to mlan_ssid_bssid structure
1353  * @param wait_option     wait_option
1354  *
1355  * @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1356  */
1357 mlan_status
woal_inform_bss_from_scan_result(moal_private * priv,mlan_ssid_bssid * ssid_bssid,t_u8 wait_option)1358 woal_inform_bss_from_scan_result(moal_private *priv,
1359 				 mlan_ssid_bssid *ssid_bssid, t_u8 wait_option)
1360 {
1361 	mlan_status ret = MLAN_STATUS_SUCCESS;
1362 	struct ieee80211_channel *chan;
1363 	mlan_scan_resp scan_resp;
1364 	BSSDescriptor_t *scan_table;
1365 	t_u64 ts = 0;
1366 	u16 cap_info = 0;
1367 	int i = 0;
1368 	struct cfg80211_bss *pub = NULL;
1369 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
1370 	struct timespec tstamp;
1371 #endif
1372 	ENTER();
1373 	if (!priv->wdev || !priv->wdev->wiphy) {
1374 		LEAVE();
1375 		return MLAN_STATUS_FAILURE;
1376 	}
1377 
1378 	memset(&scan_resp, 0, sizeof(scan_resp));
1379 	if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
1380 						       wait_option,
1381 						       &scan_resp)) {
1382 		ret = MLAN_STATUS_FAILURE;
1383 		goto done;
1384 	}
1385 
1386 	if (scan_resp.num_in_scan_table) {
1387 		scan_table = (BSSDescriptor_t *)scan_resp.pscan_table;
1388 		for (i = 0; i < scan_resp.num_in_scan_table; i++) {
1389 			if (ssid_bssid) {
1390 				/* Inform specific BSS only */
1391 				if (memcmp
1392 				    (ssid_bssid->ssid.ssid,
1393 				     scan_table[i].ssid.ssid,
1394 				     ssid_bssid->ssid.ssid_len) ||
1395 				    memcmp(ssid_bssid->bssid,
1396 					   scan_table[i].mac_address, ETH_ALEN))
1397 					continue;
1398 			}
1399 			if (!scan_table[i].freq) {
1400 				scan_table[i].freq =
1401 					ieee80211_channel_to_frequency((int)
1402 								       scan_table
1403 								       [i].
1404 								       channel
1405 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
1406 								       ,
1407 								       woal_band_cfg_to_ieee_band
1408 								       (scan_table
1409 									[i].
1410 									bss_band)
1411 #endif
1412 					);
1413 			}
1414 			chan = ieee80211_get_channel(priv->wdev->wiphy,
1415 						     scan_table[i].freq);
1416 			if (!chan) {
1417 				PRINTM(MCMND,
1418 				       "Fail to get chan with freq: channel=%d freq=%d\n",
1419 				       (int)scan_table[i].channel,
1420 				       (int)scan_table[i].freq);
1421 				continue;
1422 			}
1423 #if defined(WIFI_DIRECT_SUPPORT)
1424 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
1425 			if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
1426 			    !ssid_bssid) {
1427 				if (!strncmp
1428 				    (scan_table[i].ssid.ssid, "DIRECT-",
1429 				     strlen("DIRECT-"))) {
1430 					PRINTM(MCMND,
1431 					       "wlan: P2P device " MACSTR
1432 					       " found, channel=%d\n",
1433 					       MAC2STR(scan_table[i].
1434 						       mac_address),
1435 					       (int)chan->hw_value);
1436 				}
1437 			}
1438 #endif
1439 #endif
1440 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
1441 			/** Andorid's Location service is expecting timestamp to be
1442 			* local time (in microsecond) since boot;
1443 			* and not the TSF found in the beacon. */
1444 			get_monotonic_boottime(&tstamp);
1445 			ts = (t_u64)tstamp.tv_sec * 1000000 +
1446 				tstamp.tv_nsec / 1000;
1447 #else
1448 			memcpy(&ts, scan_table[i].time_stamp, sizeof(ts));
1449 #endif
1450 			memcpy(&cap_info, &scan_table[i].cap_info,
1451 			       sizeof(cap_info));
1452 			pub = cfg80211_inform_bss(priv->wdev->wiphy, chan,
1453 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
1454 						  CFG80211_BSS_FTYPE_UNKNOWN,
1455 #endif
1456 						  scan_table[i].mac_address,
1457 						  ts, cap_info,
1458 						  scan_table[i].beacon_period,
1459 						  scan_table[i].pbeacon_buf +
1460 						  WLAN_802_11_FIXED_IE_SIZE,
1461 						  scan_table[i].
1462 						  beacon_buf_size -
1463 						  WLAN_802_11_FIXED_IE_SIZE,
1464 						  -RSSI_DBM_TO_MDM(scan_table
1465 								   [i].rssi),
1466 						  GFP_KERNEL);
1467 			if (pub) {
1468 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
1469 				pub->len_information_elements =
1470 					pub->len_beacon_ies;
1471 #endif
1472 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
1473 				cfg80211_put_bss(priv->wdev->wiphy, pub);
1474 #else
1475 				cfg80211_put_bss(pub);
1476 #endif
1477 			}
1478 		}
1479 	}
1480 done:
1481 	LEAVE();
1482 	return ret;
1483 }
1484 
1485 /**
1486  * @brief Informs the CFG802.11 subsystem of a new IBSS connection.
1487  *
1488  * The following information are sent to the CFG802.11 subsystem
1489  * to register the new IBSS connection. If we do not register the
1490  * new IBSS, a kernel panic will result.
1491  *      - MAC address
1492  *      - Capabilities
1493  *      - Beacon period
1494  *      - RSSI value
1495  *      - Channel
1496  *      - Supported rates IE
1497  *      - Extended capabilities IE
1498  *      - DS parameter set IE
1499  *      - HT Capability IE
1500  *      - Vendor Specific IE (221)
1501  *      - WPA IE
1502  *      - RSN IE
1503  *
1504  * @param priv              A pointer to moal_private structure
1505  * @param cahn              A pointer to ieee80211_channel structure
1506  * @param beacon_interval   Beacon interval
1507  *
1508  * @return                  MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1509  */
1510 static mlan_status
woal_cfg80211_inform_ibss_bss(moal_private * priv,struct ieee80211_channel * chan,t_u16 beacon_interval)1511 woal_cfg80211_inform_ibss_bss(moal_private *priv,
1512 			      struct ieee80211_channel *chan,
1513 			      t_u16 beacon_interval)
1514 {
1515 	mlan_status ret = MLAN_STATUS_SUCCESS;
1516 	mlan_bss_info bss_info;
1517 	mlan_ds_get_signal signal;
1518 	t_u8 ie_buf[MLAN_MAX_SSID_LENGTH + sizeof(IEEEtypes_Header_t)];
1519 	int ie_len = 0;
1520 	struct cfg80211_bss *bss = NULL;
1521 
1522 	ENTER();
1523 
1524 	ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
1525 	if (ret)
1526 		goto done;
1527 
1528 	memset(ie_buf, 0, sizeof(ie_buf));
1529 	ie_buf[0] = WLAN_EID_SSID;
1530 	ie_buf[1] = bss_info.ssid.ssid_len;
1531 
1532 	memcpy(&ie_buf[sizeof(IEEEtypes_Header_t)],
1533 	       &bss_info.ssid.ssid, bss_info.ssid.ssid_len);
1534 	ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t);
1535 
1536 	/* Get signal information from the firmware */
1537 	memset(&signal, 0, sizeof(mlan_ds_get_signal));
1538 	if (MLAN_STATUS_SUCCESS !=
1539 	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
1540 		PRINTM(MERROR, "Error getting signal information\n");
1541 		ret = MLAN_STATUS_FAILURE;
1542 		goto done;
1543 	}
1544 
1545 	bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
1546 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
1547 				  CFG80211_BSS_FTYPE_UNKNOWN,
1548 #endif
1549 				  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
1550 				  beacon_interval, ie_buf, ie_len,
1551 				  signal.bcn_rssi_avg, GFP_KERNEL);
1552 	if (bss)
1553 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
1554 		cfg80211_put_bss(priv->wdev->wiphy, bss);
1555 #else
1556 		cfg80211_put_bss(bss);
1557 #endif
1558 done:
1559 	LEAVE();
1560 	return ret;
1561 }
1562 
1563 /**
1564  * @brief Process country IE before assoicate
1565  *
1566  * @param priv            A pointer to moal_private structure
1567  * @param bss             A pointer to cfg80211_bss structure
1568  *
1569  * @return                0 -- success, otherwise fail
1570  */
1571 static int
woal_process_country_ie(moal_private * priv,struct cfg80211_bss * bss)1572 woal_process_country_ie(moal_private *priv, struct cfg80211_bss *bss)
1573 {
1574 	u8 *country_ie, country_ie_len;
1575 	int ret = 0;
1576 	mlan_ioctl_req *req = NULL;
1577 	mlan_ds_11d_cfg *cfg_11d = NULL;
1578 	mlan_status status = MLAN_STATUS_SUCCESS;
1579 
1580 	ENTER();
1581 	country_ie = (u8 *)ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);
1582 	if (!country_ie) {
1583 		PRINTM(MIOCTL, "No country IE found!\n");
1584 		woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
1585 		LEAVE();
1586 		return 0;
1587 	}
1588 
1589 	country_ie_len = country_ie[1];
1590 	if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {
1591 		PRINTM(MIOCTL, "Wrong Country IE length!\n");
1592 		woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
1593 		LEAVE();
1594 		return 0;
1595 	}
1596 	PRINTM(MIOCTL, "Find bss country IE: %c%c band=%d\n", country_ie[2],
1597 	       country_ie[3], priv->phandle->band);
1598 	priv->phandle->country_code[0] = country_ie[2];
1599 	priv->phandle->country_code[1] = country_ie[3];
1600 	priv->phandle->country_code[2] = ' ';
1601 	if (MLAN_STATUS_SUCCESS !=
1602 	    woal_set_region_code(priv, priv->phandle->country_code))
1603 		PRINTM(MERROR, "Set country code failed!\n");
1604 
1605 	/* Allocate an IOCTL request buffer */
1606 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
1607 	if (req == NULL) {
1608 		PRINTM(MERROR, "Fail to allocate mlan_ds_11d_cfg buffer\n");
1609 		ret = MLAN_STATUS_FAILURE;
1610 		goto done;
1611 	}
1612 
1613 	cfg_11d = (mlan_ds_11d_cfg *)req->pbuf;
1614 	cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
1615 	req->req_id = MLAN_IOCTL_11D_CFG;
1616 	req->action = MLAN_ACT_SET;
1617 
1618 	/* Set country code */
1619 	cfg_11d->param.domain_info.country_code[0] =
1620 		priv->phandle->country_code[0];
1621 	cfg_11d->param.domain_info.country_code[1] =
1622 		priv->phandle->country_code[1];
1623 	cfg_11d->param.domain_info.country_code[2] = ' ';
1624 
1625     /** IEEE80211_BAND_2GHZ or IEEE80211_BAND_5GHZ */
1626 	cfg_11d->param.domain_info.band = priv->phandle->band;
1627 
1628 	country_ie_len -= COUNTRY_CODE_LEN;
1629 	cfg_11d->param.domain_info.no_of_sub_band =
1630 		MIN(MRVDRV_MAX_SUBBAND_802_11D,
1631 		    (country_ie_len /
1632 		     sizeof(struct ieee80211_country_ie_triplet)));
1633 	memcpy((u8 *)cfg_11d->param.domain_info.sub_band,
1634 	       &country_ie[2] + COUNTRY_CODE_LEN,
1635 	       cfg_11d->param.domain_info.no_of_sub_band *
1636 	       sizeof(mlan_ds_subband_set_t));
1637 
1638 	/* Send domain info command to FW */
1639 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
1640 	if (status != MLAN_STATUS_SUCCESS) {
1641 		ret = MLAN_STATUS_FAILURE;
1642 		PRINTM(MERROR, "11D: Error setting domain info in FW\n");
1643 		goto done;
1644 	}
1645 done:
1646 	if (status != MLAN_STATUS_PENDING)
1647 		kfree(req);
1648 	LEAVE();
1649 	return ret;
1650 }
1651 
1652 /**
1653  * @brief Request scan based on connect parameter
1654  *
1655  * @param priv            A pointer to moal_private structure
1656  * @param conn_param      A pointer to connect parameters
1657  * @param wait_option     wait option
1658  *
1659  * @return                0 -- success, otherwise fail
1660  */
1661 int
woal_cfg80211_connect_scan(moal_private * priv,struct cfg80211_connect_params * conn_param,t_u8 wait_option)1662 woal_cfg80211_connect_scan(moal_private *priv,
1663 			   struct cfg80211_connect_params *conn_param,
1664 			   t_u8 wait_option)
1665 {
1666 	moal_handle *handle = priv->phandle;
1667 	int ret = 0;
1668 	wlan_user_scan_cfg scan_req;
1669 	enum ieee80211_band band;
1670 	struct ieee80211_supported_band *sband;
1671 	struct ieee80211_channel *ch;
1672 	int chan_idx = 0, i;
1673 	ENTER();
1674 	if (handle->scan_pending_on_block == MTRUE) {
1675 		PRINTM(MINFO, "scan already in processing...\n");
1676 		LEAVE();
1677 		return ret;
1678 	}
1679 #ifdef REASSOCIATION
1680 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
1681 		PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
1682 		LEAVE();
1683 		return -EBUSY;
1684 	}
1685 #endif /* REASSOCIATION */
1686 	priv->report_scan_result = MTRUE;
1687 	memset(&scan_req, 0x00, sizeof(scan_req));
1688 	memcpy(scan_req.ssid_list[0].ssid, conn_param->ssid,
1689 	       conn_param->ssid_len);
1690 	scan_req.ssid_list[0].max_len = 0;
1691 	if (conn_param->channel) {
1692 		scan_req.chan_list[0].chan_number =
1693 			conn_param->channel->hw_value;
1694 		scan_req.chan_list[0].radio_type = conn_param->channel->band;
1695 		if (conn_param->channel->
1696 		    flags & (IEEE80211_CHAN_PASSIVE_SCAN |
1697 			     IEEE80211_CHAN_RADAR))
1698 			scan_req.chan_list[0].scan_type =
1699 				MLAN_SCAN_TYPE_PASSIVE;
1700 		else
1701 			scan_req.chan_list[0].scan_type = MLAN_SCAN_TYPE_ACTIVE;
1702 		scan_req.chan_list[0].scan_time = 0;
1703 	} else {
1704 		for (band = 0; (band < IEEE80211_NUM_BANDS); band++) {
1705 			if (!priv->wdev->wiphy->bands[band])
1706 				continue;
1707 			sband = priv->wdev->wiphy->bands[band];
1708 			for (i = 0; (i < sband->n_channels); i++) {
1709 				ch = &sband->channels[i];
1710 				if (ch->flags & IEEE80211_CHAN_DISABLED)
1711 					continue;
1712 				scan_req.chan_list[chan_idx].radio_type = band;
1713 				if (ch->
1714 				    flags & (IEEE80211_CHAN_PASSIVE_SCAN |
1715 					     IEEE80211_CHAN_RADAR))
1716 					scan_req.chan_list[chan_idx].scan_type =
1717 						MLAN_SCAN_TYPE_PASSIVE;
1718 				else
1719 					scan_req.chan_list[chan_idx].scan_type =
1720 						MLAN_SCAN_TYPE_ACTIVE;
1721 				scan_req.chan_list[chan_idx].chan_number =
1722 					(u32)ch->hw_value;
1723 				chan_idx++;
1724 			}
1725 		}
1726 	}
1727 	ret = woal_request_userscan(priv, wait_option, &scan_req);
1728 #ifdef REASSOCIATION
1729 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
1730 #endif
1731 	LEAVE();
1732 	return ret;
1733 
1734 }
1735 
1736 /**
1737  * @brief Request the driver for (re)association
1738  *
1739  * @param priv            A pointer to moal_private structure
1740  * @param sme             A pointer to connect parameters
1741  * @param wait_option     wait option
1742  *
1743  * @return                0 -- success, otherwise fail
1744  */
1745 int
woal_cfg80211_assoc(moal_private * priv,void * sme,t_u8 wait_option)1746 woal_cfg80211_assoc(moal_private *priv, void *sme, t_u8 wait_option)
1747 {
1748 	struct cfg80211_ibss_params *ibss_param = NULL;
1749 	struct cfg80211_connect_params *conn_param = NULL;
1750 	mlan_802_11_ssid req_ssid;
1751 	mlan_ssid_bssid ssid_bssid;
1752 	mlan_ioctl_req *req = NULL;
1753 	int ret = 0;
1754 	t_u32 auth_type = 0, mode;
1755 	int wpa_enabled = 0;
1756 	int group_enc_mode = 0, pairwise_enc_mode = 0;
1757 	int alg_is_wep = 0;
1758 
1759 	t_u8 *ssid, ssid_len = 0, *bssid;
1760 	t_u8 *ie = NULL;
1761 	int ie_len = 0;
1762 	enum nl80211_channel_type chan_type = 0;
1763 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
1764 	struct cfg80211_chan_def *chan_def = NULL;
1765 #endif
1766 	struct ieee80211_channel *channel = NULL;
1767 	t_u16 beacon_interval = 0;
1768 	bool privacy;
1769 	struct cfg80211_bss *bss = NULL;
1770 	mlan_status status = MLAN_STATUS_SUCCESS;
1771 
1772 	ENTER();
1773 
1774 	if (!sme) {
1775 		LEAVE();
1776 		return -EFAULT;
1777 	}
1778 
1779 	mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype);
1780 
1781 	if (mode == MLAN_BSS_MODE_IBSS) {
1782 		ibss_param = (struct cfg80211_ibss_params *)sme;
1783 		ssid = (t_u8 *)ibss_param->ssid;
1784 		ssid_len = ibss_param->ssid_len;
1785 		bssid = (t_u8 *)ibss_param->bssid;
1786 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
1787 		channel = ibss_param->channel;
1788 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
1789 		chan_type = ibss_param->channel_type;
1790 #else
1791 		chan_type = 0;
1792 #endif
1793 #else
1794 		chan_def = &ibss_param->chandef;
1795 		channel = ibss_param->chandef.chan;
1796 #endif
1797 		if (channel)
1798 			priv->phandle->band = channel->band;
1799 		if (ibss_param->ie_len)
1800 			ie = (t_u8 *)ibss_param->ie;
1801 		ie_len = ibss_param->ie_len;
1802 		beacon_interval = ibss_param->beacon_interval;
1803 		privacy = ibss_param->privacy;
1804 
1805 	} else {
1806 		conn_param = (struct cfg80211_connect_params *)sme;
1807 		ssid = (t_u8 *)conn_param->ssid;
1808 		ssid_len = conn_param->ssid_len;
1809 		bssid = (t_u8 *)conn_param->bssid;
1810 		channel = conn_param->channel;
1811 		if (channel)
1812 			priv->phandle->band = channel->band;
1813 		if (conn_param->ie_len)
1814 			ie = (t_u8 *)conn_param->ie;
1815 		ie_len = conn_param->ie_len;
1816 		privacy = conn_param->privacy;
1817 		bss = cfg80211_get_bss(priv->wdev->wiphy, channel, bssid, ssid,
1818 				       ssid_len, WLAN_CAPABILITY_ESS,
1819 				       WLAN_CAPABILITY_ESS);
1820 		if (bss) {
1821 			if (!reg_alpha2 ||
1822 			    strncmp(reg_alpha2, "99", strlen("99")))
1823 				woal_process_country_ie(priv, bss);
1824 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
1825 			cfg80211_put_bss(priv->wdev->wiphy, bss);
1826 #else
1827 			cfg80211_put_bss(bss);
1828 #endif
1829 		} else
1830 			woal_send_domain_info_cmd_fw(priv, wait_option);
1831 #ifdef STA_WEXT
1832 		if (IS_STA_WEXT(cfg80211_wext)) {
1833 			switch (conn_param->crypto.wpa_versions) {
1834 			case NL80211_WPA_VERSION_2:
1835 				priv->wpa_version = IW_AUTH_WPA_VERSION_WPA2;
1836 				break;
1837 			case NL80211_WPA_VERSION_1:
1838 				priv->wpa_version = IW_AUTH_WPA_VERSION_WPA;
1839 				break;
1840 			default:
1841 				priv->wpa_version = 0;
1842 				break;
1843 			}
1844 			if (conn_param->crypto.n_akm_suites) {
1845 				switch (conn_param->crypto.akm_suites[0]) {
1846 				case WLAN_AKM_SUITE_PSK:
1847 					priv->key_mgmt = IW_AUTH_KEY_MGMT_PSK;
1848 					break;
1849 				case WLAN_AKM_SUITE_8021X:
1850 					priv->key_mgmt =
1851 						IW_AUTH_KEY_MGMT_802_1X;
1852 					break;
1853 				default:
1854 					priv->key_mgmt = 0;
1855 					break;
1856 				}
1857 			}
1858 		}
1859 #endif
1860 	}
1861 
1862 	memset(&req_ssid, 0, sizeof(mlan_802_11_ssid));
1863 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
1864 
1865 	req_ssid.ssid_len = ssid_len;
1866 	if (ssid_len > MW_ESSID_MAX_SIZE) {
1867 		PRINTM(MERROR, "Invalid SSID - aborting\n");
1868 		ret = -EINVAL;
1869 		goto done;
1870 	}
1871 
1872 	memcpy(req_ssid.ssid, ssid, ssid_len);
1873 	if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
1874 		PRINTM(MERROR, "Invalid SSID - aborting\n");
1875 		ret = -EINVAL;
1876 		goto done;
1877 	}
1878 
1879 	if ((mode == MLAN_BSS_MODE_IBSS) && channel) {
1880 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
1881 		chan_type = woal_channel_to_nl80211_channel_type(chan_def);
1882 #endif
1883 		if (MLAN_STATUS_SUCCESS != woal_set_rf_channel(priv,
1884 							       channel,
1885 							       chan_type,
1886 							       wait_option)) {
1887 			ret = -EFAULT;
1888 			goto done;
1889 		}
1890 	}
1891 
1892 	if (MLAN_STATUS_SUCCESS !=
1893 	    woal_set_ewpa_mode(priv, wait_option, &ssid_bssid)) {
1894 		ret = -EFAULT;
1895 		goto done;
1896 	}
1897 
1898 	if (MLAN_STATUS_SUCCESS !=
1899 	    woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0,
1900 				  KEY_INDEX_CLEAR_ALL, NULL, 1, wait_option)) {
1901 		/* Disable keys and clear all previous security settings */
1902 		ret = -EFAULT;
1903 		goto done;
1904 	}
1905 #ifdef STA_CFG80211
1906 	if (IS_STA_CFG80211(cfg80211_wext)) {
1907 		/** Check if current roaming support OKC offload roaming */
1908 		if (conn_param && conn_param->crypto.n_akm_suites &&
1909 		    conn_param->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X) {
1910 			if (priv->okc_roaming_ie && priv->okc_ie_len) {
1911 				ie = priv->okc_roaming_ie;
1912 				ie_len = priv->okc_ie_len;
1913 			}
1914 		}
1915 	}
1916 #endif
1917 
1918 	if ((priv->ft_pre_connect ||
1919 	     (conn_param && conn_param->auth_type == NL80211_AUTHTYPE_FT))
1920 	    && priv->ft_ie_len) {
1921 		ie = priv->ft_ie;
1922 		ie_len = priv->ft_ie_len;
1923 		priv->ft_ie_len = 0;
1924 	}
1925 	if (ie && ie_len) {	/* Set the IE */
1926 		if (MLAN_STATUS_SUCCESS !=
1927 		    woal_cfg80211_assoc_ies_cfg(priv, ie, ie_len,
1928 						wait_option)) {
1929 			ret = -EFAULT;
1930 			goto done;
1931 		}
1932 	}
1933 
1934 	if (conn_param && mode != MLAN_BSS_MODE_IBSS) {
1935 		/* These parameters are only for managed mode */
1936 		if (conn_param->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
1937 			auth_type = MLAN_AUTH_MODE_OPEN;
1938 		else if (conn_param->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
1939 			auth_type = MLAN_AUTH_MODE_SHARED;
1940 		else if (conn_param->auth_type == NL80211_AUTHTYPE_NETWORK_EAP)
1941 			auth_type = MLAN_AUTH_MODE_NETWORKEAP;
1942 		else if (conn_param->auth_type == NL80211_AUTHTYPE_FT)
1943 			auth_type = MLAN_AUTH_MODE_FT;
1944 		else
1945 			auth_type = MLAN_AUTH_MODE_AUTO;
1946 		if (priv->ft_pre_connect)
1947 			auth_type = MLAN_AUTH_MODE_FT;
1948 		if (MLAN_STATUS_SUCCESS !=
1949 		    woal_set_auth_mode(priv, wait_option, auth_type)) {
1950 			ret = -EFAULT;
1951 			goto done;
1952 		}
1953 
1954 		if (conn_param->crypto.n_ciphers_pairwise) {
1955 			pairwise_enc_mode =
1956 				woal_cfg80211_get_encryption_mode(conn_param->
1957 								  crypto.ciphers_pairwise
1958 								  [0],
1959 								  &wpa_enabled);
1960 			ret = woal_cfg80211_set_auth(priv, pairwise_enc_mode,
1961 						     wpa_enabled, wait_option);
1962 			if (ret)
1963 				goto done;
1964 		}
1965 
1966 		if (conn_param->crypto.cipher_group) {
1967 			group_enc_mode =
1968 				woal_cfg80211_get_encryption_mode(conn_param->
1969 								  crypto.cipher_group,
1970 								  &wpa_enabled);
1971 			ret = woal_cfg80211_set_auth(priv, group_enc_mode,
1972 						     wpa_enabled, wait_option);
1973 			if (ret)
1974 				goto done;
1975 		}
1976 
1977 		if (conn_param->key) {
1978 			alg_is_wep =
1979 				woal_cfg80211_is_alg_wep(pairwise_enc_mode) |
1980 				woal_cfg80211_is_alg_wep(group_enc_mode);
1981 			if (alg_is_wep) {
1982 				PRINTM(MINFO,
1983 				       "Setting wep encryption with key len %d\n",
1984 				       conn_param->key_len);
1985 				/* Set the WEP key */
1986 				if (MLAN_STATUS_SUCCESS !=
1987 				    woal_cfg80211_set_wep_keys(priv,
1988 							       conn_param->key,
1989 							       conn_param->
1990 							       key_len,
1991 							       conn_param->
1992 							       key_idx,
1993 							       wait_option)) {
1994 					ret = -EFAULT;
1995 					goto done;
1996 				}
1997 				/* Enable the WEP key by key index */
1998 				if (MLAN_STATUS_SUCCESS !=
1999 				    woal_cfg80211_set_wep_keys(priv, NULL, 0,
2000 							       conn_param->
2001 							       key_idx,
2002 							       wait_option)) {
2003 					ret = -EFAULT;
2004 					goto done;
2005 				}
2006 			}
2007 		}
2008 	}
2009 
2010 	if (mode == MLAN_BSS_MODE_IBSS) {
2011 		mlan_ds_bss *bss = NULL;
2012 		/* Change beacon interval */
2013 		if ((beacon_interval < MLAN_MIN_BEACON_INTERVAL) ||
2014 		    (beacon_interval > MLAN_MAX_BEACON_INTERVAL)) {
2015 			ret = -EINVAL;
2016 			goto done;
2017 		}
2018 		kfree(req);
2019 		req = NULL;
2020 
2021 		req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2022 		if (req == NULL) {
2023 			ret = -ENOMEM;
2024 			goto done;
2025 		}
2026 		bss = (mlan_ds_bss *)req->pbuf;
2027 		req->req_id = MLAN_IOCTL_BSS;
2028 		req->action = MLAN_ACT_SET;
2029 		bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL;
2030 		bss->param.bcn_interval = beacon_interval;
2031 		status = woal_request_ioctl(priv, req, wait_option);
2032 		if (status != MLAN_STATUS_SUCCESS) {
2033 			ret = -EFAULT;
2034 			goto done;
2035 		}
2036 
2037 		/* "privacy" is set only for ad-hoc mode */
2038 		if (privacy) {
2039 			/*
2040 			 * Keep MLAN_ENCRYPTION_MODE_WEP40 for now so that
2041 			 * the firmware can find a matching network from the
2042 			 * scan. cfg80211 does not give us the encryption
2043 			 * mode at this stage so just setting it to wep here
2044 			 */
2045 			if (MLAN_STATUS_SUCCESS !=
2046 			    woal_set_auth_mode(priv, wait_option,
2047 					       MLAN_AUTH_MODE_OPEN)) {
2048 				ret = -EFAULT;
2049 				goto done;
2050 			}
2051 
2052 			wpa_enabled = 0;
2053 			ret = woal_cfg80211_set_auth(priv,
2054 						     MLAN_ENCRYPTION_MODE_WEP104,
2055 						     wpa_enabled, wait_option);
2056 			if (ret)
2057 				goto done;
2058 		}
2059 	}
2060 	memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid));
2061 	if (bssid)
2062 		memcpy(&ssid_bssid.bssid, bssid, ETH_ALEN);
2063 	if (MLAN_STATUS_SUCCESS !=
2064 	    woal_find_essid(priv, &ssid_bssid, wait_option)) {
2065 		/* Do specific SSID scanning */
2066 		if (mode != MLAN_BSS_MODE_IBSS)
2067 			ret = woal_cfg80211_connect_scan(priv, conn_param,
2068 							 wait_option);
2069 		else
2070 			ret = woal_request_scan(priv, wait_option, &req_ssid);
2071 		if (ret) {
2072 			ret = -EFAULT;
2073 			goto done;
2074 		}
2075 	}
2076 
2077 	/* Disconnect before try to associate */
2078 	if (mode == MLAN_BSS_MODE_IBSS)
2079 		woal_disconnect(priv, wait_option, NULL,
2080 				DEF_DEAUTH_REASON_CODE);
2081 
2082 	if (mode != MLAN_BSS_MODE_IBSS) {
2083 		if (MLAN_STATUS_SUCCESS !=
2084 		    woal_find_best_network(priv, wait_option, &ssid_bssid)) {
2085 			ret = -EFAULT;
2086 			goto done;
2087 		}
2088 		/* Inform the BSS information to kernel, otherwise
2089 		 * kernel will give a panic after successful assoc */
2090 		if (MLAN_STATUS_SUCCESS !=
2091 		    woal_inform_bss_from_scan_result(priv, &ssid_bssid,
2092 						     wait_option)) {
2093 			ret = -EFAULT;
2094 			goto done;
2095 		}
2096 	} else if (MLAN_STATUS_SUCCESS !=
2097 		   woal_find_best_network(priv, wait_option, &ssid_bssid))
2098 		/* Adhoc start, Check the channel command */
2099 		woal_11h_channel_check_ioctl(priv, wait_option);
2100 
2101 	PRINTM(MINFO, "Trying to associate to %s and bssid " MACSTR "\n",
2102 	       (char *)req_ssid.ssid, MAC2STR(ssid_bssid.bssid));
2103 
2104 	/* Zero SSID implies use BSSID to connect */
2105 	if (bssid)
2106 		memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid));
2107 	else			/* Connect to BSS by ESSID */
2108 		memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH);
2109 	if (channel) {
2110 		ssid_bssid.channel_flags = channel->flags;
2111 		PRINTM(MCMND, "channel flags=0x%x\n", channel->flags);
2112 	}
2113 	if (MLAN_STATUS_SUCCESS !=
2114 	    woal_bss_start(priv, MOAL_IOCTL_WAIT_TIMEOUT, &ssid_bssid)) {
2115 		ret = -EFAULT;
2116 		goto done;
2117 	}
2118 
2119 	/* Inform the IBSS information to kernel, otherwise
2120 	 * kernel will give a panic after successful assoc */
2121 	if (mode == MLAN_BSS_MODE_IBSS) {
2122 		if (MLAN_STATUS_SUCCESS !=
2123 		    woal_cfg80211_inform_ibss_bss(priv, channel,
2124 						  beacon_interval)) {
2125 			ret = -EFAULT;
2126 			goto done;
2127 		}
2128 	}
2129 
2130 done:
2131 	if (ret) {
2132 		/* clear the encryption mode */
2133 		woal_cfg80211_set_auth(priv, MLAN_ENCRYPTION_MODE_NONE, MFALSE,
2134 				       wait_option);
2135 		/* clear IE */
2136 		ie_len = 0;
2137 		if (MLAN_STATUS_SUCCESS !=
2138 		    woal_set_get_gen_ie(priv, MLAN_ACT_SET, NULL, &ie_len,
2139 					wait_option)) {
2140 			PRINTM(MERROR, "Could not clear RSN IE\n");
2141 			ret = -EFAULT;
2142 		}
2143 	}
2144 	if (status != MLAN_STATUS_PENDING)
2145 		kfree(req);
2146 	LEAVE();
2147 	return ret;
2148 }
2149 
2150 /**
2151  * @brief Request the driver to dump the station information
2152  *
2153  * @param priv            A pointer to moal_private structure
2154  * @param sinfo           A pointer to station_info structure
2155  *
2156  * @return                0 -- success, otherwise fail
2157  */
2158 static mlan_status
woal_cfg80211_dump_station_info(moal_private * priv,struct station_info * sinfo)2159 woal_cfg80211_dump_station_info(moal_private *priv, struct station_info *sinfo)
2160 {
2161 	mlan_status ret = MLAN_STATUS_SUCCESS;
2162 	mlan_ds_get_signal signal;
2163 	mlan_ds_get_stats stats;
2164 	mlan_ioctl_req *req = NULL;
2165 	mlan_ds_rate *rate = NULL;
2166 	t_u16 Rates[12] = {
2167 		0x02, 0x04, 0x0B, 0x16,
2168 		0x0C, 0x12, 0x18, 0x24,
2169 		0x30, 0x48, 0x60, 0x6c
2170 	};
2171 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
2172 	mlan_bss_info bss_info;
2173 	t_u8 dtim_period = 0;
2174 #endif
2175 
2176 	ENTER();
2177 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
2178 	sinfo->filled =
2179 		BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_TX_BYTES)
2180 		| BIT(NL80211_STA_INFO_RX_PACKETS) |
2181 		BIT(NL80211_STA_INFO_TX_PACKETS) | BIT(NL80211_STA_INFO_SIGNAL)
2182 		| BIT(NL80211_STA_INFO_TX_BITRATE);
2183 #else
2184 	sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
2185 		STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
2186 		STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
2187 #endif
2188 
2189 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
2190 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
2191 	sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
2192 #else
2193 	sinfo->filled |= STATION_INFO_TX_FAILED;
2194 #endif
2195 #endif
2196 
2197 	/* Get signal information from the firmware */
2198 	memset(&signal, 0, sizeof(mlan_ds_get_signal));
2199 	if (MLAN_STATUS_SUCCESS !=
2200 	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
2201 		PRINTM(MERROR, "Error getting signal information\n");
2202 		ret = MLAN_STATUS_FAILURE;
2203 		goto done;
2204 	}
2205 
2206 	/* Get stats information from the firmware */
2207 	memset(&stats, 0, sizeof(mlan_ds_get_stats));
2208 	if (MLAN_STATUS_SUCCESS !=
2209 	    woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) {
2210 		PRINTM(MERROR, "Error getting stats information\n");
2211 		ret = MLAN_STATUS_FAILURE;
2212 		goto done;
2213 	}
2214 
2215 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
2216 	if (req == NULL) {
2217 		ret = MLAN_STATUS_FAILURE;
2218 		goto done;
2219 	}
2220 	rate = (mlan_ds_rate *)req->pbuf;
2221 	rate->sub_command = MLAN_OID_GET_DATA_RATE;
2222 	req->req_id = MLAN_IOCTL_RATE;
2223 	req->action = MLAN_ACT_GET;
2224 	ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
2225 	if (ret != MLAN_STATUS_SUCCESS)
2226 		goto done;
2227 	if (rate->param.data_rate.tx_rate_format != MLAN_RATE_FORMAT_LG) {
2228 		if (rate->param.data_rate.tx_rate_format == MLAN_RATE_FORMAT_HT) {
2229 			sinfo->txrate.flags = RATE_INFO_FLAGS_MCS;
2230 			if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40)
2231 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
2232 				sinfo->txrate.bw = RATE_INFO_BW_40;
2233 #else
2234 				sinfo->txrate.flags |=
2235 					RATE_INFO_FLAGS_40_MHZ_WIDTH;
2236 #endif
2237 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
2238 			else
2239 				sinfo->txrate.bw = RATE_INFO_BW_20;
2240 #endif
2241 		}
2242 		if (rate->param.data_rate.tx_ht_gi == MLAN_HT_SGI)
2243 			sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
2244 		sinfo->txrate.mcs = rate->param.data_rate.tx_mcs_index;
2245 	} else {
2246 		/* Bit rate is in 500 kb/s units. Convert it to 100kb/s units */
2247 		sinfo->txrate.legacy =
2248 			Rates[rate->param.data_rate.tx_data_rate] * 5;
2249 	}
2250 	sinfo->rx_bytes = priv->stats.rx_bytes;
2251 	sinfo->tx_bytes = priv->stats.tx_bytes;
2252 	sinfo->rx_packets = priv->stats.rx_packets;
2253 	sinfo->tx_packets = priv->stats.tx_packets;
2254 	sinfo->signal = signal.bcn_rssi_avg;
2255 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
2256 	sinfo->tx_failed = stats.failed;
2257 #endif
2258 
2259 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
2260 	/* Update BSS information */
2261 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
2262 	sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
2263 #else
2264 	sinfo->filled |= STATION_INFO_BSS_PARAM;
2265 #endif
2266 	sinfo->bss_param.flags = 0;
2267 	ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
2268 	if (ret)
2269 		goto done;
2270 	if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_PREAMBLE)
2271 		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE;
2272 	if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_SLOT_TIME)
2273 		sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME;
2274 	sinfo->bss_param.beacon_interval = bss_info.beacon_interval;
2275 	/* Get DTIM period */
2276 	ret = woal_set_get_dtim_period(priv, MLAN_ACT_GET,
2277 				       MOAL_IOCTL_WAIT, &dtim_period);
2278 	if (ret) {
2279 		PRINTM(MERROR, "Get DTIM period failed\n");
2280 		goto done;
2281 	}
2282 	sinfo->bss_param.dtim_period = dtim_period;
2283 #endif
2284 
2285 done:
2286 	if (ret != MLAN_STATUS_PENDING)
2287 		kfree(req);
2288 
2289 	LEAVE();
2290 	return ret;
2291 }
2292 
2293 /********************************************************
2294 				Global Functions
2295 ********************************************************/
2296 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2297 /**
2298  * @brief Set all radar channel's dfs_state
2299  *
2300  * @param wiphy           A pointer to wiphy structure
2301  *
2302  * @return                N/A
2303  */
2304 void
woal_update_radar_chans_dfs_state(struct wiphy * wiphy)2305 woal_update_radar_chans_dfs_state(struct wiphy *wiphy)
2306 {
2307 	enum ieee80211_band band;
2308 	struct ieee80211_supported_band *sband;
2309 	int i;
2310 	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
2311 		sband = wiphy->bands[band];
2312 		if (!sband)
2313 			continue;
2314 		for (i = 0; i < sband->n_channels; i++) {
2315 			if (sband->channels[i].flags & IEEE80211_CHAN_RADAR) {
2316 				if (dfs_offload)
2317 					sband->channels[i].dfs_state =
2318 						NL80211_DFS_AVAILABLE;
2319 				else
2320 					sband->channels[i].dfs_state =
2321 						NL80211_DFS_USABLE;
2322 			}
2323 		}
2324 	}
2325 	PRINTM(MCMND, "Set radar dfs_state: dfs_offload=%d\n", dfs_offload);
2326 }
2327 #endif
2328 
2329 /**
2330  * @brief Request the driver to change regulatory domain
2331  *
2332  * @param wiphy           A pointer to wiphy structure
2333  * @param request         A pointer to regulatory_request structure
2334  *
2335  * @return                0
2336  */
2337 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
2338 static void
2339 #else
2340 static int
2341 #endif
woal_cfg80211_reg_notifier(struct wiphy * wiphy,struct regulatory_request * request)2342 woal_cfg80211_reg_notifier(struct wiphy *wiphy,
2343 			   struct regulatory_request *request)
2344 {
2345 	moal_private *priv = NULL;
2346 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
2347 	t_u8 region[COUNTRY_CODE_LEN];
2348 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
2349 	int ret = 0;
2350 #endif
2351 
2352 	ENTER();
2353 
2354 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
2355 	if (!priv) {
2356 		PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
2357 		LEAVE();
2358 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
2359 		return -EINVAL;
2360 #else
2361 		return;
2362 #endif
2363 	}
2364 
2365 	PRINTM(MIOCTL, "cfg80211 regulatory domain callback "
2366 	       "%c%c\n", request->alpha2[0], request->alpha2[1]);
2367 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
2368 	if (dfs_offload)
2369 		woal_update_radar_chans_dfs_state(wiphy);
2370 #endif
2371 	memset(region, 0, sizeof(region));
2372 	memcpy(region, request->alpha2, sizeof(request->alpha2));
2373 	region[2] = ' ';
2374 	if (MTRUE == is_cfg80211_special_region_code(region)) {
2375 		PRINTM(MIOCTL, "Skip configure special region code\n");
2376 		LEAVE();
2377 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
2378 		return ret;
2379 #else
2380 		return;
2381 #endif
2382 	}
2383 	if ((handle->country_code[0] != request->alpha2[0]) ||
2384 	    (handle->country_code[1] != request->alpha2[1])) {
2385 		t_u8 country_code[COUNTRY_CODE_LEN];
2386 		memset(country_code, 0, sizeof(country_code));
2387 		country_code[0] = request->alpha2[0];
2388 		country_code[1] = request->alpha2[1];
2389 		if (cntry_txpwr) {
2390 			if (MLAN_STATUS_SUCCESS !=
2391 			    woal_request_country_power_table(priv,
2392 							     country_code)) {
2393 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
2394 				return -EFAULT;
2395 #else
2396 				return;
2397 #endif
2398 			}
2399 		}
2400 	}
2401 	handle->country_code[0] = request->alpha2[0];
2402 	handle->country_code[1] = request->alpha2[1];
2403 	handle->country_code[2] = ' ';
2404 	if (MLAN_STATUS_SUCCESS !=
2405 	    woal_set_region_code(priv, handle->country_code))
2406 		PRINTM(MERROR, "Set country code failed!\n");
2407 	switch (request->initiator) {
2408 	case NL80211_REGDOM_SET_BY_DRIVER:
2409 		PRINTM(MIOCTL, "Regulatory domain BY_DRIVER\n");
2410 		break;
2411 	case NL80211_REGDOM_SET_BY_CORE:
2412 		PRINTM(MIOCTL, "Regulatory domain BY_CORE\n");
2413 		break;
2414 	case NL80211_REGDOM_SET_BY_USER:
2415 		PRINTM(MIOCTL, "Regulatory domain BY_USER\n");
2416 		break;
2417 		/* TODO: apply driver specific changes in channel flags based
2418 		   on the request initiator if necessory. * */
2419 	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
2420 		PRINTM(MIOCTL, "Regulatory domain BY_COUNTRY_IE\n");
2421 		break;
2422 	}
2423 	if (priv->wdev && priv->wdev->wiphy &&
2424 	    (request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE))
2425 		woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
2426 
2427 	LEAVE();
2428 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
2429 	return ret;
2430 #endif
2431 }
2432 
2433 #ifdef UAP_CFG80211
2434 /**
2435  * @brief Swithces BSS role of interface
2436  *
2437  * @param priv          A pointer to moal_private structure
2438  * @param wait_option   Wait option (MOAL_IOCTL_WAIT or MOAL_NO_WAIT)
2439  * @param bss_role      bss role
2440  *
2441  * @return         0 --success, otherwise fail
2442  */
2443 mlan_status
woal_role_switch(moal_private * priv,t_u8 wait_option,t_u8 bss_role)2444 woal_role_switch(moal_private *priv, t_u8 wait_option, t_u8 bss_role)
2445 {
2446 	int ret = 0;
2447 	mlan_ds_bss *bss = NULL;
2448 	mlan_ioctl_req *req = NULL;
2449 	mlan_status status = MLAN_STATUS_SUCCESS;
2450 
2451 	ENTER();
2452 
2453 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
2454 	if (req == NULL) {
2455 		ret = -ENOMEM;
2456 		goto done;
2457 	}
2458 	bss = (mlan_ds_bss *)req->pbuf;
2459 	bss->sub_command = MLAN_OID_BSS_ROLE;
2460 	req->req_id = MLAN_IOCTL_BSS;
2461 	req->action = MLAN_ACT_SET;
2462 	bss->param.bss_role = bss_role;
2463 
2464 	status = woal_request_ioctl(priv, req, wait_option);
2465 	if (status != MLAN_STATUS_SUCCESS) {
2466 		ret = -EFAULT;
2467 		goto done;
2468 	}
2469 done:
2470 	if (status != MLAN_STATUS_PENDING)
2471 		kfree(req);
2472 	LEAVE();
2473 	return ret;
2474 }
2475 
2476 /**
2477  *  @brief request scan
2478  *
2479  *  @param priv                 A pointer to moal_private structure
2480  *  @param scan_cfg             A pointer to wlan_user_scan_cfg structure
2481  *
2482  *  @return                     MLAN_STATUS_SUCCESS -- success, otherwise fail
2483  */
2484 mlan_status
woal_uap_scan(moal_private * priv,wlan_user_scan_cfg * scan_cfg)2485 woal_uap_scan(moal_private *priv, wlan_user_scan_cfg *scan_cfg)
2486 {
2487 	mlan_status ret = MLAN_STATUS_SUCCESS;
2488 	moal_handle *handle = priv->phandle;
2489 	moal_private *tmp_priv;
2490 	u8 role;
2491 
2492 	ENTER();
2493 	if (priv->bss_index > 0)
2494 		tmp_priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
2495 	else
2496 		tmp_priv = priv;
2497 	if (!tmp_priv) {
2498 		LEAVE();
2499 		return MLAN_STATUS_FAILURE;
2500 	}
2501 	role = GET_BSS_ROLE(tmp_priv);
2502 	if (role == MLAN_BSS_ROLE_UAP)
2503 		woal_role_switch(tmp_priv, MOAL_IOCTL_WAIT, MLAN_BSS_ROLE_STA);
2504 #ifdef REASSOCIATION
2505 	if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) {
2506 		PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n");
2507 		goto done;
2508 	}
2509 #endif /* REASSOCIATION */
2510 	tmp_priv->report_scan_result = MTRUE;
2511 	ret = woal_request_userscan(tmp_priv, MOAL_IOCTL_WAIT, scan_cfg);
2512 	woal_sched_timeout(5);
2513 #ifdef REASSOCIATION
2514 	MOAL_REL_SEMAPHORE(&handle->reassoc_sem);
2515 #endif
2516 done:
2517 	if (role == MLAN_BSS_ROLE_UAP)
2518 		woal_role_switch(tmp_priv, MOAL_IOCTL_WAIT, MLAN_BSS_ROLE_UAP);
2519 	LEAVE();
2520 	return ret;
2521 }
2522 #endif
2523 
2524 static int
woal_find_wps_ie_in_probereq(const t_u8 * ie,int len)2525 woal_find_wps_ie_in_probereq(const t_u8 *ie, int len)
2526 {
2527 	int left_len = len;
2528 	const t_u8 *pos = ie;
2529 	t_u8 ie_id, ie_len;
2530 	IEEEtypes_VendorSpecific_t *pvendor_ie = NULL;
2531 	const u8 wps_oui[4] = { 0x00, 0x50, 0xf2, 0x04 };
2532 
2533 	while (left_len >= 2) {
2534 		ie_id = *pos;
2535 		ie_len = *(pos + 1);
2536 		if ((ie_len + 2) > left_len)
2537 			break;
2538 		if (ie_id == VENDOR_SPECIFIC_221) {
2539 			pvendor_ie = (IEEEtypes_VendorSpecific_t *)pos;
2540 			if (!memcmp
2541 			    (pvendor_ie->vend_hdr.oui, wps_oui,
2542 			     sizeof(pvendor_ie->vend_hdr.oui)) &&
2543 			    pvendor_ie->vend_hdr.oui_type == wps_oui[3])
2544 				return MTRUE;
2545 		}
2546 
2547 		pos += (ie_len + 2);
2548 		left_len -= (ie_len + 2);
2549 	}
2550 
2551 	return MFALSE;
2552 }
2553 
2554 /**
2555  *  @brief check if the scan result expired
2556  *
2557  *  @param priv         A pointer to moal_private
2558  *
2559  *
2560  *  @return             MTRUE/MFALSE;
2561  */
2562 t_u8
woal_is_scan_result_expired(moal_private * priv)2563 woal_is_scan_result_expired(moal_private *priv)
2564 {
2565 	mlan_scan_resp scan_resp;
2566 	struct timeval t;
2567 	ENTER();
2568 	if (!woal_is_any_interface_active(priv->phandle)) {
2569 		LEAVE();
2570 		return MTRUE;
2571 	}
2572 
2573 	if (MLAN_STATUS_SUCCESS !=
2574 	    woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) {
2575 		LEAVE();
2576 		return MTRUE;
2577 	}
2578 	do_gettimeofday(&t);
2579 /** scan result expired value */
2580 #define SCAN_RESULT_EXPIRTED      1
2581 	if (t.tv_sec > (scan_resp.age_in_secs + SCAN_RESULT_EXPIRTED)) {
2582 		LEAVE();
2583 		return MTRUE;
2584 	}
2585 	LEAVE();
2586 	return MFALSE;
2587 }
2588 
2589 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
2590 /**
2591  * @brief Request the driver to do a scan. Always returning
2592  * zero meaning that the scan request is given to driver,
2593  * and will be valid until passed to cfg80211_scan_done().
2594  * To inform scan results, call cfg80211_inform_bss().
2595  *
2596  * @param wiphy           A pointer to wiphy structure
2597  * @param request         A pointer to cfg80211_scan_request structure
2598  *
2599  * @return                0 -- success, otherwise fail
2600  */
2601 static int
woal_cfg80211_scan(struct wiphy * wiphy,struct cfg80211_scan_request * request)2602 woal_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
2603 #else
2604 /**
2605  * @brief Request the driver to do a scan. Always returning
2606  * zero meaning that the scan request is given to driver,
2607  * and will be valid until passed to cfg80211_scan_done().
2608  * To inform scan results, call cfg80211_inform_bss().
2609  *
2610  * @param wiphy           A pointer to wiphy structure
2611  * @param dev             A pointer to net_device structure
2612  * @param request         A pointer to cfg80211_scan_request structure
2613  *
2614  * @return                0 -- success, otherwise fail
2615  */
2616 static int
2617 woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
2618 		   struct cfg80211_scan_request *request)
2619 #endif
2620 {
2621 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
2622 	struct net_device *dev = request->wdev->netdev;
2623 #endif
2624 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
2625 	wlan_user_scan_cfg scan_req;
2626 	mlan_bss_info bss_info;
2627 	struct ieee80211_channel *chan;
2628 	int ret = 0, i;
2629 	unsigned long flags;
2630 
2631 	ENTER();
2632 
2633 	PRINTM(MINFO, "Received scan request on %s\n", dev->name);
2634 	if (priv->phandle->scan_pending_on_block == MTRUE) {
2635 		PRINTM(MCMND, "scan already in processing...\n");
2636 		LEAVE();
2637 		return -EAGAIN;
2638 	}
2639 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
2640 	if (priv->last_event & EVENT_BG_SCAN_REPORT) {
2641 		PRINTM(MCMND, "block scan while pending BGSCAN result\n");
2642 		priv->last_event = 0;
2643 		LEAVE();
2644 		return -EAGAIN;
2645 	}
2646 #endif
2647 #if defined(STA_CFG80211) || defined(UAP_CFG80211)
2648 #ifdef WIFI_DIRECT_SUPPORT
2649 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
2650 	if (priv->phandle->is_go_timer_set &&
2651 	    priv->wdev->iftype != NL80211_IFTYPE_P2P_GO) {
2652 		PRINTM(MCMND, "block scan in go timer....\n");
2653 		LEAVE();
2654 		return -EAGAIN;
2655 	}
2656 #endif
2657 #endif
2658 #endif
2659 	if (priv->fake_scan_complete || !woal_is_scan_result_expired(priv)) {
2660 		PRINTM(MEVENT, "Reporting fake scan results\n");
2661 		woal_inform_bss_from_scan_result(priv, NULL, MOAL_IOCTL_WAIT);
2662 		woal_cfg80211_scan_done(request, MFALSE);
2663 		return ret;
2664 	}
2665 	memset(&bss_info, 0, sizeof(bss_info));
2666 	if (MLAN_STATUS_SUCCESS ==
2667 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
2668 		if (bss_info.scan_block) {
2669 			PRINTM(MEVENT, "Block scan in mlan module\n");
2670 			woal_inform_bss_from_scan_result(priv, NULL,
2671 							 MOAL_IOCTL_WAIT);
2672 			woal_cfg80211_scan_done(request, MFALSE);
2673 			return ret;
2674 		}
2675 	}
2676 	if (priv->phandle->scan_request &&
2677 	    priv->phandle->scan_request != request) {
2678 		PRINTM(MCMND,
2679 		       "different scan_request is coming before previous one is finished on %s...\n",
2680 		       dev->name);
2681 		LEAVE();
2682 		return -EBUSY;
2683 	}
2684 	spin_lock_irqsave(&priv->phandle->scan_req_lock, flags);
2685 	priv->phandle->scan_request = request;
2686 	spin_unlock_irqrestore(&priv->phandle->scan_req_lock, flags);
2687 	memset(&scan_req, 0x00, sizeof(scan_req));
2688 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
2689 	if (!is_broadcast_ether_addr(request->bssid)) {
2690 		memcpy(scan_req.specific_bssid, request->bssid, ETH_ALEN);
2691 		PRINTM(MIOCTL, "scan: bssid=" MACSTR "\n",
2692 		       MAC2STR(scan_req.specific_bssid));
2693 	}
2694 #endif
2695 
2696 	if (priv->phandle->scan_request->n_channels <= 38)
2697 		scan_req.ext_scan_type = EXT_SCAN_ENHANCE;
2698 
2699 #ifdef WIFI_DIRECT_SUPPORT
2700 	if (priv->phandle->miracast_mode ||
2701 	    woal_is_any_interface_active(priv->phandle))
2702 		scan_req.scan_chan_gap = priv->phandle->scan_chan_gap;
2703 	else
2704 		scan_req.scan_chan_gap = 0;
2705 #endif
2706 	for (i = 0; i < priv->phandle->scan_request->n_ssids; i++) {
2707 		memcpy(scan_req.ssid_list[i].ssid,
2708 		       priv->phandle->scan_request->ssids[i].ssid,
2709 		       priv->phandle->scan_request->ssids[i].ssid_len);
2710 		if (priv->phandle->scan_request->ssids[i].ssid_len)
2711 			scan_req.ssid_list[i].max_len = 0;
2712 		else
2713 			scan_req.ssid_list[i].max_len = 0xff;
2714 		PRINTM(MIOCTL, "scan: ssid=%s\n", scan_req.ssid_list[i].ssid);
2715 	}
2716 #if defined(WIFI_DIRECT_SUPPORT)
2717 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
2718 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
2719 	    priv->phandle->scan_request->n_ssids) {
2720 		if (!memcmp(scan_req.ssid_list[0].ssid, "DIRECT-", 7))
2721 			scan_req.ssid_list[0].max_len = 0xfe;
2722 	}
2723 #endif
2724 #endif
2725 	for (i = 0;
2726 	     i < MIN(WLAN_USER_SCAN_CHAN_MAX,
2727 		     priv->phandle->scan_request->n_channels); i++) {
2728 		chan = priv->phandle->scan_request->channels[i];
2729 		scan_req.chan_list[i].chan_number = chan->hw_value;
2730 		scan_req.chan_list[i].radio_type = chan->band;
2731 		if ((chan->
2732 		     flags & (IEEE80211_CHAN_PASSIVE_SCAN |
2733 			      IEEE80211_CHAN_RADAR))
2734 		    || !priv->phandle->scan_request->n_ssids)
2735 			scan_req.chan_list[i].scan_type =
2736 				MLAN_SCAN_TYPE_PASSIVE;
2737 		else
2738 			scan_req.chan_list[i].scan_type = MLAN_SCAN_TYPE_ACTIVE;
2739 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
2740 		scan_req.chan_list[i].scan_time =
2741 			priv->phandle->scan_request->duration;
2742 #else
2743 		scan_req.chan_list[i].scan_time = 0;
2744 #endif
2745 #if defined(WIFI_DIRECT_SUPPORT)
2746 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
2747 		if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT &&
2748 		    priv->phandle->scan_request->n_ssids) {
2749 			if (!memcmp(scan_req.ssid_list[0].ssid, "DIRECT-", 7))
2750 				scan_req.chan_list[i].scan_time =
2751 					MIN_SPECIFIC_SCAN_CHAN_TIME;
2752 		}
2753 #endif
2754 #endif
2755 #ifdef WIFI_DIRECT_SUPPORT
2756 		if (priv->phandle->miracast_mode)
2757 			scan_req.chan_list[i].scan_time =
2758 				priv->phandle->miracast_scan_time;
2759 		else if (woal_is_any_interface_active(priv->phandle))
2760 			scan_req.chan_list[i].scan_time =
2761 				MIN_SPECIFIC_SCAN_CHAN_TIME;
2762 #endif
2763 #ifdef UAP_CFG80211
2764 		if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
2765 			scan_req.chan_list[i].scan_time =
2766 				MIN_SPECIFIC_SCAN_CHAN_TIME;
2767 #endif
2768 	}
2769 	if (priv->phandle->scan_request->ie &&
2770 	    priv->phandle->scan_request->ie_len) {
2771 		if (woal_find_wps_ie_in_probereq
2772 		    ((t_u8 *)priv->phandle->scan_request->ie,
2773 		     priv->phandle->scan_request->ie_len)) {
2774 			PRINTM(MIOCTL,
2775 			       "Notify firmware only keep probe response\n");
2776 			scan_req.proberesp_only = MTRUE;
2777 		}
2778 		if (MLAN_STATUS_SUCCESS !=
2779 		    woal_cfg80211_mgmt_frame_ie(priv, NULL, 0,
2780 						NULL, 0, NULL, 0,
2781 						(t_u8 *)priv->phandle->
2782 						scan_request->ie,
2783 						priv->phandle->scan_request->
2784 						ie_len, MGMT_MASK_PROBE_REQ,
2785 						MOAL_IOCTL_WAIT)) {
2786 			PRINTM(MERROR, "Fail to set scan request IE\n");
2787 			ret = -EFAULT;
2788 			goto done;
2789 		}
2790 	} else {
2791 		/** Clear SCAN IE in Firmware */
2792 		if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
2793 			woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0,
2794 						    NULL, 0, NULL, 0,
2795 						    MGMT_MASK_PROBE_REQ,
2796 						    MOAL_IOCTL_WAIT);
2797 	}
2798 #ifdef UAP_CFG80211
2799 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
2800 	/** use sync scan for uap */
2801 		ret = woal_uap_scan(priv, &scan_req);
2802 		if (!ret) {
2803 			LEAVE();
2804 			return ret;
2805 		} else {
2806 			PRINTM(MERROR, "Uap SCAN failure\n");
2807 			goto done;
2808 		}
2809 	}
2810 #endif
2811 	if (MLAN_STATUS_SUCCESS != woal_do_scan(priv, &scan_req)) {
2812 		PRINTM(MERROR, "woal_do_scan fails!\n");
2813 		ret = -EAGAIN;
2814 		goto done;
2815 	}
2816 done:
2817 	if (ret) {
2818 		spin_lock_irqsave(&priv->phandle->scan_req_lock, flags);
2819 		woal_cfg80211_scan_done(request, MTRUE);
2820 		priv->phandle->scan_request = NULL;
2821 		priv->phandle->scan_priv = NULL;
2822 		spin_unlock_irqrestore(&priv->phandle->scan_req_lock, flags);
2823 	} else
2824 		PRINTM(MMSG, "wlan: %s START SCAN\n", dev->name);
2825 	LEAVE();
2826 	return ret;
2827 }
2828 
2829 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
2830 static void
woal_cfg80211_abort_scan(struct wiphy * wiphy,struct wireless_dev * wdev)2831 woal_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev)
2832 {
2833 	moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
2834 	ENTER();
2835 	PRINTM(MMSG, "wlan: ABORT SCAN start\n");
2836 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
2837 	LEAVE();
2838 	return;
2839 }
2840 #endif
2841 /**
2842  * @brief construct and send ft action request
2843  *
2844 *  @param priv     A pointer to moal_private structure
2845  * @param ie       A pointer to ft ie
2846  * @param le       Value of ie len
2847  * @param bssid    A pointer to target ap bssid
2848  * @
2849  * @return         0 -- success, otherwise fail
2850  */
2851 static int
woal_send_ft_action_requst(moal_private * priv,t_u8 * ie,t_u8 len,t_u8 * bssid,t_u8 * target_ap)2852 woal_send_ft_action_requst(moal_private *priv, t_u8 *ie, t_u8 len, t_u8 *bssid,
2853 			   t_u8 *target_ap)
2854 {
2855 	IEEE80211_MGMT *mgmt = NULL;
2856 	mlan_status status = MLAN_STATUS_SUCCESS;
2857 	pmlan_buffer pmbuf = NULL;
2858 	t_u32 pkt_type;
2859 	t_u32 tx_control;
2860 	t_u16 packet_len = 0;
2861 	t_u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
2862 	int ret = 0;
2863 
2864 	ENTER();
2865 
2866 	/* pkt_type + tx_control */
2867 #define HEADER_SIZE				8
2868 	/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl + addr4 */
2869 #define MGMT_HEADER_LEN		(2 + 2 + 6 + 6 + 6 + 2 +6)
2870 	/* 14   = category + action + sta addr + target ap */
2871 #define FT_REQUEST_LEN 14
2872 	packet_len = (t_u16)len + MGMT_HEADER_LEN + FT_REQUEST_LEN;
2873 	pmbuf = woal_alloc_mlan_buffer(priv->phandle,
2874 				       MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
2875 				       packet_len + sizeof(packet_len));
2876 	if (!pmbuf) {
2877 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
2878 		ret = -ENOMEM;
2879 		goto done;
2880 	}
2881 
2882 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
2883 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
2884 	tx_control = 0;
2885 	/* Add pkt_type and tx_control */
2886 	memcpy(pmbuf->pbuf + pmbuf->data_offset, &pkt_type, sizeof(pkt_type));
2887 	memcpy(pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type), &tx_control,
2888 	       sizeof(tx_control));
2889 	/*Add packet len */
2890 	memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE, &packet_len,
2891 	       sizeof(packet_len));
2892 
2893 	mgmt = (IEEE80211_MGMT *)(pmbuf->pbuf + pmbuf->data_offset +
2894 				  HEADER_SIZE + sizeof(packet_len));
2895 	memset(mgmt, 0, MGMT_HEADER_LEN);
2896 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2897 					  IEEE80211_STYPE_ACTION);
2898 	memcpy(mgmt->da, bssid, ETH_ALEN);
2899 	memcpy(mgmt->sa, priv->current_addr, ETH_ALEN);
2900 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
2901 	memcpy(mgmt->addr4, addr, ETH_ALEN);
2902 
2903 	mgmt->u.ft_req.category = 0x06;	/**ft action code 0x6*/
2904 	mgmt->u.ft_req.action = 0x1; /**ft action request*/
2905 	memcpy(mgmt->u.ft_req.sta_addr, priv->current_addr, ETH_ALEN);
2906 	memcpy(mgmt->u.ft_req.target_ap_addr, target_ap, ETH_ALEN);
2907 
2908 	if (ie && len)
2909 		memcpy((t_u8 *)(&mgmt->u.ft_req.variable), ie, len);
2910 
2911 	pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
2912 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
2913 	pmbuf->bss_index = priv->bss_index;
2914 	pmbuf->priority = 7;
2915 
2916 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
2917 
2918 	switch (status) {
2919 	case MLAN_STATUS_PENDING:
2920 		atomic_inc(&priv->phandle->tx_pending);
2921 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
2922 		break;
2923 	case MLAN_STATUS_SUCCESS:
2924 		woal_free_mlan_buffer(priv->phandle, pmbuf);
2925 		break;
2926 	case MLAN_STATUS_FAILURE:
2927 	default:
2928 		woal_free_mlan_buffer(priv->phandle, pmbuf);
2929 		ret = -EFAULT;
2930 		break;
2931 	}
2932 
2933 done:
2934 	LEAVE();
2935 	return ret;
2936 }
2937 
2938 /**
2939  * @brief construct and send ft auth request
2940  *
2941 *  @param priv     A pointer to moal_private structure
2942  * @param ie       A pointer to ft ie
2943  * @param le       Value of ie len
2944  * @param bssid    A pointer to target ap bssid
2945  * @
2946  * @return         0 -- success, otherwise fail
2947  */
2948 static int
woal_send_ft_auth_requst(moal_private * priv,t_u8 * ie,t_u8 len,t_u8 * bssid)2949 woal_send_ft_auth_requst(moal_private *priv, t_u8 *ie, t_u8 len, t_u8 *bssid)
2950 {
2951 	IEEE80211_MGMT *mgmt = NULL;
2952 	mlan_status status = MLAN_STATUS_SUCCESS;
2953 	pmlan_buffer pmbuf = NULL;
2954 	t_u32 pkt_type;
2955 	t_u32 tx_control;
2956 	t_u16 packet_len = 0;
2957 	t_u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
2958 	int ret = 0;
2959 
2960 	ENTER();
2961 	/* pkt_type + tx_control */
2962 #define HEADER_SIZE				8
2963 	/* frmctl + durationid + addr1 + addr2 + addr3 + seqctl + addr4 */
2964 #define MGMT_HEADER_LEN		(2 + 2 + 6 + 6 + 6 + 2 +6)
2965 	/* 6   = auth_alg + auth_transaction +auth_status */
2966 #define AUTH_BODY_LEN 6
2967 	packet_len = (t_u16)len + MGMT_HEADER_LEN + AUTH_BODY_LEN;
2968 	pmbuf = woal_alloc_mlan_buffer(priv->phandle,
2969 				       MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE +
2970 				       packet_len + sizeof(packet_len));
2971 	if (!pmbuf) {
2972 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
2973 		ret = -ENOMEM;
2974 		goto done;
2975 	}
2976 
2977 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
2978 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
2979 	tx_control = 0;
2980 	/* Add pkt_type and tx_control */
2981 	memcpy(pmbuf->pbuf + pmbuf->data_offset, &pkt_type, sizeof(pkt_type));
2982 	memcpy(pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type), &tx_control,
2983 	       sizeof(tx_control));
2984 	/*Add packet len */
2985 	memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE, &packet_len,
2986 	       sizeof(packet_len));
2987 
2988 	mgmt = (IEEE80211_MGMT *)(pmbuf->pbuf + pmbuf->data_offset +
2989 				  HEADER_SIZE + sizeof(packet_len));
2990 	memset(mgmt, 0, MGMT_HEADER_LEN);
2991 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
2992 					  IEEE80211_STYPE_AUTH);
2993 	memcpy(mgmt->da, bssid, ETH_ALEN);
2994 	memcpy(mgmt->sa, priv->current_addr, ETH_ALEN);
2995 	memcpy(mgmt->bssid, bssid, ETH_ALEN);
2996 	memcpy(mgmt->addr4, addr, ETH_ALEN);
2997 
2998 	mgmt->u.auth.auth_alg = cpu_to_le16(WLAN_AUTH_FT);
2999 	mgmt->u.auth.auth_transaction = cpu_to_le16(1);
3000 	mgmt->u.auth.status_code = cpu_to_le16(0);
3001 	if (ie && len)
3002 		memcpy((t_u8 *)(&mgmt->u.auth.variable), ie, len);
3003 
3004 	pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len);
3005 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
3006 	pmbuf->bss_index = priv->bss_index;
3007 	pmbuf->priority = 7;
3008 
3009 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
3010 
3011 	switch (status) {
3012 	case MLAN_STATUS_PENDING:
3013 		atomic_inc(&priv->phandle->tx_pending);
3014 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
3015 		break;
3016 	case MLAN_STATUS_SUCCESS:
3017 		woal_free_mlan_buffer(priv->phandle, pmbuf);
3018 		break;
3019 	case MLAN_STATUS_FAILURE:
3020 	default:
3021 		woal_free_mlan_buffer(priv->phandle, pmbuf);
3022 		ret = -EFAULT;
3023 		break;
3024 	}
3025 
3026 done:
3027 	LEAVE();
3028 	return ret;
3029 }
3030 
3031 /**
3032  * @brief connect the AP through ft over air.
3033  *
3034  * @param priv            A pointer to moal_private structure
3035  * @param bssid           A pointer to bssid
3036  * @param chan            struct ieee80211_channel
3037  *
3038  * @return                0 -- success, otherwise fail
3039  */
3040 static int
woal_connect_ft_over_air(moal_private * priv,t_u8 * bssid,struct ieee80211_channel * chan)3041 woal_connect_ft_over_air(moal_private *priv, t_u8 *bssid,
3042 			 struct ieee80211_channel *chan)
3043 {
3044 	struct wiphy *wiphy = priv->wdev->wiphy;
3045 	mlan_bss_info bss_info;
3046 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3047 	t_u8 status = 0;
3048 #endif
3049 	t_u8 wait_option = MOAL_IOCTL_WAIT;
3050 	int ret = 0;
3051 	long timeout = 0;
3052 
3053 	ENTER();
3054 
3055 	if (!bssid) {
3056 		PRINTM(MERROR,
3057 		       "Invalid bssid, unable to connect AP to through FT\n");
3058 		LEAVE();
3059 		return -EFAULT;
3060 	}
3061 
3062 	if (!priv->ft_roaming_triggered_by_driver) {
3063 		wait_option = MOAL_IOCTL_WAIT;
3064 		memset(&bss_info, 0, sizeof(bss_info));
3065 		woal_get_bss_info(priv, wait_option, &bss_info);
3066 	}
3067 
3068 	if (priv->ft_roaming_triggered_by_driver || (priv->media_connected &&
3069 						     bss_info.mdid ==
3070 						     priv->ft_md &&
3071 						     bss_info.ft_cap ==
3072 						     priv->ft_cap)) {
3073 		ret = MTRUE;
3074 
3075 		/*enable auth register frame */
3076 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
3077 		woal_cfg80211_mgmt_frame_register(wiphy, priv->netdev,
3078 						  IEEE80211_STYPE_AUTH, MTRUE);
3079 #else
3080 		woal_cfg80211_mgmt_frame_register(wiphy, priv->wdev,
3081 						  IEEE80211_STYPE_AUTH, MTRUE);
3082 #endif
3083 
3084 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3085 #define AUTH_TX_DEFAULT_WAIT_TIME  1200
3086 		woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MFALSE,
3087 						    &status, chan, 0,
3088 						    AUTH_TX_DEFAULT_WAIT_TIME);
3089 #endif
3090 		/*construct auth request and send out */
3091 		woal_send_ft_auth_requst(priv, priv->ft_ie, priv->ft_ie_len,
3092 					 bssid);
3093 		PRINTM(MMSG, "wlan: send out FT auth,wait for auth response\n");
3094 		/*wait until received auth response */
3095 		priv->ft_wait_condition = MFALSE;
3096 		timeout =
3097 			wait_event_timeout(priv->ft_wait_q,
3098 					   priv->ft_wait_condition, 1 * HZ);
3099 		if (!timeout) {
3100 			/*connet fail */
3101 			if (!priv->ft_roaming_triggered_by_driver) {
3102 				woal_inform_bss_from_scan_result(priv, NULL,
3103 								 wait_option);
3104 				cfg80211_connect_result(priv->netdev,
3105 							priv->cfg_bssid, NULL,
3106 							0, NULL, 0,
3107 							WLAN_STATUS_SUCCESS,
3108 							GFP_KERNEL);
3109 			}
3110 			priv->ft_roaming_triggered_by_driver = MFALSE;
3111 			PRINTM(MMSG,
3112 			       "wlan: keep connected to bssid " MACSTR "\n",
3113 			       MAC2STR(priv->cfg_bssid));
3114 		} else {
3115 			PRINTM(MMSG, "wlan: FT auth received \n");
3116 			memcpy(priv->target_ap_bssid, bssid, ETH_ALEN);
3117 		}
3118 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3119 		woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MTRUE,
3120 						    &status, NULL, 0, 0);
3121 #endif
3122 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
3123 		woal_cfg80211_mgmt_frame_register(wiphy, priv->netdev,
3124 						  IEEE80211_STYPE_AUTH, MFALSE);
3125 #else
3126 		woal_cfg80211_mgmt_frame_register(wiphy, priv->wdev,
3127 						  IEEE80211_STYPE_AUTH, MFALSE);
3128 #endif
3129 	}
3130 
3131 	LEAVE();
3132 	return ret;
3133 }
3134 
3135 /**
3136  * @brief connect the AP through ft over DS.
3137  *
3138  * @param priv            A pointer to moal_private structure
3139  * @param bssid           A pointer to bssid
3140  * @param chan            struct ieee80211_channel
3141  *
3142  * @return                0 -- success, otherwise fail
3143  */
3144 static int
woal_connect_ft_over_ds(moal_private * priv,t_u8 * bssid,struct ieee80211_channel * pchan)3145 woal_connect_ft_over_ds(moal_private *priv, t_u8 *bssid,
3146 			struct ieee80211_channel *pchan)
3147 {
3148 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3149 	t_u8 status = 0;
3150 #endif
3151 	t_u8 wait_option = MOAL_IOCTL_WAIT;
3152 	struct ieee80211_channel chan;
3153 	mlan_bss_info bss_info;
3154 	int ret = 0;
3155 	long timeout = 0;
3156 
3157 	ENTER();
3158 
3159 	if (!priv->ft_roaming_triggered_by_driver)
3160 		wait_option = MOAL_IOCTL_WAIT;
3161 
3162 	memset(&bss_info, 0, sizeof(bss_info));
3163 	woal_get_bss_info(priv, wait_option, &bss_info);
3164 	chan.band = (bss_info.bss_chan < 36) ?
3165 		IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
3166 	chan.center_freq = ieee80211_channel_to_frequency(bss_info.bss_chan
3167 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3168 							  , chan.band
3169 #endif
3170 		);
3171 
3172 	if (priv->media_connected) {
3173 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3174 		woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MFALSE,
3175 						    &status, &chan, 0, 1200);
3176 #endif
3177 		/*construct ft action request and send out */
3178 		woal_send_ft_action_requst(priv, priv->ft_ie, priv->ft_ie_len,
3179 					   (t_u8 *)priv->cfg_bssid, bssid);
3180 		PRINTM(MMSG,
3181 		       "wlan: send out FT request,wait for FT response\n");
3182 		/*wait until received auth response */
3183 		priv->ft_wait_condition = MFALSE;
3184 		timeout =
3185 			wait_event_timeout(priv->ft_wait_q,
3186 					   priv->ft_wait_condition, 1 * HZ);
3187 		if (!timeout) {
3188 			/*go over air, as current AP may be unreachable */
3189 			PRINTM(MMSG, "wlan: go over air\n");
3190 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3191 			woal_cfg80211_remain_on_channel_cfg(priv, wait_option,
3192 							    MTRUE, &status,
3193 							    NULL, 0, 0);
3194 #endif
3195 			woal_connect_ft_over_air(priv, bssid, pchan);
3196 			LEAVE();
3197 			return ret;
3198 		} else {
3199 			PRINTM(MMSG, "wlan: received FT response\n");
3200 			memcpy(priv->target_ap_bssid, bssid, ETH_ALEN);
3201 		}
3202 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3203 		woal_cfg80211_remain_on_channel_cfg(priv, wait_option, MTRUE,
3204 						    &status, NULL, 0, 0);
3205 #endif
3206 
3207 	}
3208 
3209 	LEAVE();
3210 	return ret;
3211 }
3212 
3213 /**
3214  * @brief start FT Roaming.
3215  *
3216  * @param priv               A pointer to moal_private structure
3217  * @param ssid_bssid         A pointer to mlan_ssid_bssid structure
3218  *
3219  *
3220  * @return                   0 -- success, otherwise fail
3221  */
3222 static int
woal_start_ft_roaming(moal_private * priv,mlan_ssid_bssid * ssid_bssid)3223 woal_start_ft_roaming(moal_private *priv, mlan_ssid_bssid *ssid_bssid)
3224 {
3225 	struct ieee80211_channel chan;
3226 	int ret = 0;
3227 
3228 	ENTER();
3229 	PRINTM(MEVENT, "Try to start FT roaming......\n");
3230 	chan.band = (ssid_bssid->channel < 36) ?
3231 		IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
3232 	chan.center_freq = ieee80211_channel_to_frequency(ssid_bssid->channel
3233 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3234 							  , chan.band
3235 #endif
3236 		);
3237 
3238 	priv->ft_roaming_triggered_by_driver = MTRUE;
3239 	if (!(priv->last_event & EVENT_PRE_BCN_LOST) &&
3240 	    (ssid_bssid->ft_cap & MBIT(0))) {
3241 		woal_connect_ft_over_ds(priv, (t_u8 *)&ssid_bssid->bssid,
3242 					&chan);
3243 	} else {
3244 		/*if pre beacon lost, it need to send auth request instead ft action request when ft over ds */
3245 
3246 		woal_connect_ft_over_air(priv, (t_u8 *)&ssid_bssid->bssid,
3247 					 &chan);
3248 	}
3249 
3250 	LEAVE();
3251 	return ret;
3252 }
3253 
3254 /**
3255  * @brief Request the driver to connect to the ESS with
3256  * the specified parameters from kernel
3257  *
3258  * @param wiphy           A pointer to wiphy structure
3259  * @param dev             A pointer to net_device structure
3260  * @param sme             A pointer to cfg80211_connect_params structure
3261  *
3262  * @return                0 -- success, otherwise fail
3263  */
3264 static int
woal_cfg80211_connect(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_connect_params * sme)3265 woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
3266 		      struct cfg80211_connect_params *sme)
3267 {
3268 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3269 	int ret = 0;
3270 	mlan_bss_info bss_info;
3271 	unsigned long flags;
3272 	mlan_ds_misc_assoc_rsp assoc_rsp;
3273 	IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
3274 	mlan_ssid_bssid ssid_bssid;
3275 	moal_handle *handle = priv->phandle;
3276 	int i;
3277 
3278 	ENTER();
3279 
3280 	PRINTM(MINFO, "Received association request on %s\n", dev->name);
3281 #ifdef UAP_CFG80211
3282 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
3283 		LEAVE();
3284 		return 0;
3285 	}
3286 #endif
3287 	if (priv->wdev->iftype != NL80211_IFTYPE_STATION
3288 #if defined(WIFI_DIRECT_SUPPORT)
3289 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
3290 	    && priv->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT
3291 #endif /* KERNEL_VERSION */
3292 #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */
3293 		) {
3294 		PRINTM(MERROR,
3295 		       "Received infra assoc request when station not in infra mode\n");
3296 		LEAVE();
3297 		return -EINVAL;
3298 	}
3299 
3300 	memset(&ssid_bssid, 0, sizeof(ssid_bssid));
3301 	memcpy(&ssid_bssid.ssid.ssid, sme->ssid, sme->ssid_len);
3302 	ssid_bssid.ssid.ssid_len = sme->ssid_len;
3303 	if (sme->bssid)
3304 		memcpy(&ssid_bssid.bssid, sme->bssid, ETH_ALEN);
3305 	/* Not allowed to connect to the same AP which is already connected
3306 	   with other interface */
3307 	for (i = 0; i < handle->priv_num; i++) {
3308 		if (handle->priv[i] != priv &&
3309 		    MTRUE == woal_is_connected(handle->priv[i], &ssid_bssid)) {
3310 			PRINTM(MMSG,
3311 			       "wlan: already connected with other interface, bssid "
3312 			       MACSTR "\n",
3313 			       MAC2STR(handle->priv[i]->cfg_bssid));
3314 			LEAVE();
3315 			return -EINVAL;
3316 		}
3317 	}
3318 
3319 	/** cancel pending scan */
3320 	woal_cancel_scan(priv, MOAL_IOCTL_WAIT);
3321 
3322 #if defined(WIFI_DIRECT_SUPPORT)
3323 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
3324 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT
3325 	    && (priv->wdev->iftype == NL80211_IFTYPE_STATION
3326 		|| priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
3327 		/* if bsstype == wifi direct, and iftype == station or p2p client,
3328 		 * that means wpa_supplicant wants to enable wifi direct
3329 		 * functionality, so we should init p2p client.
3330 		 *
3331 		 * Note that due to kernel iftype check, ICS wpa_supplicant
3332 		 * could not updaet iftype to init p2p client, so we have to
3333 		 * done it here.
3334 		 * */
3335 		if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_client(priv)) {
3336 			PRINTM(MERROR,
3337 			       "Init p2p client for wpa_supplicant failed.\n");
3338 			ret = -EFAULT;
3339 
3340 			LEAVE();
3341 			return ret;
3342 		}
3343 	}
3344 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
3345 		/* WAR for P2P connection with Samsung TV */
3346 		woal_sched_timeout(200);
3347 	}
3348 #endif
3349 #endif
3350 	/*Fast BSS Transition use ft-over-air */
3351 	if (priv->media_connected && priv->ft_ie_len &&
3352 	    !(priv->ft_cap & MBIT(0))) {
3353 		ret = woal_connect_ft_over_air(priv, (t_u8 *)sme->bssid,
3354 					       sme->channel);
3355 		if (ret == MTRUE) {
3356 			LEAVE();
3357 			return 0;
3358 		}
3359 	}
3360 	priv->cfg_connect = MTRUE;
3361 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
3362 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE);
3363 	priv->assoc_status = 0;
3364 	ret = woal_cfg80211_assoc(priv, (void *)sme, MOAL_IOCTL_WAIT);
3365 
3366 	if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)
3367 		woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE);
3368 	if (!ret) {
3369 		memset(&assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
3370 		woal_get_assoc_rsp(priv, &assoc_rsp, MOAL_IOCTL_WAIT);
3371 		passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp.assoc_resp_buf;
3372 		priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD;
3373 		if (priv->bss_type == MLAN_BSS_TYPE_STA)
3374 			woal_save_conn_params(priv, sme);
3375 		memset(&bss_info, 0, sizeof(bss_info));
3376 		woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
3377 		priv->channel = bss_info.bss_chan;
3378 	}
3379 	spin_lock_irqsave(&priv->connect_lock, flags);
3380 	priv->cfg_connect = MFALSE;
3381 	if (!ret && priv->media_connected) {
3382 		PRINTM(MMSG,
3383 		       "wlan: Connected to bssid " MACSTR " successfully\n",
3384 		       MAC2STR(priv->cfg_bssid));
3385 		spin_unlock_irqrestore(&priv->connect_lock, flags);
3386 		cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
3387 					passoc_rsp->ie_buffer,
3388 					assoc_rsp.assoc_resp_len -
3389 					ASSOC_RESP_FIXED_SIZE,
3390 					WLAN_STATUS_SUCCESS, GFP_KERNEL);
3391 	} else {
3392 		PRINTM(MINFO, "wlan: Failed to connect to bssid " MACSTR "\n",
3393 		       MAC2STR(priv->cfg_bssid));
3394 		memset(priv->cfg_bssid, 0, ETH_ALEN);
3395 		priv->ft_ie_len = 0;
3396 		priv->ft_pre_connect = MFALSE;
3397 		spin_unlock_irqrestore(&priv->connect_lock, flags);
3398 		cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0,
3399 					NULL, 0, woal_get_assoc_status(priv),
3400 					GFP_KERNEL);
3401 
3402 	}
3403 	LEAVE();
3404 	return 0;
3405 }
3406 
3407 /**
3408  * @brief Request the driver to disconnect
3409  *
3410  * @param wiphy           A pointer to wiphy structure
3411  * @param dev             A pointer to net_device structure
3412  * @param reason_code     Reason code
3413  *
3414  * @return                0 -- success, otherwise fail
3415  */
3416 static int
woal_cfg80211_disconnect(struct wiphy * wiphy,struct net_device * dev,t_u16 reason_code)3417 woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
3418 			 t_u16 reason_code)
3419 {
3420 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3421 	long start_time;
3422 
3423 	ENTER();
3424 	PRINTM(MMSG,
3425 	       "wlan: Received disassociation request on %s, reason: %u\n",
3426 	       dev->name, reason_code);
3427 #ifdef UAP_CFG80211
3428 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
3429 		LEAVE();
3430 		return 0;
3431 	}
3432 #endif
3433 	priv->phandle->driver_state = woal_check_driver_status(priv->phandle);
3434 	if (priv->phandle->driver_state) {
3435 		PRINTM(MERROR,
3436 		       "Block woal_cfg80211_disconnect in abnormal driver state\n");
3437 		LEAVE();
3438 		return -EFAULT;
3439 	}
3440 
3441 	if (priv->cfg_disconnect) {
3442 		PRINTM(MERROR, "Disassociation already in progress\n");
3443 		LEAVE();
3444 		return -EBUSY;
3445 	}
3446 
3447 	if (priv->media_connected == MFALSE) {
3448 		PRINTM(MMSG, " Already disconnected\n");
3449 		LEAVE();
3450 		return 0;
3451 	}
3452 
3453 	priv->cfg_disconnect = MTRUE;
3454 	start_time = jiffies;
3455 	if (woal_disconnect
3456 	    (priv, MOAL_IOCTL_WAIT_TIMEOUT, priv->cfg_bssid,
3457 	     reason_code) != MLAN_STATUS_SUCCESS) {
3458 		priv->cfg_disconnect = MFALSE;
3459 		LEAVE();
3460 		return -EFAULT;
3461 	}
3462        /**Add delay to avoid auth failure after wps success */
3463 	if ((jiffies - start_time) < 1 * HZ)
3464 		woal_sched_timeout(1500);
3465 
3466 	priv->cfg_disconnect = MFALSE;
3467 
3468 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
3469 	if (priv->wdev->iftype == NL80211_IFTYPE_STATION)
3470 		cfg80211_disconnected(priv->netdev, 0, NULL, 0,
3471 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
3472 				      true,
3473 #endif
3474 				      GFP_KERNEL);
3475 #endif
3476 
3477 	memset(priv->cfg_bssid, 0, ETH_ALEN);
3478 	if (priv->bss_type == MLAN_BSS_TYPE_STA)
3479 		woal_clear_conn_params(priv);
3480 	priv->channel = 0;
3481 
3482 	LEAVE();
3483 	return 0;
3484 }
3485 
3486 /**
3487  * @brief Request the driver to get the station information
3488  *
3489  * @param wiphy           A pointer to wiphy structure
3490  * @param dev             A pointer to net_device structure
3491  * @param mac             MAC address of the station
3492  * @param sinfo           A pointer to station_info structure
3493  *
3494  * @return                0 -- success, otherwise fail
3495  */
3496 static int
woal_cfg80211_get_station(struct wiphy * wiphy,struct net_device * dev,const t_u8 * mac,struct station_info * sinfo)3497 woal_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
3498 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
3499 			  const t_u8 *mac,
3500 #else
3501 			  t_u8 *mac,
3502 #endif
3503 			  struct station_info *sinfo)
3504 {
3505 	mlan_status ret = MLAN_STATUS_SUCCESS;
3506 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3507 
3508 	ENTER();
3509 
3510 #ifdef UAP_CFG80211
3511 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
3512 		LEAVE();
3513 		return woal_uap_cfg80211_get_station(wiphy, dev, mac, sinfo);
3514 	}
3515 #endif
3516 	if (priv->media_connected == MFALSE) {
3517 		PRINTM(MINFO, "cfg80211: Media not connected!\n");
3518 		LEAVE();
3519 		return -ENOENT;
3520 	}
3521 
3522 	if (MLAN_STATUS_SUCCESS != woal_cfg80211_dump_station_info(priv, sinfo)) {
3523 		PRINTM(MERROR, "cfg80211: Failed to get station info\n");
3524 		ret = -EFAULT;
3525 	}
3526 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,2,0)
3527 	woal_check_auto_tdls(wiphy, dev);
3528 #endif
3529 	LEAVE();
3530 	return ret;
3531 }
3532 
3533 /**
3534  * @brief Request the driver to dump the station information
3535  *
3536  * @param wiphy           A pointer to wiphy structure
3537  * @param dev             A pointer to net_device structure
3538  * @param idx             Station index
3539  * @param mac             MAC address of the station
3540  * @param sinfo           A pointer to station_info structure
3541  *
3542  * @return                0 -- success, otherwise fail
3543  */
3544 static int
woal_cfg80211_dump_station(struct wiphy * wiphy,struct net_device * dev,int idx,t_u8 * mac,struct station_info * sinfo)3545 woal_cfg80211_dump_station(struct wiphy *wiphy,
3546 			   struct net_device *dev, int idx,
3547 			   t_u8 *mac, struct station_info *sinfo)
3548 {
3549 	mlan_status ret = MLAN_STATUS_SUCCESS;
3550 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3551 
3552 	ENTER();
3553 
3554 #ifdef UAP_CFG80211
3555 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
3556 		LEAVE();
3557 		return woal_uap_cfg80211_dump_station(wiphy, dev, idx, mac,
3558 						      sinfo);
3559 	}
3560 #endif
3561 
3562 	if (!priv->media_connected || idx != 0) {
3563 		PRINTM(MINFO,
3564 		       "cfg80211: Media not connected or not for this station!\n");
3565 		LEAVE();
3566 		return -ENOENT;
3567 	}
3568 
3569 	memcpy(mac, priv->cfg_bssid, ETH_ALEN);
3570 
3571 	if (MLAN_STATUS_SUCCESS != woal_cfg80211_dump_station_info(priv, sinfo)) {
3572 		PRINTM(MERROR, "cfg80211: Failed to get station info\n");
3573 		ret = -EFAULT;
3574 	}
3575 
3576 	LEAVE();
3577 	return ret;
3578 }
3579 
3580 /**
3581  *  @brief Convert driver band configuration to IEEE band type
3582  *
3583  *  @param bandcfg  Driver band configuration
3584  *
3585  *  @return         IEEE band type
3586  */
3587 t_u8
woal_bandcfg_to_ieee_band(Band_Config_t bandcfg)3588 woal_bandcfg_to_ieee_band(Band_Config_t bandcfg)
3589 {
3590 	t_u8 ret_radio_type = 0;
3591 
3592 	ENTER();
3593 
3594 	switch (bandcfg.chanBand) {
3595 	case BAND_5GHZ:
3596 		ret_radio_type = IEEE80211_BAND_5GHZ;
3597 		break;
3598 	case BAND_2GHZ:
3599 	default:
3600 		ret_radio_type = IEEE80211_BAND_2GHZ;
3601 		break;
3602 	}
3603 	LEAVE();
3604 	return ret_radio_type;
3605 }
3606 
3607 /**
3608  * @brief Request the driver to dump survey info
3609  *
3610  * @param wiphy           A pointer to wiphy structure
3611  * @param dev             A pointer to net_device structure
3612  * @param idx             Station index
3613  * @param survey          A pointer to survey_info structure
3614  *
3615  * @return                0 -- success, otherwise fail
3616  */
3617 static int
woal_cfg80211_dump_survey(struct wiphy * wiphy,struct net_device * dev,int idx,struct survey_info * survey)3618 woal_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
3619 			  int idx, struct survey_info *survey)
3620 {
3621 	int ret = -ENOENT;
3622 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3623 	enum ieee80211_band band;
3624 	ChanStatistics_t *pchan_stats = NULL;
3625 	mlan_scan_resp scan_resp;
3626 
3627 	ENTER();
3628 	PRINTM(MIOCTL, "dump_survey idx=%d\n", idx);
3629 
3630 	memset(&scan_resp, 0, sizeof(scan_resp));
3631 	if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv,
3632 						       MOAL_IOCTL_WAIT,
3633 						       &scan_resp)) {
3634 		ret = -EFAULT;
3635 		goto done;
3636 	}
3637 	pchan_stats = (ChanStatistics_t *)scan_resp.pchan_stats;
3638 	if (idx > scan_resp.num_in_chan_stats || idx < 0) {
3639 		ret = -EFAULT;
3640 		goto done;
3641 	}
3642 	if (idx == scan_resp.num_in_chan_stats ||
3643 	    !pchan_stats[idx].cca_scan_duration)
3644 		goto done;
3645 	ret = 0;
3646 	memset(survey, 0, sizeof(*survey));
3647 	band = woal_bandcfg_to_ieee_band(pchan_stats[idx].bandcfg);
3648 	survey->channel =
3649 		ieee80211_get_channel(wiphy,
3650 				      ieee80211_channel_to_frequency(pchan_stats
3651 								     [idx].
3652 								     chan_num
3653 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
3654 								     , band
3655 #endif
3656 				      ));
3657 	survey->filled = SURVEY_INFO_NOISE_DBM;
3658 	survey->noise = pchan_stats[idx].noise;
3659 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
3660 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
3661 	survey->filled |= SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY;
3662 	survey->time = pchan_stats[idx].cca_scan_duration;
3663 	survey->time_busy = pchan_stats[idx].cca_busy_duration;
3664 #else
3665 	survey->filled |=
3666 		SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY;
3667 	survey->channel_time = pchan_stats[idx].cca_scan_duration;
3668 	survey->channel_time_busy = pchan_stats[idx].cca_busy_duration;
3669 #endif
3670 #endif
3671 done:
3672 	LEAVE();
3673 	return ret;
3674 }
3675 
3676 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
3677 /**
3678  * @brief Function gets channel info from cfg80211
3679  *
3680  * @param wiphy           A pointer to wiphy structure
3681  * @param wdev            A pointer to wireless_dev structure
3682  * @param chandef         A pointer to cfg80211_chan_def
3683  *
3684  * @return                0 -- success, otherwise fail
3685  */
3686 static int
woal_cfg80211_get_channel(struct wiphy * wiphy,struct wireless_dev * wdev,struct cfg80211_chan_def * chandef)3687 woal_cfg80211_get_channel(struct wiphy *wiphy,
3688 			  struct wireless_dev *wdev,
3689 			  struct cfg80211_chan_def *chandef)
3690 {
3691 	moal_private *priv = (moal_private *)woal_get_netdev_priv(wdev->netdev);
3692 	chan_band_info channel;
3693 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
3694 
3695 	memset(&channel, 0x00, sizeof(channel));
3696 
3697 	if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
3698 		if ((handle->mon_if) &&
3699 		    (handle->mon_if->mon_ndev == wdev->netdev)) {
3700 			*chandef = handle->mon_if->chandef;
3701 			return 0;
3702 		}
3703 		return -EFAULT;
3704 	}
3705 #ifdef UAP_SUPPORT
3706 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
3707 		if (priv->bss_started == MTRUE) {
3708 			if (MLAN_STATUS_SUCCESS !=
3709 			    woal_set_get_ap_channel(priv, MLAN_ACT_GET,
3710 						    MOAL_IOCTL_WAIT,
3711 						    &channel)) {
3712 				PRINTM(MERROR, "Fail to get ap channel \n");
3713 				return -EFAULT;
3714 			}
3715 		} else {
3716 			PRINTM(MERROR, "get_channel when AP is not started\n");
3717 			return -EFAULT;
3718 		}
3719 	} else
3720 #endif
3721 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
3722 		if (priv->media_connected == MTRUE) {
3723 			if (MLAN_STATUS_SUCCESS !=
3724 			    woal_get_sta_channel(priv, MOAL_IOCTL_WAIT,
3725 						 &channel)) {
3726 				PRINTM(MERROR, "Fail to get sta channel \n");
3727 				return -EFAULT;
3728 			}
3729 		} else {
3730 			PRINTM(MERROR,
3731 			       "get_channel when STA is not connected\n");
3732 			return -EFAULT;
3733 		}
3734 	} else {
3735 		PRINTM(MERROR, "BssRole not support %d.\n", GET_BSS_ROLE(priv));
3736 		return -EFAULT;
3737 	}
3738 
3739 	if (MLAN_STATUS_FAILURE == woal_chandef_create(priv, chandef, &channel))
3740 		return -EFAULT;
3741 	else
3742 		return 0;
3743 }
3744 #endif
3745 
3746 /**
3747  * @brief Request the driver to Join the specified
3748  * IBSS (or create if necessary)
3749  *
3750  * @param wiphy           A pointer to wiphy structure
3751  * @param dev             A pointer to net_device structure
3752  * @param params          A pointer to cfg80211_ibss_params structure
3753  *
3754  * @return                0 -- success, otherwise fail
3755  */
3756 static int
woal_cfg80211_join_ibss(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_ibss_params * params)3757 woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
3758 			struct cfg80211_ibss_params *params)
3759 {
3760 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3761 	int ret = 0;
3762 
3763 	ENTER();
3764 
3765 	if (priv->wdev->iftype != NL80211_IFTYPE_ADHOC) {
3766 		PRINTM(MERROR,
3767 		       "Request IBSS join received when station not in ibss mode\n");
3768 		LEAVE();
3769 		return -EINVAL;
3770 	}
3771 
3772 	ret = woal_cfg80211_assoc(priv, (void *)params, MOAL_IOCTL_WAIT);
3773 
3774 	if (!ret) {
3775 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
3776 		cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
3777 				     params->chandef.chan, GFP_KERNEL);
3778 #else
3779 		cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
3780 #endif
3781 		PRINTM(MINFO, "Joined/created adhoc network with bssid"
3782 		       MACSTR " successfully\n", MAC2STR(priv->cfg_bssid));
3783 	} else {
3784 		PRINTM(MINFO, "Failed creating/joining adhoc network\n");
3785 		memset(priv->cfg_bssid, 0, ETH_ALEN);
3786 	}
3787 
3788 	LEAVE();
3789 	return ret;
3790 }
3791 
3792 /**
3793  * @brief Request the driver to leave the IBSS
3794  *
3795  * @param wiphy           A pointer to wiphy structure
3796  * @param dev             A pointer to net_device structure
3797  *
3798  * @return                0 -- success, otherwise fail
3799  */
3800 static int
woal_cfg80211_leave_ibss(struct wiphy * wiphy,struct net_device * dev)3801 woal_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
3802 {
3803 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3804 
3805 	ENTER();
3806 
3807 	if (priv->cfg_disconnect) {
3808 		PRINTM(MERROR, "IBSS leave already in progress\n");
3809 		LEAVE();
3810 		return -EBUSY;
3811 	}
3812 
3813 	if (priv->media_connected == MFALSE) {
3814 		LEAVE();
3815 		return -EINVAL;
3816 	}
3817 
3818 	priv->cfg_disconnect = 1;
3819 
3820 	PRINTM(MINFO, "Leaving from IBSS " MACSTR "\n",
3821 	       MAC2STR(priv->cfg_bssid));
3822 	if (woal_disconnect
3823 	    (priv, MOAL_IOCTL_WAIT, priv->cfg_bssid,
3824 	     DEF_DEAUTH_REASON_CODE) != MLAN_STATUS_SUCCESS) {
3825 		priv->cfg_disconnect = 0;
3826 		LEAVE();
3827 		return -EFAULT;
3828 	}
3829 	priv->cfg_disconnect = 0;
3830 	memset(priv->cfg_bssid, 0, ETH_ALEN);
3831 
3832 	LEAVE();
3833 	return 0;
3834 }
3835 
3836 /**
3837  * @brief Request the driver to change the IEEE power save
3838  * mdoe
3839  *
3840  * @param wiphy           A pointer to wiphy structure
3841  * @param dev             A pointer to net_device structure
3842  * @param enabled         Enable or disable
3843  * @param timeout         Timeout value
3844  *
3845  * @return                0 -- success, otherwise fail
3846  */
3847 static int
woal_cfg80211_set_power_mgmt(struct wiphy * wiphy,struct net_device * dev,bool enabled,int timeout)3848 woal_cfg80211_set_power_mgmt(struct wiphy *wiphy,
3849 			     struct net_device *dev, bool enabled, int timeout)
3850 {
3851 	int ret = 0, disabled;
3852 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
3853 
3854 	ENTER();
3855 	if (hw_test || (ps_mode == MLAN_INIT_PARA_DISABLED)) {
3856 		PRINTM(MIOCTL, "block set power hw_test=%d ps_mode=%d\n",
3857 		       hw_test, ps_mode);
3858 		LEAVE();
3859 		return -EFAULT;
3860 	}
3861 	priv->phandle->driver_state = woal_check_driver_status(priv->phandle);
3862 	if (priv->phandle->driver_state) {
3863 		PRINTM(MERROR,
3864 		       "Block woal_cfg80211_set_power_mgmt in abnormal driver state\n");
3865 		LEAVE();
3866 		return -EFAULT;
3867 	}
3868 #if defined(WIFI_DIRECT_SUPPORT)
3869 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
3870 	if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) {
3871 		PRINTM(MIOCTL, "skip set power for p2p interface\n");
3872 		LEAVE();
3873 		return ret;
3874 	}
3875 #endif
3876 #endif
3877 	if (enabled)
3878 		disabled = 0;
3879 	else
3880 		disabled = 1;
3881 
3882 	if (MLAN_STATUS_SUCCESS !=
3883 	    woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, timeout,
3884 				    MOAL_IOCTL_WAIT)) {
3885 		ret = -EOPNOTSUPP;
3886 	}
3887 
3888 	LEAVE();
3889 	return ret;
3890 }
3891 
3892 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
3893 /**
3894  * @brief Request the driver to get the transmit power info
3895  *
3896  * @param wiphy           A pointer to wiphy structure
3897  * @param type            TX power adjustment type
3898  * @param dbm             TX power in dbm
3899  *
3900  * @return                0 -- success, otherwise fail
3901  */
3902 static int
woal_cfg80211_get_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,int * dbm)3903 woal_cfg80211_get_tx_power(struct wiphy *wiphy,
3904 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
3905 			   struct wireless_dev *wdev,
3906 #endif
3907 			   int *dbm)
3908 {
3909 	int ret = 0;
3910 	moal_private *priv = NULL;
3911 	mlan_power_cfg_t power_cfg;
3912 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
3913 
3914 	ENTER();
3915 
3916 	if (!handle) {
3917 		PRINTM(MFATAL, "Unable to get handle\n");
3918 		LEAVE();
3919 		return -EFAULT;
3920 	}
3921 
3922 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
3923 
3924 	if (!priv) {
3925 		PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
3926 		LEAVE();
3927 		return -EFAULT;
3928 	}
3929 
3930 	if (MLAN_STATUS_SUCCESS !=
3931 	    woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) {
3932 		LEAVE();
3933 		return -EFAULT;
3934 	}
3935 
3936 	*dbm = power_cfg.power_level;
3937 
3938 	LEAVE();
3939 	return ret;
3940 }
3941 
3942 /**
3943  * @brief Request the driver to change the transmit power
3944  *
3945  * @param wiphy           A pointer to wiphy structure
3946  * @param type            TX power adjustment type
3947  * @param dbm             TX power in dbm
3948  *
3949  * @return                0 -- success, otherwise fail
3950  */
3951 static int
woal_cfg80211_set_tx_power(struct wiphy * wiphy,struct wireless_dev * wdev,enum tx_power_setting type,int dbm)3952 woal_cfg80211_set_tx_power(struct wiphy *wiphy,
3953 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
3954 			   struct wireless_dev *wdev,
3955 #endif
3956 #if CFG80211_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
3957 			   enum tx_power_setting type,
3958 #else
3959 			   enum nl80211_tx_power_setting type,
3960 #endif
3961 			   int dbm)
3962 {
3963 	int ret = 0;
3964 	moal_private *priv = NULL;
3965 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
3966 	mlan_power_cfg_t power_cfg;
3967 
3968 	ENTER();
3969 
3970 	priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY);
3971 	if (!priv) {
3972 		PRINTM(MFATAL, "Unable to get priv in %s()\n", __func__);
3973 		LEAVE();
3974 		return -EFAULT;
3975 	}
3976 
3977 	if (type) {
3978 		power_cfg.is_power_auto = 0;
3979 		power_cfg.power_level = dbm;
3980 	} else
3981 		power_cfg.is_power_auto = 1;
3982 
3983 	if (MLAN_STATUS_SUCCESS !=
3984 	    woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg))
3985 		ret = -EFAULT;
3986 
3987 	LEAVE();
3988 	return ret;
3989 }
3990 #endif
3991 
3992 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 35)
3993 /**
3994  * CFG802.11 operation handler for connection quality monitoring.
3995  *
3996  * @param wiphy           A pointer to wiphy structure
3997  * @param dev             A pointer to net_device structure
3998  * @param rssi_thold	  rssi threshold
3999  * @param rssi_hyst		  rssi hysteresis
4000  */
4001 static int
woal_cfg80211_set_cqm_rssi_config(struct wiphy * wiphy,struct net_device * dev,s32 rssi_thold,u32 rssi_hyst)4002 woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
4003 				  struct net_device *dev,
4004 				  s32 rssi_thold, u32 rssi_hyst)
4005 {
4006 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
4007 	ENTER();
4008 	priv->cqm_rssi_thold = rssi_thold;
4009 	priv->cqm_rssi_high_thold = rssi_thold;
4010 	priv->cqm_rssi_hyst = rssi_hyst;
4011 
4012 	PRINTM(MIOCTL, "rssi_thold=%d rssi_hyst=%d\n",
4013 	       (int)rssi_thold, (int)rssi_hyst);
4014 	woal_set_rssi_threshold(priv, 0, MOAL_IOCTL_WAIT);
4015 	LEAVE();
4016 	return 0;
4017 }
4018 #endif
4019 
4020 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
4021 /**
4022  * @brief remain on channel config
4023  *
4024  * @param priv              A pointer to moal_private structure
4025  * @param wait_option       Wait option
4026  * @param cancel			cancel remain on channel flag
4027  * @param status            A pointer to status, success, in process or reject
4028  * @param chan              A pointer to ieee80211_channel structure
4029  * @param channel_type      channel_type,
4030  * @param duration          Duration wait to receive frame
4031  *
4032  * @return                  0 -- success, otherwise fail
4033  */
4034 int
woal_cfg80211_remain_on_channel_cfg(moal_private * priv,t_u8 wait_option,t_u8 remove,t_u8 * status,struct ieee80211_channel * chan,enum nl80211_channel_type channel_type,t_u32 duration)4035 woal_cfg80211_remain_on_channel_cfg(moal_private *priv,
4036 				    t_u8 wait_option, t_u8 remove, t_u8 *status,
4037 				    struct ieee80211_channel *chan,
4038 				    enum nl80211_channel_type channel_type,
4039 				    t_u32 duration)
4040 {
4041 	mlan_ds_remain_chan chan_cfg;
4042 	int ret = 0;
4043 
4044 	ENTER();
4045 
4046 	if (!status || (!chan && !remove)) {
4047 		LEAVE();
4048 		return -EFAULT;
4049 	}
4050 	memset(&chan_cfg, 0, sizeof(mlan_ds_remain_chan));
4051 	if (remove) {
4052 		chan_cfg.remove = MTRUE;
4053 	} else {
4054 #ifdef WIFI_DIRECT_SUPPORT
4055 		if (priv->phandle->is_go_timer_set) {
4056 			PRINTM(MINFO,
4057 			       "block remain on channel while go timer is on\n");
4058 			LEAVE();
4059 			return -EBUSY;
4060 		}
4061 #endif
4062 		if (chan->band == IEEE80211_BAND_2GHZ)
4063 			chan_cfg.bandcfg.chanBand = BAND_2GHZ;
4064 		else if (chan->band == IEEE80211_BAND_5GHZ)
4065 			chan_cfg.bandcfg.chanBand = BAND_5GHZ;
4066 		switch (channel_type) {
4067 		case NL80211_CHAN_HT40MINUS:
4068 			chan_cfg.bandcfg.chan2Offset = SEC_CHAN_BELOW;
4069 			break;
4070 		case NL80211_CHAN_HT40PLUS:
4071 			chan_cfg.bandcfg.chan2Offset = SEC_CHAN_ABOVE;
4072 			break;
4073 
4074 		case NL80211_CHAN_NO_HT:
4075 		case NL80211_CHAN_HT20:
4076 		default:
4077 			break;
4078 		}
4079 		chan_cfg.channel =
4080 			ieee80211_frequency_to_channel(chan->center_freq);
4081 		chan_cfg.remain_period = duration;
4082 	}
4083 	if (MLAN_STATUS_SUCCESS ==
4084 	    woal_set_remain_channel_ioctl(priv, wait_option, &chan_cfg))
4085 		*status = chan_cfg.status;
4086 	else
4087 		ret = -EFAULT;
4088 	LEAVE();
4089 	return ret;
4090 }
4091 
4092 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
4093 /**
4094  * @brief tx mgmt frame
4095  *
4096  * @param wiphy                 A pointer to wiphy structure
4097  * @param wdev                  A pointer to wireless_dev structure
4098  * @param cookie                A pointer to frame cookie
4099  *
4100  * @return                0 -- success, otherwise fail
4101  */
4102 static int
woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy * wiphy,struct wireless_dev * wdev,u64 cookie)4103 woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
4104 				  struct wireless_dev *wdev, u64 cookie)
4105 #else
4106 /**
4107  * @brief tx mgmt frame
4108  *
4109  * @param wiphy                 A pointer to wiphy structure
4110  * @param dev                   A pointer to net_device structure
4111  * @param cookie                A pointer to frame cookie
4112  *
4113  * @return                0 -- success, otherwise fail
4114  */
4115 static int
4116 woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
4117 				  struct net_device *dev, u64 cookie)
4118 #endif
4119 {
4120 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
4121 	struct net_device *dev = wdev->netdev;
4122 #endif
4123 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
4124 	int ret = 0;
4125 	t_u8 status = 1;
4126 	moal_private *remain_priv = NULL;
4127 
4128 	ENTER();
4129 
4130 	if (priv->phandle->remain_on_channel) {
4131 		remain_priv =
4132 			priv->phandle->priv[priv->phandle->remain_bss_index];
4133 		if (!remain_priv) {
4134 			PRINTM(MERROR,
4135 			       "mgmt_tx_cancel_wait: Wrong remain_bss_index=%d\n",
4136 			       priv->phandle->remain_bss_index);
4137 			ret = -EFAULT;
4138 			goto done;
4139 		}
4140 		if (woal_cfg80211_remain_on_channel_cfg
4141 		    (remain_priv, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0,
4142 		     0)) {
4143 			PRINTM(MERROR,
4144 			       "mgmt_tx_cancel_wait: Fail to cancel remain on channel\n");
4145 			ret = -EFAULT;
4146 			goto done;
4147 		}
4148 		if (priv->phandle->cookie) {
4149 			cfg80211_remain_on_channel_expired(
4150 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
4151 								  remain_priv->
4152 								  netdev,
4153 #else
4154 								  remain_priv->
4155 								  wdev,
4156 #endif
4157 								  priv->
4158 								  phandle->
4159 								  cookie,
4160 								  &priv->
4161 								  phandle->chan,
4162 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
4163 								  priv->
4164 								  phandle->
4165 								  channel_type,
4166 #endif
4167 								  GFP_ATOMIC);
4168 			priv->phandle->cookie = 0;
4169 		}
4170 		priv->phandle->remain_on_channel = MFALSE;
4171 	}
4172 
4173 done:
4174 	LEAVE();
4175 	return ret;
4176 }
4177 
4178 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
4179 /**
4180  * @brief Make chip remain on channel
4181  *
4182  * @param wiphy                 A pointer to wiphy structure
4183  * @param wdev                  A pointer to wireless_dev structure
4184  * @param chan                  A pointer to ieee80211_channel structure
4185  * @param channel_type          Channel type
4186  * @param duration              Duration for timer
4187  * @param cookie                A pointer to timer cookie
4188  *
4189  * @return                  0 -- success, otherwise fail
4190  */
4191 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)4192 woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
4193 				struct wireless_dev *wdev,
4194 				struct ieee80211_channel *chan,
4195 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
4196 				enum nl80211_channel_type channel_type,
4197 #endif
4198 				unsigned int duration, u64 * cookie)
4199 #else
4200 /**
4201  * @brief Make chip remain on channel
4202  *
4203  * @param wiphy                 A pointer to wiphy structure
4204  * @param dev                   A pointer to net_device structure
4205  * @param chan                  A pointer to ieee80211_channel structure
4206  * @param channel_type          Channel type
4207  * @param duration              Duration for timer
4208  * @param cookie                A pointer to timer cookie
4209  *
4210  * @return                  0 -- success, otherwise fail
4211  */
4212 static int
4213 woal_cfg80211_remain_on_channel(struct wiphy *wiphy,
4214 				struct net_device *dev,
4215 				struct ieee80211_channel *chan,
4216 				enum nl80211_channel_type channel_type,
4217 				unsigned int duration, u64 * cookie)
4218 #endif
4219 {
4220 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
4221 	struct net_device *dev = wdev->netdev;
4222 #endif
4223 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
4224 	int ret = 0;
4225 	t_u8 status = 1;
4226 	moal_private *remain_priv = NULL;
4227 
4228 	ENTER();
4229 
4230 	if (!chan || !cookie) {
4231 		PRINTM(MERROR, "Invalid parameter for remain on channel\n");
4232 		ret = -EFAULT;
4233 		goto done;
4234 	}
4235 	/** cancel previous remain on channel */
4236 	if (priv->phandle->remain_on_channel &&
4237 	    ((priv->phandle->chan.center_freq != chan->center_freq)
4238 	    )) {
4239 		remain_priv =
4240 			priv->phandle->priv[priv->phandle->remain_bss_index];
4241 		if (!remain_priv) {
4242 			PRINTM(MERROR,
4243 			       "remain_on_channel: Wrong remain_bss_index=%d\n",
4244 			       priv->phandle->remain_bss_index);
4245 			ret = -EFAULT;
4246 			goto done;
4247 		}
4248 		if (woal_cfg80211_remain_on_channel_cfg
4249 		    (remain_priv, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0,
4250 		     0)) {
4251 			PRINTM(MERROR,
4252 			       "remain_on_channel: Fail to cancel remain on channel\n");
4253 			ret = -EFAULT;
4254 			goto done;
4255 		}
4256 		priv->phandle->cookie = 0;
4257 		priv->phandle->remain_on_channel = MFALSE;
4258 	}
4259 	if (MLAN_STATUS_SUCCESS !=
4260 	    woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT,
4261 						MFALSE, &status, chan,
4262 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
4263 						channel_type,
4264 #else
4265 						0,
4266 #endif
4267 						(t_u32)duration)) {
4268 		ret = -EFAULT;
4269 		goto done;
4270 	}
4271 
4272 	if (status) {
4273 		PRINTM(MMSG,
4274 		       "%s: Set remain on Channel: channel=%d with status=%d\n",
4275 		       dev->name,
4276 		       ieee80211_frequency_to_channel(chan->center_freq),
4277 		       status);
4278 		if (!priv->phandle->remain_on_channel) {
4279 			priv->phandle->is_remain_timer_set = MTRUE;
4280 			woal_mod_timer(&priv->phandle->remain_timer, duration);
4281 		}
4282 	}
4283 
4284 	/* remain on channel operation success */
4285 	/* we need update the value cookie */
4286 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
4287 	*cookie = (u64) random32() | 1;
4288 #else
4289 	*cookie = (u64) prandom_u32() | 1;
4290 #endif
4291 	priv->phandle->remain_on_channel = MTRUE;
4292 	priv->phandle->remain_bss_index = priv->bss_index;
4293 	priv->phandle->cookie = *cookie;
4294 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
4295 	priv->phandle->channel_type = channel_type;
4296 #endif
4297 	memcpy(&priv->phandle->chan, chan, sizeof(struct ieee80211_channel));
4298 
4299 	if (status == 0)
4300 		PRINTM(MIOCTL,
4301 		       "%s: Set remain on Channel: channel=%d cookie = %#llx\n",
4302 		       dev->name,
4303 		       ieee80211_frequency_to_channel(chan->center_freq),
4304 		       priv->phandle->cookie);
4305 
4306 	cfg80211_ready_on_channel(
4307 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
4308 					 dev,
4309 #else
4310 					 priv->wdev,
4311 #endif
4312 					 *cookie, chan,
4313 #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
4314 					 channel_type,
4315 #endif
4316 					 duration, GFP_KERNEL);
4317 
4318 done:
4319 	LEAVE();
4320 	return ret;
4321 }
4322 
4323 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
4324 /**
4325  * @brief Cancel remain on channel
4326  *
4327  * @param wiphy                 A pointer to wiphy structure
4328  * @param wdev                  A pointer to wireless_dev structure
4329  * @param cookie                A pointer to timer cookie
4330  *
4331  * @return                  0 -- success, otherwise fail
4332  */
4333 static int
woal_cfg80211_cancel_remain_on_channel(struct wiphy * wiphy,struct wireless_dev * wdev,u64 cookie)4334 woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4335 				       struct wireless_dev *wdev, u64 cookie)
4336 #else
4337 /**
4338  * @brief Cancel remain on channel
4339  *
4340  * @param wiphy                 A pointer to wiphy structure
4341  * @param dev                   A pointer to net_device structure
4342  * @param cookie                A pointer to timer cookie
4343  *
4344  * @return                  0 -- success, otherwise fail
4345  */
4346 static int
4347 woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
4348 				       struct net_device *dev, u64 cookie)
4349 #endif
4350 {
4351 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
4352 	struct net_device *dev = wdev->netdev;
4353 #endif
4354 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
4355 	moal_private *remain_priv = NULL;
4356 	int ret = 0;
4357 	t_u8 status = 1;
4358 
4359 	ENTER();
4360 	PRINTM(MIOCTL, "Cancel remain on Channel: cookie = %#llx\n", cookie);
4361 	remain_priv = priv->phandle->priv[priv->phandle->remain_bss_index];
4362 	if (!remain_priv) {
4363 		PRINTM(MERROR,
4364 		       "cancel_remain_on_channel: Wrong remain_bss_index=%d\n",
4365 		       priv->phandle->remain_bss_index);
4366 		ret = -EFAULT;
4367 		goto done;
4368 	}
4369 	if (woal_cfg80211_remain_on_channel_cfg
4370 	    (remain_priv, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) {
4371 		PRINTM(MERROR,
4372 		       "cancel_remain_on_channel: Fail to cancel remain on channel\n");
4373 		ret = -EFAULT;
4374 		goto done;
4375 	}
4376 
4377 	priv->phandle->remain_on_channel = MFALSE;
4378 	if (priv->phandle->cookie)
4379 		priv->phandle->cookie = 0;
4380 done:
4381 	LEAVE();
4382 	return ret;
4383 }
4384 #endif /* KERNEL_VERSION */
4385 
4386 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
4387 /**
4388  * @brief start sched scan
4389  *
4390  * @param wiphy                 A pointer to wiphy structure
4391  * @param dev                   A pointer to net_device structure
4392  * @param request               A pointer to struct cfg80211_sched_scan_request
4393  *
4394  * @return                  0 -- success, otherwise fail
4395  */
4396 int
woal_cfg80211_sched_scan_start(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_sched_scan_request * request)4397 woal_cfg80211_sched_scan_start(struct wiphy *wiphy,
4398 			       struct net_device *dev,
4399 			       struct cfg80211_sched_scan_request *request)
4400 {
4401 	struct ieee80211_channel *chan = NULL;
4402 	int i = 0;
4403 	int ret = 0;
4404 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
4405 	struct cfg80211_ssid *ssid = NULL;
4406 	ENTER();
4407 #ifdef UAP_CFG80211
4408 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
4409 		LEAVE();
4410 		return -EFAULT;
4411 	}
4412 #endif
4413 
4414 	memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg));
4415 	if (!request) {
4416 		PRINTM(MERROR, "Invalid sched_scan req parameter\n");
4417 		LEAVE();
4418 		return -EINVAL;
4419 	}
4420 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
4421 	PRINTM(MIOCTL,
4422 	       "%s sched scan: n_ssids=%d n_match_sets=%d n_channels=%d interval=%d ie_len=%d\n",
4423 	       priv->netdev->name, request->n_ssids, request->n_match_sets,
4424 	       request->n_channels, request->scan_plans[0].interval,
4425 	       (int)request->ie_len);
4426 #else
4427 	PRINTM(MIOCTL,
4428 	       "%s sched scan: n_ssids=%d n_match_sets=%d n_channels=%d interval=%d ie_len=%d\n",
4429 	       priv->netdev->name, request->n_ssids, request->n_match_sets,
4430 	       request->n_channels, request->interval, (int)request->ie_len);
4431 #endif
4432     /** We have pending scan, start bgscan later */
4433 	if (priv->phandle->scan_pending_on_block)
4434 		priv->scan_cfg.start_later = MTRUE;
4435 	for (i = 0; i < request->n_match_sets; i++) {
4436 		ssid = &request->match_sets[i].ssid;
4437 		strncpy(priv->scan_cfg.ssid_list[i].ssid, ssid->ssid,
4438 			ssid->ssid_len);
4439 		priv->scan_cfg.ssid_list[i].max_len = 0;
4440 		PRINTM(MIOCTL, "sched scan: ssid=%s\n", ssid->ssid);
4441 	}
4442 	/** Add broadcast scan, when n_match_sets = 0 */
4443 	if (!request->n_match_sets)
4444 		priv->scan_cfg.ssid_list[0].max_len = 0xff;
4445 	for (i = 0; i < MIN(WLAN_BG_SCAN_CHAN_MAX, request->n_channels); i++) {
4446 		chan = request->channels[i];
4447 		priv->scan_cfg.chan_list[i].chan_number = chan->hw_value;
4448 		priv->scan_cfg.chan_list[i].radio_type = chan->band;
4449 		if (chan->
4450 		    flags & (IEEE80211_CHAN_PASSIVE_SCAN |
4451 			     IEEE80211_CHAN_RADAR))
4452 			priv->scan_cfg.chan_list[i].scan_type =
4453 				MLAN_SCAN_TYPE_PASSIVE;
4454 		else
4455 			priv->scan_cfg.chan_list[i].scan_type =
4456 				MLAN_SCAN_TYPE_ACTIVE;
4457 		priv->scan_cfg.chan_list[i].scan_time = 0;
4458 #ifdef WIFI_DIRECT_SUPPORT
4459 		if (priv->phandle->miracast_mode)
4460 			priv->scan_cfg.chan_list[i].scan_time =
4461 				priv->phandle->miracast_scan_time;
4462 #endif
4463 	}
4464 	priv->scan_cfg.chan_per_scan =
4465 		MIN(WLAN_BG_SCAN_CHAN_MAX, request->n_channels);
4466 
4467 	/** set scan request IES */
4468 	if (request->ie && request->ie_len) {
4469 		if (MLAN_STATUS_SUCCESS !=
4470 		    woal_cfg80211_mgmt_frame_ie(priv, NULL, 0,
4471 						NULL, 0, NULL, 0,
4472 						(t_u8 *)request->ie,
4473 						request->ie_len,
4474 						MGMT_MASK_PROBE_REQ,
4475 						MOAL_IOCTL_WAIT)) {
4476 			PRINTM(MERROR, "Fail to set sched scan IE\n");
4477 			ret = -EFAULT;
4478 			goto done;
4479 		}
4480 	} else {
4481 		/** Clear SCAN IE in Firmware */
4482 		if (priv->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK)
4483 			woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0,
4484 						    NULL, 0, NULL, 0,
4485 						    MGMT_MASK_PROBE_REQ,
4486 						    MOAL_IOCTL_WAIT);
4487 	}
4488 
4489 	/* Interval between scan cycles in milliseconds,supplicant set to 10 second */
4490 	/* We want to use 30 second for per scan cycle */
4491 	priv->scan_cfg.scan_interval = MIN_BGSCAN_INTERVAL;
4492 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
4493 	/* only support 1 scan plan now */
4494 	if (request->scan_plans[0].interval > MIN_BGSCAN_INTERVAL)
4495 		priv->scan_cfg.scan_interval = request->scan_plans[0].interval;
4496 #else
4497 	if (request->interval > MIN_BGSCAN_INTERVAL)
4498 		priv->scan_cfg.scan_interval = request->interval;
4499 #endif
4500 	priv->scan_cfg.repeat_count = DEF_REPEAT_COUNT;
4501 	priv->scan_cfg.report_condition =
4502 		BG_SCAN_SSID_MATCH | BG_SCAN_WAIT_ALL_CHAN_DONE;
4503 	priv->scan_cfg.bss_type = MLAN_BSS_MODE_INFRA;
4504 	priv->scan_cfg.action = BG_SCAN_ACT_SET;
4505 	priv->scan_cfg.enable = MTRUE;
4506 #ifdef WIFI_DIRECT_SUPPORT
4507 	if (priv->phandle->miracast_mode)
4508 		priv->scan_cfg.scan_chan_gap = priv->phandle->scan_chan_gap;
4509 	else
4510 		priv->scan_cfg.scan_chan_gap = 0;
4511 #endif
4512 
4513 	if (MLAN_STATUS_SUCCESS ==
4514 	    woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &priv->scan_cfg)) {
4515 		priv->sched_scanning = MTRUE;
4516 		priv->bg_scan_start = MTRUE;
4517 		priv->bg_scan_reported = MFALSE;
4518 	} else
4519 		ret = -EFAULT;
4520 done:
4521 	LEAVE();
4522 	return ret;
4523 }
4524 
4525 /**
4526  * @brief stop sched scan
4527  *
4528  * @param wiphy                 A pointer to wiphy structure
4529  * @param dev                   A pointer to net_device structure
4530  *
4531  * @return                      0 -- success, otherwise fail
4532  */
4533 int
woal_cfg80211_sched_scan_stop(struct wiphy * wiphy,struct net_device * dev,u64 reqid)4534 woal_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev
4535 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
4536 			      , u64 reqid
4537 #endif
4538 	)
4539 {
4540 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
4541 	ENTER();
4542 	PRINTM(MIOCTL, "sched scan stop\n");
4543 	priv->sched_scanning = MFALSE;
4544 	woal_stop_bg_scan(priv, MOAL_NO_WAIT);
4545 	priv->bg_scan_start = MFALSE;
4546 	priv->bg_scan_reported = MFALSE;
4547 	LEAVE();
4548 	return 0;
4549 }
4550 #endif
4551 
4552 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
4553 /**
4554  * @brief cfg80211_resume handler
4555  *
4556  * @param wiphy                 A pointer to wiphy structure
4557  *
4558  * @return                      0 -- success, otherwise fail
4559  */
4560 int
woal_cfg80211_resume(struct wiphy * wiphy)4561 woal_cfg80211_resume(struct wiphy *wiphy)
4562 {
4563 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
4564 	moal_private *priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA);
4565 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) && defined(CONFIG_PM)
4566 	struct cfg80211_wowlan_wakeup wakeup_report;
4567 #endif
4568 	mlan_ds_hs_wakeup_reason wakeup_reason;
4569 	int i;
4570 
4571 	PRINTM(MCMND, "<--- Enter woal_cfg80211_resume --->\n");
4572 	for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
4573 		if (handle->priv[i] &&
4574 		    (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
4575 			if (handle->priv[i]->last_event & EVENT_BG_SCAN_REPORT) {
4576 				if (handle->priv[i]->sched_scanning) {
4577 					woal_inform_bss_from_scan_result
4578 						(handle->priv[i], NULL,
4579 						 MOAL_IOCTL_WAIT);
4580 					cfg80211_sched_scan_results(handle->
4581 								    priv[i]->
4582 								    wdev->wiphy
4583 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
4584 								    , 0
4585 #endif
4586 						);
4587 					handle->priv[i]->last_event = 0;
4588 					PRINTM(MIOCTL,
4589 					       "Report sched scan result in cfg80211 resume\n");
4590 				}
4591 				if (!hw_test &&
4592 				    handle->priv[i]->roaming_enabled) {
4593 					handle->priv[i]->roaming_required =
4594 						MTRUE;
4595 #ifdef ANDROID_KERNEL
4596 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
4597 					__pm_wakeup_event(&handle->ws,
4598 							  ROAMING_WAKE_LOCK_TIMEOUT);
4599 #else
4600 					wake_lock_timeout(&handle->wake_lock,
4601 							  ROAMING_WAKE_LOCK_TIMEOUT);
4602 #endif
4603 #endif
4604 					wake_up_interruptible(&handle->
4605 							      reassoc_thread.
4606 							      wait_q);
4607 				}
4608 			}
4609 		}
4610 	}
4611 
4612 	woal_get_wakeup_reason(priv, &wakeup_reason);
4613 
4614 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) && defined(CONFIG_PM)
4615 	memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup));
4616 	wakeup_report.pattern_idx = -1;
4617 
4618 	switch (wakeup_reason.hs_wakeup_reason) {
4619 	case NO_HSWAKEUP_REASON:
4620 		break;
4621 	case BCAST_DATA_MATCHED:
4622 		break;
4623 	case MCAST_DATA_MATCHED:
4624 		break;
4625 	case UCAST_DATA_MATCHED:
4626 		break;
4627 	case MASKTABLE_EVENT_MATCHED:
4628 		break;
4629 	case NON_MASKABLE_EVENT_MATCHED:
4630 		break;
4631 	case NON_MASKABLE_CONDITION_MATCHED:
4632 		if (wiphy->wowlan_config->disconnect)
4633 			wakeup_report.disconnect = true;
4634 		break;
4635 	case MAGIC_PATTERN_MATCHED:
4636 		if (wiphy->wowlan_config->magic_pkt)
4637 			wakeup_report.magic_pkt = true;
4638 		if (wiphy->wowlan_config->n_patterns)
4639 			wakeup_report.pattern_idx = 1;
4640 		break;
4641 	case CONTROL_FRAME_MATCHED:
4642 		break;
4643 	case MANAGEMENT_FRAME_MATCHED:
4644 		break;
4645 	case GTK_REKEY_FAILURE:
4646 		if (wiphy->wowlan_config->gtk_rekey_failure)
4647 			wakeup_report.gtk_rekey_failure = true;
4648 		break;
4649 	default:
4650 		break;
4651 	}
4652 
4653 	if ((wakeup_reason.hs_wakeup_reason > 0) &&
4654 	    (wakeup_reason.hs_wakeup_reason <= 10)) {
4655 		cfg80211_report_wowlan_wakeup(priv->wdev, &wakeup_report,
4656 					      GFP_KERNEL);
4657 	}
4658 #endif
4659 
4660 	handle->cfg80211_suspend = MFALSE;
4661 	PRINTM(MCMND, "<--- Leave woal_cfg80211_resume --->\n");
4662 	return 0;
4663 }
4664 
4665 /**
4666  * @brief cfg80211_suspend handler
4667  *
4668  * @param wiphy                 A pointer to wiphy structure
4669  * @param wow                   A pointer to cfg80211_wowlan
4670  *
4671  * @return                      0 -- success, otherwise fail
4672  */
4673 int
woal_cfg80211_suspend(struct wiphy * wiphy,struct cfg80211_wowlan * wow)4674 woal_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
4675 {
4676 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
4677 	int i;
4678 	int ret = 0;
4679 
4680 	PRINTM(MCMND, "<--- Enter woal_cfg80211_suspend --->\n");
4681 	for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) {
4682 		if (handle->priv[i] &&
4683 		    (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) {
4684 			if (handle->scan_request) {
4685 				PRINTM(MIOCTL,
4686 				       "Cancel pending scan in woal_cfg80211_suspend\n");
4687 				woal_cancel_scan(handle->priv[i],
4688 						 MOAL_IOCTL_WAIT);
4689 			}
4690 			handle->priv[i]->last_event = 0;
4691 		}
4692 	}
4693 
4694 	handle->cfg80211_suspend = MTRUE;
4695 
4696 	PRINTM(MCMND, "<--- Leave woal_cfg80211_suspend --->\n");
4697 	return ret;
4698 }
4699 #endif
4700 
4701 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
4702 static void
woal_cfg80211_set_wakeup(struct wiphy * wiphy,bool enabled)4703 woal_cfg80211_set_wakeup(struct wiphy *wiphy, bool enabled)
4704 {
4705 	moal_handle *handle = (moal_handle *)woal_get_wiphy_priv(wiphy);
4706 
4707 	device_set_wakeup_enable(handle->hotplug_device, enabled);
4708 }
4709 #endif
4710 
4711 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,2,0)
4712 /**
4713  *  @brief TDLS operation ioctl handler
4714  *
4715  *  @param priv     A pointer to moal_private structure
4716  *  @param peer     A pointer to peer mac
4717  *  @apram action   action for TDLS
4718  *  @return         0 --success, otherwise fail
4719  */
4720 static int
woal_tdls_oper(moal_private * priv,u8 * peer,t_u8 action)4721 woal_tdls_oper(moal_private *priv, u8 *peer, t_u8 action)
4722 {
4723 	mlan_ioctl_req *ioctl_req = NULL;
4724 	mlan_ds_misc_cfg *misc = NULL;
4725 	int ret = 0;
4726 	mlan_status status = MLAN_STATUS_SUCCESS;
4727 
4728 	ENTER();
4729 
4730 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
4731 	if (ioctl_req == NULL) {
4732 		ret = -ENOMEM;
4733 		goto done;
4734 	}
4735 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
4736 	misc->sub_command = MLAN_OID_MISC_TDLS_OPER;
4737 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
4738 	ioctl_req->action = MLAN_ACT_SET;
4739 	misc->param.tdls_oper.tdls_action = action;
4740 	memcpy(misc->param.tdls_oper.peer_mac, peer, ETH_ALEN);
4741 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
4742 	if (status != MLAN_STATUS_SUCCESS) {
4743 		ret = -EFAULT;
4744 		goto done;
4745 	}
4746 done:
4747 	if (status != MLAN_STATUS_PENDING)
4748 		kfree(ioctl_req);
4749 	LEAVE();
4750 	return ret;
4751 }
4752 
4753 /**
4754  *  @brief TDLS operation ioctl handler
4755  *
4756  *  @param priv         A pointer to moal_private structure
4757  *  @param peer         A pointer to peer mac
4758  *  @param tdls_ies     A pointer to mlan_ds_misc_tdls_ies structure
4759  *  @param flags        TDLS ie flags
4760  *
4761  *  @return         0 --success, otherwise fail
4762  */
4763 static int
woal_tdls_get_ies(moal_private * priv,u8 * peer,mlan_ds_misc_tdls_ies * tdls_ies,t_u16 flags)4764 woal_tdls_get_ies(moal_private *priv, u8 *peer, mlan_ds_misc_tdls_ies *tdls_ies,
4765 		  t_u16 flags)
4766 {
4767 	mlan_ioctl_req *ioctl_req = NULL;
4768 	mlan_ds_misc_cfg *misc = NULL;
4769 	int ret = 0;
4770 	mlan_status status = MLAN_STATUS_SUCCESS;
4771 
4772 	ENTER();
4773 
4774 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
4775 	if (ioctl_req == NULL) {
4776 		ret = -ENOMEM;
4777 		goto done;
4778 	}
4779 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
4780 	misc->sub_command = MLAN_OID_MISC_GET_TDLS_IES;
4781 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
4782 	ioctl_req->action = MLAN_ACT_GET;
4783 	misc->param.tdls_ies.flags = flags;
4784 	memcpy(misc->param.tdls_ies.peer_mac, peer, ETH_ALEN);
4785 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
4786 	if (status != MLAN_STATUS_SUCCESS) {
4787 		ret = -EFAULT;
4788 		goto done;
4789 	}
4790 	if (tdls_ies)
4791 		memcpy(tdls_ies, &misc->param.tdls_ies,
4792 		       sizeof(mlan_ds_misc_tdls_ies));
4793 done:
4794 	if (status != MLAN_STATUS_PENDING)
4795 		kfree(ioctl_req);
4796 	LEAVE();
4797 	return ret;
4798 }
4799 
4800 /**
4801  * @brief append tdls ext_capability
4802  *
4803  * @param skb                   A pointer to sk_buff structure
4804  *
4805  * @return                      N/A
4806  */
4807 static void
woal_tdls_add_ext_capab(struct sk_buff * skb,mlan_ds_misc_tdls_ies * tdls_ies)4808 woal_tdls_add_ext_capab(struct sk_buff *skb, mlan_ds_misc_tdls_ies *tdls_ies)
4809 {
4810 	u8 *pos = NULL;
4811 	if (tdls_ies->ext_cap[0] == WLAN_EID_EXT_CAPABILITY) {
4812 		pos = (void *)skb_put(skb, sizeof(IEEEtypes_ExtCap_t));
4813 		memcpy(pos, tdls_ies->ext_cap, sizeof(IEEEtypes_ExtCap_t));
4814 	} else {
4815 		PRINTM(MERROR, "Fail to append tdls ext_capability\n");
4816 	}
4817 }
4818 
4819 /**
4820  * @brief append supported rates
4821  *
4822  * @param priv                  A pointer to moal_private structure
4823  * @param skb                   A pointer to sk_buff structure
4824  * @param band                  AP's band
4825  *
4826  * @return                      N/A
4827  */
4828 static void
woal_add_supported_rates_ie(moal_private * priv,struct sk_buff * skb,enum ieee80211_band band)4829 woal_add_supported_rates_ie(moal_private *priv, struct sk_buff *skb,
4830 			    enum ieee80211_band band)
4831 {
4832 	t_u8 basic_rates[] = {
4833 		0x82, 0x84, 0x8b, 0x96,
4834 		0x0c, 0x12, 0x18, 0x24
4835 	};
4836 	t_u8 basic_rates_5G[] = {
4837 		0x0c, 0x12, 0x18, 0x24,
4838 		0x30, 0x48, 0x60, 0x6c
4839 	};
4840 	t_u8 *pos;
4841 	t_u8 rate_num = 0;
4842 	if (band == IEEE80211_BAND_2GHZ)
4843 		rate_num = sizeof(basic_rates);
4844 	else
4845 		rate_num = sizeof(basic_rates_5G);
4846 
4847 	if (skb_tailroom(skb) < rate_num + 2)
4848 		return;
4849 
4850 	pos = skb_put(skb, rate_num + 2);
4851 	*pos++ = WLAN_EID_SUPP_RATES;
4852 	*pos++ = rate_num;
4853 	if (band == IEEE80211_BAND_2GHZ)
4854 		memcpy(pos, basic_rates, rate_num);
4855 	else
4856 		memcpy(pos, basic_rates_5G, rate_num);
4857 	return;
4858 }
4859 
4860 /**
4861  * @brief append ext_supported rates
4862  *
4863  * @param priv                  A pointer to moal_private structure
4864  * @param skb                   A pointer to sk_buff structure
4865  * @param band                  AP's band
4866  *
4867  * @return                      N/A
4868  */
4869 static void
woal_add_ext_supported_rates_ie(moal_private * priv,struct sk_buff * skb,enum ieee80211_band band)4870 woal_add_ext_supported_rates_ie(moal_private *priv, struct sk_buff *skb,
4871 				enum ieee80211_band band)
4872 {
4873 	t_u8 ext_rates[] = { 0x0c, 0x12, 0x18, 0x60 };
4874 	t_u8 *pos;
4875 	t_u8 rate_num = sizeof(ext_rates);
4876 
4877 	if (band != IEEE80211_BAND_2GHZ)
4878 		return;
4879 
4880 	if (skb_tailroom(skb) < rate_num + 2)
4881 		return;
4882 
4883 	pos = skb_put(skb, rate_num + 2);
4884 	*pos++ = WLAN_EID_EXT_SUPP_RATES;
4885 	*pos++ = rate_num;
4886 	memcpy(pos, ext_rates, rate_num);
4887 	return;
4888 }
4889 
4890 /**
4891  * @brief append wmm ie
4892  *
4893  * @param priv                  A pointer to moal_private structure
4894  * @param skb                   A pointer to sk_buff structure
4895  * @param wmm_type         WMM_TYPE_INFO/WMM_TYPE_PARAMETER
4896   * @param pQosInfo           A pointer to qos info
4897  *
4898  * @return                      N/A
4899  */
4900 static void
woal_add_wmm_ie(moal_private * priv,struct sk_buff * skb,t_u8 wmm_type,t_u8 * pQosInfo)4901 woal_add_wmm_ie(moal_private *priv, struct sk_buff *skb, t_u8 wmm_type,
4902 		t_u8 *pQosInfo)
4903 {
4904 	t_u8 wmmInfoElement[] = { 0x00, 0x50, 0xf2,
4905 		0x02, 0x00, 0x01
4906 	};
4907 	t_u8 wmmParamElement[] = { 0x00, 0x50, 0xf2,
4908 		0x02, 0x01, 0x01
4909 	};
4910 	t_u8 ac_vi[] = { 0x42, 0x43, 0x5e, 0x00 };
4911 	t_u8 ac_vo[] = { 0x62, 0x32, 0x2f, 0x00 };
4912 	t_u8 ac_be[] = { 0x03, 0xa4, 0x00, 0x00 };
4913 	t_u8 ac_bk[] = { 0x27, 0xa4, 0x00, 0x00 };
4914 	t_u8 qosInfo = 0x0;
4915 	t_u8 reserved = 0;
4916 	t_u8 wmm_id = 221;
4917 	t_u8 wmmParamIe_len = 24;
4918 	t_u8 wmmInfoIe_len = 7;
4919 	t_u8 len = 0;
4920 	t_u8 *pos;
4921 
4922 	if (skb_tailroom(skb) < wmmParamIe_len + 2)
4923 		return;
4924 
4925 	qosInfo = (pQosInfo == NULL) ? 0xf : (*pQosInfo);
4926 	/*wmm parameter */
4927 	if (wmm_type == WMM_TYPE_PARAMETER) {
4928 		pos = skb_put(skb, wmmParamIe_len + 2);
4929 		len = wmmParamIe_len;
4930 	} else {
4931 		pos = skb_put(skb, wmmInfoIe_len + 2);
4932 		len = wmmInfoIe_len;
4933 	}
4934 
4935 	*pos++ = wmm_id;
4936 	*pos++ = len;
4937 	/*wmm parameter */
4938 	if (wmm_type == WMM_TYPE_PARAMETER) {
4939 		memcpy(pos, wmmParamElement, sizeof(wmmParamElement));
4940 		pos += sizeof(wmmParamElement);
4941 	} else {
4942 		memcpy(pos, wmmInfoElement, sizeof(wmmInfoElement));
4943 		pos += sizeof(wmmInfoElement);
4944 	}
4945 	*pos++ = qosInfo;
4946 	/*wmm parameter */
4947 	if (wmm_type == WMM_TYPE_PARAMETER) {
4948 		*pos++ = reserved;
4949 		memcpy(pos, ac_be, sizeof(ac_be));
4950 		pos += sizeof(ac_be);
4951 		memcpy(pos, ac_bk, sizeof(ac_bk));
4952 		pos += sizeof(ac_bk);
4953 		memcpy(pos, ac_vi, sizeof(ac_vi));
4954 		pos += sizeof(ac_vi);
4955 		memcpy(pos, ac_vo, sizeof(ac_vo));
4956 	}
4957 	return;
4958 }
4959 
4960 /**
4961  * @brief update tdls peer status
4962  *
4963  * @param priv                  A pointer to moal_private structure
4964  * @param peer_addr             A point to peer mac address
4965  * @param link_status           link status
4966  *
4967  * @return                      N/A
4968 */
4969 t_void
woal_updata_peer_status(moal_private * priv,t_u8 * peer_addr,tdlsStatus_e link_status)4970 woal_updata_peer_status(moal_private *priv, t_u8 *peer_addr,
4971 			tdlsStatus_e link_status)
4972 {
4973 	struct tdls_peer *peer = NULL;
4974 	unsigned long flags;
4975 	if (priv && priv->enable_auto_tdls) {
4976 		spin_lock_irqsave(&priv->tdls_lock, flags);
4977 		list_for_each_entry(peer, &priv->tdls_list, link) {
4978 			if (!memcmp(peer->peer_addr, peer_addr, ETH_ALEN)) {
4979 				if ((link_status == TDLS_NOT_SETUP) &&
4980 				    (peer->link_status ==
4981 				     TDLS_SETUP_INPROGRESS))
4982 					peer->num_failure++;
4983 				else if (link_status == TDLS_SETUP_COMPLETE)
4984 					peer->num_failure = 0;
4985 				peer->link_status = link_status;
4986 				break;
4987 			}
4988 		}
4989 		spin_unlock_irqrestore(&priv->tdls_lock, flags);
4990 	}
4991 }
4992 
4993 /**
4994  * @brief add tdls peer
4995  *
4996  * @param priv                  A pointer to moal_private structure
4997  * @param peer                  A point to peer address
4998  *
4999  * @return                      N/A
5000 */
5001 t_void
woal_add_tdls_peer(moal_private * priv,t_u8 * peer)5002 woal_add_tdls_peer(moal_private *priv, t_u8 *peer)
5003 {
5004 	struct tdls_peer *tdls_peer = NULL;
5005 	unsigned long flags;
5006 	t_u8 find_peer = MFALSE;
5007 	if (priv && priv->enable_auto_tdls) {
5008 		spin_lock_irqsave(&priv->tdls_lock, flags);
5009 		list_for_each_entry(tdls_peer, &priv->tdls_list, link) {
5010 			if (!memcmp(tdls_peer->peer_addr, peer, ETH_ALEN)) {
5011 				tdls_peer->link_status = TDLS_SETUP_INPROGRESS;
5012 				tdls_peer->rssi_jiffies = jiffies;
5013 				find_peer = MTRUE;
5014 				break;
5015 			}
5016 		}
5017 		if (!find_peer) {
5018 			/* create new TDLS peer */
5019 			tdls_peer =
5020 				kzalloc(sizeof(struct tdls_peer), GFP_ATOMIC);
5021 			if (tdls_peer) {
5022 				memcpy(tdls_peer->peer_addr, peer, ETH_ALEN);
5023 				tdls_peer->link_status = TDLS_SETUP_INPROGRESS;
5024 				tdls_peer->rssi_jiffies = jiffies;
5025 				INIT_LIST_HEAD(&tdls_peer->link);
5026 				list_add_tail(&tdls_peer->link,
5027 					      &priv->tdls_list);
5028 				PRINTM(MCMND,
5029 				       "Add to TDLS list: peer=" MACSTR "\n",
5030 				       MAC2STR(peer));
5031 			}
5032 		}
5033 		spin_unlock_irqrestore(&priv->tdls_lock, flags);
5034 	}
5035 }
5036 
5037 /**
5038  * @brief check auto tdls
5039  *
5040  * @param wiphy                 A pointer to wiphy structure
5041  * @param dev                   A pointer to net_device structure
5042  *
5043  * @return                      N/A
5044 */
5045 void
woal_check_auto_tdls(struct wiphy * wiphy,struct net_device * dev)5046 woal_check_auto_tdls(struct wiphy *wiphy, struct net_device *dev)
5047 {
5048 	t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
5049 	struct tdls_peer *tdls_peer = NULL;
5050 	unsigned long flags;
5051 	t_u8 tdls_discovery = MFALSE;
5052 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5053 
5054 	ENTER();
5055 	if (priv && priv->enable_auto_tdls) {
5056 		priv->tdls_check_tx = MFALSE;
5057 		spin_lock_irqsave(&priv->tdls_lock, flags);
5058 		list_for_each_entry(tdls_peer, &priv->tdls_list, link) {
5059 			if ((jiffies - tdls_peer->rssi_jiffies) >
5060 			    TDLS_IDLE_TIME) {
5061 				tdls_peer->rssi = 0;
5062 				if (tdls_peer->num_failure <
5063 				    TDLS_MAX_FAILURE_COUNT)
5064 					tdls_discovery = MTRUE;
5065 			}
5066 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
5067 			if (tdls_peer->rssi &&
5068 			    (tdls_peer->rssi >= TDLS_RSSI_LOW_THRESHOLD)) {
5069 				if (tdls_peer->link_status ==
5070 				    TDLS_SETUP_COMPLETE) {
5071 					tdls_peer->link_status = TDLS_TEAR_DOWN;
5072 					PRINTM(MMSG,
5073 					       "Wlan: Tear down TDLS link, peer="
5074 					       MACSTR " rssi=%d\n",
5075 					       MAC2STR(tdls_peer->peer_addr),
5076 					       -tdls_peer->rssi);
5077 					cfg80211_tdls_oper_request(dev,
5078 								   tdls_peer->
5079 								   peer_addr,
5080 								   NL80211_TDLS_TEARDOWN,
5081 								   TDLS_TEARN_DOWN_REASON_UNSPECIFIC,
5082 								   GFP_ATOMIC);
5083 				}
5084 			} else if (tdls_peer->rssi &&
5085 				   (tdls_peer->rssi <=
5086 				    TDLS_RSSI_HIGH_THRESHOLD)) {
5087 				if ((tdls_peer->link_status == TDLS_NOT_SETUP)
5088 				    && (tdls_peer->num_failure <
5089 					TDLS_MAX_FAILURE_COUNT)) {
5090 					priv->tdls_check_tx = MTRUE;
5091 					PRINTM(MCMND,
5092 					       "Wlan: Find TDLS peer=" MACSTR
5093 					       " rssi=%d\n",
5094 					       MAC2STR(tdls_peer->peer_addr),
5095 					       -tdls_peer->rssi);
5096 
5097 				}
5098 			}
5099 #endif
5100 		}
5101 		spin_unlock_irqrestore(&priv->tdls_lock, flags);
5102 	}
5103 	if (tdls_discovery)
5104 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
5105 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
5106 		woal_cfg80211_tdls_mgmt(wiphy, dev, bcast_addr,
5107 					TDLS_DISCOVERY_REQUEST, 1, 0, 0, 0,
5108 					NULL, 0);
5109 #else
5110 		woal_cfg80211_tdls_mgmt(wiphy, dev, bcast_addr,
5111 					TDLS_DISCOVERY_REQUEST, 1, 0, 0, NULL,
5112 					0);
5113 #endif
5114 #else
5115 		woal_cfg80211_tdls_mgmt(wiphy, dev, bcast_addr,
5116 					TDLS_DISCOVERY_REQUEST, 1, 0, NULL, 0);
5117 #endif
5118 	LEAVE();
5119 }
5120 
5121 /**
5122  * @brief woal construct tdls data frame
5123  *
5124  * @param priv                  A pointer to moal_private structure
5125  * @param peer                  A pointer to peer mac
5126  * @param action_code           tdls action code
5127  * @param dialog_token          dialog_token
5128  * @param status_code           status_code
5129  * @param skb                   skb buffer
5130  *
5131  * @return                      0 -- success, otherwise fail
5132  */
5133 static int
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)5134 woal_construct_tdls_data_frame(moal_private *priv,
5135 			       t_u8 *peer, t_u8 action_code, t_u8 dialog_token,
5136 			       t_u16 status_code, struct sk_buff *skb)
5137 {
5138 
5139 	struct ieee80211_tdls_data *tf;
5140 	t_u16 capability;
5141 	IEEEtypes_HTCap_t *HTcap;
5142 	IEEEtypes_HTInfo_t *HTInfo;
5143 	IEEEtypes_2040BSSCo_t *BSSCo;
5144 	IEEEtypes_Generic_t *pSupp_chan = NULL, *pRegulatory_class = NULL;
5145 	mlan_ds_misc_tdls_ies *tdls_ies = NULL;
5146 	int ret = 0;
5147 	mlan_bss_info bss_info;
5148 	enum ieee80211_band band;
5149 	mlan_fw_info fw_info;
5150 
5151 	ENTER();
5152 
5153 	memset(&bss_info, 0, sizeof(bss_info));
5154 	if (MLAN_STATUS_SUCCESS !=
5155 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
5156 		PRINTM(MERROR, "Fail to get bss info\n");
5157 		LEAVE();
5158 		return -EFAULT;
5159 	}
5160 	band = woal_band_cfg_to_ieee_band(bss_info.bss_band);
5161 	tdls_ies = kzalloc(sizeof(mlan_ds_misc_tdls_ies), GFP_KERNEL);
5162 	if (!tdls_ies) {
5163 		PRINTM(MERROR, "Fail to alloc memory for tdls_ies\n");
5164 		LEAVE();
5165 		return -ENOMEM;
5166 	}
5167 
5168 	capability = 0x2421;
5169 
5170 	tf = (void *)skb_put(skb, offsetof(struct ieee80211_tdls_data, u));
5171 	memcpy(tf->da, peer, ETH_ALEN);
5172 	memcpy(tf->sa, priv->current_addr, ETH_ALEN);
5173 	tf->ether_type = cpu_to_be16(MLAN_ETHER_PKT_TYPE_TDLS_ACTION);
5174 	tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
5175 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
5176 
5177 	switch (action_code) {
5178 	case WLAN_TDLS_SETUP_REQUEST:
5179 		woal_tdls_get_ies(priv, peer, tdls_ies,
5180 				  TDLS_IE_FLAGS_SETUP | TDLS_IE_FLAGS_EXTCAP |
5181 				  TDLS_IE_FLAGS_HTCAP |
5182 				  TDLS_IE_FLAGS_SUPP_CS_IE);
5183 
5184 		tf->category = WLAN_CATEGORY_TDLS;
5185 		tf->action_code = WLAN_TDLS_SETUP_REQUEST;
5186 		skb_put(skb, sizeof(tf->u.setup_req));
5187 		tf->u.setup_req.dialog_token = dialog_token;
5188 		tf->u.setup_req.capability = cpu_to_le16(capability);
5189 		woal_add_supported_rates_ie(priv, skb, band);
5190 		woal_add_ext_supported_rates_ie(priv, skb, band);
5191 		break;
5192 	case WLAN_TDLS_SETUP_RESPONSE:
5193 		woal_tdls_get_ies(priv, peer, tdls_ies,
5194 				  TDLS_IE_FLAGS_EXTCAP | TDLS_IE_FLAGS_HTCAP |
5195 				  TDLS_IE_FLAGS_SUPP_CS_IE);
5196 
5197 		tf->category = WLAN_CATEGORY_TDLS;
5198 		tf->action_code = WLAN_TDLS_SETUP_RESPONSE;
5199 
5200 		skb_put(skb, sizeof(tf->u.setup_resp));
5201 		tf->u.setup_resp.status_code = cpu_to_le16(status_code);
5202 		tf->u.setup_resp.dialog_token = dialog_token;
5203 		tf->u.setup_resp.capability = cpu_to_le16(capability);
5204 
5205 		woal_add_supported_rates_ie(priv, skb, band);
5206 		woal_add_ext_supported_rates_ie(priv, skb, band);
5207 		break;
5208 	case WLAN_TDLS_SETUP_CONFIRM:
5209 		woal_tdls_get_ies(priv, peer, tdls_ies,
5210 				  TDLS_IE_FLAGS_EXTCAP | TDLS_IE_FLAGS_HTINFO |
5211 				  TDLS_IE_FLAGS_QOS_INFO);
5212 
5213 		tf->category = WLAN_CATEGORY_TDLS;
5214 		tf->action_code = WLAN_TDLS_SETUP_CONFIRM;
5215 
5216 		skb_put(skb, sizeof(tf->u.setup_cfm));
5217 		tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
5218 		tf->u.setup_cfm.dialog_token = dialog_token;
5219 
5220 		break;
5221 	case WLAN_TDLS_TEARDOWN:
5222 		tf->category = WLAN_CATEGORY_TDLS;
5223 		tf->action_code = WLAN_TDLS_TEARDOWN;
5224 
5225 		skb_put(skb, sizeof(tf->u.teardown));
5226 		tf->u.teardown.reason_code = cpu_to_le16(status_code);
5227 		break;
5228 	case WLAN_TDLS_DISCOVERY_REQUEST:
5229 		tf->category = WLAN_CATEGORY_TDLS;
5230 		tf->action_code = WLAN_TDLS_DISCOVERY_REQUEST;
5231 
5232 		skb_put(skb, sizeof(tf->u.discover_req));
5233 		tf->u.discover_req.dialog_token = dialog_token;
5234 		break;
5235 	default:
5236 		ret = -EINVAL;
5237 		goto done;
5238 	}
5239 
5240 	if (action_code == WLAN_TDLS_SETUP_REQUEST ||
5241 	    action_code == WLAN_TDLS_SETUP_RESPONSE) {
5242 		/* supported chanel ie */
5243 		if (tdls_ies->supp_chan[0] == SUPPORTED_CHANNELS) {
5244 			pSupp_chan =
5245 				(void *)skb_put(skb,
5246 						sizeof(IEEEtypes_Header_t) +
5247 						tdls_ies->supp_chan[1]);
5248 			memset(pSupp_chan, 0,
5249 			       sizeof(IEEEtypes_Header_t) +
5250 			       tdls_ies->supp_chan[1]);
5251 			memcpy(pSupp_chan, tdls_ies->supp_chan,
5252 			       sizeof(IEEEtypes_Header_t) +
5253 			       tdls_ies->supp_chan[1]);
5254 		}
5255 		/* supported regulatory class ie */
5256 		if (tdls_ies->regulatory_class[0] == REGULATORY_CLASS) {
5257 			pRegulatory_class =
5258 				(void *)skb_put(skb,
5259 						sizeof(IEEEtypes_Header_t) +
5260 						tdls_ies->regulatory_class[1]);
5261 			memset(pRegulatory_class, 0,
5262 			       sizeof(IEEEtypes_Header_t) +
5263 			       tdls_ies->regulatory_class[1]);
5264 			memcpy(pRegulatory_class, tdls_ies->regulatory_class,
5265 			       sizeof(IEEEtypes_Header_t) +
5266 			       tdls_ies->regulatory_class[1]);
5267 		}
5268 		woal_tdls_add_ext_capab(skb, tdls_ies);
5269 	}
5270 
5271 	/* TODO we should fill in ht_cap and htinfo with correct value */
5272 	switch (action_code) {
5273 	case WLAN_TDLS_SETUP_REQUEST:
5274 	case WLAN_TDLS_SETUP_RESPONSE:
5275 		/*HT capability */
5276 		if (tdls_ies->ht_cap[0] == HT_CAPABILITY) {
5277 			HTcap = (void *)skb_put(skb, sizeof(IEEEtypes_HTCap_t));
5278 			memset(HTcap, 0, sizeof(IEEEtypes_HTCap_t));
5279 			memcpy(HTcap, tdls_ies->ht_cap,
5280 			       sizeof(IEEEtypes_HTCap_t));
5281 		} else {
5282 			PRINTM(MIOCTL, "No TDLS HT capability\n");
5283 		}
5284 
5285 		/*20_40_bss_coexist */
5286 		BSSCo = (void *)skb_put(skb, sizeof(IEEEtypes_2040BSSCo_t));
5287 		memset(BSSCo, 0, sizeof(IEEEtypes_2040BSSCo_t));
5288 		BSSCo->ieee_hdr.element_id = BSSCO_2040;
5289 		BSSCo->ieee_hdr.len =
5290 			sizeof(IEEEtypes_2040BSSCo_t) -
5291 			sizeof(IEEEtypes_Header_t);
5292 		BSSCo->bss_co_2040.bss_co_2040_value = 0x01;
5293 
5294 		break;
5295 	case WLAN_TDLS_SETUP_CONFIRM:
5296 		/*HT information */
5297 		if (tdls_ies->ht_info[0] == HT_OPERATION) {
5298 			HTInfo = (void *)skb_put(skb,
5299 						 sizeof(IEEEtypes_HTInfo_t));
5300 			memset(HTInfo, 0, sizeof(IEEEtypes_HTInfo_t));
5301 			memcpy(HTInfo, tdls_ies->ht_info,
5302 			       sizeof(IEEEtypes_HTInfo_t));
5303 		} else
5304 			PRINTM(MIOCTL, "No TDLS HT information\n");
5305 		break;
5306 	default:
5307 		break;
5308 	}
5309 
5310 	if (action_code == WLAN_TDLS_SETUP_REQUEST ||
5311 	    action_code == WLAN_TDLS_SETUP_RESPONSE) {
5312 		/*wmm info */
5313 		woal_add_wmm_ie(priv, skb, WMM_TYPE_INFO, NULL);
5314 	} else if (action_code == WLAN_TDLS_SETUP_CONFIRM) {
5315 		/*wmm parameter */
5316 		woal_add_wmm_ie(priv, skb, WMM_TYPE_PARAMETER,
5317 				&tdls_ies->QosInfo);
5318 	}
5319 
5320 done:
5321 	kfree(tdls_ies);
5322 	return ret;
5323 }
5324 
5325 /**
5326  * @brief woal construct tdls action frame
5327  *
5328  * @param priv                  A pointer to moal_private structure
5329  * @param peer                  A pointer to peer mac
5330  * @param action_code           tdls action code
5331  * @param dialog_token          dialog_token
5332  * @param status_code           status_code
5333  * @param skb                   skb buffer
5334  *
5335  * @return                      0 -- success, otherwise fail
5336  */
5337 static int
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)5338 woal_construct_tdls_action_frame(moal_private *priv,
5339 				 t_u8 *peer, t_u8 action_code,
5340 				 t_u8 dialog_token, t_u16 status_code,
5341 				 struct sk_buff *skb)
5342 {
5343 	struct ieee80211_mgmt *mgmt;
5344 	t_u8 addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
5345 	t_u16 capability;
5346 	t_u8 *pos = NULL;
5347 	mlan_ds_misc_tdls_ies *tdls_ies = NULL;
5348 	mlan_bss_info bss_info;
5349 	enum ieee80211_band band;
5350 	IEEEtypes_Generic_t *pSupp_chan = NULL, *pRegulatory_class = NULL;
5351 
5352 	int ret = 0;
5353 
5354 	ENTER();
5355 
5356 	memset(&bss_info, 0, sizeof(bss_info));
5357 	if (MLAN_STATUS_SUCCESS !=
5358 	    woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) {
5359 		PRINTM(MERROR, "Fail to get bss info\n");
5360 		LEAVE();
5361 		return -EFAULT;
5362 	}
5363 	band = woal_band_cfg_to_ieee_band(bss_info.bss_band);
5364 
5365 	tdls_ies = kzalloc(sizeof(mlan_ds_misc_tdls_ies), GFP_KERNEL);
5366 	if (!tdls_ies) {
5367 		PRINTM(MERROR, "Fail to alloc memory for tdls_ies\n");
5368 		LEAVE();
5369 		return -ENOMEM;
5370 	}
5371 
5372 	mgmt = (void *)skb_put(skb, 24);
5373 	memset(mgmt, 0, 24);
5374 	memcpy(mgmt->da, peer, ETH_ALEN);
5375 	memcpy(mgmt->sa, priv->current_addr, ETH_ALEN);
5376 	memcpy(mgmt->bssid, priv->cfg_bssid, ETH_ALEN);
5377 
5378 	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
5379 					  IEEE80211_STYPE_ACTION);
5380 	/* add address 4 */
5381 	pos = skb_put(skb, ETH_ALEN);
5382 
5383 	capability = 0x2421;
5384 
5385 	switch (action_code) {
5386 	case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
5387 		woal_tdls_get_ies(priv, peer, tdls_ies,
5388 				  TDLS_IE_FLAGS_EXTCAP |
5389 				  TDLS_IE_FLAGS_SUPP_CS_IE);
5390 		skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
5391 		mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
5392 		mgmt->u.action.u.tdls_discover_resp.action_code =
5393 			WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
5394 		mgmt->u.action.u.tdls_discover_resp.dialog_token = dialog_token;
5395 		mgmt->u.action.u.tdls_discover_resp.capability =
5396 			cpu_to_le16(capability);
5397 		/* move back for addr4 */
5398 		memmove(pos + ETH_ALEN, &mgmt->u.action.category,
5399 			1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
5400 		/** init address 4 */
5401 		memcpy(pos, addr, ETH_ALEN);
5402 
5403 		woal_add_supported_rates_ie(priv, skb, band);
5404 		woal_add_ext_supported_rates_ie(priv, skb, band);
5405 		woal_tdls_add_ext_capab(skb, tdls_ies);
5406 		/* supported chanel ie */
5407 		if (tdls_ies->supp_chan[0] == SUPPORTED_CHANNELS) {
5408 			pSupp_chan =
5409 				(void *)skb_put(skb,
5410 						sizeof(IEEEtypes_Header_t) +
5411 						tdls_ies->supp_chan[1]);
5412 			memset(pSupp_chan, 0,
5413 			       sizeof(IEEEtypes_Header_t) +
5414 			       tdls_ies->supp_chan[1]);
5415 			memcpy(pSupp_chan, tdls_ies->supp_chan,
5416 			       sizeof(IEEEtypes_Header_t) +
5417 			       tdls_ies->supp_chan[1]);
5418 		}
5419 		/* supported regulatory class ie */
5420 		if (tdls_ies->regulatory_class[0] == REGULATORY_CLASS) {
5421 			pRegulatory_class =
5422 				(void *)skb_put(skb,
5423 						sizeof(IEEEtypes_Header_t) +
5424 						tdls_ies->regulatory_class[1]);
5425 			memset(pRegulatory_class, 0,
5426 			       sizeof(IEEEtypes_Header_t) +
5427 			       tdls_ies->regulatory_class[1]);
5428 			memcpy(pRegulatory_class, tdls_ies->regulatory_class,
5429 			       sizeof(IEEEtypes_Header_t) +
5430 			       tdls_ies->regulatory_class[1]);
5431 		}
5432 
5433 		break;
5434 	default:
5435 		ret = -EINVAL;
5436 		break;
5437 	}
5438 	if (tdls_ies)
5439 		kfree(tdls_ies);
5440 	return ret;
5441 }
5442 
5443 /**
5444  * @brief woal add tdls link identifier ie
5445  *
5446  * @param skb                   skb buffer
5447  * @param src_addr              source address
5448  * @param peer                  peer address
5449  * @param bssid                 AP's bssid
5450  *
5451  * @return                      NA
5452  */
5453 static void
woal_tdls_add_link_ie(struct sk_buff * skb,u8 * src_addr,u8 * peer,u8 * bssid)5454 woal_tdls_add_link_ie(struct sk_buff *skb, u8 *src_addr, u8 *peer, u8 *bssid)
5455 {
5456 	struct ieee80211_tdls_lnkie *lnkid;
5457 
5458 	lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
5459 
5460 	lnkid->ie_type = WLAN_EID_LINK_ID;
5461 	lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
5462 
5463 	memcpy(lnkid->bssid, bssid, ETH_ALEN);
5464 	memcpy(lnkid->init_sta, src_addr, ETH_ALEN);
5465 	memcpy(lnkid->resp_sta, peer, ETH_ALEN);
5466 }
5467 
5468 /**
5469  * @brief woal send tdls action frame
5470  *
5471  * @param wiphy                 A pointer to wiphy structure
5472  * @param dev                   A pointer to net_device structure
5473  * @param peer                  A pointer to peer mac
5474  * @param action_code           tdls action code
5475  * @param dialog_token          dialog_token
5476  * @param status_code           status_code
5477  * @param extra_ies              A pointer to extra ie buffer
5478  * @param extra_ies_len          etra ie len
5479  * @param skb                   skb buffer
5480  *
5481  * @return                      0 -- success, otherwise fail
5482  */
5483 static int
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)5484 woal_send_tdls_action_frame(struct wiphy *wiphy, struct net_device *dev,
5485 			    t_u8 *peer, u8 action_code, t_u8 dialog_token,
5486 			    t_u16 status_code, const t_u8 *extra_ies,
5487 			    size_t extra_ies_len)
5488 {
5489 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5490 	pmlan_buffer pmbuf = NULL;
5491 	mlan_status status = MLAN_STATUS_SUCCESS;
5492 	struct sk_buff *skb = NULL;
5493 	t_u8 *pos;
5494 	t_u32 pkt_type;
5495 	t_u32 tx_control;
5496 	t_u16 pkt_len;
5497 	int ret = 0;
5498 
5499 	ENTER();
5500 
5501 #define HEADER_SIZE				8	/* pkt_type + tx_control */
5502 
5503 	pmbuf = woal_alloc_mlan_buffer(priv->phandle, MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE + sizeof(pkt_len) + max(sizeof(struct ieee80211_mgmt), sizeof(struct ieee80211_tdls_data)) + 50 +	/* supported rates */
5504 				       sizeof(IEEEtypes_ExtCap_t) +	/* ext capab */
5505 				       extra_ies_len +
5506 				       sizeof(IEEEtypes_tdls_linkie));
5507 	if (!pmbuf) {
5508 		PRINTM(MERROR, "Fail to allocate mlan_buffer\n");
5509 		ret = -ENOMEM;
5510 		goto done;
5511 	}
5512 
5513 	skb = (struct sk_buff *)pmbuf->pdesc;
5514 
5515 	skb_put(skb, MLAN_MIN_DATA_HEADER_LEN);
5516 
5517 	pos = skb_put(skb, HEADER_SIZE + sizeof(pkt_len));
5518 	pkt_type = MRVL_PKT_TYPE_MGMT_FRAME;
5519 	tx_control = 0;
5520 	memset(pos, 0, HEADER_SIZE + sizeof(pkt_len));
5521 	memcpy(pos, &pkt_type, sizeof(pkt_type));
5522 	memcpy(pos + sizeof(pkt_type), &tx_control, sizeof(tx_control));
5523 
5524 	woal_construct_tdls_action_frame(priv, peer, action_code,
5525 					 dialog_token, status_code, skb);
5526 
5527 	if (extra_ies_len)
5528 		memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
5529 
5530 	/* the TDLS link IE is always added last */
5531 	/* we are the responder */
5532 	woal_tdls_add_link_ie(skb, peer, priv->current_addr, priv->cfg_bssid);
5533 
5534 	/*
5535 	 * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
5536 	 * we should default to AC_VI.
5537 	 */
5538 	skb_set_queue_mapping(skb, WMM_AC_VI);
5539 	skb->priority = 5;
5540 
5541 	pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN;
5542 	pmbuf->data_len = skb->len - pmbuf->data_offset;
5543 	pmbuf->priority = skb->priority;
5544 	pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA;
5545 	pmbuf->bss_index = priv->bss_index;
5546 
5547 	pkt_len = pmbuf->data_len - HEADER_SIZE - sizeof(pkt_len);
5548 	memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE, &pkt_len,
5549 	       sizeof(pkt_len));
5550 
5551 	DBG_HEXDUMP(MDAT_D, "TDLS action:", pmbuf->pbuf + pmbuf->data_offset,
5552 		    pmbuf->data_len);
5553 
5554 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
5555 
5556 	switch (status) {
5557 	case MLAN_STATUS_PENDING:
5558 		atomic_inc(&priv->phandle->tx_pending);
5559 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
5560 		break;
5561 	case MLAN_STATUS_SUCCESS:
5562 		woal_free_mlan_buffer(priv->phandle, pmbuf);
5563 		break;
5564 	case MLAN_STATUS_FAILURE:
5565 	default:
5566 		woal_free_mlan_buffer(priv->phandle, pmbuf);
5567 		ret = -EFAULT;
5568 		break;
5569 	}
5570 
5571 done:
5572 	LEAVE();
5573 	return ret;
5574 }
5575 
5576 /**
5577  * @brief woal send tdls data frame
5578  *
5579  * @param wiphy                 A pointer to wiphy structure
5580  * @param dev                   A pointer to net_device structure
5581  * @param peer                  A pointer to peer mac
5582  * @param action_code           tdls action code
5583  * @param dialog_token          dialog_token
5584  * @param status_code           status_code
5585  * @param extra_ies              A pointer to extra ie buffer
5586  * @param extra_ies_len          etra ie len
5587  * @param skb                   skb buffer
5588  *
5589  * @return                      0 -- success, otherwise fail
5590  */
5591 static int
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)5592 woal_send_tdls_data_frame(struct wiphy *wiphy, struct net_device *dev,
5593 			  t_u8 *peer, u8 action_code, t_u8 dialog_token,
5594 			  t_u16 status_code, const t_u8 *extra_ies,
5595 			  size_t extra_ies_len)
5596 {
5597 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5598 	pmlan_buffer pmbuf = NULL;
5599 	mlan_status status = MLAN_STATUS_SUCCESS;
5600 	struct sk_buff *skb = NULL;
5601 	int ret = 0;
5602 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
5603 	t_u32 index = 0;
5604 #endif
5605 
5606 	ENTER();
5607 
5608 	skb = dev_alloc_skb(priv->extra_tx_head_len + MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) + max(sizeof(struct ieee80211_mgmt), sizeof(struct ieee80211_tdls_data)) + 50 +	/* supported rates */
5609 			    sizeof(IEEEtypes_ExtCap_t) +	/* ext capab */
5610 			    3 +	/* Qos Info */
5611 			    sizeof(IEEEtypes_WmmParameter_t) +	/*wmm ie */
5612 			    sizeof(IEEEtypes_HTCap_t) +
5613 			    sizeof(IEEEtypes_2040BSSCo_t) +
5614 			    sizeof(IEEEtypes_HTInfo_t) + extra_ies_len +
5615 			    sizeof(IEEEtypes_tdls_linkie));
5616 	if (!skb)
5617 		return -ENOMEM;
5618 
5619 	skb_reserve(skb,
5620 		    MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer) +
5621 		    priv->extra_tx_head_len);
5622 
5623 	woal_construct_tdls_data_frame(priv, peer,
5624 				       action_code, dialog_token,
5625 				       status_code, skb);
5626 
5627 	if (extra_ies_len)
5628 		memcpy(skb_put(skb, extra_ies_len), extra_ies, extra_ies_len);
5629 
5630 	/* the TDLS link IE is always added last */
5631 	switch (action_code) {
5632 	case WLAN_TDLS_SETUP_REQUEST:
5633 	case WLAN_TDLS_SETUP_CONFIRM:
5634 	case WLAN_TDLS_TEARDOWN:
5635 	case WLAN_TDLS_DISCOVERY_REQUEST:
5636 		/* we are the initiator */
5637 		woal_tdls_add_link_ie(skb, priv->current_addr, peer,
5638 				      priv->cfg_bssid);
5639 		break;
5640 	case WLAN_TDLS_SETUP_RESPONSE:
5641 		/* we are the responder */
5642 		woal_tdls_add_link_ie(skb, peer, priv->current_addr,
5643 				      priv->cfg_bssid);
5644 		break;
5645 	default:
5646 		ret = -ENOTSUPP;
5647 		goto fail;
5648 	}
5649 
5650 	/*
5651 	 * According to 802.11z: Setup req/resp are sent in AC_BK, otherwise
5652 	 * we should default to AC_VI.
5653 	 */
5654 	switch (action_code) {
5655 	case WLAN_TDLS_SETUP_REQUEST:
5656 	case WLAN_TDLS_SETUP_RESPONSE:
5657 		skb_set_queue_mapping(skb, WMM_AC_BK);
5658 		skb->priority = 2;
5659 		break;
5660 	default:
5661 		skb_set_queue_mapping(skb, WMM_AC_VI);
5662 		skb->priority = 5;
5663 		break;
5664 	}
5665 
5666 	pmbuf = (mlan_buffer *)skb->head;
5667 	memset((t_u8 *)pmbuf, 0, sizeof(mlan_buffer));
5668 	pmbuf->bss_index = priv->bss_index;
5669 	pmbuf->pdesc = skb;
5670 	pmbuf->pbuf = skb->head + sizeof(mlan_buffer);
5671 
5672 	pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer));
5673 	pmbuf->data_len = skb->len;
5674 	pmbuf->priority = skb->priority;
5675 	pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
5676 
5677 	DBG_HEXDUMP(MDAT_D, "TDLS data:", pmbuf->pbuf + pmbuf->data_offset,
5678 		    pmbuf->data_len);
5679 
5680 	status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf);
5681 
5682 	switch (status) {
5683 	case MLAN_STATUS_PENDING:
5684 		atomic_inc(&priv->phandle->tx_pending);
5685 #if CFG80211_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
5686 		index = skb_get_queue_mapping(skb);
5687 		atomic_inc(&priv->wmm_tx_pending[index]);
5688 #endif
5689 		queue_work(priv->phandle->workqueue, &priv->phandle->main_work);
5690 		/*delay 10 ms to guarantee the teardown/confirm frame can be sent out before disalbe/enable tdls link
5691 		 * if we don't delay and return immediately, wpa_supplicant will call disalbe/enable tdls link
5692 		 * this may cause tdls link disabled/enabled before teardown/confirm frame sent out */
5693 		if (action_code == WLAN_TDLS_TEARDOWN ||
5694 		    action_code == WLAN_TDLS_SETUP_CONFIRM)
5695 			woal_sched_timeout(10);
5696 		break;
5697 	case MLAN_STATUS_SUCCESS:
5698 		dev_kfree_skb(skb);
5699 		break;
5700 	case MLAN_STATUS_FAILURE:
5701 	default:
5702 		dev_kfree_skb(skb);
5703 		ret = -ENOTSUPP;
5704 		break;
5705 	}
5706 
5707 	LEAVE();
5708 	return ret;
5709 fail:
5710 	dev_kfree_skb(skb);
5711 	return ret;
5712 }
5713 
5714 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
5715 /**
5716  * @brief Tx TDLS packet
5717  *
5718  * @param wiphy                 A pointer to wiphy structure
5719  * @param dev                   A pointer to net_device structure
5720  * @param peer                  A pointer to peer mac
5721  * @param action_code           tdls action code
5722  * @param dialog_token          dialog_token
5723  * @param status_code           status_code
5724  * @param peer_capability       peer capability
5725  * @param initiator             initiator
5726  * @param extra_ies              A pointer to extra ie buffer
5727  * @param extra_ies_len          etra ie len
5728  *
5729  * @return                      0 -- success, otherwise fail
5730  */
5731 int
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)5732 woal_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
5733 			const t_u8 *peer,
5734 			u8 action_code, t_u8 dialog_token,
5735 			t_u16 status_code, t_u32 peer_capability,
5736 			bool initiator,
5737 			const t_u8 *extra_ies, size_t extra_ies_len)
5738 #else
5739 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
5740 /**
5741  * @brief Tx TDLS packet
5742  *
5743  * @param wiphy                 A pointer to wiphy structure
5744  * @param dev                   A pointer to net_device structure
5745  * @param peer                  A pointer to peer mac
5746  * @param action_code           tdls action code
5747  * @param dialog_token          dialog_token
5748  * @param status_code           status_code
5749  * @param peer_capability       peer capability
5750  * @param extra_ies              A pointer to extra ie buffer
5751  * @param extra_ies_len          etra ie len
5752  *
5753  * @return                      0 -- success, otherwise fail
5754  */
5755 int
5756 woal_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
5757 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
5758 			const t_u8 *peer,
5759 #else
5760 			t_u8 *peer,
5761 #endif
5762 			u8 action_code, t_u8 dialog_token,
5763 			t_u16 status_code, t_u32 peer_capability,
5764 			const t_u8 *extra_ies, size_t extra_ies_len)
5765 #else
5766 /**
5767  * @brief Tx TDLS packet
5768  *
5769  * @param wiphy                 A pointer to wiphy structure
5770  * @param dev                   A pointer to net_device structure
5771  * @param peer                  A pointer to peer mac
5772  * @param action_code           tdls action code
5773  * @param dialog_token          dialog_token
5774  * @param status_code           status_code
5775  * @param extra_ies              A pointer to extra ie buffer
5776  * @param extra_ies_len          etra ie len
5777  *
5778  * @return                      0 -- success, otherwise fail
5779  */
5780 int
5781 woal_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
5782 			t_u8 *peer, u8 action_code, t_u8 dialog_token,
5783 			t_u16 status_code, const t_u8 *extra_ies,
5784 			size_t extra_ies_len)
5785 #endif
5786 #endif
5787 {
5788 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5789 	int ret = 0;
5790 	mlan_bss_info bss_info;
5791 
5792 	ENTER();
5793 
5794 	if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS)) {
5795 		LEAVE();
5796 		return -ENOTSUPP;
5797 	}
5798 	/* make sure we are not in uAP mode and Go mode */
5799 	if (priv->bss_type != MLAN_BSS_TYPE_STA) {
5800 		LEAVE();
5801 		return -ENOTSUPP;
5802 	}
5803 
5804 	/* check if AP prohited TDLS */
5805 	memset(&bss_info, 0, sizeof(bss_info));
5806 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
5807 	if (IS_EXTCAP_TDLS_PROHIBITED(bss_info.ext_cap)) {
5808 		PRINTM(MMSG, "TDLS is prohibited by AP\n");
5809 		LEAVE();
5810 		return -ENOTSUPP;
5811 	}
5812 
5813 	switch (action_code) {
5814 	case TDLS_SETUP_REQUEST:
5815 		woal_add_tdls_peer(priv, (t_u8 *)peer);
5816 		PRINTM(MMSG,
5817 		       "wlan: Send TDLS Setup Request to " MACSTR
5818 		       " status_code=%d\n", MAC2STR(peer), status_code);
5819 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
5820 						action_code, dialog_token,
5821 						status_code, extra_ies,
5822 						extra_ies_len);
5823 		break;
5824 	case TDLS_SETUP_RESPONSE:
5825 		PRINTM(MMSG,
5826 		       "wlan: Send TDLS Setup Response to " MACSTR
5827 		       " status_code=%d\n", MAC2STR(peer), status_code);
5828 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
5829 						action_code, dialog_token,
5830 						status_code, extra_ies,
5831 						extra_ies_len);
5832 		break;
5833 	case TDLS_SETUP_CONFIRM:
5834 		PRINTM(MMSG,
5835 		       "wlan: Send TDLS Confirm to " MACSTR " status_code=%d\n",
5836 		       MAC2STR(peer), status_code);
5837 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
5838 						action_code, dialog_token,
5839 						status_code, extra_ies,
5840 						extra_ies_len);
5841 		break;
5842 	case TDLS_TEARDOWN:
5843 		PRINTM(MMSG, "wlan: Send TDLS Tear down to " MACSTR "\n",
5844 		       MAC2STR(peer));
5845 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
5846 						action_code, dialog_token,
5847 						status_code, extra_ies,
5848 						extra_ies_len);
5849 		break;
5850 	case TDLS_DISCOVERY_REQUEST:
5851 		PRINTM(MMSG,
5852 		       "wlan: Send TDLS Discovery Request to " MACSTR "\n",
5853 		       MAC2STR(peer));
5854 		ret = woal_send_tdls_data_frame(wiphy, dev, (t_u8 *)peer,
5855 						action_code, dialog_token,
5856 						status_code, extra_ies,
5857 						extra_ies_len);
5858 		break;
5859 	case TDLS_DISCOVERY_RESPONSE:
5860 		PRINTM(MMSG,
5861 		       "wlan: Send TDLS Discovery Response to " MACSTR "\n",
5862 		       MAC2STR(peer));
5863 		ret = woal_send_tdls_action_frame(wiphy, dev, (t_u8 *)peer,
5864 						  action_code, dialog_token,
5865 						  status_code, extra_ies,
5866 						  extra_ies_len);
5867 		break;
5868 	default:
5869 		break;
5870 	}
5871 
5872 	LEAVE();
5873 	return ret;
5874 
5875 }
5876 
5877 /**
5878  * @brief cfg80211_tdls_oper handler
5879  *
5880  * @param wiphy                 A pointer to wiphy structure
5881  * @param dev                   A pointer to net_device structure
5882  * @param peer                  tdls peer mac
5883  * @param oper                  tdls operation code
5884  *
5885  * @return                  	0 -- success, otherwise fail
5886  */
5887 int
woal_cfg80211_tdls_oper(struct wiphy * wiphy,struct net_device * dev,const u8 * peer,enum nl80211_tdls_operation oper)5888 woal_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
5889 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
5890 			const u8 *peer,
5891 #else
5892 			u8 *peer,
5893 #endif
5894 			enum nl80211_tdls_operation oper)
5895 {
5896 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5897 	t_u8 action;
5898 	int ret = 0;
5899 	t_u8 event_buf[32];
5900 	int custom_len = 0;
5901 
5902 	ENTER();
5903 
5904 	if (!(wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS))
5905 		return -ENOTSUPP;
5906 
5907 	if (!(wiphy->flags & WIPHY_FLAG_TDLS_EXTERNAL_SETUP))
5908 		return -ENOTSUPP;
5909 	/* make sure we are in managed mode, and associated */
5910 	if (priv->bss_type != MLAN_BSS_TYPE_STA)
5911 		return -ENOTSUPP;
5912 
5913 	PRINTM(MIOCTL, "wlan: TDLS peer=" MACSTR ", oper=%d\n", MAC2STR(peer),
5914 	       oper);
5915 	switch (oper) {
5916 	case NL80211_TDLS_ENABLE_LINK:
5917 		/*Configure TDLS link first */
5918 		woal_tdls_oper(priv, (u8 *)peer, WLAN_TDLS_CONFIG_LINK);
5919 		woal_updata_peer_status(priv, (t_u8 *)peer,
5920 					TDLS_SETUP_COMPLETE);
5921 		PRINTM(MMSG, "wlan: TDLS_ENABLE_LINK: peer=" MACSTR "\n",
5922 		       MAC2STR(peer));
5923 		action = WLAN_TDLS_ENABLE_LINK;
5924 		memset(event_buf, 0, sizeof(event_buf));
5925 		custom_len = strlen(CUS_EVT_TDLS_CONNECTED);
5926 		memcpy(event_buf, CUS_EVT_TDLS_CONNECTED, custom_len);
5927 		memcpy(event_buf + custom_len, peer, ETH_ALEN);
5928 		woal_broadcast_event(priv, event_buf, custom_len + ETH_ALEN);
5929 		break;
5930 	case NL80211_TDLS_DISABLE_LINK:
5931 		woal_updata_peer_status(priv, (t_u8 *)peer, TDLS_NOT_SETUP);
5932 		PRINTM(MMSG, "wlan: TDLS_DISABLE_LINK: peer=" MACSTR "\n",
5933 		       MAC2STR(peer));
5934 		action = WLAN_TDLS_DISABLE_LINK;
5935 		memset(event_buf, 0, sizeof(event_buf));
5936 		custom_len = strlen(CUS_EVT_TDLS_TEARDOWN);
5937 		memcpy(event_buf, CUS_EVT_TDLS_TEARDOWN, custom_len);
5938 		memcpy(event_buf + custom_len, peer, ETH_ALEN);
5939 		woal_broadcast_event(priv, event_buf, custom_len + ETH_ALEN);
5940 		break;
5941 	case NL80211_TDLS_TEARDOWN:
5942 	case NL80211_TDLS_SETUP:
5943 	case NL80211_TDLS_DISCOVERY_REQ:
5944 		return 0;
5945 
5946 	default:
5947 		return -ENOTSUPP;
5948 	}
5949 	ret = woal_tdls_oper(priv, (u8 *)peer, action);
5950 
5951 	LEAVE();
5952 	return ret;
5953 }
5954 
5955 /**
5956  * @brief add station
5957  *
5958  * @param wiphy                 A pointer to wiphy structure
5959  * @param dev                   A pointer to net_device structure
5960  * @param mac                  A pointer to peer mac
5961  * @param params           	station parameters
5962  *
5963  * @return                  	0 -- success, otherwise fail
5964  */
5965 static int
woal_cfg80211_add_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)5966 woal_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
5967 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
5968 			  const u8 *mac,
5969 #else
5970 			  u8 *mac,
5971 #endif
5972 			  struct station_parameters *params)
5973 {
5974 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
5975 	int ret = 0;
5976 	ENTER();
5977 	if (!(params->sta_flags_set & MBIT(NL80211_STA_FLAG_TDLS_PEER)))
5978 		goto done;
5979 	/* make sure we are in connected mode */
5980 	if ((priv->bss_type != MLAN_BSS_TYPE_STA) ||
5981 	    (priv->media_connected == MFALSE)) {
5982 		ret = -ENOTSUPP;
5983 		goto done;
5984 	}
5985 	PRINTM(MMSG, "wlan: TDLS add peer station, address =" MACSTR "\n",
5986 	       MAC2STR(mac));
5987 	ret = woal_tdls_oper(priv, (u8 *)mac, WLAN_TDLS_CREATE_LINK);
5988 done:
5989 	return ret;
5990 }
5991 
5992 /**
5993  * @brief change station info
5994  *
5995  * @param wiphy                 A pointer to wiphy structure
5996  * @param dev                   A pointer to net_device structure
5997  * @param mac                   A pointer to peer mac
5998  * @param params                station parameters
5999  *
6000  * @return                      0 -- success, otherwise fail
6001  */
6002 static int
woal_cfg80211_change_station(struct wiphy * wiphy,struct net_device * dev,const u8 * mac,struct station_parameters * params)6003 woal_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev,
6004 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
6005 			     const u8 *mac,
6006 #else
6007 			     u8 *mac,
6008 #endif
6009 			     struct station_parameters *params)
6010 {
6011 	int ret = 0;
6012 
6013 	ENTER();
6014 
6015     /**do nothing*/
6016 
6017 	LEAVE();
6018 	return ret;
6019 }
6020 
6021 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
6022 /**
6023  * @brief tdls channel switch
6024  *
6025  * @param wiphy                 A pointer to wiphy structure
6026  * @param dev                   A pointer to net_device structure
6027  * @param addr                  A pointer to peer addr
6028  * @param oper_class            The operating class
6029  * @param chandef               A pointer to cfg80211_chan_def structure
6030  *
6031  * @return                      0 -- success, otherwise fail
6032  */
6033 static int
woal_cfg80211_tdls_channel_switch(struct wiphy * wiphy,struct net_device * dev,const u8 * addr,u8 oper_class,struct cfg80211_chan_def * chandef)6034 woal_cfg80211_tdls_channel_switch(struct wiphy *wiphy,
6035 				  struct net_device *dev,
6036 				  const u8 *addr, u8 oper_class,
6037 				  struct cfg80211_chan_def *chandef)
6038 {
6039 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
6040 	mlan_ioctl_req *ioctl_req = NULL;
6041 	mlan_ds_misc_cfg *misc = NULL;
6042 	mlan_ds_misc_tdls_config *tdls_data = NULL;
6043 	tdls_all_config *tdls_all_cfg = NULL;
6044 	int ret = 0;
6045 	mlan_status status = MLAN_STATUS_SUCCESS;
6046 	mlan_bss_info bss_info;
6047 
6048 	ENTER();
6049 
6050 	/* check if AP prohited TDLS channel switch */
6051 	memset(&bss_info, 0, sizeof(bss_info));
6052 	woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
6053 	if (IS_EXTCAP_TDLS_CHLSWITCHPROHIB(bss_info.ext_cap)) {
6054 		PRINTM(MMSG, "TDLS Channel Switching is prohibited by AP\n");
6055 		LEAVE();
6056 		return -ENOTSUPP;
6057 	}
6058 
6059 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
6060 	if (ioctl_req == NULL) {
6061 		ret = -ENOMEM;
6062 		goto done;
6063 	}
6064 
6065 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
6066 	misc->sub_command = MLAN_OID_MISC_TDLS_OPER;
6067 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
6068 	ioctl_req->action = MLAN_ACT_SET;
6069 
6070 	tdls_data = &misc->param.tdls_config;
6071 	tdls_data->tdls_action = WLAN_TDLS_INIT_CHAN_SWITCH;
6072 
6073 	tdls_all_cfg = (tdls_all_config *)tdls_data->tdls_data;
6074 	memcpy(tdls_all_cfg->u.tdls_chan_switch.peer_mac_addr, addr, ETH_ALEN);
6075 	tdls_all_cfg->u.tdls_chan_switch.primary_channel =
6076 		chandef->chan->hw_value;
6077 	tdls_all_cfg->u.tdls_chan_switch.band = chandef->chan->band;
6078 	tdls_all_cfg->u.tdls_chan_switch.regulatory_class = oper_class;
6079 
6080 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
6081 	if (status != MLAN_STATUS_SUCCESS) {
6082 		PRINTM(MERROR, "TDLS channel switch request failed.\n");
6083 		ret = -EFAULT;
6084 		goto done;
6085 	}
6086 
6087 done:
6088 	if (status != MLAN_STATUS_PENDING)
6089 		kfree(ioctl_req);
6090 	LEAVE();
6091 	return ret;
6092 }
6093 
6094 /**
6095  * @brief tdls cancel channel switch
6096  *
6097  * @param wiphy                 A pointer to wiphy structure
6098  * @param dev                   A pointer to net_device structure
6099  * @param addr                  A pointer to peer addr
6100  *
6101  */
6102 void
woal_cfg80211_tdls_cancel_channel_switch(struct wiphy * wiphy,struct net_device * dev,const u8 * addr)6103 woal_cfg80211_tdls_cancel_channel_switch(struct wiphy *wiphy,
6104 					 struct net_device *dev, const u8 *addr)
6105 {
6106 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
6107 	mlan_ioctl_req *ioctl_req = NULL;
6108 	mlan_ds_misc_cfg *misc = NULL;
6109 	mlan_ds_misc_tdls_config *tdls_data = NULL;
6110 	mlan_status status = MLAN_STATUS_SUCCESS;
6111 	int ret = 0;
6112 
6113 	ENTER();
6114 
6115 	if (!priv || !priv->phandle) {
6116 		PRINTM(MERROR, "priv or handle is null\n");
6117 		ret = -EFAULT;
6118 		goto done;
6119 	}
6120 
6121 	ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
6122 	if (ioctl_req == NULL) {
6123 		ret = -ENOMEM;
6124 		goto done;
6125 	}
6126 
6127 	misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf;
6128 	misc->sub_command = MLAN_OID_MISC_TDLS_CONFIG;
6129 	ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
6130 	ioctl_req->action = MLAN_ACT_SET;
6131 
6132 	tdls_data = &misc->param.tdls_config;
6133 	tdls_data->tdls_action = WLAN_TDLS_STOP_CHAN_SWITCH;
6134 	memcpy(tdls_data->tdls_data, addr, ETH_ALEN);
6135 
6136 	status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT);
6137 	if (status != MLAN_STATUS_SUCCESS) {
6138 		ret = -EFAULT;
6139 		goto done;
6140 	}
6141 
6142 	PRINTM(MIOCTL, "Tdls channel switch stop!\n");
6143 done:
6144 	if (status != MLAN_STATUS_PENDING)
6145 		kfree(ioctl_req);
6146 
6147 	LEAVE();
6148 }
6149 #endif
6150 #endif
6151 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,10,0)
6152 /**
6153  * @brief Update ft ie for Fast BSS Transition
6154  *
6155  * @param wiphy           A pointer to wiphy structure
6156  * @param dev             A pointer to net_device structure
6157  * @param ftie           A pointer to cfg80211_update_ft_ies_params structure
6158  *
6159  * @return                0 success , other failure
6160  */
6161 int
woal_cfg80211_update_ft_ies(struct wiphy * wiphy,struct net_device * dev,struct cfg80211_update_ft_ies_params * ftie)6162 woal_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev,
6163 			    struct cfg80211_update_ft_ies_params *ftie)
6164 {
6165 	moal_private *priv = (moal_private *)woal_get_netdev_priv(dev);
6166 	IEEEtypes_MobilityDomain_t *md_ie = NULL;
6167 	int ret = 0;
6168 	mlan_ds_misc_assoc_rsp assoc_rsp;
6169 	IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
6170 	mlan_bss_info bss_info;
6171 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
6172 	struct cfg80211_roam_info roam_info;
6173 #endif
6174 
6175 	ENTER();
6176 
6177 	if (!ftie) {
6178 		LEAVE();
6179 		return ret;
6180 	}
6181 #ifdef MLAN_64BIT
6182 	PRINTM(MINFO, "==>woal_cfg80211_update_ft_ies %lx \n", ftie->ie_len);
6183 #else
6184 	PRINTM(MINFO, "==>woal_cfg80211_update_ft_ies %x \n", ftie->ie_len);
6185 #endif
6186 	md_ie = (IEEEtypes_MobilityDomain_t *)woal_parse_ie_tlv(ftie->ie,
6187 								ftie->ie_len,
6188 								MOBILITY_DOMAIN);
6189 	if (!md_ie) {
6190 		PRINTM(MERROR, "No Mobility domain IE\n");
6191 		LEAVE();
6192 		return ret;
6193 	}
6194 	priv->ft_cap = md_ie->ft_cap;
6195 	memset(priv->ft_ie, 0, MAX_IE_SIZE);
6196 	memcpy(priv->ft_ie, ftie->ie, MIN(ftie->ie_len, MAX_IE_SIZE));
6197 	priv->ft_ie_len = ftie->ie_len;
6198 	priv->ft_md = ftie->md;
6199 
6200 	if (!priv->ft_pre_connect) {
6201 		LEAVE();
6202 		return ret;
6203 	}
6204 	/* check if is different AP */
6205 	if (!memcmp
6206 	    (&priv->target_ap_bssid, priv->cfg_bssid, MLAN_MAC_ADDR_LENGTH)) {
6207 		PRINTM(MMSG, "This is the same AP, no Fast bss transition\n");
6208 		priv->ft_pre_connect = MFALSE;
6209 		priv->ft_ie_len = 0;
6210 		LEAVE();
6211 		return 0;
6212 	}
6213 
6214 	/* start fast BSS transition to target AP */
6215 	priv->assoc_status = 0;
6216 	priv->sme_current.bssid = priv->conn_bssid;
6217 	memcpy((void *)priv->sme_current.bssid, &priv->target_ap_bssid,
6218 	       MLAN_MAC_ADDR_LENGTH);
6219 	ret = woal_cfg80211_assoc(priv, (void *)&priv->sme_current,
6220 				  MOAL_IOCTL_WAIT);
6221 
6222 	if ((priv->ft_cap & MBIT(0)) || priv->ft_roaming_triggered_by_driver) {
6223 		if (!ret) {
6224 			woal_inform_bss_from_scan_result(priv, NULL,
6225 							 MOAL_IOCTL_WAIT);
6226 			memset(&assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
6227 			woal_get_assoc_rsp(priv, &assoc_rsp, MOAL_IOCTL_WAIT);
6228 			passoc_rsp =
6229 				(IEEEtypes_AssocRsp_t *)assoc_rsp.
6230 				assoc_resp_buf;
6231 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
6232 			memset(&roam_info, 0,
6233 			       sizeof(struct cfg80211_roam_info));
6234 			roam_info.bssid = priv->cfg_bssid;
6235 			roam_info.req_ie = priv->sme_current.ie;
6236 			roam_info.req_ie_len = priv->sme_current.ie_len;
6237 			roam_info.resp_ie = passoc_rsp->ie_buffer;
6238 			roam_info.resp_ie_len =
6239 				assoc_rsp.assoc_resp_len -
6240 				ASSOC_RESP_FIXED_SIZE;
6241 			cfg80211_roamed(priv->netdev, &roam_info, GFP_KERNEL);
6242 #else
6243 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
6244 			cfg80211_roamed(priv->netdev, NULL, priv->cfg_bssid,
6245 					priv->sme_current.ie,
6246 					priv->sme_current.ie_len,
6247 					passoc_rsp->ie_buffer,
6248 					assoc_rsp.assoc_resp_len -
6249 					ASSOC_RESP_FIXED_SIZE, GFP_KERNEL);
6250 #else
6251 			cfg80211_roamed(priv->netdev, priv->cfg_bssid,
6252 					priv->sme_current.ie,
6253 					priv->sme_current.ie_len,
6254 					passoc_rsp->ie_buffer,
6255 					assoc_rsp.assoc_resp_len -
6256 					ASSOC_RESP_FIXED_SIZE, GFP_KERNEL);
6257 #endif
6258 #endif
6259 			PRINTM(MMSG,
6260 			       "Fast BSS transition to bssid " MACSTR
6261 			       " successfully\n", MAC2STR(priv->cfg_bssid));
6262 		} else {
6263 			PRINTM(MMSG,
6264 			       "Fast BSS transition failed, keep connect to "
6265 			       MACSTR " \n", MAC2STR(priv->cfg_bssid));
6266 			priv->ft_ie_len = 0;
6267 		}
6268 		priv->ft_roaming_triggered_by_driver = MFALSE;
6269 
6270 	} else {
6271 		PRINTM(MMSG, "Fast BSS Transition use ft-over-air\n");
6272 		if (!ret) {
6273 			memset(&assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
6274 			woal_get_assoc_rsp(priv, &assoc_rsp, MOAL_IOCTL_WAIT);
6275 			passoc_rsp =
6276 				(IEEEtypes_AssocRsp_t *)assoc_rsp.
6277 				assoc_resp_buf;
6278 			cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
6279 						NULL, 0, passoc_rsp->ie_buffer,
6280 						assoc_rsp.assoc_resp_len -
6281 						ASSOC_RESP_FIXED_SIZE,
6282 						WLAN_STATUS_SUCCESS,
6283 						GFP_KERNEL);
6284 			PRINTM(MMSG,
6285 			       "wlan: Fast Bss transition to bssid " MACSTR
6286 			       " successfully\n", MAC2STR(priv->cfg_bssid));
6287 
6288 			memset(&bss_info, 0, sizeof(bss_info));
6289 			woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
6290 			priv->channel = bss_info.bss_chan;
6291 		} else {
6292 			PRINTM(MMSG,
6293 			       "wlan: Failed to connect to bssid " MACSTR "\n",
6294 			       MAC2STR(priv->cfg_bssid));
6295 			cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
6296 						NULL, 0, NULL, 0,
6297 						woal_get_assoc_status(priv),
6298 						GFP_KERNEL);
6299 			memset(priv->cfg_bssid, 0, ETH_ALEN);
6300 			priv->ft_ie_len = 0;
6301 		}
6302 	}
6303 
6304 	priv->ft_pre_connect = MFALSE;
6305 	LEAVE();
6306 	return 0;
6307 }
6308 #endif
6309 
6310 /**
6311  * @brief Save connect parameters for roaming
6312  *
6313  * @param priv            A pointer to moal_private
6314  * @param sme             A pointer to cfg80211_connect_params structure
6315  */
6316 void
woal_save_conn_params(moal_private * priv,struct cfg80211_connect_params * sme)6317 woal_save_conn_params(moal_private *priv, struct cfg80211_connect_params *sme)
6318 {
6319 	ENTER();
6320 	woal_clear_conn_params(priv);
6321 	memcpy(&priv->sme_current, sme, sizeof(struct cfg80211_connect_params));
6322 	if (sme->channel) {
6323 		priv->sme_current.channel = &priv->conn_chan;
6324 		memcpy(priv->sme_current.channel, sme->channel,
6325 		       sizeof(struct ieee80211_channel));
6326 	}
6327 	if (sme->bssid) {
6328 		priv->sme_current.bssid = priv->conn_bssid;
6329 		memcpy((void *)priv->sme_current.bssid, sme->bssid,
6330 		       MLAN_MAC_ADDR_LENGTH);
6331 	}
6332 	if (sme->ssid && sme->ssid_len) {
6333 		priv->sme_current.ssid = priv->conn_ssid;
6334 		memset(priv->conn_ssid, 0, MLAN_MAX_SSID_LENGTH);
6335 		memcpy((void *)priv->sme_current.ssid, sme->ssid,
6336 		       sme->ssid_len);
6337 	}
6338 	if (sme->ie && sme->ie_len) {
6339 		priv->sme_current.ie = kzalloc(sme->ie_len, GFP_KERNEL);
6340 		memcpy((void *)priv->sme_current.ie, sme->ie, sme->ie_len);
6341 	}
6342 	if (sme->key && sme->key_len && (sme->key_len <= MAX_WEP_KEY_SIZE)) {
6343 		priv->sme_current.key = priv->conn_wep_key;
6344 		memcpy((t_u8 *)priv->sme_current.key, sme->key, sme->key_len);
6345 	}
6346 }
6347 
6348 /**
6349  * @brief clear connect parameters for ing
6350  *
6351  * @param priv            A pointer to moal_private
6352  */
6353 void
woal_clear_conn_params(moal_private * priv)6354 woal_clear_conn_params(moal_private *priv)
6355 {
6356 	ENTER();
6357 	if (priv->sme_current.ie_len)
6358 		kfree(priv->sme_current.ie);
6359 	memset(&priv->sme_current, 0, sizeof(struct cfg80211_connect_params));
6360 	priv->roaming_required = MFALSE;
6361 	LEAVE();
6362 }
6363 
6364 /**
6365  * @brief Build new roaming connect ie for okc
6366  *
6367  * @param priv            A pointer to moal_private
6368  * @param entry           A pointer to pmksa_entry
6369  **/
6370 int
woal_update_okc_roaming_ie(moal_private * priv,struct pmksa_entry * entry)6371 woal_update_okc_roaming_ie(moal_private *priv, struct pmksa_entry *entry)
6372 {
6373 	struct cfg80211_connect_params *sme = &priv->sme_current;
6374 	int ret = MLAN_STATUS_SUCCESS;
6375 	const t_u8 *sme_pos, *sme_ptr;
6376 	t_u8 *okc_ie_pos;
6377 	t_u8 id, ie_len;
6378 	int left_len;
6379 
6380 	ENTER();
6381 
6382 	if (!sme->ie || !sme->ie_len) {
6383 		PRINTM(MERROR, "No connect ie saved in driver\n");
6384 		ret = MLAN_STATUS_FAILURE;
6385 		goto done;
6386 	}
6387 
6388 	if (!entry) {
6389 		PRINTM(MERROR, "No roaming ap pmkid\n");
6390 		ret = MLAN_STATUS_FAILURE;
6391 		goto done;
6392 	}
6393 
6394 	if (!priv->okc_roaming_ie) {
6395 		int okc_ie_len = sme->ie_len + sizeof(t_u16) + PMKID_LEN;
6396 
6397 	/** Alloc new buffer for okc roaming ie */
6398 		priv->okc_roaming_ie = kzalloc(okc_ie_len, GFP_KERNEL);
6399 		if (!priv->okc_roaming_ie) {
6400 			PRINTM(MERROR, "Fail to allocate assoc req ie\n");
6401 			ret = MLAN_STATUS_FAILURE;
6402 			goto done;
6403 		}
6404 	}
6405 
6406 	/* Build OKC RSN IE with PMKID list
6407 	 * Format of RSN IE: length(bytes) and container
6408 	 * | 1| 1 |   2   |          4            |           2               |
6409 	 * |id|len|version|group data cipher suite|pairwise cipher suite count|
6410 	 * |          4 * m           |       2       |    4 * n     |   2    |
6411 	 * |pairwise cipher suite list|AKM suite count|AKM suite list|RSN Cap |
6412 	 * |    2     |  16 * s  |              4              |
6413 	 * |PMKIDCount|PMKID List|Group Management Cipher Suite|
6414 	 */
6415 #define PAIRWISE_CIPHER_COUNT_OFFSET 8
6416 #define AKM_SUITE_COUNT_OFFSET(n) (10 + (n) * 4)
6417 #define PMKID_COUNT_OFFSET(n) (14 + (n) * 4)
6418 
6419 	sme_pos = sme->ie;
6420 	left_len = sme->ie_len;
6421 	okc_ie_pos = priv->okc_roaming_ie;
6422 	priv->okc_ie_len = 0;
6423 
6424 	while (left_len >= 2) {
6425 		id = *sme_pos;
6426 		ie_len = *(sme_pos + 1);
6427 		if ((ie_len + 2) > left_len) {
6428 			PRINTM(MERROR, "Invalid ie len %d\n", ie_len);
6429 			ret = MLAN_STATUS_FAILURE;
6430 			goto done;
6431 		}
6432 
6433 		if (id == RSN_IE) {
6434 			t_u16 pairwise_count, akm_count;
6435 			t_u8 *rsn_ie_len;
6436 			int rsn_offset;
6437 
6438 			pairwise_count =
6439 				*(t_u16 *)(sme_pos +
6440 					   PAIRWISE_CIPHER_COUNT_OFFSET);
6441 			akm_count =
6442 				*(t_u16 *)(sme_pos +
6443 					   AKM_SUITE_COUNT_OFFSET
6444 					   (pairwise_count));
6445 			rsn_offset =
6446 				PMKID_COUNT_OFFSET(pairwise_count + akm_count);
6447 			sme_ptr = (t_u8 *)(sme_pos + rsn_offset);
6448 
6449 			memcpy(okc_ie_pos, sme_pos, rsn_offset);
6450 			rsn_ie_len = okc_ie_pos + 1;
6451 			okc_ie_pos += rsn_offset;
6452 			*(t_u16 *)okc_ie_pos = 1;
6453 			okc_ie_pos += sizeof(t_u16);
6454 			memcpy(okc_ie_pos, entry->pmkid, PMKID_LEN);
6455 			okc_ie_pos += PMKID_LEN;
6456 			priv->okc_ie_len +=
6457 				rsn_offset + sizeof(t_u16) + PMKID_LEN;
6458 			*rsn_ie_len =
6459 				rsn_offset - 2 + sizeof(t_u16) + PMKID_LEN;
6460 
6461 			if ((ie_len + 2) > rsn_offset) {
6462 		/** Previous conn ie include pmkid list */
6463 				u16 pmkid_count = *(t_u16 *)sme_ptr;
6464 				rsn_offset +=
6465 					(sizeof(t_u16) +
6466 					 PMKID_LEN * pmkid_count);
6467 				if ((ie_len + 2) > rsn_offset) {
6468 					sme_ptr +=
6469 						(sizeof(t_u16) +
6470 						 PMKID_LEN * pmkid_count);
6471 					memcpy(okc_ie_pos, sme_ptr,
6472 					       (ie_len + 2 - rsn_offset));
6473 					okc_ie_pos += (ie_len + 2 - rsn_offset);
6474 					priv->okc_ie_len +=
6475 						(ie_len + 2 - rsn_offset);
6476 					*rsn_ie_len +=
6477 						(ie_len + 2 - rsn_offset);
6478 				}
6479 			}
6480 		} else {
6481 			memcpy(okc_ie_pos, sme_pos, ie_len + 2);
6482 			okc_ie_pos += ie_len + 2;
6483 			priv->okc_ie_len += ie_len + 2;
6484 		}
6485 
6486 		sme_pos += (ie_len + 2);
6487 		left_len -= (ie_len + 2);
6488 	}
6489 
6490 done:
6491 	if (ret != MLAN_STATUS_SUCCESS) {
6492 		if (priv->okc_roaming_ie) {
6493 			kfree(priv->okc_roaming_ie);
6494 			priv->okc_roaming_ie = NULL;
6495 			priv->okc_ie_len = 0;
6496 		}
6497 	}
6498 
6499 	LEAVE();
6500 	return ret;
6501 }
6502 
6503 /**
6504  * @brief Start roaming: driver handle roaming
6505  *
6506  * @param priv      A pointer to moal_private structure
6507  *
6508  * @return          N/A
6509  */
6510 void
woal_start_roaming(moal_private * priv)6511 woal_start_roaming(moal_private *priv)
6512 {
6513 	mlan_ds_get_signal signal;
6514 	mlan_ssid_bssid ssid_bssid;
6515 	char rssi_low[10];
6516 	int ret = 0;
6517 	mlan_ds_misc_assoc_rsp assoc_rsp;
6518 	IEEEtypes_AssocRsp_t *passoc_rsp = NULL;
6519 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
6520 	struct cfg80211_roam_info roam_info;
6521 #endif
6522 
6523 	ENTER();
6524 	if (priv->ft_roaming_triggered_by_driver) {
6525 		PRINTM(MIOCTL, "FT roaming is in processing ...... \n");
6526 		LEAVE();
6527 		return;
6528 	}
6529 
6530 	if (priv->last_event & EVENT_BG_SCAN_REPORT) {
6531 		woal_inform_bss_from_scan_result(priv, NULL, MOAL_IOCTL_WAIT);
6532 		PRINTM(MIOCTL, "Report bgscan result\n");
6533 	}
6534 	if (priv->media_connected == MFALSE || !priv->sme_current.ssid_len) {
6535 		PRINTM(MIOCTL, "Not connected, ignore roaming\n");
6536 		LEAVE();
6537 		return;
6538 	}
6539 
6540 	/* Get signal information from the firmware */
6541 	memset(&signal, 0, sizeof(mlan_ds_get_signal));
6542 	if (MLAN_STATUS_SUCCESS !=
6543 	    woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) {
6544 		PRINTM(MERROR, "Error getting signal information\n");
6545 		ret = -EFAULT;
6546 		goto done;
6547 	}
6548 	memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid));
6549 	ssid_bssid.ssid.ssid_len = priv->sme_current.ssid_len;
6550 	memcpy(ssid_bssid.ssid.ssid, priv->sme_current.ssid,
6551 	       priv->sme_current.ssid_len);
6552 	if (MLAN_STATUS_SUCCESS !=
6553 	    woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) {
6554 		PRINTM(MIOCTL, "Can not find better network\n");
6555 		ret = -EFAULT;
6556 		goto done;
6557 	}
6558 	/* check if we found different AP */
6559 	if (!memcmp(&ssid_bssid.bssid, priv->cfg_bssid, MLAN_MAC_ADDR_LENGTH)) {
6560 		PRINTM(MIOCTL, "This is the same AP, no roaming\n");
6561 		ret = -EFAULT;
6562 		goto done;
6563 	}
6564 	PRINTM(MIOCTL, "Find AP: bssid=" MACSTR ", signal=%d\n",
6565 	       MAC2STR(ssid_bssid.bssid), ssid_bssid.rssi);
6566 	/* check signal */
6567 	if (!(priv->last_event & EVENT_PRE_BCN_LOST)) {
6568 		if ((abs(signal.bcn_rssi_avg) - abs(ssid_bssid.rssi)) <
6569 		    DELTA_RSSI) {
6570 			PRINTM(MERROR, "New AP's signal is not good too.\n");
6571 			ret = -EFAULT;
6572 			goto done;
6573 		}
6574 	}
6575 /**check if need start FT Roaming*/
6576 	if (priv->ft_ie_len && (priv->ft_md == ssid_bssid.ft_md) &&
6577 	    (priv->ft_cap == ssid_bssid.ft_cap)) {
6578 		woal_start_ft_roaming(priv, &ssid_bssid);
6579 		goto done;
6580 	}
6581 	/* start roaming to new AP */
6582 	priv->sme_current.bssid = priv->conn_bssid;
6583 	memcpy((void *)priv->sme_current.bssid, &ssid_bssid.bssid,
6584 	       MLAN_MAC_ADDR_LENGTH);
6585 
6586 #ifdef STA_CFG80211
6587 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
6588 	if (IS_STA_CFG80211(cfg80211_wext)) {
6589 	/** Check if current roaming support OKC offload roaming */
6590 		if (priv->sme_current.crypto.n_akm_suites &&
6591 		    priv->sme_current.crypto.akm_suites[0] ==
6592 		    WLAN_AKM_SUITE_8021X) {
6593 			struct pmksa_entry *entry = NULL;
6594 
6595 	    /** Get OKC PMK Cache entry
6596              *  Firstly try to get pmksa from cfg80211
6597              */
6598 			priv->wait_target_ap_pmkid = MTRUE;
6599 			cfg80211_pmksa_candidate_notify(priv->netdev, 0,
6600 							priv->sme_current.bssid,
6601 							MTRUE, GFP_ATOMIC);
6602 			if (wait_event_interruptible_timeout(priv->okc_wait_q,
6603 							     !priv->
6604 							     wait_target_ap_pmkid,
6605 							     OKC_WAIT_TARGET_PMKSA_TIMEOUT))
6606 			{
6607 				PRINTM(MIOCTL, "OKC Roaming is ready\n");
6608 				entry = priv->target_ap_pmksa;
6609 			} else {
6610 		/** Try to get pmksa from pmksa list */
6611 				priv->wait_target_ap_pmkid = MFALSE;
6612 				entry = woal_get_pmksa_entry(priv,
6613 							     priv->sme_current.
6614 							     bssid);
6615 			}
6616 	    /** Build okc roaming ie */
6617 			woal_update_okc_roaming_ie(priv, entry);
6618 			priv->target_ap_pmksa = NULL;
6619 		}
6620 	}
6621 #endif
6622 #endif
6623 
6624 	ret = woal_cfg80211_assoc(priv, (void *)&priv->sme_current,
6625 				  MOAL_IOCTL_WAIT);
6626 	if (!ret) {
6627 		const t_u8 *ie;
6628 		int ie_len;
6629 
6630 		woal_inform_bss_from_scan_result(priv, NULL, MOAL_IOCTL_WAIT);
6631 		memset(&assoc_rsp, 0, sizeof(mlan_ds_misc_assoc_rsp));
6632 		woal_get_assoc_rsp(priv, &assoc_rsp, MOAL_IOCTL_WAIT);
6633 		passoc_rsp = (IEEEtypes_AssocRsp_t *)assoc_rsp.assoc_resp_buf;
6634 
6635 	/** Update connect ie in roam event */
6636 		ie = priv->sme_current.ie;
6637 		ie_len = priv->sme_current.ie_len;
6638 #ifdef STA_CFG80211
6639 		if (IS_STA_CFG80211(cfg80211_wext)) {
6640 	/** Check if current roaming support OKC offload roaming */
6641 			if (priv->sme_current.crypto.n_akm_suites &&
6642 			    priv->sme_current.crypto.akm_suites[0] ==
6643 			    WLAN_AKM_SUITE_8021X) {
6644 				if (priv->okc_roaming_ie && priv->okc_ie_len) {
6645 					ie = priv->okc_roaming_ie;
6646 					ie_len = priv->okc_ie_len;
6647 				}
6648 			}
6649 		}
6650 #endif
6651 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
6652 		memset(&roam_info, 0, sizeof(struct cfg80211_roam_info));
6653 		roam_info.bssid = priv->cfg_bssid;
6654 		roam_info.req_ie = ie;
6655 		roam_info.req_ie_len = ie_len;
6656 		roam_info.resp_ie = passoc_rsp->ie_buffer;
6657 		roam_info.resp_ie_len =
6658 			assoc_rsp.assoc_resp_len - ASSOC_RESP_FIXED_SIZE;
6659 		cfg80211_roamed(priv->netdev, &roam_info, GFP_KERNEL);
6660 #else
6661 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
6662 		cfg80211_roamed(priv->netdev, NULL, priv->cfg_bssid, ie, ie_len,
6663 				passoc_rsp->ie_buffer,
6664 				assoc_rsp.assoc_resp_len -
6665 				ASSOC_RESP_FIXED_SIZE, GFP_KERNEL);
6666 #else
6667 		cfg80211_roamed(priv->netdev, priv->cfg_bssid, ie, ie_len,
6668 				passoc_rsp->ie_buffer,
6669 				assoc_rsp.assoc_resp_len -
6670 				ASSOC_RESP_FIXED_SIZE, GFP_KERNEL);
6671 #endif
6672 #endif
6673 		PRINTM(MMSG, "Roamed to bssid " MACSTR " successfully\n",
6674 		       MAC2STR(priv->cfg_bssid));
6675 	} else {
6676 		PRINTM(MIOCTL, "Roaming to bssid " MACSTR " failed\n",
6677 		       MAC2STR(ssid_bssid.bssid));
6678 	}
6679 done:
6680 	/* config rssi low threshold again */
6681 	priv->last_event = 0;
6682 	priv->rssi_low = DEFAULT_RSSI_LOW_THRESHOLD;
6683 	sprintf(rssi_low, "%d", priv->rssi_low);
6684 	woal_set_rssi_low_threshold(priv, rssi_low, MOAL_IOCTL_WAIT);
6685 	LEAVE();
6686 	return;
6687 }
6688 
6689 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
6690 /**
6691  *  @brief This function update channel region config
6692  *
6693  *  @param buf              Buffer containing channel region config
6694  *  @param num_chan         Length of buffer
6695  *  @param regd             ieee80211_regdomain to be updated
6696  *
6697  *  @return                 N/A
6698  */
6699 static struct ieee80211_regdomain *
create_custom_regdomain(t_u8 * buf,t_u16 num_chan)6700 create_custom_regdomain(t_u8 *buf, t_u16 num_chan)
6701 {
6702 	struct ieee80211_reg_rule *rule;
6703 	bool new_rule;
6704 	int idx, freq, prev_freq = 0;
6705 	t_u32 bw, prev_bw = 0;
6706 	t_u8 chflags, prev_chflags = 0, valid_rules = 0;
6707 	struct ieee80211_regdomain *regd = NULL;
6708 	int regd_size;
6709 
6710 	regd_size = sizeof(struct ieee80211_regdomain) +
6711 		num_chan * sizeof(struct ieee80211_reg_rule);
6712 
6713 	regd = kzalloc(regd_size, GFP_KERNEL);
6714 	if (!regd) {
6715 		return NULL;
6716 	}
6717 
6718 	for (idx = 0; idx < num_chan; idx++) {
6719 		t_u8 chan;
6720 		enum ieee80211_band band;
6721 
6722 		chan = *buf++;
6723 		if (!chan) {
6724 			return NULL;
6725 		}
6726 		chflags = *buf++;
6727 		band = (chan <= 14) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
6728 		freq = ieee80211_channel_to_frequency(chan, band);
6729 		new_rule = false;
6730 
6731 		if (chflags & MARVELL_CHANNEL_DISABLED)
6732 			continue;
6733 
6734 		if (band == IEEE80211_BAND_5GHZ) {
6735 			if (!(chflags & MARVELL_CHANNEL_NOHT80))
6736 				bw = MHZ_TO_KHZ(80);
6737 			else if (!(chflags & MARVELL_CHANNEL_NOHT40))
6738 				bw = MHZ_TO_KHZ(40);
6739 			else
6740 				bw = MHZ_TO_KHZ(20);
6741 		} else {
6742 			if (!(chflags & MARVELL_CHANNEL_NOHT40))
6743 				bw = MHZ_TO_KHZ(40);
6744 			else
6745 				bw = MHZ_TO_KHZ(20);
6746 		}
6747 
6748 		if (idx == 0 || prev_chflags != chflags || prev_bw != bw ||
6749 		    freq - prev_freq > 20) {
6750 			valid_rules++;
6751 			new_rule = true;
6752 		}
6753 
6754 		rule = &regd->reg_rules[valid_rules - 1];
6755 
6756 		rule->freq_range.end_freq_khz = MHZ_TO_KHZ(freq + 10);
6757 
6758 		prev_chflags = chflags;
6759 		prev_freq = freq;
6760 		prev_bw = bw;
6761 
6762 		if (!new_rule)
6763 			continue;
6764 
6765 		rule->freq_range.start_freq_khz = MHZ_TO_KHZ(freq - 10);
6766 		rule->power_rule.max_eirp = DBM_TO_MBM(19);
6767 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
6768 		if (chflags & MARVELL_CHANNEL_PASSIVE)
6769 			rule->flags = NL80211_RRF_NO_IR;
6770 #endif
6771 		if (chflags & MARVELL_CHANNEL_DFS)
6772 			rule->flags = NL80211_RRF_DFS;
6773 
6774 		rule->freq_range.max_bandwidth_khz = bw;
6775 	}
6776 
6777 	regd->n_reg_rules = valid_rules;
6778 
6779 	/* set alpha2 from FW. */
6780 	regd->alpha2[0] = '9';
6781 	regd->alpha2[1] = '9';
6782 
6783 	return regd;
6784 }
6785 
6786 /**
6787  *  @brief create custom channel regulatory config
6788  *
6789  *  @param priv         A pointer to moal_private structure
6790  *
6791  *  @return		        if success pointer to ieee80211_regdomain, else NULL
6792  */
6793 static struct ieee80211_regdomain *
woal_create_custom_regdomain(moal_private * priv)6794 woal_create_custom_regdomain(moal_private *priv)
6795 {
6796 	mlan_ds_misc_cfg *misc = NULL;
6797 	mlan_ioctl_req *req = NULL;
6798 	mlan_status status = MLAN_STATUS_SUCCESS;
6799 	struct ieee80211_regdomain *regd = NULL;
6800 	t_u16 num_chan;
6801 
6802 	ENTER();
6803 
6804 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg) +
6805 					REGULATORY_CFG_LEN);
6806 	if (req == NULL) {
6807 		goto done;
6808 	}
6809 	misc = (mlan_ds_misc_cfg *)req->pbuf;
6810 	misc->sub_command = MLAN_OID_MISC_GET_CHAN_REGION_CFG;
6811 	req->req_id = MLAN_IOCTL_MISC_CFG;
6812 	req->action = MLAN_ACT_GET;
6813 	memset(&misc->param.custom_reg_domain, 0,
6814 	       sizeof(misc->param.custom_reg_domain));
6815 	/* Passing maximum buffer length to mlan */
6816 	misc->param.custom_reg_domain.cfg_len = REGULATORY_CFG_LEN;
6817 	status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
6818 	if (status != MLAN_STATUS_SUCCESS) {
6819 		goto done;
6820 	}
6821 
6822 	if (misc->param.custom_reg_domain.cfg_len) {
6823 		num_chan = misc->param.custom_reg_domain.cfg_len / 2;
6824 		if (num_chan > NL80211_MAX_SUPP_REG_RULES) {
6825 			goto done;
6826 		}
6827 
6828 		regd = create_custom_regdomain(misc->param.custom_reg_domain.
6829 					       cfg_buf, num_chan);
6830 	}
6831 
6832 done:
6833 	if (status != MLAN_STATUS_PENDING)
6834 		kfree(req);
6835 	LEAVE();
6836 	return regd;
6837 }
6838 #endif
6839 
6840 /**
6841  * @brief Register the device with cfg80211
6842  *
6843  * @param dev       A pointer to net_device structure
6844  * @param bss_type  BSS type
6845  *
6846  * @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
6847  */
6848 mlan_status
woal_register_sta_cfg80211(struct net_device * dev,t_u8 bss_type)6849 woal_register_sta_cfg80211(struct net_device *dev, t_u8 bss_type)
6850 {
6851 	mlan_status ret = MLAN_STATUS_SUCCESS;
6852 	moal_private *priv = (moal_private *)netdev_priv(dev);
6853 	struct wireless_dev *wdev = NULL;
6854 	int psmode = 0;
6855 
6856 	ENTER();
6857 
6858 	wdev = (struct wireless_dev *)&priv->w_dev;
6859 	memset(wdev, 0, sizeof(struct wireless_dev));
6860 	wdev->wiphy = priv->phandle->wiphy;
6861 	if (!wdev->wiphy) {
6862 		LEAVE();
6863 		return MLAN_STATUS_FAILURE;
6864 	}
6865 	if (bss_type == MLAN_BSS_TYPE_STA) {
6866 		wdev->iftype = NL80211_IFTYPE_STATION;
6867 		priv->roaming_enabled = MFALSE;
6868 		priv->roaming_required = MFALSE;
6869 	}
6870 #if defined(WIFI_DIRECT_SUPPORT)
6871 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
6872 	if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
6873 		wdev->iftype = NL80211_IFTYPE_STATION;
6874 #endif
6875 #endif
6876 	if (bss_type == MLAN_BSS_TYPE_NAN)
6877 		wdev->iftype = NL80211_IFTYPE_STATION;
6878 	dev_net_set(dev, wiphy_net(wdev->wiphy));
6879 	dev->ieee80211_ptr = wdev;
6880 	SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
6881 	priv->wdev = wdev;
6882 	/* Get IEEE power save mode */
6883 	if (MLAN_STATUS_SUCCESS ==
6884 	    woal_set_get_power_mgmt(priv, MLAN_ACT_GET, &psmode, 0,
6885 				    MOAL_IOCTL_WAIT)) {
6886 		/* Save the IEEE power save mode to wiphy, because after
6887 		 * warmreset wiphy power save should be updated instead
6888 		 * of using the last saved configuration */
6889 		if (psmode)
6890 			priv->wdev->ps = MTRUE;
6891 		else
6892 			priv->wdev->ps = MFALSE;
6893 	}
6894 	woal_send_domain_info_cmd_fw(priv, MOAL_IOCTL_WAIT);
6895 	LEAVE();
6896 	return ret;
6897 }
6898 
6899 /**
6900  * @brief Initialize the wiphy
6901  *
6902  * @param priv            A pointer to moal_private structure
6903  * @param wait_option     Wait option
6904  *
6905  * @return                MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
6906  */
6907 mlan_status
woal_cfg80211_init_wiphy(moal_private * priv,t_u8 wait_option)6908 woal_cfg80211_init_wiphy(moal_private *priv, t_u8 wait_option)
6909 {
6910 	mlan_status ret = MLAN_STATUS_SUCCESS;
6911 	int retry_count, rts_thr, frag_thr;
6912 	struct wiphy *wiphy = NULL;
6913 	mlan_ioctl_req *req = NULL;
6914 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
6915 	mlan_ds_radio_cfg *radio = NULL;
6916 #endif
6917 	mlan_ds_11n_cfg *cfg_11n = NULL;
6918 	t_u32 hw_dev_cap;
6919 #ifdef UAP_SUPPORT
6920 	mlan_uap_bss_param *sys_cfg = NULL;
6921 #endif
6922 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 0, 0)
6923 	t_u16 enable = 0;
6924 #endif
6925 
6926 	ENTER();
6927 
6928 	wiphy = priv->phandle->wiphy;
6929 	/* Get 11n tx parameters from MLAN */
6930 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
6931 	if (req == NULL) {
6932 		ret = MLAN_STATUS_FAILURE;
6933 		goto done;
6934 	}
6935 	cfg_11n = (mlan_ds_11n_cfg *)req->pbuf;
6936 	cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG;
6937 	req->req_id = MLAN_IOCTL_11N_CFG;
6938 	req->action = MLAN_ACT_GET;
6939 	cfg_11n->param.htcap_cfg.hw_cap_req = MTRUE;
6940 
6941 	ret = woal_request_ioctl(priv, req, wait_option);
6942 	if (ret != MLAN_STATUS_SUCCESS)
6943 		goto done;
6944 	hw_dev_cap = cfg_11n->param.htcap_cfg.htcap;
6945 
6946 	/* Get supported MCS sets */
6947 	memset(req->pbuf, 0, sizeof(mlan_ds_11n_cfg));
6948 	cfg_11n->sub_command = MLAN_OID_11N_CFG_SUPPORTED_MCS_SET;
6949 	req->req_id = MLAN_IOCTL_11N_CFG;
6950 	req->action = MLAN_ACT_GET;
6951 
6952 	ret = woal_request_ioctl(priv, req, wait_option);
6953 	if (ret != MLAN_STATUS_SUCCESS)
6954 		goto done;
6955 
6956 	/* Initialize parameters for 2GHz and 5GHz bands */
6957 	if (wiphy->bands[IEEE80211_BAND_2GHZ])
6958 		woal_cfg80211_setup_ht_cap(&wiphy->bands[IEEE80211_BAND_2GHZ]->
6959 					   ht_cap, hw_dev_cap,
6960 					   cfg_11n->param.supported_mcs_set);
6961 	/* For 2.4G band only card, this shouldn't be set */
6962 	if (wiphy->bands[IEEE80211_BAND_5GHZ]) {
6963 		woal_cfg80211_setup_ht_cap(&wiphy->bands[IEEE80211_BAND_5GHZ]->
6964 					   ht_cap, hw_dev_cap,
6965 					   cfg_11n->param.supported_mcs_set);
6966 	}
6967 	kfree(req);
6968 
6969 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
6970 	/* Get antenna modes */
6971 	req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
6972 	if (req == NULL) {
6973 		ret = MLAN_STATUS_FAILURE;
6974 		goto done;
6975 	}
6976 	radio = (mlan_ds_radio_cfg *)req->pbuf;
6977 	radio->sub_command = MLAN_OID_ANT_CFG;
6978 	req->req_id = MLAN_IOCTL_RADIO_CFG;
6979 	req->action = MLAN_ACT_GET;
6980 
6981 	ret = woal_request_ioctl(priv, req, wait_option);
6982 	if (ret != MLAN_STATUS_SUCCESS)
6983 		goto done;
6984 
6985 	/* Set available antennas to wiphy */
6986 	wiphy->available_antennas_tx = radio->param.ant_cfg_1x1.antenna;
6987 	wiphy->available_antennas_rx = radio->param.ant_cfg_1x1.antenna;
6988 #endif /* CFG80211_VERSION_CODE */
6989 
6990 	/* Set retry limit count to wiphy */
6991 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
6992 		if (MLAN_STATUS_SUCCESS !=
6993 		    woal_set_get_retry(priv, MLAN_ACT_GET, wait_option,
6994 				       &retry_count)) {
6995 			ret = MLAN_STATUS_FAILURE;
6996 			goto done;
6997 		}
6998 	}
6999 #ifdef UAP_SUPPORT
7000 	else {
7001 		sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
7002 		if (!sys_cfg) {
7003 			PRINTM(MERROR,
7004 			       "Fail to alloc memory for mlan_uap_bss_param\n");
7005 			ret = MLAN_STATUS_FAILURE;
7006 			goto done;
7007 		}
7008 		if (MLAN_STATUS_SUCCESS !=
7009 		    woal_set_get_sys_config(priv, MLAN_ACT_GET, wait_option,
7010 					    sys_cfg)) {
7011 			ret = MLAN_STATUS_FAILURE;
7012 			kfree(sys_cfg);
7013 			goto done;
7014 		}
7015 		retry_count = sys_cfg->retry_limit;
7016 		kfree(sys_cfg);
7017 	}
7018 #endif
7019 	wiphy->retry_long = (t_u8)retry_count;
7020 	wiphy->retry_short = (t_u8)retry_count;
7021 	wiphy->max_scan_ie_len = MAX_IE_SIZE;
7022 
7023 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
7024 	wiphy->mgmt_stypes = ieee80211_mgmt_stypes;
7025 #endif
7026 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
7027 	wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION;
7028 #endif /* KERNEL_VERSION */
7029 
7030 	/* Set RTS threshold to wiphy */
7031 	if (MLAN_STATUS_SUCCESS !=
7032 	    woal_set_get_rts(priv, MLAN_ACT_GET, wait_option, &rts_thr)) {
7033 		ret = MLAN_STATUS_FAILURE;
7034 		goto done;
7035 	}
7036 	if (rts_thr < MLAN_RTS_MIN_VALUE || rts_thr > MLAN_RTS_MAX_VALUE)
7037 		rts_thr = MLAN_FRAG_RTS_DISABLED;
7038 	wiphy->rts_threshold = (t_u32)rts_thr;
7039 
7040 	/* Set fragment threshold to wiphy */
7041 	if (MLAN_STATUS_SUCCESS !=
7042 	    woal_set_get_frag(priv, MLAN_ACT_GET, wait_option, &frag_thr)) {
7043 		ret = MLAN_STATUS_FAILURE;
7044 		goto done;
7045 	}
7046 	if (frag_thr < MLAN_RTS_MIN_VALUE || frag_thr > MLAN_RTS_MAX_VALUE)
7047 		frag_thr = MLAN_FRAG_RTS_DISABLED;
7048 	wiphy->frag_threshold = (t_u32)frag_thr;
7049 #if CFG80211_VERSION_CODE > KERNEL_VERSION(3, 0, 0)
7050 	/* Enable multi-channel by default if multi-channel is supported */
7051 	if (cfg80211_iface_comb_ap_sta.num_different_channels > 1)
7052 		enable = 1;
7053 	ret = woal_mc_policy_cfg(priv, &enable, wait_option, MLAN_ACT_SET);
7054 #endif
7055 
7056 done:
7057 	LEAVE();
7058 	if (ret != MLAN_STATUS_PENDING)
7059 		kfree(req);
7060 	return ret;
7061 }
7062 
7063 /*
7064  * This function registers the device with CFG802.11 subsystem.
7065  *
7066  * @param priv       A pointer to moal_private
7067  *
7068  */
7069 mlan_status
woal_register_cfg80211(moal_private * priv)7070 woal_register_cfg80211(moal_private *priv)
7071 {
7072 	mlan_status ret = MLAN_STATUS_SUCCESS;
7073 	struct wiphy *wiphy;
7074 	void *wdev_priv = NULL;
7075 	mlan_fw_info fw_info;
7076 	char *country = NULL;
7077 	int index = 0;
7078 
7079 	ENTER();
7080 
7081 	woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info);
7082 
7083 	wiphy = wiphy_new(&woal_cfg80211_ops, sizeof(moal_handle *));
7084 	if (!wiphy) {
7085 		PRINTM(MERROR, "Could not allocate wiphy device\n");
7086 		ret = MLAN_STATUS_FAILURE;
7087 		goto err_wiphy;
7088 	}
7089 #ifdef CONFIG_PM
7090 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
7091 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
7092 	if (fw_info.fw_supplicant_support)
7093 		wiphy->wowlan = &wowlan_support_with_gtk;
7094 	else
7095 		wiphy->wowlan = &wowlan_support;
7096 #else
7097 	wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_MAGIC_PKT;
7098 	if (fw_info.fw_supplicant_support) {
7099 		wiphy->wowlan.flags |=
7100 			WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
7101 			WIPHY_WOWLAN_GTK_REKEY_FAILURE;
7102 	}
7103 	wiphy->wowlan.n_patterns = MAX_NUM_FILTERS;
7104 	wiphy->wowlan.pattern_min_len = 1;
7105 	wiphy->wowlan.pattern_max_len = WOWLAN_MAX_PATTERN_LEN;
7106 	wiphy->wowlan.max_pkt_offset = WOWLAN_MAX_OFFSET_LEN;
7107 #endif
7108 #endif
7109 #endif
7110 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
7111 	wiphy->coalesce = &coalesce_support;
7112 #endif
7113 	wiphy->max_scan_ssids = MRVDRV_MAX_SSID_LIST_LENGTH;
7114 	wiphy->max_scan_ie_len = MAX_IE_SIZE;
7115 	wiphy->interface_modes = 0;
7116 	wiphy->interface_modes =
7117 		MBIT(NL80211_IFTYPE_STATION) | MBIT(NL80211_IFTYPE_ADHOC) |
7118 		MBIT(NL80211_IFTYPE_AP);
7119 	wiphy->interface_modes |= MBIT(NL80211_IFTYPE_MONITOR);
7120 
7121 #if defined(WIFI_DIRECT_SUPPORT)
7122 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
7123 	wiphy->interface_modes |= MBIT(NL80211_IFTYPE_P2P_GO) |
7124 		MBIT(NL80211_IFTYPE_P2P_CLIENT);
7125 #endif
7126 #endif
7127 
7128 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
7129 	woal_register_cfg80211_vendor_command(wiphy);
7130 #endif
7131 	/* Make this wiphy known to this driver only */
7132 	wiphy->privid = mrvl_wiphy_privid;
7133 
7134 	if (!fw_info.fw_bands)
7135 		fw_info.fw_bands = BAND_B | BAND_G;
7136 	if (fw_info.fw_bands & BAND_A) {
7137 		wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz;
7138 		priv->phandle->band = IEEE80211_BAND_5GHZ;
7139 	}
7140 	/* Supported bands */
7141 	if (fw_info.fw_bands & (BAND_B | BAND_G | BAND_GN)) {
7142 		wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz;
7143 		/* If 2.4G enable, it will overwrite default to 2.4G */
7144 		priv->phandle->band = IEEE80211_BAND_2GHZ;
7145 	}
7146 
7147 	if (fw_info.fw_bands & BAND_A) {
7148 	/** reduce scan time from 110ms to 80ms */
7149 		woal_set_scan_time(priv, INIT_ACTIVE_SCAN_CHAN_TIME,
7150 				   INIT_PASSIVE_SCAN_CHAN_TIME,
7151 				   INIT_SPECIFIC_SCAN_CHAN_TIME);
7152 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
7153 		cfg80211_iface_comb_ap_sta.radar_detect_widths |=
7154 			MBIT(NL80211_CHAN_WIDTH_40);
7155 #endif
7156 	} else
7157 		woal_set_scan_time(priv, ACTIVE_SCAN_CHAN_TIME,
7158 				   PASSIVE_SCAN_CHAN_TIME,
7159 				   SPECIFIC_SCAN_CHAN_TIME);
7160 
7161 	/* Initialize cipher suits */
7162 	wiphy->cipher_suites = cfg80211_cipher_suites;
7163 	wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites);
7164 #ifdef UAP_CFG80211
7165 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
7166 	wiphy->max_acl_mac_addrs = MAX_MAC_FILTER_NUM;
7167 #endif
7168 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
7169 	if (fw_info.max_ap_assoc_sta)
7170 		wiphy->max_ap_assoc_sta = fw_info.max_ap_assoc_sta;
7171 #endif
7172 #endif
7173 
7174 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
7175 	if (cfg80211_drcs) {
7176 		cfg80211_iface_comb_ap_sta.num_different_channels = 2;
7177 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
7178 		cfg80211_iface_comb_ap_sta.radar_detect_widths = 0;
7179 #endif
7180 	}
7181 	/* Initialize interface combinations */
7182 	wiphy->iface_combinations = &cfg80211_iface_comb_ap_sta;
7183 	wiphy->n_iface_combinations = 1;
7184 #endif
7185 
7186 	memcpy(wiphy->perm_addr, priv->current_addr, ETH_ALEN);
7187 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
7188 
7189 	wiphy->flags = 0;
7190 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
7191 	wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
7192 #endif
7193 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
7194 	wiphy->flags |=
7195 		WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_OFFCHAN_TX;
7196 	wiphy->flags |=
7197 		WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
7198 	wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
7199 #endif
7200 #ifdef ANDROID_KERNEL
7201 	wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME;
7202 #endif
7203 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
7204 #if CFG80211_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
7205 	wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
7206 #else
7207 	wiphy->max_sched_scan_reqs = 1;
7208 #endif
7209 	wiphy->max_sched_scan_ssids = MRVDRV_MAX_SSID_LIST_LENGTH;
7210 	wiphy->max_sched_scan_ie_len = MAX_IE_SIZE;
7211 	wiphy->max_match_sets = MRVDRV_MAX_SSID_LIST_LENGTH;
7212 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
7213 	wiphy->max_sched_scan_plans = 1;
7214 #endif
7215 #endif
7216 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,2,0)
7217 	wiphy->flags |=
7218 		WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
7219 #endif
7220 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,19,0)
7221 	wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
7222 #endif
7223 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3,4,0)
7224 	wiphy->features |= NL80211_FEATURE_HT_IBSS;
7225 #endif
7226 	wiphy->reg_notifier = woal_cfg80211_reg_notifier;
7227 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
7228 	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
7229 #endif
7230 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
7231 	/* Indicate to cfg80211 that the driver can support
7232 	 * CSA and ESCA,i.e., both types of channel switch
7233 	 * Applications like hostapd 2.6 will append CSA IE
7234 	 * and ECSA IE and expect the driver to advertise 2
7235 	 * in max_num_csa_counters to successfully issue a
7236 	 * channel switch
7237 	 */
7238 	wiphy->max_num_csa_counters = MAX_CSA_COUNTERS_NUM;
7239 #endif
7240 	wiphy->flags |= WIPHY_FLAG_CONTROL_PORT_PROTOCOL;
7241 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
7242 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
7243 #endif
7244 	/* Set struct moal_handle pointer in wiphy_priv */
7245 	wdev_priv = wiphy_priv(wiphy);
7246 	*(unsigned long *)wdev_priv = (unsigned long)priv->phandle;
7247 
7248 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
7249 	set_wiphy_dev(wiphy, (struct device *)priv->phandle->hotplug_device);
7250 #endif
7251 	/* Set phy name */
7252 	for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
7253 		if (m_handle[index] == priv->phandle) {
7254 			dev_set_name(&wiphy->dev, mwiphy_name, index);
7255 			break;
7256 		}
7257 	}
7258 
7259 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
7260 	if (beacon_hints) {
7261 		/* REGULATORY_DISABLE_BEACON_HINTS: NO-IR flag won't be removed on chn where an AP is visible! */
7262 		wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
7263 	}
7264 	if (country_ie_ignore) {
7265 		PRINTM(MIOCTL, "Don't follow countryIE provided by AP.\n");
7266 		wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
7267 	} else {
7268 		PRINTM(MIOCTL, "Follow countryIE provided by AP.\n");
7269 	}
7270 #endif
7271 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
7272 	if (fw_region) {
7273 		priv->phandle->regd = woal_create_custom_regdomain(priv);
7274 		if (priv->phandle->regd) {
7275 			wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
7276 				REGULATORY_DISABLE_BEACON_HINTS |
7277 				REGULATORY_COUNTRY_IE_IGNORE;
7278 			wiphy_apply_custom_regulatory(wiphy,
7279 						      priv->phandle->regd);
7280 		} else {
7281 			PRINTM(MERROR,
7282 			       "creating custom regulatory domain failed\n");
7283 		}
7284 	}
7285 #endif
7286 	if (reg_alpha2 && !strncmp(reg_alpha2, "99", strlen("99"))) {
7287 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
7288 		wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
7289 			REGULATORY_DISABLE_BEACON_HINTS |
7290 			REGULATORY_COUNTRY_IE_IGNORE;
7291 #else
7292 		wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
7293 #endif
7294 		wiphy_apply_custom_regulatory(wiphy, &mrvl_regdom);
7295 	}
7296 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
7297 	if (woal_request_extcap(priv,
7298 				(t_u8 *)&priv->extended_capabilities,
7299 				sizeof(priv->extended_capabilities)) < 0)
7300 		PRINTM(MERROR,
7301 		       "Failed to get driver extended capability, use default\n");
7302 	DBG_HEXDUMP(MCMD_D, "wiphy ext cap",
7303 		    (t_u8 *)&priv->extended_capabilities,
7304 		    sizeof(priv->extended_capabilities));
7305 	wiphy->extended_capabilities = (t_u8 *)&priv->extended_capabilities;
7306 	wiphy->extended_capabilities_mask =
7307 		(t_u8 *)&priv->extended_capabilities;
7308 	wiphy->extended_capabilities_len = sizeof(priv->extended_capabilities);
7309 #endif
7310 	if (wiphy_register(wiphy) < 0) {
7311 		PRINTM(MERROR, "Wiphy device registration failed!\n");
7312 		ret = MLAN_STATUS_FAILURE;
7313 		goto err_wiphy;
7314 	}
7315 #if defined(WIFI_DIRECT_SUPPORT)
7316 #if CFG80211_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION
7317 	if (!p2p_enh)
7318 		wiphy->interface_modes &= ~(MBIT(NL80211_IFTYPE_P2P_GO) |
7319 					    MBIT(NL80211_IFTYPE_P2P_CLIENT));
7320 #endif
7321 #endif
7322 	wiphy->interface_modes &= ~(MBIT(NL80211_IFTYPE_MONITOR));
7323 
7324 	if ((!reg_alpha2 || strncmp(reg_alpha2, "99", strlen("99")))
7325 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
7326 	    && !priv->phandle->regd
7327 #endif
7328 		) {
7329 	/** we will try driver parameter first */
7330 		if (reg_alpha2 && woal_is_valid_alpha2(reg_alpha2)) {
7331 			PRINTM(MIOCTL, "Notify reg_alpha2 %c%c\n",
7332 			       reg_alpha2[0], reg_alpha2[1]);
7333 			regulatory_hint(wiphy, reg_alpha2);
7334 		} else {
7335 			country = region_code_2_string(fw_info.region_code);
7336 			if (country) {
7337 				if (fw_info.region_code != 0) {
7338 					PRINTM(MIOCTL,
7339 					       "Notify hw region code=%d %c%c\n",
7340 					       fw_info.region_code, country[0],
7341 					       country[1]);
7342 					regulatory_hint(wiphy, country);
7343 				}
7344 			} else
7345 				PRINTM(MERROR,
7346 				       "hw region code=%d not supported\n",
7347 				       fw_info.region_code);
7348 		}
7349 	}
7350 	priv->phandle->wiphy = wiphy;
7351 	woal_cfg80211_init_wiphy(priv, MOAL_IOCTL_WAIT);
7352 
7353 	return ret;
7354 err_wiphy:
7355 	if (wiphy)
7356 		wiphy_free(wiphy);
7357 	LEAVE();
7358 	return ret;
7359 }
7360 
7361 module_param(cfg80211_drcs, int, 0);
7362 MODULE_PARM_DESC(cfg80211_drcs,
7363 		 "1: Enable DRCS support; 0: Disable DRCS support");
7364 module_param(reg_alpha2, charp, 0660);
7365 MODULE_PARM_DESC(reg_alpha2, "Regulatory alpha2");
7366 #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
7367 module_param(country_ie_ignore, int, 0);
7368 MODULE_PARM_DESC(country_ie_ignore,
7369 		 "0: Follow countryIE from AP and beacon hint enable; 1: Ignore countryIE from AP and beacon hint disable");
7370 module_param(beacon_hints, int, 0);
7371 MODULE_PARM_DESC(beacon_hints,
7372 		 "0: enable beacon hints(default); 1: disable beacon hints");
7373 #endif
7374