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 = ®d->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