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