blob: 138b634affc57d0fd86aa354a40c4c80da3313f9 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08002 * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_cfg80211.c
30 *
31 * WLAN Host Device Driver cfg80211 APIs implementation
32 *
33 */
34
35#include <linux/version.h>
36#include <linux/module.h>
37#include <linux/kernel.h>
38#include <linux/init.h>
39#include <linux/etherdevice.h>
40#include <linux/wireless.h>
41#include <wlan_hdd_includes.h>
42#include <net/arp.h>
43#include <net/cfg80211.h>
44#include <cdf_trace.h>
45#ifdef CONFIG_CNSS
46#include <net/cnss.h>
47#endif
48#include <wlan_hdd_wowl.h>
49#include <ani_global.h>
50#include "sir_params.h"
51#include "dot11f.h"
52#include "wlan_hdd_assoc.h"
53#include "wlan_hdd_wext.h"
54#include "sme_api.h"
Peng Xu278d0122015-09-24 16:34:17 -070055#include "sme_power_save_api.h"
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080056#include "wlan_hdd_p2p.h"
57#include "wlan_hdd_cfg80211.h"
58#include "wlan_hdd_hostapd.h"
59#include "wlan_hdd_softap_tx_rx.h"
60#include "wlan_hdd_main.h"
61#include "wlan_hdd_power.h"
62#include "wlan_hdd_trace.h"
63#include "cdf_types.h"
64#include "cdf_trace.h"
65#include "cds_utils.h"
66#include "cds_sched.h"
67#include "wlan_hdd_scan.h"
68#include <qc_sap_ioctl.h>
69#include "wlan_hdd_tdls.h"
70#include "wlan_hdd_wmm.h"
71#include "wma_types.h"
72#include "wlan_hdd_misc.h"
73#include "wlan_hdd_nan.h"
74#include <wlan_hdd_ipa.h>
75#include "wlan_logging_sock_svc.h"
76
77#ifdef FEATURE_WLAN_EXTSCAN
78#include "wlan_hdd_ext_scan.h"
79#endif
80
81#ifdef WLAN_FEATURE_LINK_LAYER_STATS
82#include "wlan_hdd_stats.h"
83#endif
84#include "cds_concurrency.h"
85#include "qwlan_version.h"
86#include "wlan_hdd_memdump.h"
87
88#include "wlan_hdd_ocb.h"
89
Ravi Joshideb5a8d2015-11-09 19:11:43 -080090#include "wlan_hdd_subnet_detect.h"
91
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080092#define g_mode_rates_size (12)
93#define a_mode_rates_size (8)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080094#define GET_IE_LEN_IN_BSS_DESC(lenInBss) (lenInBss + sizeof(lenInBss) - \
95 ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields)))
96
97/*
98 * Android CTS verifier needs atleast this much wait time (in msec)
99 */
100#define MAX_REMAIN_ON_CHANNEL_DURATION (5000)
101
102/*
103 * Refer @tCfgProtection structure for definition of the bit map.
104 * below value is obtained by setting the following bit-fields.
105 * enable obss, fromllb, overlapOBSS and overlapFromllb protection.
106 */
107#define IBSS_CFG_PROTECTION_ENABLE_MASK 0x8282
108
109#define HDD2GHZCHAN(freq, chan, flag) { \
110 .band = IEEE80211_BAND_2GHZ, \
111 .center_freq = (freq), \
112 .hw_value = (chan), \
113 .flags = (flag), \
114 .max_antenna_gain = 0, \
115 .max_power = 30, \
116}
117
118#define HDD5GHZCHAN(freq, chan, flag) { \
119 .band = IEEE80211_BAND_5GHZ, \
120 .center_freq = (freq), \
121 .hw_value = (chan), \
122 .flags = (flag), \
123 .max_antenna_gain = 0, \
124 .max_power = 30, \
125}
126
127#define HDD_G_MODE_RATETAB(rate, rate_id, flag) \
128 { \
129 .bitrate = rate, \
130 .hw_value = rate_id, \
131 .flags = flag, \
132 }
133
134#ifdef WLAN_FEATURE_VOWIFI_11R
135#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03
136#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04
137#endif
138
139#define HDD_CHANNEL_14 14
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800140
Peng Xu4d67c8f2015-10-16 16:02:26 -0700141#define MAX_TXPOWER_SCALE 4
142
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800143static const u32 hdd_cipher_suites[] = {
144 WLAN_CIPHER_SUITE_WEP40,
145 WLAN_CIPHER_SUITE_WEP104,
146 WLAN_CIPHER_SUITE_TKIP,
147#ifdef FEATURE_WLAN_ESE
148#define WLAN_CIPHER_SUITE_BTK 0x004096fe /* use for BTK */
149#define WLAN_CIPHER_SUITE_KRK 0x004096ff /* use for KRK */
150 WLAN_CIPHER_SUITE_BTK,
151 WLAN_CIPHER_SUITE_KRK,
152 WLAN_CIPHER_SUITE_CCMP,
153#else
154 WLAN_CIPHER_SUITE_CCMP,
155#endif
156#ifdef FEATURE_WLAN_WAPI
157 WLAN_CIPHER_SUITE_SMS4,
158#endif
159#ifdef WLAN_FEATURE_11W
160 WLAN_CIPHER_SUITE_AES_CMAC,
161#endif
162};
163
164static struct ieee80211_channel hdd_channels_2_4_ghz[] = {
165 HDD2GHZCHAN(2412, 1, 0),
166 HDD2GHZCHAN(2417, 2, 0),
167 HDD2GHZCHAN(2422, 3, 0),
168 HDD2GHZCHAN(2427, 4, 0),
169 HDD2GHZCHAN(2432, 5, 0),
170 HDD2GHZCHAN(2437, 6, 0),
171 HDD2GHZCHAN(2442, 7, 0),
172 HDD2GHZCHAN(2447, 8, 0),
173 HDD2GHZCHAN(2452, 9, 0),
174 HDD2GHZCHAN(2457, 10, 0),
175 HDD2GHZCHAN(2462, 11, 0),
176 HDD2GHZCHAN(2467, 12, 0),
177 HDD2GHZCHAN(2472, 13, 0),
178 HDD2GHZCHAN(2484, 14, 0),
179};
180
181static struct ieee80211_channel hdd_social_channels_2_4_ghz[] = {
182 HDD2GHZCHAN(2412, 1, 0),
183 HDD2GHZCHAN(2437, 6, 0),
184 HDD2GHZCHAN(2462, 11, 0),
185};
186
187static struct ieee80211_channel hdd_channels_5_ghz[] = {
188 HDD5GHZCHAN(4920, 240, 0),
189 HDD5GHZCHAN(4940, 244, 0),
190 HDD5GHZCHAN(4960, 248, 0),
191 HDD5GHZCHAN(4980, 252, 0),
192 HDD5GHZCHAN(5040, 208, 0),
193 HDD5GHZCHAN(5060, 212, 0),
194 HDD5GHZCHAN(5080, 216, 0),
195 HDD5GHZCHAN(5180, 36, 0),
196 HDD5GHZCHAN(5200, 40, 0),
197 HDD5GHZCHAN(5220, 44, 0),
198 HDD5GHZCHAN(5240, 48, 0),
199 HDD5GHZCHAN(5260, 52, 0),
200 HDD5GHZCHAN(5280, 56, 0),
201 HDD5GHZCHAN(5300, 60, 0),
202 HDD5GHZCHAN(5320, 64, 0),
203 HDD5GHZCHAN(5500, 100, 0),
204 HDD5GHZCHAN(5520, 104, 0),
205 HDD5GHZCHAN(5540, 108, 0),
206 HDD5GHZCHAN(5560, 112, 0),
207 HDD5GHZCHAN(5580, 116, 0),
208 HDD5GHZCHAN(5600, 120, 0),
209 HDD5GHZCHAN(5620, 124, 0),
210 HDD5GHZCHAN(5640, 128, 0),
211 HDD5GHZCHAN(5660, 132, 0),
212 HDD5GHZCHAN(5680, 136, 0),
213 HDD5GHZCHAN(5700, 140, 0),
214 HDD5GHZCHAN(5720, 144, 0),
215 HDD5GHZCHAN(5745, 149, 0),
216 HDD5GHZCHAN(5765, 153, 0),
217 HDD5GHZCHAN(5785, 157, 0),
218 HDD5GHZCHAN(5805, 161, 0),
219 HDD5GHZCHAN(5825, 165, 0),
220#ifndef FEATURE_STATICALLY_ADD_11P_CHANNELS
221 HDD5GHZCHAN(5852, 170, 0),
222 HDD5GHZCHAN(5855, 171, 0),
223 HDD5GHZCHAN(5860, 172, 0),
224 HDD5GHZCHAN(5865, 173, 0),
225 HDD5GHZCHAN(5870, 174, 0),
226 HDD5GHZCHAN(5875, 175, 0),
227 HDD5GHZCHAN(5880, 176, 0),
228 HDD5GHZCHAN(5885, 177, 0),
229 HDD5GHZCHAN(5890, 178, 0),
230 HDD5GHZCHAN(5895, 179, 0),
231 HDD5GHZCHAN(5900, 180, 0),
232 HDD5GHZCHAN(5905, 181, 0),
233 HDD5GHZCHAN(5910, 182, 0),
234 HDD5GHZCHAN(5915, 183, 0),
235 HDD5GHZCHAN(5920, 184, 0),
236#endif
237};
238
239static struct ieee80211_rate g_mode_rates[] = {
240 HDD_G_MODE_RATETAB(10, 0x1, 0),
241 HDD_G_MODE_RATETAB(20, 0x2, 0),
242 HDD_G_MODE_RATETAB(55, 0x4, 0),
243 HDD_G_MODE_RATETAB(110, 0x8, 0),
244 HDD_G_MODE_RATETAB(60, 0x10, 0),
245 HDD_G_MODE_RATETAB(90, 0x20, 0),
246 HDD_G_MODE_RATETAB(120, 0x40, 0),
247 HDD_G_MODE_RATETAB(180, 0x80, 0),
248 HDD_G_MODE_RATETAB(240, 0x100, 0),
249 HDD_G_MODE_RATETAB(360, 0x200, 0),
250 HDD_G_MODE_RATETAB(480, 0x400, 0),
251 HDD_G_MODE_RATETAB(540, 0x800, 0),
252};
253
254static struct ieee80211_rate a_mode_rates[] = {
255 HDD_G_MODE_RATETAB(60, 0x10, 0),
256 HDD_G_MODE_RATETAB(90, 0x20, 0),
257 HDD_G_MODE_RATETAB(120, 0x40, 0),
258 HDD_G_MODE_RATETAB(180, 0x80, 0),
259 HDD_G_MODE_RATETAB(240, 0x100, 0),
260 HDD_G_MODE_RATETAB(360, 0x200, 0),
261 HDD_G_MODE_RATETAB(480, 0x400, 0),
262 HDD_G_MODE_RATETAB(540, 0x800, 0),
263};
264
265static struct ieee80211_supported_band wlan_hdd_band_2_4_ghz = {
266 .channels = hdd_channels_2_4_ghz,
267 .n_channels = ARRAY_SIZE(hdd_channels_2_4_ghz),
268 .band = IEEE80211_BAND_2GHZ,
269 .bitrates = g_mode_rates,
270 .n_bitrates = g_mode_rates_size,
271 .ht_cap.ht_supported = 1,
272 .ht_cap.cap = IEEE80211_HT_CAP_SGI_20
273 | IEEE80211_HT_CAP_GRN_FLD
274 | IEEE80211_HT_CAP_DSSSCCK40
275 | IEEE80211_HT_CAP_LSIG_TXOP_PROT
276 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40,
277 .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
278 .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
279 .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
280 .ht_cap.mcs.rx_highest = cpu_to_le16(72),
281 .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
282};
283
284static struct ieee80211_supported_band wlan_hdd_band_p2p_2_4_ghz = {
285 .channels = hdd_social_channels_2_4_ghz,
286 .n_channels = ARRAY_SIZE(hdd_social_channels_2_4_ghz),
287 .band = IEEE80211_BAND_2GHZ,
288 .bitrates = g_mode_rates,
289 .n_bitrates = g_mode_rates_size,
290 .ht_cap.ht_supported = 1,
291 .ht_cap.cap = IEEE80211_HT_CAP_SGI_20
292 | IEEE80211_HT_CAP_GRN_FLD
293 | IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_LSIG_TXOP_PROT,
294 .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
295 .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
296 .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
297 .ht_cap.mcs.rx_highest = cpu_to_le16(72),
298 .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
299};
300
301static struct ieee80211_supported_band wlan_hdd_band_5_ghz = {
302 .channels = hdd_channels_5_ghz,
303 .n_channels = ARRAY_SIZE(hdd_channels_5_ghz),
304 .band = IEEE80211_BAND_5GHZ,
305 .bitrates = a_mode_rates,
306 .n_bitrates = a_mode_rates_size,
307 .ht_cap.ht_supported = 1,
308 .ht_cap.cap = IEEE80211_HT_CAP_SGI_20
309 | IEEE80211_HT_CAP_GRN_FLD
310 | IEEE80211_HT_CAP_DSSSCCK40
311 | IEEE80211_HT_CAP_LSIG_TXOP_PROT
312 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40,
313 .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
314 .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
315 .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
316 .ht_cap.mcs.rx_highest = cpu_to_le16(72),
317 .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
318 .vht_cap.vht_supported = 1,
319};
320
321/* This structure contain information what kind of frame are expected in
322 TX/RX direction for each kind of interface */
323static const struct ieee80211_txrx_stypes
324 wlan_hdd_txrx_stypes[NUM_NL80211_IFTYPES] = {
325 [NL80211_IFTYPE_STATION] = {
326 .tx = 0xffff,
327 .rx = BIT(SIR_MAC_MGMT_ACTION) |
328 BIT(SIR_MAC_MGMT_PROBE_REQ),
329 },
330 [NL80211_IFTYPE_AP] = {
331 .tx = 0xffff,
332 .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) |
333 BIT(SIR_MAC_MGMT_REASSOC_REQ) |
334 BIT(SIR_MAC_MGMT_PROBE_REQ) |
335 BIT(SIR_MAC_MGMT_DISASSOC) |
336 BIT(SIR_MAC_MGMT_AUTH) |
337 BIT(SIR_MAC_MGMT_DEAUTH) |
338 BIT(SIR_MAC_MGMT_ACTION),
339 },
340 [NL80211_IFTYPE_ADHOC] = {
341 .tx = 0xffff,
342 .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) |
343 BIT(SIR_MAC_MGMT_REASSOC_REQ) |
344 BIT(SIR_MAC_MGMT_PROBE_REQ) |
345 BIT(SIR_MAC_MGMT_DISASSOC) |
346 BIT(SIR_MAC_MGMT_AUTH) |
347 BIT(SIR_MAC_MGMT_DEAUTH) |
348 BIT(SIR_MAC_MGMT_ACTION),
349 },
350 [NL80211_IFTYPE_P2P_CLIENT] = {
351 .tx = 0xffff,
352 .rx = BIT(SIR_MAC_MGMT_ACTION) |
353 BIT(SIR_MAC_MGMT_PROBE_REQ),
354 },
355 [NL80211_IFTYPE_P2P_GO] = {
356 /* This is also same as for SoftAP */
357 .tx = 0xffff,
358 .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) |
359 BIT(SIR_MAC_MGMT_REASSOC_REQ) |
360 BIT(SIR_MAC_MGMT_PROBE_REQ) |
361 BIT(SIR_MAC_MGMT_DISASSOC) |
362 BIT(SIR_MAC_MGMT_AUTH) |
363 BIT(SIR_MAC_MGMT_DEAUTH) |
364 BIT(SIR_MAC_MGMT_ACTION),
365 },
366};
367
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800368/* Interface limits and combinations registered by the driver */
369
370/* STA ( + STA ) combination */
371static const struct ieee80211_iface_limit
372 wlan_hdd_sta_iface_limit[] = {
373 {
374 .max = 3, /* p2p0 is a STA as well */
375 .types = BIT(NL80211_IFTYPE_STATION),
376 },
377};
378
Krunal Soni7bc4f912015-11-15 23:41:56 -0800379#ifndef QCA_WIFI_3_0_EMU
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800380/* ADHOC (IBSS) limit */
381static const struct ieee80211_iface_limit
382 wlan_hdd_adhoc_iface_limit[] = {
383 {
384 .max = 1,
385 .types = BIT(NL80211_IFTYPE_STATION),
386 },
387 {
388 .max = 1,
389 .types = BIT(NL80211_IFTYPE_ADHOC),
390 },
391};
Krunal Soni7bc4f912015-11-15 23:41:56 -0800392#else
393/* ADHOC (IBSS) limit */
394static const struct ieee80211_iface_limit
395 wlan_hdd_adhoc_iface_limit[] = {
396 {
397 .max = 1,
398 .types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP),
399 },
400 {
401 .max = 1,
402 .types = BIT(NL80211_IFTYPE_ADHOC),
403 },
404};
405#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800406
407/* AP ( + AP ) combination */
408static const struct ieee80211_iface_limit
409 wlan_hdd_ap_iface_limit[] = {
410 {
411 .max = (CDF_MAX_NO_OF_SAP_MODE + SAP_MAX_OBSS_STA_CNT),
412 .types = BIT(NL80211_IFTYPE_AP),
413 },
414};
415
416/* P2P limit */
417static const struct ieee80211_iface_limit
418 wlan_hdd_p2p_iface_limit[] = {
419 {
420 .max = 1,
421 .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
422 },
423 {
424 .max = 1,
425 .types = BIT(NL80211_IFTYPE_P2P_GO),
426 },
427};
428
429static const struct ieee80211_iface_limit
430 wlan_hdd_sta_ap_iface_limit[] = {
431 {
432 /* We need 1 extra STA interface for OBSS scan when SAP starts
433 * with HT40 in STA+SAP concurrency mode
434 */
435 .max = (1 + SAP_MAX_OBSS_STA_CNT),
436 .types = BIT(NL80211_IFTYPE_STATION),
437 },
438 {
439 .max = CDF_MAX_NO_OF_SAP_MODE,
440 .types = BIT(NL80211_IFTYPE_AP),
441 },
442};
443
444/* STA + P2P combination */
445static const struct ieee80211_iface_limit
446 wlan_hdd_sta_p2p_iface_limit[] = {
447 {
448 /* One reserved for dedicated P2PDEV usage */
449 .max = 2,
450 .types = BIT(NL80211_IFTYPE_STATION)
451 },
452 {
453 /* Support for two identical (GO + GO or CLI + CLI)
454 * or dissimilar (GO + CLI) P2P interfaces
455 */
456 .max = 2,
457 .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT),
458 },
459};
460
461/* STA + AP + P2PGO combination */
462static const struct ieee80211_iface_limit
463wlan_hdd_sta_ap_p2pgo_iface_limit[] = {
464 /* Support for AP+P2PGO interfaces */
465 {
466 .max = 2,
467 .types = BIT(NL80211_IFTYPE_STATION)
468 },
469 {
470 .max = 1,
471 .types = BIT(NL80211_IFTYPE_P2P_GO)
472 },
473 {
474 .max = 1,
475 .types = BIT(NL80211_IFTYPE_AP)
476 }
477};
478
479/* SAP + P2P combination */
480static const struct ieee80211_iface_limit
481wlan_hdd_sap_p2p_iface_limit[] = {
482 {
483 /* 1 dedicated for p2p0 which is a STA type */
484 .max = 1,
485 .types = BIT(NL80211_IFTYPE_STATION)
486 },
487 {
488 /* The p2p interface in SAP+P2P can be GO/CLI.
489 * The p2p connection can be formed on p2p0 or p2p-p2p0-x.
490 */
491 .max = 1,
492 .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT)
493 },
494 {
495 /* SAP+GO to support only one SAP interface */
496 .max = 1,
497 .types = BIT(NL80211_IFTYPE_AP)
498 }
499};
500
501/* P2P + P2P combination */
502static const struct ieee80211_iface_limit
503wlan_hdd_p2p_p2p_iface_limit[] = {
504 {
505 /* 1 dedicated for p2p0 which is a STA type */
506 .max = 1,
507 .types = BIT(NL80211_IFTYPE_STATION)
508 },
509 {
510 /* The p2p interface in P2P+P2P can be GO/CLI.
511 * For P2P+P2P, the new interfaces are formed on p2p-p2p0-x.
512 */
513 .max = 2,
514 .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT)
515 },
516};
517
518static struct ieee80211_iface_combination
519 wlan_hdd_iface_combination[] = {
520 /* STA */
521 {
522 .limits = wlan_hdd_sta_iface_limit,
523 .num_different_channels = 2,
524 .max_interfaces = 3,
525 .n_limits = ARRAY_SIZE(wlan_hdd_sta_iface_limit),
526 },
527 /* ADHOC */
528 {
529 .limits = wlan_hdd_adhoc_iface_limit,
Krunal Soni2c68f232015-10-26 20:52:51 -0700530 .num_different_channels = 2,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800531 .max_interfaces = 2,
532 .n_limits = ARRAY_SIZE(wlan_hdd_adhoc_iface_limit),
533 },
534 /* AP */
535 {
536 .limits = wlan_hdd_ap_iface_limit,
537 .num_different_channels = 2,
538 .max_interfaces = (SAP_MAX_OBSS_STA_CNT + CDF_MAX_NO_OF_SAP_MODE),
539 .n_limits = ARRAY_SIZE(wlan_hdd_ap_iface_limit),
540 },
541 /* P2P */
542 {
543 .limits = wlan_hdd_p2p_iface_limit,
544 .num_different_channels = 2,
545 .max_interfaces = 2,
546 .n_limits = ARRAY_SIZE(wlan_hdd_p2p_iface_limit),
547 },
548 /* STA + AP */
549 {
550 .limits = wlan_hdd_sta_ap_iface_limit,
551 .num_different_channels = 2,
552 .max_interfaces = (1 + SAP_MAX_OBSS_STA_CNT + CDF_MAX_NO_OF_SAP_MODE),
553 .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_iface_limit),
554 .beacon_int_infra_match = true,
555 },
556 /* STA + P2P */
557 {
558 .limits = wlan_hdd_sta_p2p_iface_limit,
559 .num_different_channels = 2,
560 /* one interface reserved for P2PDEV dedicated usage */
561 .max_interfaces = 4,
562 .n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_iface_limit),
563 .beacon_int_infra_match = true,
564 },
565 /* STA + P2P GO + SAP */
566 {
567 .limits = wlan_hdd_sta_ap_p2pgo_iface_limit,
568 /* we can allow 3 channels for three different persona
569 * but due to firmware limitation, allow max 2 concrnt channels.
570 */
571 .num_different_channels = 2,
572 /* one interface reserved for P2PDEV dedicated usage */
573 .max_interfaces = 4,
574 .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_p2pgo_iface_limit),
575 .beacon_int_infra_match = true,
576 },
577 /* SAP + P2P */
578 {
579 .limits = wlan_hdd_sap_p2p_iface_limit,
580 .num_different_channels = 2,
581 /* 1-p2p0 + 1-SAP + 1-P2P (on p2p0 or p2p-p2p0-x) */
582 .max_interfaces = 3,
583 .n_limits = ARRAY_SIZE(wlan_hdd_sap_p2p_iface_limit),
584 .beacon_int_infra_match = true,
585 },
586 /* P2P + P2P */
587 {
588 .limits = wlan_hdd_p2p_p2p_iface_limit,
589 .num_different_channels = 2,
590 /* 1-p2p0 + 2-P2P (on p2p-p2p0-x) */
591 .max_interfaces = 3,
592 .n_limits = ARRAY_SIZE(wlan_hdd_p2p_p2p_iface_limit),
593 .beacon_int_infra_match = true,
594 },
595};
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800596
597static struct cfg80211_ops wlan_hdd_cfg80211_ops;
598
599
600#ifdef WLAN_NL80211_TESTMODE
601enum wlan_hdd_tm_attr {
602 WLAN_HDD_TM_ATTR_INVALID = 0,
603 WLAN_HDD_TM_ATTR_CMD = 1,
604 WLAN_HDD_TM_ATTR_DATA = 2,
605 WLAN_HDD_TM_ATTR_STREAM_ID = 3,
606 WLAN_HDD_TM_ATTR_TYPE = 4,
607 /* keep last */
608 WLAN_HDD_TM_ATTR_AFTER_LAST,
609 WLAN_HDD_TM_ATTR_MAX = WLAN_HDD_TM_ATTR_AFTER_LAST - 1,
610};
611
612enum wlan_hdd_tm_cmd {
613 WLAN_HDD_TM_CMD_WLAN_FTM = 0,
614 WLAN_HDD_TM_CMD_WLAN_HB = 1,
615};
616
617#define WLAN_HDD_TM_DATA_MAX_LEN 5000
618
619static const struct nla_policy wlan_hdd_tm_policy[WLAN_HDD_TM_ATTR_MAX + 1] = {
620 [WLAN_HDD_TM_ATTR_CMD] = {.type = NLA_U32},
621 [WLAN_HDD_TM_ATTR_DATA] = {.type = NLA_BINARY,
622 .len = WLAN_HDD_TM_DATA_MAX_LEN},
623};
624#endif /* WLAN_NL80211_TESTMODE */
625
626#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
627static const struct wiphy_wowlan_support wowlan_support_cfg80211_init = {
628 .flags = WIPHY_WOWLAN_MAGIC_PKT,
629 .n_patterns = WOWL_MAX_PTRNS_ALLOWED,
630 .pattern_min_len = 1,
631 .pattern_max_len = WOWL_PTRN_MAX_SIZE,
632};
633#endif
634
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800635/**
Abhishek Singh1bdb1572015-10-16 16:24:19 +0530636 * hdd_add_channel_switch_support()- Adds Channel Switch flag if supported
637 * @flags: Pointer to the flags to Add channel switch flag.
638 *
639 * This Function adds Channel Switch support flag, if channel switch is
640 * supported by kernel.
641 * Return: void.
642 */
643#ifdef CHANNEL_SWITCH_SUPPORTED
644static inline void hdd_add_channel_switch_support(uint32_t *flags)
645{
Krishna Kumaar Natarajan8a8df262015-12-04 11:43:46 -0800646 *flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
Abhishek Singh1bdb1572015-10-16 16:24:19 +0530647 return;
648}
649#else
650static inline void hdd_add_channel_switch_support(uint32_t *flags)
651{
652 return;
653}
654#endif
655
Manikandan Mohan22b83722015-12-15 15:03:23 -0800656#ifdef FEATURE_WLAN_TDLS
657
658/* TDLS capabilities params */
659#define PARAM_MAX_TDLS_SESSION \
660 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS
661#define PARAM_TDLS_FEATURE_SUPPORT \
662 QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED
663
Abhishek Singh1bdb1572015-10-16 16:24:19 +0530664/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800665 * __wlan_hdd_cfg80211_get_tdls_capabilities() - Provide TDLS Capabilites.
666 * @wiphy: WIPHY structure pointer
667 * @wdev: Wireless device structure pointer
668 * @data: Pointer to the data received
669 * @data_len: Length of the data received
670 *
671 * This function provides TDLS capabilities
672 *
673 * Return: 0 on success and errno on failure
674 */
675static int __wlan_hdd_cfg80211_get_tdls_capabilities(struct wiphy *wiphy,
676 struct wireless_dev *wdev,
677 const void *data,
678 int data_len)
679{
680 int status;
681 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
682 struct sk_buff *skb;
683 uint32_t set = 0;
684
Peng Xuf5d60c82015-10-02 17:17:03 -0700685 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800686 hdd_err("Command not allowed in FTM mode");
687 return -EPERM;
688 }
689
690 status = wlan_hdd_validate_context(hdd_ctx);
691 if (status)
692 return status;
693
694 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (2 * sizeof(u32)) +
695 NLMSG_HDRLEN);
696 if (!skb) {
697 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
698 goto fail;
699 }
700
701 if (false == hdd_ctx->config->fEnableTDLSSupport) {
702 hddLog(LOGE,
703 FL("TDLS feature not Enabled or Not supported in FW"));
704 if (nla_put_u32(skb, PARAM_MAX_TDLS_SESSION, 0) ||
705 nla_put_u32(skb, PARAM_TDLS_FEATURE_SUPPORT, 0)) {
706 hddLog(LOGE, FL("nla put fail"));
707 goto fail;
708 }
709 } else {
710 set = set | WIFI_TDLS_SUPPORT;
711 set = set | (hdd_ctx->config->fTDLSExternalControl ?
712 WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT : 0);
713 set = set | (hdd_ctx->config->fEnableTDLSOffChannel ?
714 WIIF_TDLS_OFFCHANNEL_SUPPORT : 0);
715 hddLog(LOG1, FL("TDLS Feature supported value %x"), set);
716 if (nla_put_u32(skb, PARAM_MAX_TDLS_SESSION,
717 hdd_ctx->max_num_tdls_sta) ||
718 nla_put_u32(skb, PARAM_TDLS_FEATURE_SUPPORT,
719 set)) {
720 hddLog(LOGE, FL("nla put fail"));
721 goto fail;
722 }
723 }
724 return cfg80211_vendor_cmd_reply(skb);
725fail:
726 if (skb)
727 kfree_skb(skb);
728 return -EINVAL;
729}
730
731/**
732 * wlan_hdd_cfg80211_get_tdls_capabilities() - Provide TDLS Capabilites.
733 * @wiphy: WIPHY structure pointer
734 * @wdev: Wireless device structure pointer
735 * @data: Pointer to the data received
736 * @data_len: Length of the data received
737 *
738 * This function provides TDLS capabilities
739 *
740 * Return: 0 on success and errno on failure
741 */
742static int
743wlan_hdd_cfg80211_get_tdls_capabilities(struct wiphy *wiphy,
744 struct wireless_dev *wdev,
745 const void *data,
746 int data_len)
747{
748 int ret;
749
750 cds_ssr_protect(__func__);
751 ret = __wlan_hdd_cfg80211_get_tdls_capabilities(wiphy, wdev,
752 data, data_len);
753 cds_ssr_unprotect(__func__);
754
755 return ret;
756}
757#endif
758
759#ifdef QCA_HT_2040_COEX
760static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work);
761#endif
762
763#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC)
764/*
765 * FUNCTION: wlan_hdd_send_avoid_freq_event
766 * This is called when wlan driver needs to send vendor specific
767 * avoid frequency range event to userspace
768 */
769int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx,
770 tHddAvoidFreqList *pAvoidFreqList)
771{
772 struct sk_buff *vendor_event;
773
774 ENTER();
775
776 if (!pHddCtx) {
777 hddLog(LOGE, FL("HDD context is null"));
778 return -EINVAL;
779 }
780
781 if (!pAvoidFreqList) {
782 hddLog(LOGE, FL("pAvoidFreqList is null"));
783 return -EINVAL;
784 }
785
786 vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy,
787 NULL,
788 sizeof(tHddAvoidFreqList),
789 QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX,
790 GFP_KERNEL);
791 if (!vendor_event) {
792 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
793 return -EINVAL;
794 }
795
796 memcpy(skb_put(vendor_event, sizeof(tHddAvoidFreqList)),
797 (void *)pAvoidFreqList, sizeof(tHddAvoidFreqList));
798
799 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
800
801 EXIT();
802 return 0;
803}
804#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */
805
806/* vendor specific events */
807static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = {
808#ifdef FEATURE_WLAN_CH_AVOID
809 [QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX] = {
810 .vendor_id =
811 QCA_NL80211_VENDOR_ID,
812 .subcmd =
813 QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY
814 },
815#endif /* FEATURE_WLAN_CH_AVOID */
816
817#ifdef WLAN_FEATURE_NAN
818 [QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX] = {
819 .vendor_id =
820 QCA_NL80211_VENDOR_ID,
821 .subcmd =
822 QCA_NL80211_VENDOR_SUBCMD_NAN
823 },
824#endif
825
826#ifdef WLAN_FEATURE_STATS_EXT
827 [QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX] = {
828 .vendor_id =
829 QCA_NL80211_VENDOR_ID,
830 .subcmd =
831 QCA_NL80211_VENDOR_SUBCMD_STATS_EXT
832 },
833#endif /* WLAN_FEATURE_STATS_EXT */
834#ifdef FEATURE_WLAN_EXTSCAN
835 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX] = {
836 .vendor_id =
837 QCA_NL80211_VENDOR_ID,
838 .subcmd =
839 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START
840 },
841 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX] = {
842 .vendor_id =
843 QCA_NL80211_VENDOR_ID,
844 .subcmd =
845 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP
846 },
847 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX] = {
848 .
849 vendor_id
850 =
851 QCA_NL80211_VENDOR_ID,
852 .subcmd =
853 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES
854 },
855 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX] = {
856 .
857 vendor_id
858 =
859 QCA_NL80211_VENDOR_ID,
860 .
861 subcmd =
862 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS
863 },
864 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX] = {
865 .
866 vendor_id
867 =
868 QCA_NL80211_VENDOR_ID,
869 .
870 subcmd
871 =
872 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE
873 },
874 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX] = {
875 .
876 vendor_id
877 =
878 QCA_NL80211_VENDOR_ID,
879 .subcmd =
880 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT
881 },
882 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX] = {
883 .vendor_id =
884 QCA_NL80211_VENDOR_ID,
885 .subcmd =
886 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT
887 },
888 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX] = {
889 .
890 vendor_id
891 =
892 QCA_NL80211_VENDOR_ID,
893 .subcmd =
894 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND
895 },
896 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX] = {
897 .
898 vendor_id
899 =
900 QCA_NL80211_VENDOR_ID,
901 .subcmd =
902 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST
903 },
904 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX] = {
905 .
906 vendor_id
907 =
908 QCA_NL80211_VENDOR_ID,
909 .
910 subcmd
911 =
912 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST
913 },
914 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX] = {
915 .
916 vendor_id
917 =
918 QCA_NL80211_VENDOR_ID,
919 .
920 subcmd =
921 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE
922 },
923 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX] = {
924 .
925 vendor_id
926 =
927 QCA_NL80211_VENDOR_ID,
928 .
929 subcmd
930 =
931 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE
932 },
933 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX] = {
934 .
935 vendor_id
936 =
937 QCA_NL80211_VENDOR_ID,
938 .
939 subcmd
940 =
941 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE
942 },
943 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND_INDEX] = {
944 .vendor_id = QCA_NL80211_VENDOR_ID,
945 .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_FOUND
946 },
947 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST_INDEX] = {
948 .vendor_id = QCA_NL80211_VENDOR_ID,
949 .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_SSID_LOST
950 },
951#endif /* FEATURE_WLAN_EXTSCAN */
952
953#ifdef WLAN_FEATURE_LINK_LAYER_STATS
954 [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET_INDEX] = {
955 .vendor_id =
956 QCA_NL80211_VENDOR_ID,
957 .subcmd =
958 QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET
959 },
960 [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET_INDEX] = {
961 .vendor_id =
962 QCA_NL80211_VENDOR_ID,
963 .subcmd =
964 QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET
965 },
966 [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR_INDEX] = {
967 .vendor_id =
968 QCA_NL80211_VENDOR_ID,
969 .subcmd =
970 QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR
971 },
972 [QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX] = {
973 .vendor_id =
974 QCA_NL80211_VENDOR_ID,
975 .subcmd =
976 QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS
977 },
978 [QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX] = {
979 .vendor_id =
980 QCA_NL80211_VENDOR_ID,
981 .subcmd =
982 QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS
983 },
984 [QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX] = {
985 .vendor_id =
986 QCA_NL80211_VENDOR_ID,
987 .subcmd =
988 QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS
989 },
990#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
991 [QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX] = {
992 .vendor_id =
993 QCA_NL80211_VENDOR_ID,
994 .subcmd =
995 QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE
996 },
997 [QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX] = {
998 .vendor_id = QCA_NL80211_VENDOR_ID,
999 .subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS
1000 },
1001#ifdef WLAN_FEATURE_ROAM_OFFLOAD
1002 [QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX] = {
1003 .vendor_id =
1004 QCA_NL80211_VENDOR_ID,
1005 .subcmd =
1006 QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH
1007 },
1008#endif
1009 [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX] = {
1010 .vendor_id =
1011 QCA_NL80211_VENDOR_ID,
1012 .subcmd =
1013 QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED
1014 },
1015 [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX] = {
1016 .vendor_id =
1017 QCA_NL80211_VENDOR_ID,
1018 .subcmd =
1019 QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED
1020 },
1021 [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED_INDEX] = {
1022 .vendor_id =
1023 QCA_NL80211_VENDOR_ID,
1024 .subcmd =
1025 QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED
1026 },
1027 [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED_INDEX] = {
1028 .vendor_id =
1029 QCA_NL80211_VENDOR_ID,
1030 .subcmd =
1031 QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED
1032 },
1033 [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX] = {
1034 .vendor_id =
1035 QCA_NL80211_VENDOR_ID,
1036 .subcmd =
1037 QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED
1038 },
1039#ifdef FEATURE_WLAN_EXTSCAN
1040 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX] = {
1041 .vendor_id = QCA_NL80211_VENDOR_ID,
1042 .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND
1043 },
1044 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX] = {
1045 .vendor_id = QCA_NL80211_VENDOR_ID,
1046 .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND
1047 },
1048 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST_INDEX] = {
1049 .vendor_id = QCA_NL80211_VENDOR_ID,
1050 .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST
1051 },
1052 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST_INDEX] = {
1053 .vendor_id = QCA_NL80211_VENDOR_ID,
1054 .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST
1055 },
1056 [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX] = {
1057 .vendor_id = QCA_NL80211_VENDOR_ID,
1058 .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST
1059 },
1060#endif /* FEATURE_WLAN_EXTSCAN */
1061 [QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = {
1062 .vendor_id = QCA_NL80211_VENDOR_ID,
1063 .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI
1064 },
1065#ifdef WLAN_FEATURE_MEMDUMP
1066 [QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX] = {
1067 .vendor_id = QCA_NL80211_VENDOR_ID,
1068 .subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP
1069 },
1070#endif /* WLAN_FEATURE_MEMDUMP */
1071 [QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX] = {
1072 .vendor_id = QCA_NL80211_VENDOR_ID,
1073 .subcmd = QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE
1074 },
1075 [QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX] = {
1076 .vendor_id = QCA_NL80211_VENDOR_ID,
1077 .subcmd = QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN
1078 },
1079 /* OCB events */
1080 [QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX] = {
1081 .vendor_id = QCA_NL80211_VENDOR_ID,
1082 .subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT
1083 },
Ravi Joshideb5a8d2015-11-09 19:11:43 -08001084#ifdef FEATURE_LFR_SUBNET_DETECTION
1085 [QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG_INDEX] = {
1086 .vendor_id = QCA_NL80211_VENDOR_ID,
1087 .subcmd = QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG
1088 },
1089#endif /*FEATURE_LFR_SUBNET_DETECTION */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001090};
1091
1092/**
1093 * __is_driver_dfs_capable() - get driver DFS capability
1094 * @wiphy: pointer to wireless wiphy structure.
1095 * @wdev: pointer to wireless_dev structure.
1096 * @data: Pointer to the data to be passed via vendor interface
1097 * @data_len:Length of the data to be passed
1098 *
1099 * This function is called by userspace to indicate whether or not
1100 * the driver supports DFS offload.
1101 *
1102 * Return: 0 on success, negative errno on failure
1103 */
1104static int __is_driver_dfs_capable(struct wiphy *wiphy,
1105 struct wireless_dev *wdev,
1106 const void *data,
1107 int data_len)
1108{
1109 u32 dfs_capability = 0;
1110 struct sk_buff *temp_skbuff;
1111 int ret_val;
1112 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1113
1114 ENTER();
1115
1116 ret_val = wlan_hdd_validate_context(hdd_ctx);
1117 if (ret_val)
1118 return ret_val;
1119
Peng Xuf5d60c82015-10-02 17:17:03 -07001120 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001121 hdd_err("Command not allowed in FTM mode");
1122 return -EPERM;
1123 }
1124
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001125 dfs_capability = !!(wiphy->flags & WIPHY_FLAG_DFS_OFFLOAD);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001126
1127 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) +
1128 NLMSG_HDRLEN);
1129
1130 if (temp_skbuff != NULL) {
1131 ret_val = nla_put_u32(temp_skbuff, QCA_WLAN_VENDOR_ATTR_DFS,
1132 dfs_capability);
1133 if (ret_val) {
1134 hddLog(LOGE, FL("QCA_WLAN_VENDOR_ATTR_DFS put fail"));
1135 kfree_skb(temp_skbuff);
1136
1137 return ret_val;
1138 }
1139
1140 return cfg80211_vendor_cmd_reply(temp_skbuff);
1141 }
1142
1143 hddLog(LOGE, FL("dfs capability: buffer alloc fail"));
1144 return -ENOMEM;
1145}
1146
1147/**
1148 * is_driver_dfs_capable() - get driver DFS capability
1149 * @wiphy: pointer to wireless wiphy structure.
1150 * @wdev: pointer to wireless_dev structure.
1151 * @data: Pointer to the data to be passed via vendor interface
1152 * @data_len:Length of the data to be passed
1153 *
1154 * This function is called by userspace to indicate whether or not
1155 * the driver supports DFS offload. This is an SSR-protected
1156 * wrapper function.
1157 *
1158 * Return: 0 on success, negative errno on failure
1159 */
1160static int is_driver_dfs_capable(struct wiphy *wiphy,
1161 struct wireless_dev *wdev,
1162 const void *data,
1163 int data_len)
1164{
1165 int ret;
1166
1167 cds_ssr_protect(__func__);
1168 ret = __is_driver_dfs_capable(wiphy, wdev, data, data_len);
1169 cds_ssr_unprotect(__func__);
1170
1171 return ret;
1172}
1173
1174/**
1175 * wlan_hdd_sap_cfg_dfs_override() - DFS MCC restriction check
1176 *
1177 * @adapter: SAP adapter pointer
1178 *
1179 * DFS in MCC is not supported for Multi bssid SAP mode due to single physical
1180 * radio. So in case of DFS MCC scenario override current SAP given config
1181 * to follow concurrent SAP DFS config
1182 *
1183 * Return: 0 - No DFS issue, 1 - Override done and negative error codes
1184 */
1185
1186#ifdef WLAN_FEATURE_MBSSID
1187int wlan_hdd_sap_cfg_dfs_override(hdd_adapter_t *adapter)
1188{
1189 hdd_adapter_t *con_sap_adapter;
1190 tsap_Config_t *sap_config, *con_sap_config;
1191 int con_ch;
1192
1193 /*
1194 * Check if AP+AP case, once primary AP chooses a DFS
1195 * channel secondary AP should always follow primary APs channel
1196 */
1197 if (!cds_concurrent_beaconing_sessions_running())
1198 return 0;
1199
1200 con_sap_adapter = hdd_get_con_sap_adapter(adapter, true);
1201 if (!con_sap_adapter)
1202 return 0;
1203
1204 sap_config = &adapter->sessionCtx.ap.sapConfig;
1205 con_sap_config = &con_sap_adapter->sessionCtx.ap.sapConfig;
1206 con_ch = con_sap_adapter->sessionCtx.ap.operatingChannel;
1207
1208 if (!CDS_IS_DFS_CH(con_ch))
1209 return 0;
1210
1211 hddLog(LOGE, FL("Only SCC AP-AP DFS Permitted (ch=%d, con_ch=%d)"),
1212 sap_config->channel, con_ch);
1213 hddLog(LOG1, FL("Overriding guest AP's channel"));
1214 sap_config->channel = con_ch;
1215
1216 if (con_sap_config->acs_cfg.acs_mode == true) {
1217 if (con_ch != con_sap_config->acs_cfg.pri_ch &&
1218 con_ch != con_sap_config->acs_cfg.ht_sec_ch) {
1219 hddLog(LOGE, FL("Primary AP channel config error"));
1220 hddLog(LOGE, FL("Operating ch: %d ACS ch: %d %d"),
1221 con_ch, con_sap_config->acs_cfg.pri_ch,
1222 con_sap_config->acs_cfg.ht_sec_ch);
1223 return -EINVAL;
1224 }
1225 /* Sec AP ACS info is overwritten with Pri AP due to DFS
1226 * MCC restriction. So free ch list allocated in do_acs
1227 * func for Sec AP and realloc for Pri AP ch list size
1228 */
1229 if (sap_config->acs_cfg.ch_list)
1230 cdf_mem_free(sap_config->acs_cfg.ch_list);
1231
1232 cdf_mem_copy(&sap_config->acs_cfg,
1233 &con_sap_config->acs_cfg,
1234 sizeof(struct sap_acs_cfg));
1235 sap_config->acs_cfg.ch_list = cdf_mem_malloc(
1236 sizeof(uint8_t) *
1237 con_sap_config->acs_cfg.ch_list_count);
1238 if (!sap_config->acs_cfg.ch_list) {
1239 hddLog(LOGE, FL("ACS config alloc fail"));
1240 return -ENOMEM;
1241 }
1242
1243 cdf_mem_copy(sap_config->acs_cfg.ch_list,
1244 con_sap_config->acs_cfg.ch_list,
1245 con_sap_config->acs_cfg.ch_list_count);
1246
1247 } else {
1248 sap_config->acs_cfg.pri_ch = con_ch;
1249 if (sap_config->acs_cfg.ch_width > eHT_CHANNEL_WIDTH_20MHZ)
1250 sap_config->acs_cfg.ht_sec_ch = con_sap_config->sec_ch;
1251 }
1252
1253 return con_ch;
1254}
1255#else
1256int wlan_hdd_sap_cfg_dfs_override(hdd_adapter_t *adapter)
1257{
1258 return 0;
1259}
1260#endif
1261
1262/**
1263 * wlan_hdd_set_acs_ch_range : Start ACS channel range values
1264 * @sap_cfg: pointer to SAP config struct
1265 *
1266 * This function sets the default ACS start and end channel for the given band
1267 * and also parses the given ACS channel list.
1268 *
1269 * Return: None
1270 */
1271
1272static void wlan_hdd_set_acs_ch_range(tsap_Config_t *sap_cfg, bool ht_enabled,
1273 bool vht_enabled)
1274{
1275 int i;
1276 if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211B) {
1277 sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11b;
Amar Singhal7a1726a2015-10-14 16:28:11 -07001278 sap_cfg->acs_cfg.start_ch = CDS_CHANNEL_NUM(RF_CHAN_1);
1279 sap_cfg->acs_cfg.end_ch = CDS_CHANNEL_NUM(RF_CHAN_14);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001280 } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211G) {
1281 sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11g;
Amar Singhal7a1726a2015-10-14 16:28:11 -07001282 sap_cfg->acs_cfg.start_ch = CDS_CHANNEL_NUM(RF_CHAN_1);
1283 sap_cfg->acs_cfg.end_ch = CDS_CHANNEL_NUM(RF_CHAN_13);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001284 } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211A) {
1285 sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11a;
Amar Singhal7a1726a2015-10-14 16:28:11 -07001286 sap_cfg->acs_cfg.start_ch = CDS_CHANNEL_NUM(RF_CHAN_36);
1287 sap_cfg->acs_cfg.end_ch = CDS_CHANNEL_NUM(RF_CHAN_165);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001288 } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211ANY) {
1289 sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_abg;
Amar Singhal7a1726a2015-10-14 16:28:11 -07001290 sap_cfg->acs_cfg.start_ch = CDS_CHANNEL_NUM(RF_CHAN_1);
1291 sap_cfg->acs_cfg.end_ch = CDS_CHANNEL_NUM(RF_CHAN_165);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001292 }
1293
1294 if (ht_enabled)
1295 sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11n;
1296
1297 if (vht_enabled)
1298 sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac;
1299
1300
1301 /* Parse ACS Chan list from hostapd */
1302 if (!sap_cfg->acs_cfg.ch_list)
1303 return;
1304
1305 sap_cfg->acs_cfg.start_ch = sap_cfg->acs_cfg.ch_list[0];
1306 sap_cfg->acs_cfg.end_ch =
1307 sap_cfg->acs_cfg.ch_list[sap_cfg->acs_cfg.ch_list_count - 1];
1308 for (i = 0; i < sap_cfg->acs_cfg.ch_list_count; i++) {
1309 if (sap_cfg->acs_cfg.start_ch > sap_cfg->acs_cfg.ch_list[i])
1310 sap_cfg->acs_cfg.start_ch = sap_cfg->acs_cfg.ch_list[i];
1311 if (sap_cfg->acs_cfg.end_ch < sap_cfg->acs_cfg.ch_list[i])
1312 sap_cfg->acs_cfg.end_ch = sap_cfg->acs_cfg.ch_list[i];
1313 }
1314}
1315
1316
1317static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work);
1318
1319/**
1320 * wlan_hdd_cfg80211_start_acs : Start ACS Procedure for SAP
1321 * @adapter: pointer to SAP adapter struct
1322 *
1323 * This function starts the ACS procedure if there are no
1324 * constraints like MBSSID DFS restrictions.
1325 *
1326 * Return: Status of ACS Start procedure
1327 */
1328
1329static int wlan_hdd_cfg80211_start_acs(hdd_adapter_t *adapter)
1330{
1331
1332 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1333 tsap_Config_t *sap_config;
1334 tpWLAN_SAPEventCB acs_event_callback;
1335 int status;
1336
1337 sap_config = &adapter->sessionCtx.ap.sapConfig;
1338 sap_config->channel = AUTO_CHANNEL_SELECT;
1339
1340 status = wlan_hdd_sap_cfg_dfs_override(adapter);
1341 if (status < 0) {
1342 return status;
1343 } else {
1344 if (status > 0) {
1345 /*notify hostapd about channel override */
1346 wlan_hdd_cfg80211_acs_ch_select_evt(adapter);
1347 clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags);
1348 return 0;
1349 }
1350 }
1351 status = wlan_hdd_config_acs(hdd_ctx, adapter);
1352 if (status) {
1353 hddLog(LOGE, FL("ACS config failed"));
1354 return -EINVAL;
1355 }
1356
1357 acs_event_callback = hdd_hostapd_sap_event_cb;
1358
1359 cdf_mem_copy(sap_config->self_macaddr.bytes,
1360 adapter->macAddressCurrent.bytes, sizeof(struct cdf_mac_addr));
1361 hddLog(LOG1, FL("ACS Started for wlan%d"), adapter->dev->ifindex);
1362 status = wlansap_acs_chselect(
1363#ifdef WLAN_FEATURE_MBSSID
1364 WLAN_HDD_GET_SAP_CTX_PTR(adapter),
1365#else
1366 hdd_ctx->pcds_context,
1367#endif
1368 acs_event_callback, sap_config, adapter->dev);
1369
1370
1371 if (status) {
1372 hddLog(LOGE, FL("ACS channel select failed"));
1373 return -EINVAL;
1374 }
1375 sap_config->acs_cfg.acs_mode = true;
1376 set_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags);
1377
1378 return 0;
1379}
1380
1381/**
1382 * __wlan_hdd_cfg80211_do_acs : CFG80211 handler function for DO_ACS Vendor CMD
1383 * @wiphy: Linux wiphy struct pointer
1384 * @wdev: Linux wireless device struct pointer
1385 * @data: ACS information from hostapd
1386 * @data_len: ACS information length
1387 *
1388 * This function handle DO_ACS Vendor command from hostapd, parses ACS config
1389 * and starts ACS procedure.
1390 *
1391 * Return: ACS procedure start status
1392 */
1393
1394static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
1395 struct wireless_dev *wdev,
1396 const void *data, int data_len)
1397{
1398 struct net_device *ndev = wdev->netdev;
1399 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
1400 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
1401 tsap_Config_t *sap_config;
1402 struct sk_buff *temp_skbuff;
1403 int status = -EINVAL, i = 0;
1404 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
1405 bool ht_enabled, ht40_enabled, vht_enabled;
1406 uint8_t ch_width;
1407
1408 /* ***Note*** Donot set SME config related to ACS operation here because
1409 * ACS operation is not synchronouse and ACS for Second AP may come when
1410 * ACS operation for first AP is going on. So only do_acs is split to
1411 * seperate start_acs routine. Also SME-PMAC struct that is used to
1412 * pass paremeters from HDD to SAP is global. Thus All ACS related SME
1413 * config shall be set only from start_acs.
1414 */
1415
1416 /* nla_policy Policy template. Policy not applied as some attributes are
1417 * optional and QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST has variable length
1418 *
1419 * [QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE] = { .type = NLA_U8 },
1420 * [QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED] = { .type = NLA_FLAG },
1421 * [QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED] = { .type = NLA_FLAG },
1422 * [QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED] = { .type = NLA_FLAG },
1423 * [QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH] = { .type = NLA_U16 },
1424 * [QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST] = { .type = NLA_NESTED },
1425 */
1426
Peng Xuf5d60c82015-10-02 17:17:03 -07001427 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001428 hdd_err("Command not allowed in FTM mode");
1429 return -EPERM;
1430 }
1431
1432 if (hdd_ctx->config->force_sap_acs) {
1433 hddLog(LOGE, FL("Hostapd ACS rejected as Driver ACS enabled"));
1434 return -EPERM;
1435 }
1436
1437 status = wlan_hdd_validate_context(hdd_ctx);
1438 if (0 != status) {
1439 hddLog(LOGE, FL("HDD context is not valid"));
1440 goto out;
1441 }
1442 sap_config = &adapter->sessionCtx.ap.sapConfig;
1443 cdf_mem_zero(&sap_config->acs_cfg, sizeof(struct sap_acs_cfg));
1444
1445 status = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, data, data_len,
1446 NULL);
1447 if (status) {
1448 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid ATTR"));
1449 goto out;
1450 }
1451
1452 if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
1453 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Attr hw_mode failed"));
1454 goto out;
1455 }
1456 sap_config->acs_cfg.hw_mode = nla_get_u8(
1457 tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
1458
1459 if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED])
1460 ht_enabled =
1461 nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]);
1462 else
1463 ht_enabled = 0;
1464
1465 if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED])
1466 ht40_enabled =
1467 nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]);
1468 else
1469 ht40_enabled = 0;
1470
1471 if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED])
1472 vht_enabled =
1473 nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]);
1474 else
1475 vht_enabled = 0;
1476
1477 if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) {
1478 ch_width = nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
1479 } else {
1480 if (ht_enabled && ht40_enabled)
1481 ch_width = 40;
1482 else
1483 ch_width = 20;
1484 }
1485 if (ch_width == 80)
1486 sap_config->acs_cfg.ch_width = CH_WIDTH_80MHZ;
1487 else if (ch_width == 40)
1488 sap_config->acs_cfg.ch_width = CH_WIDTH_40MHZ;
1489 else
1490 sap_config->acs_cfg.ch_width = CH_WIDTH_20MHZ;
1491
1492 /* hw_mode = a/b/g: QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST and
1493 * QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attrs are present, and
1494 * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is used for obtaining the
1495 * channel list, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST is ignored
1496 * since it contains the frequency values of the channels in
1497 * the channel list.
1498 * hw_mode = any: only QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attr
1499 * is present
1500 */
1501 if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]) {
1502 char *tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]);
1503 sap_config->acs_cfg.ch_list_count = nla_len(
1504 tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]);
1505 if (sap_config->acs_cfg.ch_list_count) {
1506 sap_config->acs_cfg.ch_list = cdf_mem_malloc(
1507 sizeof(uint8_t) *
1508 sap_config->acs_cfg.ch_list_count);
1509 if (sap_config->acs_cfg.ch_list == NULL)
1510 goto out;
1511
1512 cdf_mem_copy(sap_config->acs_cfg.ch_list, tmp,
1513 sap_config->acs_cfg.ch_list_count);
1514 }
1515 } else if (tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) {
1516 uint32_t *freq =
1517 nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]);
1518 sap_config->acs_cfg.ch_list_count = nla_len(
1519 tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) /
1520 sizeof(uint32_t);
1521 if (sap_config->acs_cfg.ch_list_count) {
1522 sap_config->acs_cfg.ch_list = cdf_mem_malloc(
1523 sap_config->acs_cfg.ch_list_count);
1524 if (sap_config->acs_cfg.ch_list == NULL) {
1525 hddLog(LOGE, FL("ACS config alloc fail"));
1526 status = -ENOMEM;
1527 goto out;
1528 }
1529
1530 /* convert frequency to channel */
1531 for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++)
1532 sap_config->acs_cfg.ch_list[i] =
1533 ieee80211_frequency_to_channel(freq[i]);
1534 }
1535 }
1536
1537 hdd_debug("get pcl for DO_ACS vendor command");
1538
1539 /* consult policy manager to get PCL */
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08001540 status = cds_get_pcl(CDS_SAP_MODE,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001541 sap_config->acs_cfg.pcl_channels,
1542 &sap_config->acs_cfg.pcl_ch_count);
1543 if (CDF_STATUS_SUCCESS != status)
1544 hddLog(LOGE, FL("Get PCL failed"));
1545
1546 wlan_hdd_set_acs_ch_range(sap_config, ht_enabled, vht_enabled);
1547
1548 /* ACS override for android */
1549 if (hdd_ctx->config->sap_p2p_11ac_override && ht_enabled) {
1550 hddLog(LOG1, FL("ACS Config override for 11AC"));
1551 vht_enabled = 1;
1552 sap_config->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac;
1553 sap_config->acs_cfg.ch_width =
1554 hdd_ctx->config->vhtChannelWidth;
1555 /* No VHT80 in 2.4G so perform ACS accordingly */
1556 if (sap_config->acs_cfg.end_ch <= 14 &&
1557 sap_config->acs_cfg.ch_width == eHT_CHANNEL_WIDTH_80MHZ)
1558 sap_config->acs_cfg.ch_width = eHT_CHANNEL_WIDTH_40MHZ;
1559 }
1560
1561 hddLog(LOG1, FL("ACS Config for wlan%d: HW_MODE: %d ACS_BW: %d HT: %d VHT: %d START_CH: %d END_CH: %d"),
1562 adapter->dev->ifindex, sap_config->acs_cfg.hw_mode,
1563 ch_width, ht_enabled, vht_enabled,
1564 sap_config->acs_cfg.start_ch, sap_config->acs_cfg.end_ch);
1565
1566 if (sap_config->acs_cfg.ch_list_count) {
1567 hddLog(LOG1, FL("ACS channel list: len: %d"),
1568 sap_config->acs_cfg.ch_list_count);
1569 for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++)
1570 hddLog(LOG1, "%d ", sap_config->acs_cfg.ch_list[i]);
1571 }
1572 sap_config->acs_cfg.acs_mode = true;
1573 if (test_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags)) {
1574 /* ***Note*** Completion variable usage is not allowed here since
1575 * ACS scan operation may take max 2.2 sec for 5G band.
1576 * 9 Active channel X 40 ms active scan time +
1577 * 16 Passive channel X 110ms passive scan time
1578 * Since this CFG80211 call lock rtnl mutex, we cannot hold on
1579 * for this long. So we split up the scanning part.
1580 */
1581 set_bit(ACS_PENDING, &adapter->event_flags);
1582 hddLog(LOG1, FL("ACS Pending for wlan%d"),
1583 adapter->dev->ifindex);
1584 status = 0;
1585 } else {
1586 status = wlan_hdd_cfg80211_start_acs(adapter);
1587 }
1588
1589out:
1590 if (0 == status) {
1591 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
1592 NLMSG_HDRLEN);
1593 if (temp_skbuff != NULL)
1594 return cfg80211_vendor_cmd_reply(temp_skbuff);
1595 }
1596
1597 clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags);
1598
1599 return status;
1600}
1601
1602 /**
1603 * wlan_hdd_cfg80211_do_acs : CFG80211 handler function for DO_ACS Vendor CMD
1604 * @wiphy: Linux wiphy struct pointer
1605 * @wdev: Linux wireless device struct pointer
1606 * @data: ACS information from hostapd
1607 * @data_len: ACS information len
1608 *
1609 * This function handle DO_ACS Vendor command from hostapd, parses ACS config
1610 * and starts ACS procedure.
1611 *
1612 * Return: ACS procedure start status
1613 */
1614
1615static int wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy,
1616 struct wireless_dev *wdev,
1617 const void *data, int data_len)
1618{
1619 int ret;
1620
1621 cds_ssr_protect(__func__);
1622 ret = __wlan_hdd_cfg80211_do_acs(wiphy, wdev, data, data_len);
1623 cds_ssr_unprotect(__func__);
1624
1625 return ret;
1626}
1627
1628/**
1629 * wlan_hdd_cfg80211_start_pending_acs : Start pending ACS procedure for SAP
1630 * @work: Linux workqueue struct pointer for ACS work
1631 *
1632 * This function starts the ACS procedure which was marked pending when an ACS
1633 * procedure was in progress for a concurrent SAP interface.
1634 *
1635 * Return: None
1636 */
1637
1638static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work)
1639{
1640 hdd_adapter_t *adapter = container_of(work, hdd_adapter_t,
1641 acs_pending_work.work);
1642 wlan_hdd_cfg80211_start_acs(adapter);
1643}
1644
1645/**
1646 * wlan_hdd_cfg80211_acs_ch_select_evt: Callback function for ACS evt
1647 * @adapter: Pointer to SAP adapter struct
1648 * @pri_channel: SAP ACS procedure selected Primary channel
1649 * @sec_channel: SAP ACS procedure selected secondary channel
1650 *
1651 * This is a callback function from SAP module on ACS procedure is completed.
1652 * This function send the ACS selected channel information to hostapd
1653 *
1654 * Return: None
1655 */
1656
1657void wlan_hdd_cfg80211_acs_ch_select_evt(hdd_adapter_t *adapter)
1658{
1659 hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
1660 tsap_Config_t *sap_cfg = &(WLAN_HDD_GET_AP_CTX_PTR(adapter))->sapConfig;
1661 struct sk_buff *vendor_event;
1662 int ret_val;
1663 hdd_adapter_t *con_sap_adapter;
1664 uint16_t ch_width;
1665
1666 vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
1667 NULL,
1668 4 * sizeof(u8) + 1 * sizeof(u16) + 4 + NLMSG_HDRLEN,
1669 QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX,
1670 GFP_KERNEL);
1671
1672 if (!vendor_event) {
1673 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
1674 return;
1675 }
1676
1677 ret_val = hdd_vendor_put_ifindex(vendor_event, adapter->dev->ifindex);
1678 if (ret_val) {
1679 hddLog(LOGE, FL("NL80211_ATTR_IFINDEX put fail"));
1680 kfree_skb(vendor_event);
1681 return;
1682 }
1683
1684 ret_val = nla_put_u8(vendor_event,
1685 QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
1686 sap_cfg->acs_cfg.pri_ch);
1687 if (ret_val) {
1688 hddLog(LOGE,
1689 FL("QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL put fail"));
1690 kfree_skb(vendor_event);
1691 return;
1692 }
1693
1694 ret_val = nla_put_u8(vendor_event,
1695 QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
1696 sap_cfg->acs_cfg.ht_sec_ch);
1697 if (ret_val) {
1698 hddLog(LOGE,
1699 FL(
1700 "QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL put fail"));
1701 kfree_skb(vendor_event);
1702 return;
1703 }
1704
1705 ret_val = nla_put_u8(vendor_event,
1706 QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
1707 sap_cfg->acs_cfg.vht_seg0_center_ch);
1708 if (ret_val) {
1709 hddLog(LOGE,
1710 FL(
1711 "QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL put fail"));
1712 kfree_skb(vendor_event);
1713 return;
1714 }
1715
1716 ret_val = nla_put_u8(vendor_event,
1717 QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
1718 sap_cfg->acs_cfg.vht_seg1_center_ch);
1719 if (ret_val) {
1720 hddLog(LOGE,
1721 FL(
1722 "QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL put fail"));
1723 kfree_skb(vendor_event);
1724 return;
1725 }
1726
1727 if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_80MHZ)
1728 ch_width = 80;
1729 else if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_40MHZ)
1730 ch_width = 40;
1731 else
1732 ch_width = 20;
1733
1734 ret_val = nla_put_u16(vendor_event,
1735 QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
1736 ch_width);
1737 if (ret_val) {
1738 hddLog(LOGE,
1739 FL(
1740 "QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH put fail"));
1741 kfree_skb(vendor_event);
1742 return;
1743 }
1744 if (sap_cfg->acs_cfg.pri_ch > 14)
1745 ret_val = nla_put_u8(vendor_event,
1746 QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
1747 QCA_ACS_MODE_IEEE80211A);
1748 else
1749 ret_val = nla_put_u8(vendor_event,
1750 QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
1751 QCA_ACS_MODE_IEEE80211G);
1752
1753 if (ret_val) {
1754 hddLog(LOGE,
1755 FL(
1756 "QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE put fail"));
1757 kfree_skb(vendor_event);
1758 return;
1759 }
1760
1761 hddLog(LOG1,
1762 FL("ACS result for wlan%d: PRI_CH: %d SEC_CH: %d VHT_SEG0: %d VHT_SEG1: %d ACS_BW: %d"),
1763 adapter->dev->ifindex, sap_cfg->acs_cfg.pri_ch,
1764 sap_cfg->acs_cfg.ht_sec_ch, sap_cfg->acs_cfg.vht_seg0_center_ch,
1765 sap_cfg->acs_cfg.vht_seg1_center_ch, ch_width);
1766
1767 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
1768 /* ***Note*** As already mentioned Completion variable usage is not
1769 * allowed here since ACS scan operation may take max 2.2 sec.
1770 * Further in AP-AP mode pending ACS is resumed here to serailize ACS
1771 * operation.
1772 * TODO: Delayed operation is used since SME-PMAC strut is global. Thus
1773 * when Primary AP ACS is complete and secondary AP ACS is started here
1774 * immediately, Primary AP start_bss may come inbetween ACS operation
1775 * and overwrite Sec AP ACS paramters. Thus Sec AP ACS is executed with
1776 * delay. This path and below constraint will be removed on sessionizing
1777 * SAP acs parameters and decoupling SAP from PMAC (WIP).
1778 * As per design constraint user space control application must take
1779 * care of serailizing hostapd start for each VIF in AP-AP mode to avoid
1780 * this code path. Sec AP hostapd should be started after Primary AP
1781 * start beaconing which can be confirmed by getchannel iwpriv command
1782 */
1783
1784 con_sap_adapter = hdd_get_con_sap_adapter(adapter, false);
1785 if (con_sap_adapter &&
1786 test_bit(ACS_PENDING, &con_sap_adapter->event_flags)) {
1787#ifdef CONFIG_CNSS
1788 cnss_init_delayed_work(&con_sap_adapter->acs_pending_work,
1789 wlan_hdd_cfg80211_start_pending_acs);
1790#else
1791 INIT_DELAYED_WORK(&con_sap_adapter->acs_pending_work,
1792 wlan_hdd_cfg80211_start_pending_acs);
1793#endif
1794 /* Lets give 500ms for OBSS + START_BSS to complete */
1795 schedule_delayed_work(&con_sap_adapter->acs_pending_work,
1796 msecs_to_jiffies(500));
1797 clear_bit(ACS_PENDING, &con_sap_adapter->event_flags);
1798 }
1799
1800 return;
1801}
1802
1803static int
1804__wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy,
1805 struct wireless_dev *wdev,
1806 const void *data,
1807 int data_len)
1808{
1809 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1810 struct sk_buff *skb = NULL;
1811 uint32_t fset = 0;
1812 int ret;
1813
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301814 ENTER();
1815
Peng Xuf5d60c82015-10-02 17:17:03 -07001816 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001817 hdd_err("Command not allowed in FTM mode");
1818 return -EPERM;
1819 }
1820
1821 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301822 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001823 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001824
1825 if (wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) {
1826 hddLog(LOG1, FL("Infra Station mode is supported by driver"));
1827 fset |= WIFI_FEATURE_INFRA;
1828 }
1829 if (true == hdd_is_5g_supported(pHddCtx)) {
1830 hddLog(LOG1, FL("INFRA_5G is supported by firmware"));
1831 fset |= WIFI_FEATURE_INFRA_5G;
1832 }
1833#ifdef WLAN_FEATURE_P2P
1834 if ((wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) &&
1835 (wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_GO))) {
1836 hddLog(LOG1, FL("WiFi-Direct is supported by driver"));
1837 fset |= WIFI_FEATURE_P2P;
1838 }
1839#endif
1840 fset |= WIFI_FEATURE_SOFT_AP;
1841
1842 /* HOTSPOT is a supplicant feature, enable it by default */
1843 fset |= WIFI_FEATURE_HOTSPOT;
1844
1845#ifdef FEATURE_WLAN_EXTSCAN
1846 if (sme_is_feature_supported_by_fw(EXTENDED_SCAN)) {
1847 hddLog(LOG1, FL("EXTScan is supported by firmware"));
1848 fset |= WIFI_FEATURE_EXTSCAN | WIFI_FEATURE_HAL_EPNO;
1849 }
1850#endif
1851 if (wlan_hdd_nan_is_supported()) {
1852 hddLog(LOG1, FL("NAN is supported by firmware"));
1853 fset |= WIFI_FEATURE_NAN;
1854 }
1855 if (sme_is_feature_supported_by_fw(RTT)) {
1856 hddLog(LOG1, FL("RTT is supported by firmware"));
1857 fset |= WIFI_FEATURE_D2D_RTT;
1858 fset |= WIFI_FEATURE_D2AP_RTT;
1859 }
1860#ifdef FEATURE_WLAN_SCAN_PNO
1861 if (pHddCtx->config->configPNOScanSupport &&
1862 sme_is_feature_supported_by_fw(PNO)) {
1863 hddLog(LOG1, FL("PNO is supported by firmware"));
1864 fset |= WIFI_FEATURE_PNO;
1865 }
1866#endif
1867 fset |= WIFI_FEATURE_ADDITIONAL_STA;
1868#ifdef FEATURE_WLAN_TDLS
1869 if ((true == pHddCtx->config->fEnableTDLSSupport) &&
1870 sme_is_feature_supported_by_fw(TDLS)) {
1871 hddLog(LOG1, FL("TDLS is supported by firmware"));
1872 fset |= WIFI_FEATURE_TDLS;
1873 }
1874 if (sme_is_feature_supported_by_fw(TDLS) &&
1875 (true == pHddCtx->config->fEnableTDLSOffChannel) &&
1876 sme_is_feature_supported_by_fw(TDLS_OFF_CHANNEL)) {
1877 hddLog(LOG1, FL("TDLS off-channel is supported by firmware"));
1878 fset |= WIFI_FEATURE_TDLS_OFFCHANNEL;
1879 }
1880#endif
1881#ifdef WLAN_AP_STA_CONCURRENCY
1882 fset |= WIFI_FEATURE_AP_STA;
1883#endif
1884 fset |= WIFI_FEATURE_RSSI_MONITOR;
1885
1886 if (hdd_link_layer_stats_supported())
1887 fset |= WIFI_FEATURE_LINK_LAYER_STATS;
1888
1889 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(fset) +
1890 NLMSG_HDRLEN);
1891 if (!skb) {
1892 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
1893 return -EINVAL;
1894 }
1895 hddLog(LOG1, FL("Supported Features : 0x%x"), fset);
1896 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_SET, fset)) {
1897 hddLog(LOGE, FL("nla put fail"));
1898 goto nla_put_failure;
1899 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301900 ret = cfg80211_vendor_cmd_reply(skb);
1901 EXIT();
1902 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001903nla_put_failure:
1904 kfree_skb(skb);
1905 return -EINVAL;
1906}
1907
1908/**
1909 * wlan_hdd_cfg80211_get_supported_features() - get supported features
1910 * @wiphy: pointer to wireless wiphy structure.
1911 * @wdev: pointer to wireless_dev structure.
1912 * @data: Pointer to the data to be passed via vendor interface
1913 * @data_len:Length of the data to be passed
1914 *
1915 * Return: Return the Success or Failure code.
1916 */
1917static int
1918wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy,
1919 struct wireless_dev *wdev,
1920 const void *data, int data_len)
1921{
1922 int ret = 0;
1923
1924 cds_ssr_protect(__func__);
1925 ret = __wlan_hdd_cfg80211_get_supported_features(wiphy, wdev,
1926 data, data_len);
1927 cds_ssr_unprotect(__func__);
1928
1929 return ret;
1930}
1931
1932/**
1933 * __wlan_hdd_cfg80211_set_scanning_mac_oui() - set scan MAC
1934 * @wiphy: pointer to wireless wiphy structure.
1935 * @wdev: pointer to wireless_dev structure.
1936 * @data: Pointer to the data to be passed via vendor interface
1937 * @data_len:Length of the data to be passed
1938 *
1939 * Set the MAC address that is to be used for scanning.
1940 *
1941 * Return: Return the Success or Failure code.
1942 */
1943static int
1944__wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy,
1945 struct wireless_dev *wdev,
1946 const void *data,
1947 int data_len)
1948{
1949 tpSirScanMacOui pReqMsg = NULL;
1950 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
1951 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX + 1];
1952 CDF_STATUS status;
1953 int ret;
1954
1955 ENTER();
1956
Peng Xuf5d60c82015-10-02 17:17:03 -07001957 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001958 hdd_err("Command not allowed in FTM mode");
1959 return -EPERM;
1960 }
1961
1962 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05301963 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001964 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001965
1966 if (false == pHddCtx->config->enable_mac_spoofing) {
1967 hddLog(LOGW, FL("MAC address spoofing is not enabled"));
1968 return -ENOTSUPP;
1969 }
1970
1971 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX,
1972 data, data_len, NULL)) {
1973 hddLog(LOGE, FL("Invalid ATTR"));
1974 return -EINVAL;
1975 }
1976 pReqMsg = cdf_mem_malloc(sizeof(*pReqMsg));
1977 if (!pReqMsg) {
1978 hddLog(LOGE, FL("cdf_mem_malloc failed"));
1979 return -ENOMEM;
1980 }
1981 if (!tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]) {
1982 hddLog(LOGE, FL("attr mac oui failed"));
1983 goto fail;
1984 }
1985 nla_memcpy(&pReqMsg->oui[0],
1986 tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI],
1987 sizeof(pReqMsg->oui));
1988 hddLog(LOG1, FL("Oui (%02x:%02x:%02x)"), pReqMsg->oui[0],
1989 pReqMsg->oui[1], pReqMsg->oui[2]);
1990 status = sme_set_scanning_mac_oui(pHddCtx->hHal, pReqMsg);
1991 if (!CDF_IS_STATUS_SUCCESS(status)) {
1992 hddLog(CDF_TRACE_LEVEL_ERROR,
1993 FL("sme_set_scanning_mac_oui failed(err=%d)"), status);
1994 goto fail;
1995 }
1996 return 0;
1997fail:
1998 cdf_mem_free(pReqMsg);
1999 return -EINVAL;
2000}
2001
2002/**
2003 * wlan_hdd_cfg80211_set_scanning_mac_oui() - set scan MAC
2004 * @wiphy: pointer to wireless wiphy structure.
2005 * @wdev: pointer to wireless_dev structure.
2006 * @data: Pointer to the data to be passed via vendor interface
2007 * @data_len:Length of the data to be passed
2008 *
2009 * Set the MAC address that is to be used for scanning. This is an
2010 * SSR-protecting wrapper function.
2011 *
2012 * Return: Return the Success or Failure code.
2013 */
2014static int
2015wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy,
2016 struct wireless_dev *wdev,
2017 const void *data,
2018 int data_len)
2019{
2020 int ret;
2021
2022 cds_ssr_protect(__func__);
2023 ret = __wlan_hdd_cfg80211_set_scanning_mac_oui(wiphy, wdev,
2024 data, data_len);
2025 cds_ssr_unprotect(__func__);
2026
2027 return ret;
2028}
2029
2030/**
2031 * wlan_hdd_cfg80211_set_feature() - Set the bitmask for supported features
2032 * @feature_flags: pointer to the byte array of features.
2033 * @feature: Feature to be turned ON in the byte array.
2034 *
2035 * Return: None
2036 *
2037 * This is called to turn ON or SET the feature flag for the requested feature.
2038 **/
2039#define NUM_BITS_IN_BYTE 8
2040void wlan_hdd_cfg80211_set_feature(uint8_t *feature_flags, uint8_t feature)
2041{
2042 uint32_t index;
2043 uint8_t bit_mask;
2044
2045 index = feature / NUM_BITS_IN_BYTE;
2046 bit_mask = 1 << (feature % NUM_BITS_IN_BYTE);
2047 feature_flags[index] |= bit_mask;
2048}
2049
2050/**
2051 * __wlan_hdd_cfg80211_get_features() - Get the Driver Supported features
2052 * @wiphy: pointer to wireless wiphy structure.
2053 * @wdev: pointer to wireless_dev structure.
2054 * @data: Pointer to the data to be passed via vendor interface
2055 * @data_len:Length of the data to be passed
2056 *
2057 * This is called when wlan driver needs to send supported feature set to
2058 * supplicant upon a request/query from the supplicant.
2059 *
2060 * Return: Return the Success or Failure code.
2061 **/
2062#define MAX_CONCURRENT_CHAN_ON_24G 2
2063#define MAX_CONCURRENT_CHAN_ON_5G 2
2064static int
2065__wlan_hdd_cfg80211_get_features(struct wiphy *wiphy,
2066 struct wireless_dev *wdev,
2067 const void *data, int data_len)
2068{
2069 struct sk_buff *skb = NULL;
2070 uint32_t dbs_capability = 0;
2071 bool one_by_one_dbs, two_by_two_dbs;
2072 CDF_STATUS ret = CDF_STATUS_E_FAILURE;
2073 int ret_val;
2074
2075 uint8_t feature_flags[(NUM_QCA_WLAN_VENDOR_FEATURES + 7) / 8] = {0};
2076 hdd_context_t *hdd_ctx_ptr = wiphy_priv(wiphy);
2077
2078 ret_val = wlan_hdd_validate_context(hdd_ctx_ptr);
2079 if (ret_val)
2080 return ret_val;
2081
Peng Xuf5d60c82015-10-02 17:17:03 -07002082 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002083 hdd_err("Command not allowed in FTM mode");
2084 return -EPERM;
2085 }
2086
2087 if (hdd_ctx_ptr->config->isRoamOffloadEnabled) {
2088 hddLog(LOG1, FL("Key Mgmt Offload is supported"));
2089 wlan_hdd_cfg80211_set_feature(feature_flags,
2090 QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD);
2091 }
2092
2093 wlan_hdd_cfg80211_set_feature(feature_flags,
2094 QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY);
2095 if (wma_is_scan_simultaneous_capable())
2096 wlan_hdd_cfg80211_set_feature(feature_flags,
2097 QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS);
2098 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(feature_flags) +
2099 NLMSG_HDRLEN);
2100
2101 if (!skb) {
2102 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
2103 return -ENOMEM;
2104 }
2105
2106 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS,
2107 sizeof(feature_flags), feature_flags))
2108 goto nla_put_failure;
2109
2110 ret = wma_get_dbs_hw_modes(&one_by_one_dbs, &two_by_two_dbs);
2111 if (CDF_STATUS_SUCCESS == ret) {
2112 if (one_by_one_dbs)
2113 dbs_capability = DRV_DBS_CAPABILITY_1X1;
2114
2115 if (two_by_two_dbs)
2116 dbs_capability = DRV_DBS_CAPABILITY_2X2;
2117
2118 if (!one_by_one_dbs && !two_by_two_dbs)
2119 dbs_capability = DRV_DBS_CAPABILITY_DISABLED;
2120 } else {
2121 hdd_err("wma_get_dbs_hw_mode failed");
2122 dbs_capability = DRV_DBS_CAPABILITY_DISABLED;
2123 }
2124
2125 hdd_info("dbs_capability is %d", dbs_capability);
2126
2127 if (nla_put_u32(skb,
2128 QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND,
2129 MAX_CONCURRENT_CHAN_ON_24G))
2130 goto nla_put_failure;
2131
2132 if (nla_put_u32(skb,
2133 QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND,
2134 MAX_CONCURRENT_CHAN_ON_5G))
2135 goto nla_put_failure;
2136
2137 return cfg80211_vendor_cmd_reply(skb);
2138
2139nla_put_failure:
2140 kfree_skb(skb);
2141 return -EINVAL;
2142}
2143
2144/**
2145 * wlan_hdd_cfg80211_get_features() - Get the Driver Supported features
2146 * @wiphy: pointer to wireless wiphy structure.
2147 * @wdev: pointer to wireless_dev structure.
2148 * @data: Pointer to the data to be passed via vendor interface
2149 * @data_len:Length of the data to be passed
2150 *
2151 * This is called when wlan driver needs to send supported feature set to
2152 * supplicant upon a request/query from the supplicant.
2153 *
2154 * Return: Return the Success or Failure code.
2155 */
2156static int
2157wlan_hdd_cfg80211_get_features(struct wiphy *wiphy,
2158 struct wireless_dev *wdev,
2159 const void *data, int data_len)
2160{
2161 int ret;
2162
2163 cds_ssr_protect(__func__);
2164 ret = __wlan_hdd_cfg80211_get_features(wiphy, wdev,
2165 data, data_len);
2166 cds_ssr_unprotect(__func__);
2167
2168 return ret;
2169}
2170
2171
2172/**
2173 * __wlan_hdd_cfg80211_set_ext_roam_params() - Settings for roaming parameters
2174 * @wiphy: The wiphy structure
2175 * @wdev: The wireless device
2176 * @data: Data passed by framework
2177 * @data_len: Parameters to be configured passed as data
2178 *
2179 * The roaming related parameters are configured by the framework
2180 * using this interface.
2181 *
2182 * Return: Return either success or failure code.
2183 */
2184static int
2185__wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy,
2186 struct wireless_dev *wdev, const void *data, int data_len)
2187{
2188 struct net_device *dev = wdev->netdev;
2189 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2190 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
2191 uint8_t session_id;
2192 struct roam_ext_params roam_params;
2193 uint32_t cmd_type, req_id;
2194 struct nlattr *curr_attr;
2195 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX + 1];
2196 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX + 1];
2197 int rem, i;
2198 uint32_t buf_len = 0;
2199 int ret;
2200
Peng Xuf5d60c82015-10-02 17:17:03 -07002201 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002202 hdd_err("Command not allowed in FTM mode");
2203 return -EPERM;
2204 }
2205
2206 ret = wlan_hdd_validate_context(pHddCtx);
2207 if (0 != ret) {
2208 hddLog(LOGE, FL("HDD context is not valid"));
2209 return -EINVAL;
2210 }
2211
2212 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX,
2213 data, data_len,
2214 NULL)) {
2215 hddLog(LOGE, FL("Invalid ATTR"));
2216 return -EINVAL;
2217 }
2218 /* Parse and fetch Command Type*/
2219 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD]) {
2220 hddLog(LOGE, FL("roam cmd type failed"));
2221 goto fail;
2222 }
2223 session_id = pAdapter->sessionId;
2224 cdf_mem_set(&roam_params, sizeof(roam_params), 0);
2225 cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD]);
2226 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID]) {
2227 hddLog(LOGE, FL("attr request id failed"));
2228 goto fail;
2229 }
2230 req_id = nla_get_u32(
2231 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID]);
2232 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Req Id (%d)"), req_id);
2233 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Cmd Type (%d)"), cmd_type);
2234 switch (cmd_type) {
2235 case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST:
2236 i = 0;
2237 nla_for_each_nested(curr_attr,
2238 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST],
2239 rem) {
2240 if (nla_parse(tb2,
2241 QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX,
2242 nla_data(curr_attr), nla_len(curr_attr),
2243 NULL)) {
2244 hddLog(LOGE,
2245 FL("nla_parse failed"));
2246 goto fail;
2247 }
2248 /* Parse and Fetch allowed SSID list*/
2249 if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID]) {
2250 hddLog(LOGE, FL("attr allowed ssid failed"));
2251 goto fail;
2252 }
2253 buf_len = nla_len(tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID]);
2254 /*
2255 * Upper Layers include a null termination character.
2256 * Check for the actual permissible length of SSID and
2257 * also ensure not to copy the NULL termination
2258 * character to the driver buffer.
2259 */
2260 if (buf_len && (i < MAX_SSID_ALLOWED_LIST) &&
2261 ((buf_len - 1) <= SIR_MAC_MAX_SSID_LENGTH)) {
2262 nla_memcpy(
2263 roam_params.ssid_allowed_list[i].ssId,
2264 tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID],
2265 buf_len - 1);
2266 roam_params.ssid_allowed_list[i].length =
2267 buf_len - 1;
2268 hddLog(CDF_TRACE_LEVEL_DEBUG,
2269 FL("SSID[%d]: %.*s,length = %d"), i,
2270 roam_params.ssid_allowed_list[i].length,
2271 roam_params.ssid_allowed_list[i].ssId,
2272 roam_params.ssid_allowed_list[i].length);
2273 i++;
2274 } else {
2275 hddLog(LOGE, FL("Invalid buffer length"));
2276 }
2277 }
2278 roam_params.num_ssid_allowed_list = i;
2279 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Num of Allowed SSID %d"),
2280 roam_params.num_ssid_allowed_list);
2281 sme_update_roam_params(pHddCtx->hHal, session_id,
2282 roam_params, REASON_ROAM_SET_SSID_ALLOWED);
2283 break;
2284 case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_EXTSCAN_ROAM_PARAMS:
2285 /* Parse and fetch 5G Boost Threshold */
2286 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD]) {
2287 hddLog(LOGE, FL("5G boost threshold failed"));
2288 goto fail;
2289 }
2290 roam_params.raise_rssi_thresh_5g = nla_get_s32(
2291 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD]);
2292 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Boost Threshold (%d)"),
2293 roam_params.raise_rssi_thresh_5g);
2294 /* Parse and fetch 5G Penalty Threshold */
2295 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD]) {
2296 hddLog(LOGE, FL("5G penalty threshold failed"));
2297 goto fail;
2298 }
2299 roam_params.drop_rssi_thresh_5g = nla_get_s32(
2300 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD]);
2301 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Penalty Threshold (%d)"),
2302 roam_params.drop_rssi_thresh_5g);
2303 /* Parse and fetch 5G Boost Factor */
2304 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR]) {
2305 hddLog(LOGE, FL("5G boost Factor failed"));
2306 goto fail;
2307 }
2308 roam_params.raise_factor_5g = nla_get_u32(
2309 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR]);
2310 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Boost Factor (%d)"),
2311 roam_params.raise_factor_5g);
2312 /* Parse and fetch 5G Penalty factor */
2313 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR]) {
2314 hddLog(LOGE, FL("5G Penalty Factor failed"));
2315 goto fail;
2316 }
2317 roam_params.drop_factor_5g = nla_get_u32(
2318 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR]);
2319 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Penalty factor (%d)"),
2320 roam_params.drop_factor_5g);
2321 /* Parse and fetch 5G Max Boost */
2322 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST]) {
2323 hddLog(LOGE, FL("5G Max Boost failed"));
2324 goto fail;
2325 }
2326 roam_params.max_raise_rssi_5g = nla_get_u32(
2327 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST]);
2328 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("5G Max Boost (%d)"),
2329 roam_params.max_raise_rssi_5g);
2330 /* Parse and fetch Rssi Diff */
2331 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS]) {
2332 hddLog(LOGE, FL("Rssi Diff failed"));
2333 goto fail;
2334 }
2335 roam_params.rssi_diff = nla_get_s32(
2336 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS]);
2337 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("RSSI Diff (%d)"),
2338 roam_params.rssi_diff);
2339 /* Parse and fetch Alert Rssi Threshold */
2340 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER]) {
2341 hddLog(LOGE, FL("Alert Rssi Threshold failed"));
2342 goto fail;
2343 }
2344 roam_params.alert_rssi_threshold = nla_get_u32(
2345 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER]);
2346 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Alert RSSI Threshold (%d)"),
2347 roam_params.alert_rssi_threshold);
2348 sme_update_roam_params(pHddCtx->hHal, session_id,
2349 roam_params,
2350 REASON_ROAM_EXT_SCAN_PARAMS_CHANGED);
2351 break;
2352 case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM:
2353 /* Parse and fetch Activate Good Rssi Roam */
2354 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE]) {
2355 hddLog(LOGE, FL("Activate Good Rssi Roam failed"));
2356 goto fail;
2357 }
2358 roam_params.good_rssi_roam = nla_get_s32(
2359 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE]);
2360 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Activate Good Rssi Roam (%d)"),
2361 roam_params.good_rssi_roam);
2362 sme_update_roam_params(pHddCtx->hHal, session_id,
2363 roam_params, REASON_ROAM_GOOD_RSSI_CHANGED);
2364 break;
2365 case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS:
2366 /* Parse and fetch number of preferred BSSID */
2367 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID]) {
2368 hddLog(LOGE, FL("attr num of preferred bssid failed"));
2369 goto fail;
2370 }
2371 roam_params.num_bssid_favored = nla_get_u32(
2372 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID]);
2373 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Num of Preferred BSSID (%d)"),
2374 roam_params.num_bssid_favored);
2375 i = 0;
2376 nla_for_each_nested(curr_attr,
2377 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS],
2378 rem) {
2379 if (nla_parse(tb2,
2380 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX,
2381 nla_data(curr_attr), nla_len(curr_attr),
2382 NULL)) {
2383 hddLog(LOGE, FL("nla_parse failed"));
2384 goto fail;
2385 }
2386 /* Parse and fetch MAC address */
2387 if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID]) {
2388 hddLog(LOGE, FL("attr mac address failed"));
2389 goto fail;
2390 }
Srinivas Girigowdab0532392015-11-24 11:50:16 -08002391 nla_memcpy(roam_params.bssid_favored[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002392 tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID],
Srinivas Girigowdab0532392015-11-24 11:50:16 -08002393 CDF_MAC_ADDR_SIZE);
2394 hdd_debug(MAC_ADDRESS_STR,
2395 MAC_ADDR_ARRAY(roam_params.bssid_favored[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002396 /* Parse and fetch preference factor*/
2397 if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER]) {
2398 hddLog(LOGE, FL("BSSID Preference score failed"));
2399 goto fail;
2400 }
2401 roam_params.bssid_favored_factor[i] = nla_get_u32(
2402 tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER]);
2403 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("BSSID Preference score (%d)"),
2404 roam_params.bssid_favored_factor[i]);
2405 i++;
2406 }
2407 sme_update_roam_params(pHddCtx->hHal, session_id,
2408 roam_params, REASON_ROAM_SET_FAVORED_BSSID);
2409 break;
2410 case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID:
2411 /* Parse and fetch number of blacklist BSSID */
2412 if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID]) {
2413 hddLog(LOGE, FL("attr num of blacklist bssid failed"));
2414 goto fail;
2415 }
2416 roam_params.num_bssid_avoid_list = nla_get_u32(
2417 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID]);
2418 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Num of blacklist BSSID (%d)"),
2419 roam_params.num_bssid_avoid_list);
2420 i = 0;
2421 nla_for_each_nested(curr_attr,
2422 tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS],
2423 rem) {
2424 if (nla_parse(tb2,
2425 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX,
2426 nla_data(curr_attr), nla_len(curr_attr),
2427 NULL)) {
2428 hddLog(LOGE, FL("nla_parse failed"));
2429 goto fail;
2430 }
2431 /* Parse and fetch MAC address */
2432 if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID]) {
2433 hddLog(LOGE, FL("attr blacklist addr failed"));
2434 goto fail;
2435 }
Srinivas Girigowdab0532392015-11-24 11:50:16 -08002436 nla_memcpy(roam_params.bssid_avoid_list[i].bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002437 tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID],
Srinivas Girigowdab0532392015-11-24 11:50:16 -08002438 CDF_MAC_ADDR_SIZE);
2439 hdd_debug(MAC_ADDRESS_STR,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002440 MAC_ADDR_ARRAY(
Srinivas Girigowdab0532392015-11-24 11:50:16 -08002441 roam_params.bssid_avoid_list[i].bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002442 i++;
2443 }
2444 sme_update_roam_params(pHddCtx->hHal, session_id,
2445 roam_params, REASON_ROAM_SET_BLACKLIST_BSSID);
2446 break;
2447 }
2448 return 0;
2449fail:
2450 return -EINVAL;
2451}
2452
2453/**
2454 * wlan_hdd_cfg80211_set_ext_roam_params() - set ext scan roam params
2455 * @wiphy: pointer to wireless wiphy structure.
2456 * @wdev: pointer to wireless_dev structure.
2457 * @data: Pointer to the data to be passed via vendor interface
2458 * @data_len:Length of the data to be passed
2459 *
2460 * Return: Return the Success or Failure code.
2461 */
2462static int
2463wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy,
2464 struct wireless_dev *wdev,
2465 const void *data,
2466 int data_len)
2467{
2468 int ret;
2469
2470 cds_ssr_protect(__func__);
2471 ret = __wlan_hdd_cfg80211_set_ext_roam_params(wiphy, wdev,
2472 data, data_len);
2473 cds_ssr_unprotect(__func__);
2474
2475 return ret;
2476}
2477
2478static const struct nla_policy
2479wlan_hdd_set_no_dfs_flag_config_policy[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX
2480 +1] = {
2481 [QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG] = {.type = NLA_U32 },
2482};
2483
2484/**
2485 * wlan_hdd_check_dfs_channel_for_adapter() - check dfs channel in adapter
2486 * @hdd_ctx: HDD context
2487 * @device_mode: device mode
2488 * Return: bool
2489 */
2490static bool wlan_hdd_check_dfs_channel_for_adapter(hdd_context_t *hdd_ctx,
2491 device_mode_t device_mode)
2492{
2493 hdd_adapter_t *adapter;
2494 hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL;
2495 hdd_ap_ctx_t *ap_ctx;
2496 hdd_station_ctx_t *sta_ctx;
2497 CDF_STATUS cdf_status;
2498
2499 cdf_status = hdd_get_front_adapter(hdd_ctx,
2500 &adapter_node);
2501
2502 while ((NULL != adapter_node) &&
2503 (CDF_STATUS_SUCCESS == cdf_status)) {
2504 adapter = adapter_node->pAdapter;
2505
2506 if ((device_mode == adapter->device_mode) &&
2507 (device_mode == WLAN_HDD_SOFTAP)) {
2508 ap_ctx =
2509 WLAN_HDD_GET_AP_CTX_PTR(adapter);
2510
2511 /*
2512 * if there is SAP already running on DFS channel,
2513 * do not disable scan on dfs channels. Note that
2514 * with SAP on DFS, there cannot be conurrency on
2515 * single radio. But then we can have multiple
2516 * radios !!
2517 */
2518 if (CHANNEL_STATE_DFS ==
2519 cds_get_channel_state(
2520 ap_ctx->operatingChannel)) {
2521 hddLog(CDF_TRACE_LEVEL_ERROR,
2522 FL("SAP running on DFS channel"));
2523 return true;
2524 }
2525 }
2526
2527 if ((device_mode == adapter->device_mode) &&
2528 (device_mode == WLAN_HDD_INFRA_STATION)) {
2529 sta_ctx =
2530 WLAN_HDD_GET_STATION_CTX_PTR(adapter);
2531
2532 /*
2533 * if STA is already connected on DFS channel,
2534 * do not disable scan on dfs channels
2535 */
2536 if (hdd_conn_is_connected(sta_ctx) &&
2537 (CHANNEL_STATE_DFS ==
2538 cds_get_channel_state(
2539 sta_ctx->conn_info.operationChannel))) {
2540 hddLog(LOGE,
2541 FL("client connected on DFS channel"));
2542 return true;
2543 }
2544 }
2545
2546 cdf_status = hdd_get_next_adapter(hdd_ctx,
2547 adapter_node,
2548 &next);
2549 adapter_node = next;
2550 }
2551
2552 return false;
2553}
2554
2555/**
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08002556 * wlan_hdd_disable_dfs_chan_scan() - disable/enable DFS channels
2557 * @hdd_ctx: HDD context within host driver
2558 * @adapter: Adapter pointer
2559 * @no_dfs_flag: If TRUE, DFS channels cannot be used for scanning
2560 *
2561 * Loops through devices to see who is operating on DFS channels
2562 * and then disables/enables DFS channels by calling SME API.
2563 * Fails the disable request if any device is active on a DFS channel.
2564 *
2565 * Return: 0 or other error codes.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002566 */
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08002567
2568int wlan_hdd_disable_dfs_chan_scan(hdd_context_t *hdd_ctx,
2569 hdd_adapter_t *adapter,
2570 uint32_t no_dfs_flag)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002571{
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002572 tHalHandle h_hal = WLAN_HDD_GET_HAL_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002573 CDF_STATUS status;
2574 int ret_val = -EPERM;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002575
2576 if (no_dfs_flag == hdd_ctx->config->enableDFSChnlScan) {
2577 if (no_dfs_flag) {
2578 status = wlan_hdd_check_dfs_channel_for_adapter(
2579 hdd_ctx, WLAN_HDD_INFRA_STATION);
2580
2581 if (true == status)
2582 return -EOPNOTSUPP;
2583
2584 status = wlan_hdd_check_dfs_channel_for_adapter(
2585 hdd_ctx, WLAN_HDD_SOFTAP);
2586
2587 if (true == status)
2588 return -EOPNOTSUPP;
2589 }
2590
2591 hdd_ctx->config->enableDFSChnlScan = !no_dfs_flag;
2592
2593 hdd_abort_mac_scan_all_adapters(hdd_ctx);
2594
2595 /*
2596 * call the SME API to tunnel down the new channel list
2597 * to the firmware
2598 */
2599 status = sme_handle_dfs_chan_scan(
2600 h_hal, hdd_ctx->config->enableDFSChnlScan);
2601
2602 if (CDF_STATUS_SUCCESS == status) {
2603 ret_val = 0;
2604
2605 /*
2606 * Clear the SME scan cache also. Note that the
2607 * clearing of scan results is independent of session;
2608 * so no need to iterate over
2609 * all sessions
2610 */
2611 status = sme_scan_flush_result(h_hal);
2612 if (CDF_STATUS_SUCCESS != status)
2613 ret_val = -EPERM;
2614 }
2615
2616 } else {
2617 hddLog(CDF_TRACE_LEVEL_INFO,
2618 FL(" the DFS flag has not changed"));
2619 ret_val = 0;
2620 }
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08002621 return ret_val;
2622}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002623
Deepak Dhamdhere29b3b2f2015-01-22 11:09:55 -08002624/**
2625 * __wlan_hdd_cfg80211_disable_dfs_chan_scan() - DFS channel configuration
2626 * @wiphy: corestack handler
2627 * @wdev: wireless device
2628 * @data: data
2629 * @data_len: data length
2630 * Return: success(0) or reason code for failure
2631 */
2632static int __wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy,
2633 struct wireless_dev *wdev,
2634 const void *data,
2635 int data_len)
2636{
2637 struct net_device *dev = wdev->netdev;
2638 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
2639 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
2640 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + 1];
2641 int ret_val;
2642 uint32_t no_dfs_flag = 0;
2643
2644 ENTER();
2645 ret_val = wlan_hdd_validate_context(hdd_ctx);
2646
2647 if (ret_val) {
2648 hdd_err("HDD context is not valid");
2649 return ret_val;
2650 }
2651
2652 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX,
2653 data, data_len,
2654 wlan_hdd_set_no_dfs_flag_config_policy)) {
2655 hdd_err("invalid attr");
2656 return -EINVAL;
2657 }
2658
2659 if (!tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG]) {
2660 hdd_err("attr dfs flag failed");
2661 return -EINVAL;
2662 }
2663
2664 no_dfs_flag = nla_get_u32(
2665 tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG]);
2666
2667 hddLog(LOG1, FL(" DFS flag = %d"), no_dfs_flag);
2668
2669 if (no_dfs_flag > 1) {
2670 hddLog(LOGE, FL("invalid value of dfs flag"));
2671 return -EINVAL;
2672 }
2673
2674 ret_val = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter,
2675 no_dfs_flag);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002676 return ret_val;
2677}
2678
2679/**
2680 * wlan_hdd_cfg80211_disable_dfs_chan_scan () - DFS scan vendor command
2681 *
2682 * @wiphy: wiphy device pointer
2683 * @wdev: wireless device pointer
2684 * @data: Vendof command data buffer
2685 * @data_len: Buffer length
2686 *
2687 * Handles QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX. Validate it and
2688 * call wlan_hdd_disable_dfs_chan_scan to send it to firmware.
2689 *
2690 * Return: EOK or other error codes.
2691 */
2692
2693static int wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy,
2694 struct wireless_dev *wdev,
2695 const void *data,
2696 int data_len)
2697{
2698 int ret;
2699
2700 cds_ssr_protect(__func__);
2701 ret = __wlan_hdd_cfg80211_disable_dfs_chan_scan(wiphy, wdev,
2702 data, data_len);
2703 cds_ssr_unprotect(__func__);
2704
2705 return ret;
2706}
2707
2708#ifdef WLAN_FEATURE_ROAM_OFFLOAD
2709/**
2710 * __wlan_hdd_cfg80211_keymgmt_set_key() - Store the Keys in the driver session
2711 * @wiphy: pointer to wireless wiphy structure.
2712 * @wdev: pointer to wireless_dev structure.
2713 * @data: Pointer to the Key data
2714 * @data_len:Length of the data passed
2715 *
2716 * This is called when wlan driver needs to save the keys received via
2717 * vendor specific command.
2718 *
2719 * Return: Return the Success or Failure code.
2720 */
2721static int __wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy,
2722 struct wireless_dev *wdev,
2723 const void *data, int data_len)
2724{
2725 uint8_t local_pmk[SIR_ROAM_SCAN_PSK_SIZE];
2726 struct net_device *dev = wdev->netdev;
2727 hdd_adapter_t *hdd_adapter_ptr = WLAN_HDD_GET_PRIV_PTR(dev);
2728 hdd_context_t *hdd_ctx_ptr;
2729 int status;
2730
Peng Xuf5d60c82015-10-02 17:17:03 -07002731 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002732 hdd_err("Command not allowed in FTM mode");
2733 return -EPERM;
2734 }
2735
2736 if ((data == NULL) || (data_len == 0) ||
2737 (data_len > SIR_ROAM_SCAN_PSK_SIZE)) {
2738 hddLog(LOGE, FL("Invalid data"));
2739 return -EINVAL;
2740 }
2741
2742 hdd_ctx_ptr = WLAN_HDD_GET_CTX(hdd_adapter_ptr);
2743 if (!hdd_ctx_ptr) {
2744 hddLog(LOGE, FL("HDD context is null"));
2745 return -EINVAL;
2746 }
2747
2748 status = wlan_hdd_validate_context(hdd_ctx_ptr);
2749 if (0 != status) {
2750 hddLog(LOGE, FL("HDD context is invalid"));
2751 return status;
2752 }
2753 sme_update_roam_key_mgmt_offload_enabled(hdd_ctx_ptr->hHal,
2754 hdd_adapter_ptr->sessionId,
2755 true);
2756 cdf_mem_zero(&local_pmk, SIR_ROAM_SCAN_PSK_SIZE);
2757 cdf_mem_copy(local_pmk, data, data_len);
2758 sme_roam_set_psk_pmk(WLAN_HDD_GET_HAL_CTX(hdd_adapter_ptr),
2759 hdd_adapter_ptr->sessionId, local_pmk, data_len);
2760 return 0;
2761}
2762
2763/**
2764 * wlan_hdd_cfg80211_keymgmt_set_key() - Store the Keys in the driver session
2765 * @wiphy: pointer to wireless wiphy structure.
2766 * @wdev: pointer to wireless_dev structure.
2767 * @data: Pointer to the Key data
2768 * @data_len:Length of the data passed
2769 *
2770 * This is called when wlan driver needs to save the keys received via
2771 * vendor specific command.
2772 *
2773 * Return: Return the Success or Failure code.
2774 */
2775static int wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy,
2776 struct wireless_dev *wdev,
2777 const void *data, int data_len)
2778{
2779 int ret;
2780
2781 cds_ssr_protect(__func__);
2782 ret = __wlan_hdd_cfg80211_keymgmt_set_key(wiphy, wdev, data, data_len);
2783 cds_ssr_unprotect(__func__);
2784
2785 return ret;
2786}
2787
2788static const struct nla_policy qca_wlan_vendor_get_wifi_info_policy[
2789 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1] = {
2790 [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION] = {.type = NLA_U8 },
2791 [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION] = {.type = NLA_U8 },
2792};
2793
2794/**
2795 * __wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info
2796 * @wiphy: pointer to wireless wiphy structure.
2797 * @wdev: pointer to wireless_dev structure.
2798 * @data: Pointer to the data to be passed via vendor interface
2799 * @data_len:Length of the data to be passed
2800 *
2801 * This is called when wlan driver needs to send wifi driver related info
2802 * (driver/fw version) to the user space application upon request.
2803 *
2804 * Return: Return the Success or Failure code.
2805 */
2806static int
2807__wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy,
2808 struct wireless_dev *wdev,
2809 const void *data, int data_len)
2810{
2811 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
2812 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1];
2813 tSirVersionString version;
2814 uint32_t version_len;
2815 uint32_t major_spid = 0, minor_spid = 0, siid = 0, crmid = 0;
2816 uint8_t attr;
2817 int status;
2818 struct sk_buff *reply_skb = NULL;
2819
Peng Xuf5d60c82015-10-02 17:17:03 -07002820 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002821 hdd_err("Command not allowed in FTM mode");
2822 return -EPERM;
2823 }
2824
2825 status = wlan_hdd_validate_context(hdd_ctx);
2826 if (0 != status) {
2827 hddLog(LOGE, FL("HDD context is not valid"));
2828 return -EINVAL;
2829 }
2830
2831 if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX, data,
2832 data_len, qca_wlan_vendor_get_wifi_info_policy)) {
2833 hddLog(LOGE, FL("WIFI_INFO_GET NL CMD parsing failed"));
2834 return -EINVAL;
2835 }
2836
2837 if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) {
2838 hddLog(LOG1, FL("Rcvd req for Driver version"));
2839 strlcpy(version, QWLAN_VERSIONSTR, sizeof(version));
2840 attr = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION;
2841 } else if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) {
2842 hddLog(LOG1, FL("Rcvd req for FW version"));
2843 hdd_get_fw_version(hdd_ctx, &major_spid, &minor_spid, &siid,
2844 &crmid);
2845 snprintf(version, sizeof(version), "%d:%d:%d:%d",
2846 major_spid, minor_spid, siid, crmid);
2847 attr = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION;
2848 } else {
2849 hddLog(LOGE, FL("Invalid attribute in get wifi info request"));
2850 return -EINVAL;
2851 }
2852
2853 version_len = strlen(version);
2854 reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
2855 version_len + NLA_HDRLEN + NLMSG_HDRLEN);
2856 if (!reply_skb) {
2857 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
2858 return -ENOMEM;
2859 }
2860
2861 if (nla_put(reply_skb, attr, version_len, version)) {
2862 hddLog(LOGE, FL("nla put fail"));
2863 kfree_skb(reply_skb);
2864 return -EINVAL;
2865 }
2866
2867 return cfg80211_vendor_cmd_reply(reply_skb);
2868}
2869
2870/**
2871 * wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info
2872 * @wiphy: pointer to wireless wiphy structure.
2873 * @wdev: pointer to wireless_dev structure.
2874 * @data: Pointer to the data to be passed via vendor interface
2875 * @data_len:Length of the data to be passed
2876 *
2877 * This is called when wlan driver needs to send wifi driver related info
2878 * (driver/fw version) to the user space application upon request.
2879 *
2880 * Return: Return the Success or Failure code.
2881 */
2882static int
2883wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy,
2884 struct wireless_dev *wdev,
2885 const void *data, int data_len)
2886{
2887 int ret;
2888
2889 cds_ssr_protect(__func__);
2890 ret = __wlan_hdd_cfg80211_get_wifi_info(wiphy, wdev, data, data_len);
2891 cds_ssr_unprotect(__func__);
2892
2893 return ret;
2894}
2895
2896/**
2897 * __wlan_hdd_cfg80211_get_logger_supp_feature() - Get the wifi logger features
2898 * @wiphy: pointer to wireless wiphy structure.
2899 * @wdev: pointer to wireless_dev structure.
2900 * @data: Pointer to the data to be passed via vendor interface
2901 * @data_len:Length of the data to be passed
2902 *
2903 * This is called by userspace to know the supported logger features
2904 *
2905 * Return: Return the Success or Failure code.
2906 */
2907static int
2908__wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy,
2909 struct wireless_dev *wdev,
2910 const void *data, int data_len)
2911{
2912 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
2913 int status;
2914 uint32_t features;
2915 struct sk_buff *reply_skb = NULL;
2916
Peng Xuf5d60c82015-10-02 17:17:03 -07002917 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08002918 hdd_err("Command not allowed in FTM mode");
2919 return -EPERM;
2920 }
2921
2922 status = wlan_hdd_validate_context(hdd_ctx);
2923 if (0 != status) {
2924 hddLog(LOGE, FL("HDD context is not valid"));
2925 return -EINVAL;
2926 }
2927
2928 features = 0;
2929
2930 if (hdd_is_memdump_supported())
2931 features |= WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
2932 features |= WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED;
2933 features |= WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
2934 features |= WIFI_LOGGER_WAKE_LOCK_SUPPORTED;
2935
2936 reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
2937 sizeof(uint32_t) + NLA_HDRLEN + NLMSG_HDRLEN);
2938 if (!reply_skb) {
2939 hddLog(LOGE, FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
2940 return -ENOMEM;
2941 }
2942
2943 hddLog(LOG1, FL("Supported logger features: 0x%0x"), features);
2944 if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED,
2945 features)) {
2946 hddLog(LOGE, FL("nla put fail"));
2947 kfree_skb(reply_skb);
2948 return -EINVAL;
2949 }
2950
2951 return cfg80211_vendor_cmd_reply(reply_skb);
2952}
2953
2954/**
2955 * wlan_hdd_cfg80211_get_logger_supp_feature() - Get the wifi logger features
2956 * @wiphy: pointer to wireless wiphy structure.
2957 * @wdev: pointer to wireless_dev structure.
2958 * @data: Pointer to the data to be passed via vendor interface
2959 * @data_len:Length of the data to be passed
2960 *
2961 * This is called by userspace to know the supported logger features
2962 *
2963 * Return: Return the Success or Failure code.
2964 */
2965static int
2966wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy,
2967 struct wireless_dev *wdev,
2968 const void *data, int data_len)
2969{
2970 int ret;
2971
2972 cds_ssr_protect(__func__);
2973 ret = __wlan_hdd_cfg80211_get_logger_supp_feature(wiphy, wdev,
2974 data, data_len);
2975 cds_ssr_unprotect(__func__);
2976
2977 return ret;
2978}
2979
2980/**
2981 * wlan_hdd_send_roam_auth_event() - Send the roamed and authorized event
2982 * @hdd_ctx_ptr: pointer to HDD Context.
2983 * @bssid: pointer to bssid of roamed AP.
2984 * @req_rsn_ie: Pointer to request RSN IE
2985 * @req_rsn_len: Length of the request RSN IE
2986 * @rsp_rsn_ie: Pointer to response RSN IE
2987 * @rsp_rsn_len: Length of the response RSN IE
2988 * @roam_info_ptr: Pointer to the roaming related information
2989 *
2990 * This is called when wlan driver needs to send the roaming and
2991 * authorization information after roaming.
2992 *
2993 * The information that would be sent is the request RSN IE, response
2994 * RSN IE and BSSID of the newly roamed AP.
2995 *
2996 * If the Authorized status is authenticated, then additional parameters
2997 * like PTK's KCK and KEK and Replay Counter would also be passed to the
2998 * supplicant.
2999 *
3000 * The supplicant upon receiving this event would ignore the legacy
3001 * cfg80211_roamed call and use the entire information from this event.
3002 * The cfg80211_roamed should still co-exist since the kernel will
3003 * make use of the parameters even if the supplicant ignores it.
3004 *
3005 * Return: Return the Success or Failure code.
3006 */
3007int wlan_hdd_send_roam_auth_event(hdd_context_t *hdd_ctx_ptr, uint8_t *bssid,
3008 uint8_t *req_rsn_ie, uint32_t req_rsn_len, uint8_t *rsp_rsn_ie,
3009 uint32_t rsp_rsn_len, tCsrRoamInfo *roam_info_ptr)
3010{
3011 struct sk_buff *skb = NULL;
3012 ENTER();
3013
3014 if (wlan_hdd_validate_context(hdd_ctx_ptr)) {
3015 hddLog(CDF_TRACE_LEVEL_ERROR, FL("HDD context is not valid "));
3016 return -EINVAL;
3017 }
3018
Prashanth Bhattabfc25292015-11-05 11:16:21 -08003019 if (!hdd_ctx_ptr->config->isRoamOffloadEnabled ||
3020 !roam_info_ptr->roamSynchInProgress)
3021 return 0;
3022
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003023 skb = cfg80211_vendor_event_alloc(hdd_ctx_ptr->wiphy,
3024 NULL,
3025 ETH_ALEN + req_rsn_len + rsp_rsn_len +
3026 sizeof(uint8_t) + SIR_REPLAY_CTR_LEN +
3027 SIR_KCK_KEY_LEN + SIR_KCK_KEY_LEN +
Ravi Joshi277ae9b2015-11-13 11:30:43 -08003028 sizeof(uint8_t) + (8 * NLMSG_HDRLEN),
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003029 QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX,
3030 GFP_KERNEL);
3031
3032 if (!skb) {
3033 hddLog(CDF_TRACE_LEVEL_ERROR,
3034 FL("cfg80211_vendor_event_alloc failed"));
3035 return -EINVAL;
3036 }
3037
3038 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
3039 ETH_ALEN, bssid) ||
3040 nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE,
3041 req_rsn_len, req_rsn_ie) ||
3042 nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE,
3043 rsp_rsn_len, rsp_rsn_ie)) {
3044 hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla put fail"));
3045 goto nla_put_failure;
3046 }
3047 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Auth Status = %d"),
3048 roam_info_ptr->synchAuthStatus);
3049 if (roam_info_ptr->synchAuthStatus ==
3050 CSR_ROAM_AUTH_STATUS_AUTHENTICATED) {
3051 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Include Auth Params TLV's"));
Naveen Rawat14298b92015-11-25 16:27:41 -08003052 if (nla_put_u8(skb,
3053 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, true)) {
3054 hdd_err("nla put fail");
3055 goto nla_put_failure;
3056 }
3057 /* if FT connection: dont send ROAM_AUTH_KEY_REPLAY_CTR */
3058 if (roam_info_ptr->u.pConnectedProfile->AuthType !=
3059 eCSR_AUTH_TYPE_FT_RSN &&
3060 roam_info_ptr->u.pConnectedProfile->AuthType !=
3061 eCSR_AUTH_TYPE_FT_RSN_PSK &&
3062 nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR,
3063 SIR_REPLAY_CTR_LEN, roam_info_ptr->replay_ctr)) {
3064 hdd_err("non FT connection.");
3065 hdd_err("failed to send replay counter.");
3066 goto nla_put_failure;
3067 }
3068 if (nla_put(skb,
3069 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK,
3070 SIR_KCK_KEY_LEN, roam_info_ptr->kck) ||
3071 nla_put(skb,
3072 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK,
3073 SIR_KEK_KEY_LEN, roam_info_ptr->kek)) {
3074 hdd_err("nla put fail");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003075 goto nla_put_failure;
3076 }
3077 } else {
3078 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("No Auth Params TLV's"));
3079 if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED,
3080 false)) {
3081 hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla put fail"));
3082 goto nla_put_failure;
3083 }
3084 }
3085
Ravi Joshi277ae9b2015-11-13 11:30:43 -08003086 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Subnet Change Status = %d"),
3087 roam_info_ptr->subnet_change_status);
3088
3089 /*
3090 * Add subnet change status if subnet has changed
3091 * 0 = unchanged
3092 * 1 = changed
3093 * 2 = unknown
3094 */
3095 if (roam_info_ptr->subnet_change_status) {
3096 if (nla_put_u8(skb,
3097 QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS,
3098 roam_info_ptr->subnet_change_status)) {
3099 hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla put fail"));
3100 goto nla_put_failure;
3101 }
3102 }
3103
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003104 cfg80211_vendor_event(skb, GFP_KERNEL);
3105 return 0;
3106
3107nla_put_failure:
3108 kfree_skb(skb);
3109 return -EINVAL;
3110}
Prashanth Bhattabfc25292015-11-05 11:16:21 -08003111#endif /* WLAN_FEATURE_ROAM_OFFLOAD */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003112
3113static const struct nla_policy
3114wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = {
3115
3116 [QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM] = {.type = NLA_U32 },
3117 [QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR] = {.type = NLA_U16 },
3118 [QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME] = {.type = NLA_U32 },
3119};
3120
3121
3122/**
3123 * __wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration
3124 * vendor command
3125 *
3126 * @wiphy: wiphy device pointer
3127 * @wdev: wireless device pointer
3128 * @data: Vendor command data buffer
3129 * @data_len: Buffer length
3130 *
3131 * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX.
3132 *
3133 * Return: Error code.
3134 */
3135static int
3136__wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
3137 struct wireless_dev *wdev,
3138 const void *data,
3139 int data_len)
3140{
3141 struct net_device *dev = wdev->netdev;
3142 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3143 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3144 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1];
3145 int ret_val = 0;
3146 u32 modulated_dtim;
3147 u16 stats_avg_factor;
3148 u32 guard_time;
3149 CDF_STATUS status;
3150
Peng Xuf5d60c82015-10-02 17:17:03 -07003151 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003152 hdd_err("Command not allowed in FTM mode");
3153 return -EPERM;
3154 }
3155
3156 ret_val = wlan_hdd_validate_context(hdd_ctx);
3157 if (ret_val) {
3158 hddLog(LOGE, FL("HDD context is not valid"));
3159 return ret_val;
3160 }
3161
3162 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX,
3163 data, data_len,
3164 wlan_hdd_wifi_config_policy)) {
3165 hddLog(LOGE, FL("invalid attr"));
3166 return -EINVAL;
3167 }
3168
3169 if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]) {
3170 modulated_dtim = nla_get_u32(
3171 tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]);
3172
3173 status = sme_configure_modulated_dtim(hdd_ctx->hHal,
3174 adapter->sessionId,
3175 modulated_dtim);
3176
3177 if (CDF_STATUS_SUCCESS != status)
3178 ret_val = -EPERM;
3179 }
3180
3181 if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]) {
3182 stats_avg_factor = nla_get_u16(
3183 tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]);
3184 status = sme_configure_stats_avg_factor(hdd_ctx->hHal,
3185 adapter->sessionId,
3186 stats_avg_factor);
3187
3188 if (CDF_STATUS_SUCCESS != status)
3189 ret_val = -EPERM;
3190 }
3191
3192
3193 if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME]) {
3194 guard_time = nla_get_u32(
3195 tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME]);
3196 status = sme_configure_guard_time(hdd_ctx->hHal,
3197 adapter->sessionId,
3198 guard_time);
3199
3200 if (CDF_STATUS_SUCCESS != status)
3201 ret_val = -EPERM;
3202 }
3203
3204 return ret_val;
3205}
3206
3207/**
3208 * wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration
3209 * vendor command
3210 *
3211 * @wiphy: wiphy device pointer
3212 * @wdev: wireless device pointer
3213 * @data: Vendor command data buffer
3214 * @data_len: Buffer length
3215 *
3216 * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX.
3217 *
3218 * Return: EOK or other error codes.
3219 */
3220static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy,
3221 struct wireless_dev *wdev,
3222 const void *data,
3223 int data_len)
3224{
3225 int ret;
3226
3227 cds_ssr_protect(__func__);
3228 ret = __wlan_hdd_cfg80211_wifi_configuration_set(wiphy, wdev,
3229 data, data_len);
3230 cds_ssr_unprotect(__func__);
3231
3232 return ret;
3233}
3234
3235static const struct
3236nla_policy
3237qca_wlan_vendor_wifi_logger_start_policy
3238[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1] = {
3239 [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]
3240 = {.type = NLA_U32 },
3241 [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]
3242 = {.type = NLA_U32 },
3243 [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]
3244 = {.type = NLA_U32 },
3245};
3246
3247/**
3248 * __wlan_hdd_cfg80211_wifi_logger_start() - This function is used to enable
3249 * or disable the collection of packet statistics from the firmware
3250 * @wiphy: WIPHY structure pointer
3251 * @wdev: Wireless device structure pointer
3252 * @data: Pointer to the data received
3253 * @data_len: Length of the data received
3254 *
3255 * This function enables or disables the collection of packet statistics from
3256 * the firmware
3257 *
3258 * Return: 0 on success and errno on failure
3259 */
3260static int __wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy,
3261 struct wireless_dev *wdev,
3262 const void *data,
3263 int data_len)
3264{
3265 CDF_STATUS status;
3266 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3267 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1];
3268 struct sir_wifi_start_log start_log;
3269
Peng Xuf5d60c82015-10-02 17:17:03 -07003270 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003271 hdd_err("Command not allowed in FTM mode");
3272 return -EPERM;
3273 }
3274
3275 status = wlan_hdd_validate_context(hdd_ctx);
3276 if (0 != status) {
3277 hddLog(LOGE, FL("HDD context is not valid"));
3278 return -EINVAL;
3279 }
3280
3281 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX,
3282 data, data_len,
3283 qca_wlan_vendor_wifi_logger_start_policy)) {
3284 hddLog(LOGE, FL("Invalid attribute"));
3285 return -EINVAL;
3286 }
3287
3288 /* Parse and fetch ring id */
3289 if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]) {
3290 hddLog(LOGE, FL("attr ATTR failed"));
3291 return -EINVAL;
3292 }
3293 start_log.ring_id = nla_get_u32(
3294 tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]);
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08003295 hdd_info("Ring ID=%d", start_log.ring_id);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003296
3297 /* Parse and fetch verbose level */
3298 if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]) {
3299 hddLog(LOGE, FL("attr verbose_level failed"));
3300 return -EINVAL;
3301 }
3302 start_log.verbose_level = nla_get_u32(
3303 tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]);
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08003304 hdd_info("verbose_level=%d", start_log.verbose_level);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003305
3306 /* Parse and fetch flag */
3307 if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]) {
3308 hddLog(LOGE, FL("attr flag failed"));
3309 return -EINVAL;
3310 }
3311 start_log.flag = nla_get_u32(
3312 tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]);
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08003313 hdd_info("flag=%d", start_log.flag);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003314
3315 cds_set_ring_log_level(start_log.ring_id, start_log.verbose_level);
3316
3317 if (start_log.ring_id == RING_ID_WAKELOCK) {
3318 /* Start/stop wakelock events */
3319 if (start_log.verbose_level > WLAN_LOG_LEVEL_OFF)
3320 cds_set_wakelock_logging(true);
3321 else
3322 cds_set_wakelock_logging(false);
3323 return 0;
3324 }
3325
3326 status = sme_wifi_start_logger(hdd_ctx->hHal, start_log);
3327 if (!CDF_IS_STATUS_SUCCESS(status)) {
3328 hddLog(LOGE, FL("sme_wifi_start_logger failed(err=%d)"),
3329 status);
3330 return -EINVAL;
3331 }
3332 return 0;
3333}
3334
3335/**
3336 * wlan_hdd_cfg80211_wifi_logger_start() - Wrapper function used to enable
3337 * or disable the collection of packet statistics from the firmware
3338 * @wiphy: WIPHY structure pointer
3339 * @wdev: Wireless device structure pointer
3340 * @data: Pointer to the data received
3341 * @data_len: Length of the data received
3342 *
3343 * This function is used to enable or disable the collection of packet
3344 * statistics from the firmware
3345 *
3346 * Return: 0 on success and errno on failure
3347 */
3348static int wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy,
3349 struct wireless_dev *wdev,
3350 const void *data,
3351 int data_len)
3352{
3353 int ret = 0;
3354
3355 cds_ssr_protect(__func__);
3356 ret = __wlan_hdd_cfg80211_wifi_logger_start(wiphy,
3357 wdev, data, data_len);
3358 cds_ssr_unprotect(__func__);
3359
3360 return ret;
3361}
3362
3363static const struct
3364nla_policy
3365qca_wlan_vendor_wifi_logger_get_ring_data_policy
3366[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1] = {
3367 [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]
3368 = {.type = NLA_U32 },
3369};
3370
3371/**
3372 * __wlan_hdd_cfg80211_wifi_logger_get_ring_data() - Flush per packet stats
3373 * @wiphy: WIPHY structure pointer
3374 * @wdev: Wireless device structure pointer
3375 * @data: Pointer to the data received
3376 * @data_len: Length of the data received
3377 *
3378 * This function is used to flush or retrieve the per packet statistics from
3379 * the driver
3380 *
3381 * Return: 0 on success and errno on failure
3382 */
3383static int __wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy,
3384 struct wireless_dev *wdev,
3385 const void *data,
3386 int data_len)
3387{
3388 CDF_STATUS status;
3389 uint32_t ring_id;
3390 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3391 struct nlattr *tb
3392 [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1];
3393
Peng Xuf5d60c82015-10-02 17:17:03 -07003394 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003395 hdd_err("Command not allowed in FTM mode");
3396 return -EPERM;
3397 }
3398
3399 status = wlan_hdd_validate_context(hdd_ctx);
3400 if (0 != status) {
3401 hddLog(LOGE, FL("HDD context is not valid"));
3402 return -EINVAL;
3403 }
3404
3405 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX,
3406 data, data_len,
3407 qca_wlan_vendor_wifi_logger_get_ring_data_policy)) {
3408 hddLog(LOGE, FL("Invalid attribute"));
3409 return -EINVAL;
3410 }
3411
3412 /* Parse and fetch ring id */
3413 if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]) {
3414 hddLog(LOGE, FL("attr ATTR failed"));
3415 return -EINVAL;
3416 }
3417
3418 ring_id = nla_get_u32(
3419 tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]);
3420
3421 if (ring_id == RING_ID_PER_PACKET_STATS) {
3422 wlan_logging_set_per_pkt_stats();
3423 hddLog(LOG1, FL("Flushing/Retrieving packet stats"));
3424 }
3425
3426 hddLog(LOG1, FL("Bug report triggered by framework"));
3427
3428 status = cds_flush_logs(WLAN_LOG_TYPE_NON_FATAL,
3429 WLAN_LOG_INDICATOR_FRAMEWORK,
3430 WLAN_LOG_REASON_CODE_UNUSED);
3431 if (CDF_STATUS_SUCCESS != status) {
3432 hddLog(LOGE, FL("Failed to trigger bug report"));
3433 return -EINVAL;
3434 }
3435
3436 return 0;
3437}
3438
3439/**
3440 * wlan_hdd_cfg80211_wifi_logger_get_ring_data() - Wrapper to flush packet stats
3441 * @wiphy: WIPHY structure pointer
3442 * @wdev: Wireless device structure pointer
3443 * @data: Pointer to the data received
3444 * @data_len: Length of the data received
3445 *
3446 * This function is used to flush or retrieve the per packet statistics from
3447 * the driver
3448 *
3449 * Return: 0 on success and errno on failure
3450 */
3451static int wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy,
3452 struct wireless_dev *wdev,
3453 const void *data,
3454 int data_len)
3455{
3456 int ret = 0;
3457
3458 cds_ssr_protect(__func__);
3459 ret = __wlan_hdd_cfg80211_wifi_logger_get_ring_data(wiphy,
3460 wdev, data, data_len);
3461 cds_ssr_unprotect(__func__);
3462
3463 return ret;
3464}
3465
3466#ifdef WLAN_FEATURE_OFFLOAD_PACKETS
3467/**
3468 * hdd_map_req_id_to_pattern_id() - map request id to pattern id
3469 * @hdd_ctx: HDD context
3470 * @request_id: [input] request id
3471 * @pattern_id: [output] pattern id
3472 *
3473 * This function loops through request id to pattern id array
3474 * if the slot is available, store the request id and return pattern id
3475 * if entry exists, return the pattern id
3476 *
3477 * Return: 0 on success and errno on failure
3478 */
3479static int hdd_map_req_id_to_pattern_id(hdd_context_t *hdd_ctx,
3480 uint32_t request_id,
3481 uint8_t *pattern_id)
3482{
3483 uint32_t i;
3484
3485 mutex_lock(&hdd_ctx->op_ctx.op_lock);
3486 for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) {
3487 if (hdd_ctx->op_ctx.op_table[i].request_id == MAX_REQUEST_ID) {
3488 hdd_ctx->op_ctx.op_table[i].request_id = request_id;
3489 *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id;
3490 mutex_unlock(&hdd_ctx->op_ctx.op_lock);
3491 return 0;
3492 } else if (hdd_ctx->op_ctx.op_table[i].request_id ==
3493 request_id) {
3494 *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id;
3495 mutex_unlock(&hdd_ctx->op_ctx.op_lock);
3496 return 0;
3497 }
3498 }
3499 mutex_unlock(&hdd_ctx->op_ctx.op_lock);
3500 return -EINVAL;
3501}
3502
3503/**
3504 * hdd_unmap_req_id_to_pattern_id() - unmap request id to pattern id
3505 * @hdd_ctx: HDD context
3506 * @request_id: [input] request id
3507 * @pattern_id: [output] pattern id
3508 *
3509 * This function loops through request id to pattern id array
3510 * reset request id to 0 (slot available again) and
3511 * return pattern id
3512 *
3513 * Return: 0 on success and errno on failure
3514 */
3515static int hdd_unmap_req_id_to_pattern_id(hdd_context_t *hdd_ctx,
3516 uint32_t request_id,
3517 uint8_t *pattern_id)
3518{
3519 uint32_t i;
3520
3521 mutex_lock(&hdd_ctx->op_ctx.op_lock);
3522 for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) {
3523 if (hdd_ctx->op_ctx.op_table[i].request_id == request_id) {
3524 hdd_ctx->op_ctx.op_table[i].request_id = MAX_REQUEST_ID;
3525 *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id;
3526 mutex_unlock(&hdd_ctx->op_ctx.op_lock);
3527 return 0;
3528 }
3529 }
3530 mutex_unlock(&hdd_ctx->op_ctx.op_lock);
3531 return -EINVAL;
3532}
3533
3534
3535/*
3536 * define short names for the global vendor params
3537 * used by __wlan_hdd_cfg80211_offloaded_packets()
3538 */
3539#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX
3540#define PARAM_REQUEST_ID \
3541 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID
3542#define PARAM_CONTROL \
3543 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL
3544#define PARAM_IP_PACKET \
3545 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA
3546#define PARAM_SRC_MAC_ADDR \
3547 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR
3548#define PARAM_DST_MAC_ADDR \
3549 QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR
3550#define PARAM_PERIOD QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD
3551
3552/**
3553 * wlan_hdd_add_tx_ptrn() - add tx pattern
3554 * @adapter: adapter pointer
3555 * @hdd_ctx: hdd context
3556 * @tb: nl attributes
3557 *
3558 * This function reads the NL attributes and forms a AddTxPtrn message
3559 * posts it to SME.
3560 *
3561 */
3562static int
3563wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx,
3564 struct nlattr **tb)
3565{
3566 struct sSirAddPeriodicTxPtrn *add_req;
3567 CDF_STATUS status;
3568 uint32_t request_id, ret, len;
3569 uint8_t pattern_id = 0;
3570 struct cdf_mac_addr dst_addr;
3571 uint16_t eth_type = htons(ETH_P_IP);
3572
3573 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
3574 hddLog(LOGE, FL("Not in Connected state!"));
3575 return -ENOTSUPP;
3576 }
3577
3578 add_req = cdf_mem_malloc(sizeof(*add_req));
3579 if (!add_req) {
3580 hddLog(LOGE, FL("memory allocation failed"));
3581 return -ENOMEM;
3582 }
3583
3584 /* Parse and fetch request Id */
3585 if (!tb[PARAM_REQUEST_ID]) {
3586 hddLog(LOGE, FL("attr request id failed"));
3587 goto fail;
3588 }
3589
3590 request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
3591 if (request_id == MAX_REQUEST_ID) {
3592 hddLog(LOGE, FL("request_id cannot be MAX"));
3593 return -EINVAL;
3594 }
3595 hddLog(LOG1, FL("Request Id: %u"), request_id);
3596
3597 if (!tb[PARAM_PERIOD]) {
3598 hddLog(LOGE, FL("attr period failed"));
3599 goto fail;
3600 }
3601 add_req->usPtrnIntervalMs = nla_get_u32(tb[PARAM_PERIOD]);
3602 hddLog(LOG1, FL("Period: %u ms"), add_req->usPtrnIntervalMs);
3603 if (add_req->usPtrnIntervalMs == 0) {
3604 hddLog(LOGE, FL("Invalid interval zero, return failure"));
3605 goto fail;
3606 }
3607
3608 if (!tb[PARAM_SRC_MAC_ADDR]) {
3609 hddLog(LOGE, FL("attr source mac address failed"));
3610 goto fail;
3611 }
Srinivas Girigowda31896552015-11-18 22:59:52 -08003612 nla_memcpy(add_req->mac_address.bytes, tb[PARAM_SRC_MAC_ADDR],
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003613 CDF_MAC_ADDR_SIZE);
3614 hddLog(LOG1, "input src mac address: "MAC_ADDRESS_STR,
Srinivas Girigowda31896552015-11-18 22:59:52 -08003615 MAC_ADDR_ARRAY(add_req->mac_address.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003616
Srinivas Girigowda31896552015-11-18 22:59:52 -08003617 if (!cdf_is_macaddr_equal(&add_req->mac_address,
3618 &adapter->macAddressCurrent)) {
3619 hdd_err("input src mac address and connected ap bssid are different");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003620 goto fail;
3621 }
3622
3623 if (!tb[PARAM_DST_MAC_ADDR]) {
3624 hddLog(LOGE, FL("attr dst mac address failed"));
3625 goto fail;
3626 }
3627 nla_memcpy(dst_addr.bytes, tb[PARAM_DST_MAC_ADDR], CDF_MAC_ADDR_SIZE);
3628 hddLog(LOG1, "input dst mac address: "MAC_ADDRESS_STR,
3629 MAC_ADDR_ARRAY(dst_addr.bytes));
3630
3631 if (!tb[PARAM_IP_PACKET]) {
3632 hddLog(LOGE, FL("attr ip packet failed"));
3633 goto fail;
3634 }
3635 add_req->ucPtrnSize = nla_len(tb[PARAM_IP_PACKET]);
3636 hddLog(LOG1, FL("IP packet len: %u"), add_req->ucPtrnSize);
3637
3638 if (add_req->ucPtrnSize < 0 ||
3639 add_req->ucPtrnSize > (PERIODIC_TX_PTRN_MAX_SIZE -
3640 ETH_HLEN)) {
3641 hddLog(LOGE, FL("Invalid IP packet len: %d"),
3642 add_req->ucPtrnSize);
3643 goto fail;
3644 }
3645
3646 len = 0;
3647 cdf_mem_copy(&add_req->ucPattern[0], dst_addr.bytes, CDF_MAC_ADDR_SIZE);
3648 len += CDF_MAC_ADDR_SIZE;
Srinivas Girigowda31896552015-11-18 22:59:52 -08003649 cdf_mem_copy(&add_req->ucPattern[len], add_req->mac_address.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003650 CDF_MAC_ADDR_SIZE);
3651 len += CDF_MAC_ADDR_SIZE;
3652 cdf_mem_copy(&add_req->ucPattern[len], &eth_type, 2);
3653 len += 2;
3654
3655 /*
3656 * This is the IP packet, add 14 bytes Ethernet (802.3) header
3657 * ------------------------------------------------------------
3658 * | 14 bytes Ethernet (802.3) header | IP header and payload |
3659 * ------------------------------------------------------------
3660 */
3661 cdf_mem_copy(&add_req->ucPattern[len],
3662 nla_data(tb[PARAM_IP_PACKET]),
3663 add_req->ucPtrnSize);
3664 add_req->ucPtrnSize += len;
3665
3666 ret = hdd_map_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id);
3667 if (ret) {
3668 hddLog(LOGW, FL("req id to pattern id failed (ret=%d)"), ret);
3669 goto fail;
3670 }
3671 add_req->ucPtrnId = pattern_id;
3672 hddLog(LOG1, FL("pattern id: %d"), add_req->ucPtrnId);
3673
3674 status = sme_add_periodic_tx_ptrn(hdd_ctx->hHal, add_req);
3675 if (!CDF_IS_STATUS_SUCCESS(status)) {
3676 hddLog(LOGE,
3677 FL("sme_add_periodic_tx_ptrn failed (err=%d)"), status);
3678 goto fail;
3679 }
3680
3681 EXIT();
3682 cdf_mem_free(add_req);
3683 return 0;
3684
3685fail:
3686 cdf_mem_free(add_req);
3687 return -EINVAL;
3688}
3689
3690/**
3691 * wlan_hdd_del_tx_ptrn() - delete tx pattern
3692 * @adapter: adapter pointer
3693 * @hdd_ctx: hdd context
3694 * @tb: nl attributes
3695 *
3696 * This function reads the NL attributes and forms a DelTxPtrn message
3697 * posts it to SME.
3698 *
3699 */
3700static int
3701wlan_hdd_del_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx,
3702 struct nlattr **tb)
3703{
3704 struct sSirDelPeriodicTxPtrn *del_req;
3705 CDF_STATUS status;
3706 uint32_t request_id, ret;
3707 uint8_t pattern_id = 0;
3708
3709 /* Parse and fetch request Id */
3710 if (!tb[PARAM_REQUEST_ID]) {
3711 hddLog(LOGE, FL("attr request id failed"));
3712 return -EINVAL;
3713 }
3714 request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
3715 if (request_id == MAX_REQUEST_ID) {
3716 hddLog(LOGE, FL("request_id cannot be MAX"));
3717 return -EINVAL;
3718 }
3719
3720 ret = hdd_unmap_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id);
3721 if (ret) {
3722 hddLog(LOGW, FL("req id to pattern id failed (ret=%d)"), ret);
3723 return -EINVAL;
3724 }
3725
3726 del_req = cdf_mem_malloc(sizeof(*del_req));
3727 if (!del_req) {
3728 hddLog(LOGE, FL("memory allocation failed"));
3729 return -ENOMEM;
3730 }
3731
Srinivas Girigowdaa5bba7a2015-11-18 22:44:36 -08003732 cdf_copy_macaddr(&del_req->mac_address, &adapter->macAddressCurrent);
3733 hdd_info(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(del_req->mac_address.bytes));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003734 del_req->ucPtrnId = pattern_id;
3735 hddLog(LOG1, FL("Request Id: %u Pattern id: %d"),
3736 request_id, del_req->ucPtrnId);
3737
3738 status = sme_del_periodic_tx_ptrn(hdd_ctx->hHal, del_req);
3739 if (!CDF_IS_STATUS_SUCCESS(status)) {
3740 hddLog(LOGE,
3741 FL("sme_del_periodic_tx_ptrn failed (err=%d)"), status);
3742 goto fail;
3743 }
3744
3745 EXIT();
3746 cdf_mem_free(del_req);
3747 return 0;
3748
3749fail:
3750 cdf_mem_free(del_req);
3751 return -EINVAL;
3752}
3753
3754
3755/**
3756 * __wlan_hdd_cfg80211_offloaded_packets() - send offloaded packets
3757 * @wiphy: Pointer to wireless phy
3758 * @wdev: Pointer to wireless device
3759 * @data: Pointer to data
3760 * @data_len: Data length
3761 *
3762 * Return: 0 on success, negative errno on failure
3763 */
3764static int
3765__wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy,
3766 struct wireless_dev *wdev,
3767 const void *data,
3768 int data_len)
3769{
3770 struct net_device *dev = wdev->netdev;
3771 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3772 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3773 struct nlattr *tb[PARAM_MAX + 1];
3774 uint8_t control;
3775 int ret;
3776 static const struct nla_policy policy[PARAM_MAX + 1] = {
3777 [PARAM_REQUEST_ID] = { .type = NLA_U32 },
3778 [PARAM_CONTROL] = { .type = NLA_U32 },
3779 [PARAM_SRC_MAC_ADDR] = { .type = NLA_BINARY,
3780 .len = CDF_MAC_ADDR_SIZE },
3781 [PARAM_DST_MAC_ADDR] = { .type = NLA_BINARY,
3782 .len = CDF_MAC_ADDR_SIZE },
3783 [PARAM_PERIOD] = { .type = NLA_U32 },
3784 };
3785
3786 ENTER();
3787
Peng Xuf5d60c82015-10-02 17:17:03 -07003788 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003789 hdd_err("Command not allowed in FTM mode");
3790 return -EPERM;
3791 }
3792
3793 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303794 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003795 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003796
3797 if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) {
3798 hddLog(LOGE,
3799 FL("Periodic Tx Pattern Offload feature is not supported in FW!"));
3800 return -ENOTSUPP;
3801 }
3802
3803 if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) {
3804 hddLog(LOGE, FL("Invalid ATTR"));
3805 return -EINVAL;
3806 }
3807
3808 if (!tb[PARAM_CONTROL]) {
3809 hddLog(LOGE, FL("attr control failed"));
3810 return -EINVAL;
3811 }
3812 control = nla_get_u32(tb[PARAM_CONTROL]);
3813 hddLog(LOG1, FL("Control: %d"), control);
3814
3815 if (control == WLAN_START_OFFLOADED_PACKETS)
3816 return wlan_hdd_add_tx_ptrn(adapter, hdd_ctx, tb);
3817 else if (control == WLAN_STOP_OFFLOADED_PACKETS)
3818 return wlan_hdd_del_tx_ptrn(adapter, hdd_ctx, tb);
3819 else {
3820 hddLog(LOGE, FL("Invalid control: %d"), control);
3821 return -EINVAL;
3822 }
3823}
3824
3825/*
3826 * done with short names for the global vendor params
3827 * used by __wlan_hdd_cfg80211_offloaded_packets()
3828 */
3829#undef PARAM_MAX
3830#undef PARAM_REQUEST_ID
3831#undef PARAM_CONTROL
3832#undef PARAM_IP_PACKET
3833#undef PARAM_SRC_MAC_ADDR
3834#undef PARAM_DST_MAC_ADDR
3835#undef PARAM_PERIOD
3836
3837/**
3838 * wlan_hdd_cfg80211_offloaded_packets() - Wrapper to offload packets
3839 * @wiphy: wiphy structure pointer
3840 * @wdev: Wireless device structure pointer
3841 * @data: Pointer to the data received
3842 * @data_len: Length of @data
3843 *
3844 * Return: 0 on success; errno on failure
3845 */
3846static int wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy,
3847 struct wireless_dev *wdev,
3848 const void *data,
3849 int data_len)
3850{
3851 int ret = 0;
3852
3853 cds_ssr_protect(__func__);
3854 ret = __wlan_hdd_cfg80211_offloaded_packets(wiphy,
3855 wdev, data, data_len);
3856 cds_ssr_unprotect(__func__);
3857
3858 return ret;
3859}
3860#endif
3861
3862/*
3863 * define short names for the global vendor params
3864 * used by __wlan_hdd_cfg80211_monitor_rssi()
3865 */
3866#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX
3867#define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID
3868#define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL
3869#define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI
3870#define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI
3871
3872/**
3873 * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi
3874 * @wiphy: Pointer to wireless phy
3875 * @wdev: Pointer to wireless device
3876 * @data: Pointer to data
3877 * @data_len: Data length
3878 *
3879 * Return: 0 on success, negative errno on failure
3880 */
3881static int
3882__wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy,
3883 struct wireless_dev *wdev,
3884 const void *data,
3885 int data_len)
3886{
3887 struct net_device *dev = wdev->netdev;
3888 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
3889 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
3890 struct nlattr *tb[PARAM_MAX + 1];
3891 struct rssi_monitor_req req;
3892 CDF_STATUS status;
3893 int ret;
3894 uint32_t control;
3895 static const struct nla_policy policy[PARAM_MAX + 1] = {
3896 [PARAM_REQUEST_ID] = { .type = NLA_U32 },
3897 [PARAM_CONTROL] = { .type = NLA_U32 },
3898 [PARAM_MIN_RSSI] = { .type = NLA_S8 },
3899 [PARAM_MAX_RSSI] = { .type = NLA_S8 },
3900 };
3901
3902 ENTER();
3903
3904 ret = wlan_hdd_validate_context(hdd_ctx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05303905 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003906 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003907
3908 if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) {
3909 hddLog(LOGE, FL("Not in Connected state!"));
3910 return -ENOTSUPP;
3911 }
3912
3913 if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) {
3914 hddLog(LOGE, FL("Invalid ATTR"));
3915 return -EINVAL;
3916 }
3917
3918 if (!tb[PARAM_REQUEST_ID]) {
3919 hddLog(LOGE, FL("attr request id failed"));
3920 return -EINVAL;
3921 }
3922
3923 if (!tb[PARAM_CONTROL]) {
3924 hddLog(LOGE, FL("attr control failed"));
3925 return -EINVAL;
3926 }
3927
3928 req.request_id = nla_get_u32(tb[PARAM_REQUEST_ID]);
3929 req.session_id = adapter->sessionId;
3930 control = nla_get_u32(tb[PARAM_CONTROL]);
3931
3932 if (control == QCA_WLAN_RSSI_MONITORING_START) {
3933 req.control = true;
3934 if (!tb[PARAM_MIN_RSSI]) {
3935 hddLog(LOGE, FL("attr min rssi failed"));
3936 return -EINVAL;
3937 }
3938
3939 if (!tb[PARAM_MAX_RSSI]) {
3940 hddLog(LOGE, FL("attr max rssi failed"));
3941 return -EINVAL;
3942 }
3943
3944 req.min_rssi = nla_get_s8(tb[PARAM_MIN_RSSI]);
3945 req.max_rssi = nla_get_s8(tb[PARAM_MAX_RSSI]);
3946
3947 if (!(req.min_rssi < req.max_rssi)) {
3948 hddLog(LOGW, FL("min_rssi: %d must be less than max_rssi: %d"),
3949 req.min_rssi, req.max_rssi);
3950 return -EINVAL;
3951 }
3952 hddLog(LOG1, FL("Min_rssi: %d Max_rssi: %d"),
3953 req.min_rssi, req.max_rssi);
3954
3955 } else if (control == QCA_WLAN_RSSI_MONITORING_STOP)
3956 req.control = false;
3957 else {
3958 hddLog(LOGE, FL("Invalid control cmd: %d"), control);
3959 return -EINVAL;
3960 }
3961 hddLog(LOG1, FL("Request Id: %u Session_id: %d Control: %d"),
3962 req.request_id, req.session_id, req.control);
3963
3964 status = sme_set_rssi_monitoring(hdd_ctx->hHal, &req);
3965 if (!CDF_IS_STATUS_SUCCESS(status)) {
3966 hddLog(LOGE,
3967 FL("sme_set_rssi_monitoring failed(err=%d)"), status);
3968 return -EINVAL;
3969 }
3970
3971 return 0;
3972}
3973
3974/*
3975 * done with short names for the global vendor params
3976 * used by __wlan_hdd_cfg80211_monitor_rssi()
3977 */
3978#undef PARAM_MAX
3979#undef PARAM_CONTROL
3980#undef PARAM_REQUEST_ID
3981#undef PARAM_MAX_RSSI
3982#undef PARAM_MIN_RSSI
3983
3984/**
3985 * wlan_hdd_cfg80211_monitor_rssi() - SSR wrapper to rssi monitoring
3986 * @wiphy: wiphy structure pointer
3987 * @wdev: Wireless device structure pointer
3988 * @data: Pointer to the data received
3989 * @data_len: Length of @data
3990 *
3991 * Return: 0 on success; errno on failure
3992 */
3993static int
3994wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev,
3995 const void *data, int data_len)
3996{
3997 int ret;
3998
3999 cds_ssr_protect(__func__);
4000 ret = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len);
4001 cds_ssr_unprotect(__func__);
4002
4003 return ret;
4004}
4005
4006/**
4007 * hdd_rssi_threshold_breached() - rssi breached NL event
4008 * @hddctx: HDD context
4009 * @data: rssi breached event data
4010 *
4011 * This function reads the rssi breached event %data and fill in the skb with
4012 * NL attributes and send up the NL event.
4013 *
4014 * Return: none
4015 */
4016void hdd_rssi_threshold_breached(void *hddctx,
4017 struct rssi_breach_event *data)
4018{
4019 hdd_context_t *hdd_ctx = hddctx;
4020 struct sk_buff *skb;
4021
4022 ENTER();
4023
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05304024 if (wlan_hdd_validate_context(hdd_ctx))
4025 return;
4026 if (!data) {
4027 hddLog(LOGE, FL("data is null"));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004028 return;
4029 }
4030
4031 skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
4032 NULL,
4033 EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN,
4034 QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX,
4035 GFP_KERNEL);
4036
4037 if (!skb) {
4038 hddLog(LOGE, FL("cfg80211_vendor_event_alloc failed"));
4039 return;
4040 }
4041
4042 hddLog(LOG1, "Req Id: %u Current rssi: %d",
4043 data->request_id, data->curr_rssi);
4044 hddLog(LOG1, "Current BSSID: "MAC_ADDRESS_STR,
4045 MAC_ADDR_ARRAY(data->curr_bssid.bytes));
4046
4047 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
4048 data->request_id) ||
4049 nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
4050 sizeof(data->curr_bssid), data->curr_bssid.bytes) ||
4051 nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI,
4052 data->curr_rssi)) {
4053 hddLog(LOGE, FL("nla put fail"));
4054 goto fail;
4055 }
4056
4057 cfg80211_vendor_event(skb, GFP_KERNEL);
4058 return;
4059
4060fail:
4061 kfree_skb(skb);
4062 return;
4063}
4064
4065/** __wlan_hdd_cfg80211_get_preferred_freq_list() - get preferred frequency list
4066 * @wiphy: Pointer to wireless phy
4067 * @wdev: Pointer to wireless device
4068 * @data: Pointer to data
4069 * @data_len: Data length
4070 *
4071 * This function return the preferred frequency list generated by the policy
4072 * manager.
4073 *
4074 * Return: success or failure code
4075 */
4076static int __wlan_hdd_cfg80211_get_preferred_freq_list(struct wiphy *wiphy,
4077 struct wireless_dev
4078 *wdev, const void *data,
4079 int data_len)
4080{
4081 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4082 int i, ret = 0;
4083 CDF_STATUS status;
4084 uint8_t pcl[MAX_NUM_CHAN];
4085 uint32_t pcl_len = 0;
4086 uint32_t freq_list[MAX_NUM_CHAN];
4087 enum cds_con_mode intf_mode;
4088 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1];
4089 struct sk_buff *reply_skb;
4090
4091 ret = wlan_hdd_validate_context(hdd_ctx);
4092 if (ret)
4093 return -EINVAL;
4094
4095 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX,
4096 data, data_len, NULL)) {
4097 hdd_err("Invalid ATTR");
4098 return -EINVAL;
4099 }
4100
4101 if (!tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]) {
4102 hdd_err("attr interface type failed");
4103 return -EINVAL;
4104 }
4105
4106 intf_mode = nla_get_u32(tb
4107 [QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]);
4108
4109 if (intf_mode < CDS_STA_MODE || intf_mode >= CDS_MAX_NUM_OF_MODE) {
4110 hdd_err("Invalid interface type");
4111 return -EINVAL;
4112 }
4113
4114 hdd_debug("Userspace requested pref freq list");
4115
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004116 status = cds_get_pcl(intf_mode, pcl, &pcl_len);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004117 if (status != CDF_STATUS_SUCCESS) {
4118 hdd_err("Get pcl failed");
4119 return -EINVAL;
4120 }
4121
4122 /* convert channel number to frequency */
4123 for (i = 0; i < pcl_len; i++) {
4124 if (pcl[i] <= ARRAY_SIZE(hdd_channels_2_4_ghz))
4125 freq_list[i] =
4126 ieee80211_channel_to_frequency(pcl[i],
4127 IEEE80211_BAND_2GHZ);
4128 else
4129 freq_list[i] =
4130 ieee80211_channel_to_frequency(pcl[i],
4131 IEEE80211_BAND_5GHZ);
4132 }
4133
4134 /* send the freq_list back to supplicant */
4135 reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) +
4136 sizeof(u32) *
4137 pcl_len +
4138 NLMSG_HDRLEN);
4139
4140 if (!reply_skb) {
4141 hdd_err("Allocate reply_skb failed");
4142 return -EINVAL;
4143 }
4144
4145 if (nla_put_u32(reply_skb,
4146 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
4147 intf_mode) ||
4148 nla_put(reply_skb,
4149 QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST,
4150 sizeof(uint32_t) * pcl_len,
4151 freq_list)) {
4152 hdd_err("nla put fail");
4153 kfree_skb(reply_skb);
4154 return -EINVAL;
4155 }
4156
4157 return cfg80211_vendor_cmd_reply(reply_skb);
4158}
4159
4160/** wlan_hdd_cfg80211_get_preferred_freq_list () - get preferred frequency list
4161 * @wiphy: Pointer to wireless phy
4162 * @wdev: Pointer to wireless device
4163 * @data: Pointer to data
4164 * @data_len: Data length
4165 *
4166 * This function return the preferred frequency list generated by the policy
4167 * manager.
4168 *
4169 * Return: success or failure code
4170 */
4171static int wlan_hdd_cfg80211_get_preferred_freq_list(struct wiphy *wiphy,
4172 struct wireless_dev
4173 *wdev, const void *data,
4174 int data_len)
4175{
4176 int ret = 0;
4177
4178 cds_ssr_protect(__func__);
4179 ret = __wlan_hdd_cfg80211_get_preferred_freq_list(wiphy, wdev,
4180 data, data_len);
4181 cds_ssr_unprotect(__func__);
4182
4183 return ret;
4184}
4185
4186/**
4187 * __wlan_hdd_cfg80211_set_probable_oper_channel () - set probable channel
4188 * @wiphy: Pointer to wireless phy
4189 * @wdev: Pointer to wireless device
4190 * @data: Pointer to data
4191 * @data_len: Data length
4192 *
4193 * Return: 0 on success, negative errno on failure
4194 */
4195static int __wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy,
4196 struct wireless_dev *wdev,
4197 const void *data,
4198 int data_len)
4199{
Chandrasekaran, Manishekaref70c0d2015-10-20 19:54:55 +05304200 struct net_device *ndev = wdev->netdev;
4201 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004202 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4203 int ret = 0;
4204 enum cds_con_mode intf_mode;
4205 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1];
4206 uint32_t channel_hint;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004207
4208 ret = wlan_hdd_validate_context(hdd_ctx);
4209 if (ret)
4210 return ret;
4211
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004212 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX,
4213 data, data_len, NULL)) {
4214 hdd_err("Invalid ATTR");
4215 return -EINVAL;
4216 }
4217
4218 if (!tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE]) {
4219 hdd_err("attr interface type failed");
4220 return -EINVAL;
4221 }
4222
4223 intf_mode = nla_get_u32(tb
4224 [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE]);
4225
4226 if (intf_mode < CDS_STA_MODE || intf_mode >= CDS_MAX_NUM_OF_MODE) {
4227 hdd_err("Invalid interface type");
4228 return -EINVAL;
4229 }
4230
4231 if (!tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ]) {
4232 hdd_err("attr probable freq failed");
4233 return -EINVAL;
4234 }
4235
4236 channel_hint = cds_freq_to_chan(nla_get_u32(tb
4237 [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ]));
4238
4239 /* check pcl table */
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08004240 if (!cds_allow_concurrency(intf_mode,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004241 channel_hint, HW_MODE_20_MHZ)) {
4242 hdd_err("Set channel hint failed due to concurrency check");
4243 return -EINVAL;
4244 }
4245
4246 if (hdd_ctx->config->policy_manager_enabled) {
Chandrasekaran, Manishekareceb8112015-11-16 15:38:53 +05304247 ret = cdf_reset_connection_update();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004248 if (!CDF_IS_STATUS_SUCCESS(ret))
4249 hdd_err("clearing event failed");
4250
Chandrasekaran, Manishekaref70c0d2015-10-20 19:54:55 +05304251 ret = cds_current_connections_update(adapter->sessionId,
4252 channel_hint,
4253 CDS_UPDATE_REASON_SET_OPER_CHAN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004254 if (CDF_STATUS_E_FAILURE == ret) {
4255 /* return in the failure case */
4256 hdd_err("ERROR: connections update failed!!");
4257 return -EINVAL;
4258 }
4259
4260 if (CDF_STATUS_SUCCESS == ret) {
4261 /*
4262 * Success is the only case for which we expect hw mode
4263 * change to take place, hence we need to wait.
4264 * For any other return value it should be a pass
4265 * through
4266 */
Chandrasekaran, Manishekareceb8112015-11-16 15:38:53 +05304267 ret = cdf_wait_for_connection_update();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004268 if (!CDF_IS_STATUS_SUCCESS(ret)) {
4269 hdd_err("ERROR: cdf wait for event failed!!");
4270 return -EINVAL;
4271 }
4272
4273 }
4274 }
4275
4276 return 0;
4277}
4278
4279/**
4280 * wlan_hdd_cfg80211_set_probable_oper_channel () - set probable channel
4281 * @wiphy: Pointer to wireless phy
4282 * @wdev: Pointer to wireless device
4283 * @data: Pointer to data
4284 * @data_len: Data length
4285 *
4286 * Return: 0 on success, negative errno on failure
4287 */
4288static int wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy,
4289 struct wireless_dev *wdev,
4290 const void *data,
4291 int data_len)
4292{
4293 int ret = 0;
4294
4295 cds_ssr_protect(__func__);
4296 ret = __wlan_hdd_cfg80211_set_probable_oper_channel(wiphy, wdev,
4297 data, data_len);
4298 cds_ssr_unprotect(__func__);
4299
4300 return ret;
4301}
4302
Kanchanapally, Vidyullathae3062812015-05-22 17:28:57 +05304303static const struct
4304nla_policy
4305qca_wlan_vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_MAX+1] = {
4306 [QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = { .type = NLA_UNSPEC },
4307};
4308
4309/**
4310 * __wlan_hdd_cfg80211_get_link_properties() - Get link properties
4311 * @wiphy: WIPHY structure pointer
4312 * @wdev: Wireless device structure pointer
4313 * @data: Pointer to the data received
4314 * @data_len: Length of the data received
4315 *
4316 * This function is used to get link properties like nss, rate flags and
4317 * operating frequency for the active connection with the given peer.
4318 *
4319 * Return: 0 on success and errno on failure
4320 */
4321static int __wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy,
4322 struct wireless_dev *wdev,
4323 const void *data,
4324 int data_len)
4325{
4326 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4327 struct net_device *dev = wdev->netdev;
4328 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4329 hdd_station_ctx_t *hdd_sta_ctx;
4330 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX+1];
4331 uint8_t peer_mac[CDF_MAC_ADDR_SIZE];
4332 uint32_t sta_id;
4333 struct sk_buff *reply_skb;
4334 uint32_t rate_flags = 0;
4335 uint8_t nss;
4336 uint8_t final_rate_flags = 0;
4337 uint32_t freq;
4338
4339 ENTER();
4340
Peng Xuf5d60c82015-10-02 17:17:03 -07004341 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Kanchanapally, Vidyullathae3062812015-05-22 17:28:57 +05304342 hdd_err("Command not allowed in FTM mode");
4343 return -EPERM;
4344 }
4345
4346 if (0 != wlan_hdd_validate_context(hdd_ctx))
4347 return -EINVAL;
4348
4349 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len,
4350 qca_wlan_vendor_attr_policy)) {
4351 hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid attribute"));
4352 return -EINVAL;
4353 }
4354
4355 if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) {
4356 hddLog(CDF_TRACE_LEVEL_ERROR,
4357 FL("Attribute peerMac not provided for mode=%d"),
4358 adapter->device_mode);
4359 return -EINVAL;
4360 }
4361
4362 cdf_mem_copy(peer_mac, nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]),
4363 CDF_MAC_ADDR_SIZE);
4364 hddLog(CDF_TRACE_LEVEL_INFO,
4365 FL("peerMac="MAC_ADDRESS_STR" for device_mode:%d"),
4366 MAC_ADDR_ARRAY(peer_mac), adapter->device_mode);
4367
4368 if (adapter->device_mode == WLAN_HDD_INFRA_STATION ||
4369 adapter->device_mode == WLAN_HDD_P2P_CLIENT) {
4370 hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
4371 if ((hdd_sta_ctx->conn_info.connState !=
4372 eConnectionState_Associated) ||
4373 !cdf_mem_compare(hdd_sta_ctx->conn_info.bssId.bytes,
4374 peer_mac, CDF_MAC_ADDR_SIZE)) {
4375 hddLog(CDF_TRACE_LEVEL_ERROR,
4376 FL("Not Associated to mac "MAC_ADDRESS_STR),
4377 MAC_ADDR_ARRAY(peer_mac));
4378 return -EINVAL;
4379 }
4380
4381 nss = hdd_sta_ctx->conn_info.nss;
4382 freq = cds_chan_to_freq(
4383 hdd_sta_ctx->conn_info.operationChannel);
4384 rate_flags = hdd_sta_ctx->conn_info.rate_flags;
4385 } else if (adapter->device_mode == WLAN_HDD_P2P_GO ||
4386 adapter->device_mode == WLAN_HDD_SOFTAP) {
4387
4388 for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) {
4389 if (adapter->aStaInfo[sta_id].isUsed &&
4390 !cdf_is_macaddr_broadcast(
4391 &adapter->aStaInfo[sta_id].macAddrSTA) &&
4392 cdf_mem_compare(
4393 &adapter->aStaInfo[sta_id].macAddrSTA.bytes,
4394 peer_mac, CDF_MAC_ADDR_SIZE))
4395 break;
4396 }
4397
4398 if (WLAN_MAX_STA_COUNT == sta_id) {
4399 hddLog(CDF_TRACE_LEVEL_ERROR,
4400 FL("No active peer with mac="MAC_ADDRESS_STR),
4401 MAC_ADDR_ARRAY(peer_mac));
4402 return -EINVAL;
4403 }
4404
4405 nss = adapter->aStaInfo[sta_id].nss;
4406 freq = cds_chan_to_freq(
4407 (WLAN_HDD_GET_AP_CTX_PTR(adapter))->operatingChannel);
4408 rate_flags = adapter->aStaInfo[sta_id].rate_flags;
4409 } else {
4410 hddLog(CDF_TRACE_LEVEL_ERROR,
4411 FL("Not Associated! with mac "MAC_ADDRESS_STR),
4412 MAC_ADDR_ARRAY(peer_mac));
4413 return -EINVAL;
4414 }
4415
4416 if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
4417 if (rate_flags & eHAL_TX_RATE_VHT80) {
4418 final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
4419 final_rate_flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
4420 } else if (rate_flags & eHAL_TX_RATE_VHT40) {
4421 final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
4422 final_rate_flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
4423 } else if (rate_flags & eHAL_TX_RATE_VHT20) {
4424 final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
4425 } else if (rate_flags &
4426 (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
4427 final_rate_flags |= RATE_INFO_FLAGS_MCS;
4428 if (rate_flags & eHAL_TX_RATE_HT40)
4429 final_rate_flags |=
4430 RATE_INFO_FLAGS_40_MHZ_WIDTH;
4431 }
4432
4433 if (rate_flags & eHAL_TX_RATE_SGI) {
4434 if (!(final_rate_flags & RATE_INFO_FLAGS_VHT_MCS))
4435 final_rate_flags |= RATE_INFO_FLAGS_MCS;
4436 final_rate_flags |= RATE_INFO_FLAGS_SHORT_GI;
4437 }
4438 }
4439
4440 reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
4441 sizeof(u8) + sizeof(u8) + sizeof(u32) + NLMSG_HDRLEN);
4442
4443 if (NULL == reply_skb) {
4444 hddLog(CDF_TRACE_LEVEL_ERROR,
4445 FL("getLinkProperties: skb alloc failed"));
4446 return -EINVAL;
4447 }
4448
4449 if (nla_put_u8(reply_skb,
4450 QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS,
4451 nss) ||
4452 nla_put_u8(reply_skb,
4453 QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS,
4454 final_rate_flags) ||
4455 nla_put_u32(reply_skb,
4456 QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ,
4457 freq)) {
4458 hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla_put failed"));
4459 kfree_skb(reply_skb);
4460 return -EINVAL;
4461 }
4462
4463 return cfg80211_vendor_cmd_reply(reply_skb);
4464}
4465
4466/**
4467 * wlan_hdd_cfg80211_get_link_properties() - Wrapper function to get link
4468 * properties.
4469 * @wiphy: WIPHY structure pointer
4470 * @wdev: Wireless device structure pointer
4471 * @data: Pointer to the data received
4472 * @data_len: Length of the data received
4473 *
4474 * This function is used to get link properties like nss, rate flags and
4475 * operating frequency for the active connection with the given peer.
4476 *
4477 * Return: 0 on success and errno on failure
4478 */
4479static int wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy,
4480 struct wireless_dev *wdev,
4481 const void *data,
4482 int data_len)
4483{
4484 int ret = 0;
4485
4486 cds_ssr_protect(__func__);
4487 ret = __wlan_hdd_cfg80211_get_link_properties(wiphy,
4488 wdev, data, data_len);
4489 cds_ssr_unprotect(__func__);
4490
4491 return ret;
4492}
4493
Peng Xu278d0122015-09-24 16:34:17 -07004494static const struct
4495nla_policy
4496qca_wlan_vendor_ota_test_policy
4497[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1] = {
4498 [QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE] = {.type = NLA_U8 },
4499};
4500
4501/**
4502 * __wlan_hdd_cfg80211_set_ota_test () - enable/disable OTA test
4503 * @wiphy: Pointer to wireless phy
4504 * @wdev: Pointer to wireless device
4505 * @data: Pointer to data
4506 * @data_len: Data length
4507 *
4508 * Return: 0 on success, negative errno on failure
4509 */
4510static int __wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy,
4511 struct wireless_dev *wdev,
4512 const void *data,
4513 int data_len)
4514{
4515 struct net_device *dev = wdev->netdev;
4516 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4517 tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter);
4518 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4519 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1];
4520 uint8_t ota_enable = 0;
4521 CDF_STATUS status;
4522 uint32_t current_roam_state;
4523
Peng Xuf5d60c82015-10-02 17:17:03 -07004524 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Peng Xu278d0122015-09-24 16:34:17 -07004525 hdd_err("Command not allowed in FTM mode");
4526 return -EPERM;
4527 }
4528
4529 if (0 != wlan_hdd_validate_context(hdd_ctx))
4530 return -EINVAL;
4531
4532 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX,
4533 data, data_len,
4534 qca_wlan_vendor_ota_test_policy)) {
4535 hdd_err("invalid attr");
4536 return -EINVAL;
4537 }
4538
4539 if (!tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]) {
4540 hdd_err("attr ota test failed");
4541 return -EINVAL;
4542 }
4543
4544 ota_enable = nla_get_u8(
4545 tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]);
4546
4547 hdd_info(" OTA test enable = %d", ota_enable);
4548 if (ota_enable != 1) {
4549 hdd_err("Invalid value, only enable test mode is supported!");
4550 return -EINVAL;
4551 }
4552
4553 current_roam_state =
4554 sme_get_current_roam_state(hal, adapter->sessionId);
4555 status = sme_stop_roaming(hal, adapter->sessionId,
4556 eCsrHddIssued);
4557 if (status != CDF_STATUS_SUCCESS) {
4558 hdd_err("Enable/Disable roaming failed");
4559 return -EINVAL;
4560 }
4561
4562 status = sme_ps_enable_disable(hal, adapter->sessionId,
4563 SME_PS_DISABLE);
4564 if (status != CDF_STATUS_SUCCESS) {
4565 hdd_err("Enable/Disable power save failed");
4566 /* restore previous roaming setting */
4567 if (current_roam_state == eCSR_ROAMING_STATE_JOINING ||
4568 current_roam_state == eCSR_ROAMING_STATE_JOINED)
4569 status = sme_start_roaming(hal, adapter->sessionId,
4570 eCsrHddIssued);
4571 else if (current_roam_state == eCSR_ROAMING_STATE_STOP ||
4572 current_roam_state == eCSR_ROAMING_STATE_IDLE)
4573 status = sme_stop_roaming(hal, adapter->sessionId,
4574 eCsrHddIssued);
4575
4576 if (status != CDF_STATUS_SUCCESS)
4577 hdd_err("Restoring roaming state failed");
4578
4579 return -EINVAL;
4580 }
4581
4582
4583 return 0;
4584}
4585
4586/**
4587 * wlan_hdd_cfg80211_set_ota_test () - Enable or disable OTA test
4588 * @wiphy: Pointer to wireless phy
4589 * @wdev: Pointer to wireless device
4590 * @data: Pointer to data
4591 * @data_len: Data length
4592 *
4593 * Return: 0 on success, negative errno on failure
4594 */
4595static int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy,
4596 struct wireless_dev *wdev,
4597 const void *data,
4598 int data_len)
4599{
4600 int ret = 0;
4601
4602 cds_ssr_protect(__func__);
4603 ret = __wlan_hdd_cfg80211_set_ota_test(wiphy, wdev, data, data_len);
4604 cds_ssr_unprotect(__func__);
4605
4606 return ret;
4607}
4608
Peng Xu4d67c8f2015-10-16 16:02:26 -07004609/**
4610 * __wlan_hdd_cfg80211_txpower_scale () - txpower scaling
4611 * @wiphy: Pointer to wireless phy
4612 * @wdev: Pointer to wireless device
4613 * @data: Pointer to data
4614 * @data_len: Data length
4615 *
4616 * Return: 0 on success, negative errno on failure
4617 */
4618static int __wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy,
4619 struct wireless_dev *wdev,
4620 const void *data,
4621 int data_len)
4622{
4623 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4624 struct net_device *dev = wdev->netdev;
4625 hdd_adapter_t *adapter = NULL;
4626 int ret = 0;
4627 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1];
4628 uint8_t scale_value;
4629
4630 ret = wlan_hdd_validate_context(hdd_ctx);
4631 if (ret)
4632 return ret;
4633
4634 adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4635
4636 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX,
4637 data, data_len, NULL)) {
4638 hdd_err("Invalid ATTR");
4639 return -EINVAL;
4640 }
4641
4642 if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]) {
4643 hdd_err("attr tx power scale failed");
4644 return -EINVAL;
4645 }
4646
4647 scale_value = nla_get_u8(tb
4648 [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]);
4649
4650 if (scale_value > MAX_TXPOWER_SCALE) {
4651 hdd_err("Invalid tx power scale level");
4652 return -EINVAL;
4653 }
4654
4655 ret = wma_set_tx_power_scale(adapter->sessionId, scale_value);
4656
4657 if (ret != 0) {
4658 hdd_err("Set tx power scale failed");
4659 return -EINVAL;
4660 }
4661
4662 return 0;
4663}
4664
4665/**
4666 * wlan_hdd_cfg80211_txpower_scale () - txpower scaling
4667 * @wiphy: Pointer to wireless phy
4668 * @wdev: Pointer to wireless device
4669 * @data: Pointer to data
4670 * @data_len: Data length
4671 *
4672 * Return: 0 on success, negative errno on failure
4673 */
4674static int wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy,
4675 struct wireless_dev *wdev,
4676 const void *data,
4677 int data_len)
4678{
4679 int ret = 0;
4680
4681 cds_ssr_protect(__func__);
4682 ret = __wlan_hdd_cfg80211_txpower_scale(wiphy, wdev,
4683 data, data_len);
4684 cds_ssr_unprotect(__func__);
4685
4686 return ret;
4687}
4688
4689/**
4690 * __wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling
4691 * @wiphy: Pointer to wireless phy
4692 * @wdev: Pointer to wireless device
4693 * @data: Pointer to data
4694 * @data_len: Data length
4695 *
4696 * Return: 0 on success, negative errno on failure
4697 */
4698static int __wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy,
4699 struct wireless_dev *wdev,
4700 const void *data,
4701 int data_len)
4702{
4703 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
4704 struct net_device *dev = wdev->netdev;
4705 hdd_adapter_t *adapter = NULL;
4706 int ret = 0;
4707 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1];
4708 uint8_t scale_value;
4709
4710 ret = wlan_hdd_validate_context(hdd_ctx);
4711 if (ret)
4712 return ret;
4713
4714 adapter = WLAN_HDD_GET_PRIV_PTR(dev);
4715
4716 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX,
4717 data, data_len, NULL)) {
4718 hdd_err("Invalid ATTR");
4719 return -EINVAL;
4720 }
4721
4722 if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]) {
4723 hdd_err("attr tx power decrease db value failed");
4724 return -EINVAL;
4725 }
4726
4727 scale_value = nla_get_u8(tb
4728 [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]);
4729
4730 ret = wma_set_tx_power_scale_decr_db(adapter->sessionId, scale_value);
4731
4732 if (ret != 0) {
4733 hdd_err("Set tx power decrease db failed");
4734 return -EINVAL;
4735 }
4736
4737 return 0;
4738}
4739
4740/**
4741 * wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling
4742 * @wiphy: Pointer to wireless phy
4743 * @wdev: Pointer to wireless device
4744 * @data: Pointer to data
4745 * @data_len: Data length
4746 *
4747 * Return: 0 on success, negative errno on failure
4748 */
4749static int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy,
4750 struct wireless_dev *wdev,
4751 const void *data,
4752 int data_len)
4753{
4754 int ret = 0;
4755
4756 cds_ssr_protect(__func__);
4757 ret = __wlan_hdd_cfg80211_txpower_scale_decr_db(wiphy, wdev,
4758 data, data_len);
4759 cds_ssr_unprotect(__func__);
4760
4761 return ret;
4762}
4763
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08004764const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
4765 {
4766 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4767 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY,
4768 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4769 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4770 .doit = is_driver_dfs_capable
4771 },
4772
4773#ifdef WLAN_FEATURE_NAN
4774 {
4775 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4776 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN,
4777 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4778 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4779 .doit = wlan_hdd_cfg80211_nan_request
4780 },
4781#endif
4782
4783#ifdef WLAN_FEATURE_STATS_EXT
4784 {
4785 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4786 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_STATS_EXT,
4787 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4788 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4789 .doit = wlan_hdd_cfg80211_stats_ext_request
4790 },
4791#endif
4792#ifdef FEATURE_WLAN_EXTSCAN
4793 {
4794 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4795 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START,
4796 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4797 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4798 .doit = wlan_hdd_cfg80211_extscan_start
4799 },
4800 {
4801 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4802 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP,
4803 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4804 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4805 .doit = wlan_hdd_cfg80211_extscan_stop
4806 },
4807 {
4808 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4809 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS,
4810 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
4811 .doit = wlan_hdd_cfg80211_extscan_get_valid_channels
4812 },
4813 {
4814 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4815 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES,
4816 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4817 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4818 .doit = wlan_hdd_cfg80211_extscan_get_capabilities
4819 },
4820 {
4821 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4822 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS,
4823 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4824 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4825 .doit = wlan_hdd_cfg80211_extscan_get_cached_results
4826 },
4827 {
4828 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4829 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST,
4830 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4831 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4832 .doit = wlan_hdd_cfg80211_extscan_set_bssid_hotlist
4833 },
4834 {
4835 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4836 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST,
4837 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4838 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4839 .doit = wlan_hdd_cfg80211_extscan_reset_bssid_hotlist
4840 },
4841 {
4842 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4843 .info.subcmd =
4844 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE,
4845 .flags =
4846 WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV |
4847 WIPHY_VENDOR_CMD_NEED_RUNNING,
4848 .doit = wlan_hdd_cfg80211_extscan_set_significant_change
4849 },
4850 {
4851 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4852 .info.subcmd =
4853 QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE,
4854 .flags =
4855 WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV |
4856 WIPHY_VENDOR_CMD_NEED_RUNNING,
4857 .doit = wlan_hdd_cfg80211_extscan_reset_significant_change
4858 },
4859 {
4860 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4861 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_LIST,
4862 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4863 WIPHY_VENDOR_CMD_NEED_NETDEV |
4864 WIPHY_VENDOR_CMD_NEED_RUNNING,
4865 .doit = wlan_hdd_cfg80211_set_epno_list
4866 },
4867#endif /* FEATURE_WLAN_EXTSCAN */
4868
4869#ifdef WLAN_FEATURE_LINK_LAYER_STATS
4870 {
4871 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4872 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR,
4873 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4874 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4875 .doit = wlan_hdd_cfg80211_ll_stats_clear
4876 },
4877
4878 {
4879 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4880 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET,
4881 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4882 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4883 .doit = wlan_hdd_cfg80211_ll_stats_set
4884 },
4885
4886 {
4887 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4888 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET,
4889 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4890 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4891 .doit = wlan_hdd_cfg80211_ll_stats_get
4892 },
4893#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
4894#ifdef FEATURE_WLAN_TDLS
4895 {
4896 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4897 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE,
4898 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4899 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4900 .doit = wlan_hdd_cfg80211_exttdls_enable
4901 },
4902 {
4903 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4904 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE,
4905 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4906 WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
4907 .doit = wlan_hdd_cfg80211_exttdls_disable
4908 },
4909 {
4910 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4911 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS,
4912 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
4913 .doit = wlan_hdd_cfg80211_exttdls_get_status
4914 },
4915#endif
4916 {
4917 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4918 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES,
4919 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
4920 .doit = wlan_hdd_cfg80211_get_supported_features
4921 },
4922 {
4923 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4924 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI,
4925 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
4926 .doit = wlan_hdd_cfg80211_set_scanning_mac_oui
4927 },
4928 {
4929 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4930 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX,
4931 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
4932 .doit = cds_cfg80211_get_concurrency_matrix
4933 },
4934 {
4935 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4936 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG,
4937 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4938 WIPHY_VENDOR_CMD_NEED_NETDEV,
4939 .doit = wlan_hdd_cfg80211_disable_dfs_chan_scan
4940 },
4941
4942 {
4943 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4944 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS,
4945 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4946 WIPHY_VENDOR_CMD_NEED_NETDEV |
4947 WIPHY_VENDOR_CMD_NEED_RUNNING,
4948 .doit = wlan_hdd_cfg80211_do_acs
4949 },
4950
4951 {
4952 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4953 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES,
4954 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4955 WIPHY_VENDOR_CMD_NEED_NETDEV,
4956 .doit = wlan_hdd_cfg80211_get_features
4957 },
4958#ifdef WLAN_FEATURE_ROAM_OFFLOAD
4959 {
4960 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4961 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY,
4962 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4963 WIPHY_VENDOR_CMD_NEED_NETDEV |
4964 WIPHY_VENDOR_CMD_NEED_RUNNING,
4965 .doit = wlan_hdd_cfg80211_keymgmt_set_key
4966 },
4967#endif
4968#ifdef FEATURE_WLAN_EXTSCAN
4969 {
4970 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4971 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_PASSPOINT_LIST,
4972 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4973 WIPHY_VENDOR_CMD_NEED_NETDEV |
4974 WIPHY_VENDOR_CMD_NEED_RUNNING,
4975 .doit = wlan_hdd_cfg80211_set_passpoint_list
4976 },
4977 {
4978 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4979 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_RESET_PASSPOINT_LIST,
4980 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4981 WIPHY_VENDOR_CMD_NEED_NETDEV |
4982 WIPHY_VENDOR_CMD_NEED_RUNNING,
4983 .doit = wlan_hdd_cfg80211_reset_passpoint_list
4984 },
4985 {
4986 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4987 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SSID_HOTLIST,
4988 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4989 WIPHY_VENDOR_CMD_NEED_NETDEV |
4990 WIPHY_VENDOR_CMD_NEED_RUNNING,
4991 .doit = wlan_hdd_cfg80211_extscan_set_ssid_hotlist
4992 },
4993 {
4994 .info.vendor_id = QCA_NL80211_VENDOR_ID,
4995 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SSID_HOTLIST,
4996 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
4997 WIPHY_VENDOR_CMD_NEED_NETDEV |
4998 WIPHY_VENDOR_CMD_NEED_RUNNING,
4999 .doit = wlan_hdd_cfg80211_extscan_reset_ssid_hotlist
5000 },
5001#endif /* FEATURE_WLAN_EXTSCAN */
5002 {
5003 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5004 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO,
5005 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5006 WIPHY_VENDOR_CMD_NEED_NETDEV,
5007 .doit = wlan_hdd_cfg80211_get_wifi_info
5008 },
5009 {
5010 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5011 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION,
5012 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5013 WIPHY_VENDOR_CMD_NEED_NETDEV |
5014 WIPHY_VENDOR_CMD_NEED_RUNNING,
5015 .doit = wlan_hdd_cfg80211_wifi_configuration_set
5016 },
5017 {
5018 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5019 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM,
5020 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5021 WIPHY_VENDOR_CMD_NEED_NETDEV,
5022 .doit = wlan_hdd_cfg80211_set_ext_roam_params
5023 },
5024 {
5025 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5026 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START,
5027 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5028 WIPHY_VENDOR_CMD_NEED_NETDEV,
5029 .doit = wlan_hdd_cfg80211_wifi_logger_start
5030 },
5031 {
5032 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5033 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA,
5034 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5035 WIPHY_VENDOR_CMD_NEED_NETDEV,
5036 .doit = wlan_hdd_cfg80211_wifi_logger_get_ring_data
5037 },
5038 {
5039 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5040 .info.subcmd =
5041 QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST,
5042 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5043 WIPHY_VENDOR_CMD_NEED_NETDEV |
5044 WIPHY_VENDOR_CMD_NEED_RUNNING,
5045 .doit = wlan_hdd_cfg80211_get_preferred_freq_list
5046 },
5047 {
5048 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5049 .info.subcmd =
5050 QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL,
5051 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5052 WIPHY_VENDOR_CMD_NEED_NETDEV |
5053 WIPHY_VENDOR_CMD_NEED_RUNNING,
5054 .doit = wlan_hdd_cfg80211_set_probable_oper_channel
5055 },
5056#ifdef FEATURE_WLAN_TDLS
5057 {
5058 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5059 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES,
5060 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5061 WIPHY_VENDOR_CMD_NEED_NETDEV |
5062 WIPHY_VENDOR_CMD_NEED_RUNNING,
5063 .doit = wlan_hdd_cfg80211_get_tdls_capabilities
5064 },
5065#endif
5066#ifdef WLAN_FEATURE_OFFLOAD_PACKETS
5067 {
5068 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5069 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS,
5070 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5071 WIPHY_VENDOR_CMD_NEED_NETDEV |
5072 WIPHY_VENDOR_CMD_NEED_RUNNING,
5073 .doit = wlan_hdd_cfg80211_offloaded_packets
5074 },
5075#endif
5076 {
5077 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5078 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
5079 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5080 WIPHY_VENDOR_CMD_NEED_NETDEV |
5081 WIPHY_VENDOR_CMD_NEED_RUNNING,
5082 .doit = wlan_hdd_cfg80211_monitor_rssi
5083 },
5084 {
5085 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5086 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET,
5087 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5088 WIPHY_VENDOR_CMD_NEED_NETDEV |
5089 WIPHY_VENDOR_CMD_NEED_RUNNING,
5090 .doit = wlan_hdd_cfg80211_get_logger_supp_feature
5091 },
5092#ifdef WLAN_FEATURE_MEMDUMP
5093 {
5094 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5095 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP,
5096 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5097 WIPHY_VENDOR_CMD_NEED_NETDEV |
5098 WIPHY_VENDOR_CMD_NEED_RUNNING,
5099 .doit = wlan_hdd_cfg80211_get_fw_mem_dump
5100 },
5101#endif /* WLAN_FEATURE_MEMDUMP */
5102 {
5103 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5104 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN,
5105 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5106 WIPHY_VENDOR_CMD_NEED_NETDEV |
5107 WIPHY_VENDOR_CMD_NEED_RUNNING,
5108 .doit = wlan_hdd_cfg80211_vendor_scan
5109 },
5110
5111 /* OCB commands */
5112 {
5113 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5114 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG,
5115 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5116 WIPHY_VENDOR_CMD_NEED_NETDEV |
5117 WIPHY_VENDOR_CMD_NEED_RUNNING,
5118 .doit = wlan_hdd_cfg80211_ocb_set_config
5119 },
5120 {
5121 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5122 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME,
5123 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5124 WIPHY_VENDOR_CMD_NEED_NETDEV |
5125 WIPHY_VENDOR_CMD_NEED_RUNNING,
5126 .doit = wlan_hdd_cfg80211_ocb_set_utc_time
5127 },
5128 {
5129 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5130 .info.subcmd =
5131 QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT,
5132 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5133 WIPHY_VENDOR_CMD_NEED_NETDEV |
5134 WIPHY_VENDOR_CMD_NEED_RUNNING,
5135 .doit = wlan_hdd_cfg80211_ocb_start_timing_advert
5136 },
5137 {
5138 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5139 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT,
5140 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5141 WIPHY_VENDOR_CMD_NEED_NETDEV |
5142 WIPHY_VENDOR_CMD_NEED_RUNNING,
5143 .doit = wlan_hdd_cfg80211_ocb_stop_timing_advert
5144 },
5145 {
5146 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5147 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER,
5148 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5149 WIPHY_VENDOR_CMD_NEED_NETDEV |
5150 WIPHY_VENDOR_CMD_NEED_RUNNING,
5151 .doit = wlan_hdd_cfg80211_ocb_get_tsf_timer
5152 },
5153 {
5154 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5155 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS,
5156 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5157 WIPHY_VENDOR_CMD_NEED_NETDEV |
5158 WIPHY_VENDOR_CMD_NEED_RUNNING,
5159 .doit = wlan_hdd_cfg80211_dcc_get_stats
5160 },
5161 {
5162 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5163 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS,
5164 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5165 WIPHY_VENDOR_CMD_NEED_NETDEV |
5166 WIPHY_VENDOR_CMD_NEED_RUNNING,
5167 .doit = wlan_hdd_cfg80211_dcc_clear_stats
5168 },
5169 {
5170 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5171 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL,
5172 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5173 WIPHY_VENDOR_CMD_NEED_NETDEV |
5174 WIPHY_VENDOR_CMD_NEED_RUNNING,
5175 .doit = wlan_hdd_cfg80211_dcc_update_ndl
5176 },
Kanchanapally, Vidyullathae3062812015-05-22 17:28:57 +05305177 {
5178 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5179 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES,
5180 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5181 WIPHY_VENDOR_CMD_NEED_NETDEV |
5182 WIPHY_VENDOR_CMD_NEED_RUNNING,
5183 .doit = wlan_hdd_cfg80211_get_link_properties
5184 },
Peng Xu278d0122015-09-24 16:34:17 -07005185 {
5186 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OTA_TEST,
5187 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5188 WIPHY_VENDOR_CMD_NEED_NETDEV |
5189 WIPHY_VENDOR_CMD_NEED_RUNNING,
5190 .doit = wlan_hdd_cfg80211_set_ota_test
5191 },
Ravi Joshideb5a8d2015-11-09 19:11:43 -08005192#ifdef FEATURE_LFR_SUBNET_DETECTION
5193 {
5194 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5195 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG,
5196 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5197 WIPHY_VENDOR_CMD_NEED_NETDEV |
5198 WIPHY_VENDOR_CMD_NEED_RUNNING,
5199 .doit = wlan_hdd_cfg80211_set_gateway_params
5200 },
5201#endif /* FEATURE_LFR_SUBNET_DETECTION */
Peng Xu4d67c8f2015-10-16 16:02:26 -07005202 {
5203 .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE,
5204 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5205 WIPHY_VENDOR_CMD_NEED_NETDEV |
5206 WIPHY_VENDOR_CMD_NEED_RUNNING,
5207 .doit = wlan_hdd_cfg80211_txpower_scale
5208 },
5209 {
5210 .info.vendor_id = QCA_NL80211_VENDOR_ID,
5211 .info.subcmd =
5212 QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB,
5213 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
5214 WIPHY_VENDOR_CMD_NEED_NETDEV |
5215 WIPHY_VENDOR_CMD_NEED_RUNNING,
5216 .doit = wlan_hdd_cfg80211_txpower_scale_decr_db
5217 },
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005218};
5219
5220/*
5221 * FUNCTION: wlan_hdd_cfg80211_wiphy_alloc
5222 * This function is called by hdd_wlan_startup()
5223 * during initialization.
5224 * This function is used to allocate wiphy structure.
5225 */
5226struct wiphy *wlan_hdd_cfg80211_wiphy_alloc(int priv_size)
5227{
5228 struct wiphy *wiphy;
5229 ENTER();
5230
5231 /*
5232 * Create wiphy device
5233 */
5234 wiphy = wiphy_new(&wlan_hdd_cfg80211_ops, priv_size);
5235
5236 if (!wiphy) {
5237 /* Print error and jump into err label and free the memory */
5238 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: wiphy init failed",
5239 __func__);
5240 return NULL;
5241 }
5242
5243 return wiphy;
5244}
5245
5246/*
5247 * FUNCTION: wlan_hdd_cfg80211_update_band
5248 * This function is called from the supplicant through a
5249 * private ioctl to change the band value
5250 */
5251int wlan_hdd_cfg80211_update_band(struct wiphy *wiphy, eCsrBand eBand)
5252{
5253 int i, j;
5254 CHANNEL_STATE channelEnabledState;
5255
5256 ENTER();
5257
5258 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
5259
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08005260 if (NULL == wiphy->bands[i])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005261 continue;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005262
5263 for (j = 0; j < wiphy->bands[i]->n_channels; j++) {
5264 struct ieee80211_supported_band *band = wiphy->bands[i];
5265
5266 channelEnabledState =
5267 cds_get_channel_state(band->channels[j].
5268 hw_value);
5269
5270 if (IEEE80211_BAND_2GHZ == i && eCSR_BAND_5G == eBand) {
5271 /* 5G only */
5272#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY
5273 /* Enable Social channels for P2P */
5274 if (WLAN_HDD_IS_SOCIAL_CHANNEL
5275 (band->channels[j].center_freq)
5276 && CHANNEL_STATE_ENABLE ==
5277 channelEnabledState)
5278 band->channels[j].flags &=
5279 ~IEEE80211_CHAN_DISABLED;
5280 else
5281#endif
5282 band->channels[j].flags |=
5283 IEEE80211_CHAN_DISABLED;
5284 continue;
5285 } else if (IEEE80211_BAND_5GHZ == i &&
5286 eCSR_BAND_24 == eBand) {
5287 /* 2G only */
5288 band->channels[j].flags |=
5289 IEEE80211_CHAN_DISABLED;
5290 continue;
5291 }
5292
5293 if (CHANNEL_STATE_DISABLE == channelEnabledState ||
5294 CHANNEL_STATE_INVALID == channelEnabledState) {
5295 band->channels[j].flags |=
5296 IEEE80211_CHAN_DISABLED;
5297 } else if (CHANNEL_STATE_DFS == channelEnabledState) {
5298 band->channels[j].flags &=
5299 ~IEEE80211_CHAN_DISABLED;
5300 band->channels[j].flags |= IEEE80211_CHAN_RADAR;
5301 } else {
5302 band->channels[j].flags &=
5303 ~(IEEE80211_CHAN_DISABLED |
5304 IEEE80211_CHAN_RADAR);
5305 }
5306 }
5307 }
5308 return 0;
5309}
5310
5311/*
5312 * FUNCTION: wlan_hdd_cfg80211_init
5313 * This function is called by hdd_wlan_startup()
5314 * during initialization.
5315 * This function is used to initialize and register wiphy structure.
5316 */
5317int wlan_hdd_cfg80211_init(struct device *dev,
5318 struct wiphy *wiphy, struct hdd_config *pCfg)
5319{
5320 int i, j;
5321 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
5322
5323 ENTER();
5324
5325 /* Now bind the underlying wlan device with wiphy */
5326 set_wiphy_dev(wiphy, dev);
5327
5328 wiphy->mgmt_stypes = wlan_hdd_txrx_stypes;
5329
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005330#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
5331 wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
Amar Singhal01098f72015-10-08 11:55:32 -07005332 wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005333#else
5334 wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS;
Amar Singhal01098f72015-10-08 11:55:32 -07005335 wiphy->country_ie_pref |= NL80211_COUNTRY_IE_IGNORE_CORE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005336#endif
5337
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005338 wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME
5339 | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD
5340 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL
5341#ifdef FEATURE_WLAN_STA_4ADDR_SCHEME
5342 | WIPHY_FLAG_4ADDR_STATION
5343#endif
5344 | WIPHY_FLAG_OFFCHAN_TX;
5345
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005346#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
5347 wiphy->wowlan = &wowlan_support_cfg80211_init;
5348#else
5349 wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT;
5350 wiphy->wowlan.n_patterns = WOWL_MAX_PTRNS_ALLOWED;
5351 wiphy->wowlan.pattern_min_len = 1;
5352 wiphy->wowlan.pattern_max_len = WOWL_PTRN_MAX_SIZE;
5353#endif
5354
5355#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
5356 if (pCfg->isFastTransitionEnabled
5357#ifdef FEATURE_WLAN_LFR
5358 || pCfg->isFastRoamIniFeatureEnabled
5359#endif
5360#ifdef FEATURE_WLAN_ESE
5361 || pCfg->isEseIniFeatureEnabled
5362#endif
5363 ) {
5364 wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
5365 }
5366#endif
5367#ifdef FEATURE_WLAN_TDLS
5368 wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS
5369 | WIPHY_FLAG_TDLS_EXTERNAL_SETUP;
5370#endif
5371
5372 wiphy->features |= NL80211_FEATURE_HT_IBSS;
5373
5374#ifdef FEATURE_WLAN_SCAN_PNO
5375 if (pCfg->configPNOScanSupport) {
5376 wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
5377 wiphy->max_sched_scan_ssids = SIR_PNO_MAX_SUPP_NETWORKS;
5378 wiphy->max_match_sets = SIR_PNO_MAX_SUPP_NETWORKS;
5379 wiphy->max_sched_scan_ie_len = SIR_MAC_MAX_IE_LENGTH;
5380 }
5381#endif /*FEATURE_WLAN_SCAN_PNO */
5382
5383#if defined QCA_WIFI_FTM
Peng Xuf5d60c82015-10-02 17:17:03 -07005384 if (cds_get_conparam() != CDF_GLOBAL_FTM_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005385#endif
5386
5387 /* even with WIPHY_FLAG_CUSTOM_REGULATORY,
5388 driver can still register regulatory callback and
5389 it will get regulatory settings in wiphy->band[], but
5390 driver need to determine what to do with both
5391 regulatory settings */
5392
5393 wiphy->reg_notifier = hdd_reg_notifier;
5394
5395#if defined QCA_WIFI_FTM
5396}
5397#endif
5398
5399 wiphy->max_scan_ssids = MAX_SCAN_SSID;
5400
5401 wiphy->max_scan_ie_len = SIR_MAC_MAX_ADD_IE_LENGTH;
5402
5403 wiphy->max_acl_mac_addrs = MAX_ACL_MAC_ADDRESS;
5404
5405 /* Supports STATION & AD-HOC modes right now */
5406 wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
5407 | BIT(NL80211_IFTYPE_ADHOC)
5408 | BIT(NL80211_IFTYPE_P2P_CLIENT)
5409 | BIT(NL80211_IFTYPE_P2P_GO)
5410 | BIT(NL80211_IFTYPE_AP);
5411
5412 if (pCfg->advertiseConcurrentOperation) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005413 if (pCfg->enableMCC) {
5414 int i;
5415 for (i = 0; i < ARRAY_SIZE(wlan_hdd_iface_combination);
5416 i++) {
5417 if (!pCfg->allowMCCGODiffBI)
5418 wlan_hdd_iface_combination[i].
5419 beacon_int_infra_match = true;
5420 }
5421 }
5422 wiphy->n_iface_combinations =
5423 ARRAY_SIZE(wlan_hdd_iface_combination);
5424 wiphy->iface_combinations = wlan_hdd_iface_combination;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005425 }
5426
5427 /* Before registering we need to update the ht capabilitied based
5428 * on ini values*/
5429 if (!pCfg->ShortGI20MhzEnable) {
5430 wlan_hdd_band_2_4_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20;
5431 wlan_hdd_band_5_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20;
5432 wlan_hdd_band_p2p_2_4_ghz.ht_cap.cap &=
5433 ~IEEE80211_HT_CAP_SGI_20;
5434 }
5435
5436 if (!pCfg->ShortGI40MhzEnable) {
5437 wlan_hdd_band_5_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
5438 }
5439
5440 if (!pCfg->nChannelBondingMode5GHz) {
5441 wlan_hdd_band_5_ghz.ht_cap.cap &=
5442 ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
5443 }
5444
5445 wiphy->bands[IEEE80211_BAND_2GHZ] = &wlan_hdd_band_2_4_ghz;
5446 if (true == hdd_is_5g_supported(pHddCtx)) {
5447 wiphy->bands[IEEE80211_BAND_5GHZ] = &wlan_hdd_band_5_ghz;
5448 }
5449
5450 for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
5451
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08005452 if (NULL == wiphy->bands[i])
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005453 continue;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005454
5455 for (j = 0; j < wiphy->bands[i]->n_channels; j++) {
5456 struct ieee80211_supported_band *band = wiphy->bands[i];
5457
5458 if (IEEE80211_BAND_2GHZ == i &&
5459 eCSR_BAND_5G == pCfg->nBandCapability) {
5460 /* 5G only */
5461#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY
5462 /* Enable social channels for P2P */
5463 if (WLAN_HDD_IS_SOCIAL_CHANNEL
5464 (band->channels[j].center_freq))
5465 band->channels[j].flags &=
5466 ~IEEE80211_CHAN_DISABLED;
5467 else
5468#endif
5469 band->channels[j].flags |=
5470 IEEE80211_CHAN_DISABLED;
5471 continue;
5472 } else if (IEEE80211_BAND_5GHZ == i &&
5473 eCSR_BAND_24 == pCfg->nBandCapability) {
5474 /* 2G only */
5475 band->channels[j].flags |=
5476 IEEE80211_CHAN_DISABLED;
5477 continue;
5478 }
5479 }
5480 }
5481 /*Initialise the supported cipher suite details */
5482 wiphy->cipher_suites = hdd_cipher_suites;
5483 wiphy->n_cipher_suites = ARRAY_SIZE(hdd_cipher_suites);
5484
5485 /*signal strength in mBm (100*dBm) */
5486 wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
5487 wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION;
5488
Peng Xuf5d60c82015-10-02 17:17:03 -07005489 if (cds_get_conparam() != CDF_GLOBAL_FTM_MODE) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005490 wiphy->n_vendor_commands =
5491 ARRAY_SIZE(hdd_wiphy_vendor_commands);
5492 wiphy->vendor_commands = hdd_wiphy_vendor_commands;
5493
5494 wiphy->vendor_events = wlan_hdd_cfg80211_vendor_events;
5495 wiphy->n_vendor_events =
5496 ARRAY_SIZE(wlan_hdd_cfg80211_vendor_events);
5497 }
5498
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005499 if (pCfg->enableDFSMasterCap) {
5500 wiphy->flags |= WIPHY_FLAG_DFS_OFFLOAD;
5501 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005502
5503 wiphy->max_ap_assoc_sta = pCfg->maxNumberOfPeers;
5504
5505#ifdef QCA_HT_2040_COEX
5506 wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
5507#endif
5508
Abhishek Singh1bdb1572015-10-16 16:24:19 +05305509 hdd_add_channel_switch_support(&wiphy->flags);
5510
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005511 EXIT();
5512 return 0;
5513}
5514
5515/*
5516 * In this function, wiphy structure is updated after CDF
5517 * initialization. In wlan_hdd_cfg80211_init, only the
5518 * default values will be initialized. The final initialization
5519 * of all required members can be done here.
5520 */
5521void wlan_hdd_update_wiphy(struct wiphy *wiphy, struct hdd_config *pCfg)
5522{
5523 wiphy->max_ap_assoc_sta = pCfg->maxNumberOfPeers;
5524}
5525
5526/* In this function we are registering wiphy. */
5527int wlan_hdd_cfg80211_register(struct wiphy *wiphy)
5528{
5529 ENTER();
5530 /* Register our wiphy dev with cfg80211 */
5531 if (0 > wiphy_register(wiphy)) {
5532 /* print error */
5533 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: wiphy register failed",
5534 __func__);
5535 return -EIO;
5536 }
5537
5538 EXIT();
5539 return 0;
5540}
5541
5542/*
5543 HDD function to update wiphy capability based on target offload status.
5544
5545 wlan_hdd_cfg80211_init() does initialization of all wiphy related
5546 capability even before downloading firmware to the target. In discrete
5547 case, host will get know certain offload capability (say sched_scan
5548 caps) only after downloading firmware to the target and target boots up.
5549 This function is used to override setting done in wlan_hdd_cfg80211_init()
5550 based on target capability.
5551 */
5552void wlan_hdd_cfg80211_update_wiphy_caps(struct wiphy *wiphy)
5553{
5554#ifdef FEATURE_WLAN_SCAN_PNO
5555 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
5556 struct hdd_config *pCfg = pHddCtx->config;
5557
5558 /* wlan_hdd_cfg80211_init() sets sched_scan caps already in wiphy before
5559 * control comes here. Here just we need to clear it if firmware doesn't
5560 * have PNO support. */
5561 if (!pCfg->PnoOffload) {
5562 wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
5563 wiphy->max_sched_scan_ssids = 0;
5564 wiphy->max_match_sets = 0;
5565 wiphy->max_sched_scan_ie_len = 0;
5566 }
5567#endif
5568}
5569
5570/* This function registers for all frame which supplicant is interested in */
5571void wlan_hdd_cfg80211_register_frames(hdd_adapter_t *pAdapter)
5572{
5573 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
5574 /* Register for all P2P action, public action etc frames */
5575 uint16_t type = (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_ACTION << 4);
5576
5577 ENTER();
5578
Abhishek Singh7996eb72015-12-30 17:24:02 +05305579 /* Register frame indication call back */
5580 sme_register_mgmt_frame_ind_callback(hHal, hdd_indicate_mgmt_frame);
5581
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005582 /* Right now we are registering these frame when driver is getting
5583 initialized. Once we will move to 2.6.37 kernel, in which we have
5584 frame register ops, we will move this code as a part of that */
5585 /* GAS Initial Request */
5586 sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5587 (uint8_t *) GAS_INITIAL_REQ,
5588 GAS_INITIAL_REQ_SIZE);
5589
5590 /* GAS Initial Response */
5591 sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5592 (uint8_t *) GAS_INITIAL_RSP,
5593 GAS_INITIAL_RSP_SIZE);
5594
5595 /* GAS Comeback Request */
5596 sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5597 (uint8_t *) GAS_COMEBACK_REQ,
5598 GAS_COMEBACK_REQ_SIZE);
5599
5600 /* GAS Comeback Response */
5601 sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5602 (uint8_t *) GAS_COMEBACK_RSP,
5603 GAS_COMEBACK_RSP_SIZE);
5604
5605 /* P2P Public Action */
5606 sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5607 (uint8_t *) P2P_PUBLIC_ACTION_FRAME,
5608 P2P_PUBLIC_ACTION_FRAME_SIZE);
5609
5610 /* P2P Action */
5611 sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5612 (uint8_t *) P2P_ACTION_FRAME,
5613 P2P_ACTION_FRAME_SIZE);
5614
5615 /* WNM BSS Transition Request frame */
5616 sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5617 (uint8_t *) WNM_BSS_ACTION_FRAME,
5618 WNM_BSS_ACTION_FRAME_SIZE);
5619
5620 /* WNM-Notification */
5621 sme_register_mgmt_frame(hHal, pAdapter->sessionId, type,
5622 (uint8_t *) WNM_NOTIFICATION_FRAME,
5623 WNM_NOTIFICATION_FRAME_SIZE);
5624}
5625
5626void wlan_hdd_cfg80211_deregister_frames(hdd_adapter_t *pAdapter)
5627{
5628 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
5629 /* Register for all P2P action, public action etc frames */
5630 uint16_t type = (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_ACTION << 4);
5631
5632 ENTER();
5633
5634 /* Right now we are registering these frame when driver is getting
5635 initialized. Once we will move to 2.6.37 kernel, in which we have
5636 frame register ops, we will move this code as a part of that */
5637 /* GAS Initial Request */
5638
5639 sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5640 (uint8_t *) GAS_INITIAL_REQ,
5641 GAS_INITIAL_REQ_SIZE);
5642
5643 /* GAS Initial Response */
5644 sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5645 (uint8_t *) GAS_INITIAL_RSP,
5646 GAS_INITIAL_RSP_SIZE);
5647
5648 /* GAS Comeback Request */
5649 sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5650 (uint8_t *) GAS_COMEBACK_REQ,
5651 GAS_COMEBACK_REQ_SIZE);
5652
5653 /* GAS Comeback Response */
5654 sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5655 (uint8_t *) GAS_COMEBACK_RSP,
5656 GAS_COMEBACK_RSP_SIZE);
5657
5658 /* P2P Public Action */
5659 sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5660 (uint8_t *) P2P_PUBLIC_ACTION_FRAME,
5661 P2P_PUBLIC_ACTION_FRAME_SIZE);
5662
5663 /* P2P Action */
5664 sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type,
5665 (uint8_t *) P2P_ACTION_FRAME,
5666 P2P_ACTION_FRAME_SIZE);
5667
5668 /* WNM-Notification */
5669 sme_deregister_mgmt_frame(hHal, pAdapter->sessionId, type,
5670 (uint8_t *) WNM_NOTIFICATION_FRAME,
5671 WNM_NOTIFICATION_FRAME_SIZE);
5672}
5673
5674#ifdef FEATURE_WLAN_WAPI
5675void wlan_hdd_cfg80211_set_key_wapi(hdd_adapter_t *pAdapter, uint8_t key_index,
5676 const uint8_t *mac_addr, const uint8_t *key,
5677 int key_Len)
5678{
5679 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
5680 tCsrRoamSetKey setKey;
5681 bool isConnected = true;
5682 int status = 0;
5683 uint32_t roamId = 0xFF;
5684 uint8_t *pKeyPtr = NULL;
5685 int n = 0;
5686
5687 hddLog(LOG1, "Device_mode %s(%d)",
5688 hdd_device_mode_to_string(pAdapter->device_mode),
5689 pAdapter->device_mode);
5690
5691 cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey));
5692 setKey.keyId = key_index; /* Store Key ID */
5693 setKey.encType = eCSR_ENCRYPT_TYPE_WPI; /* SET WAPI Encryption */
5694 setKey.keyDirection = eSIR_TX_RX; /* Key Directionn both TX and RX */
5695 setKey.paeRole = 0; /* the PAE role */
5696 if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
5697 cdf_set_macaddr_broadcast(&setKey.peerMac);
5698 } else {
5699 cdf_mem_copy(setKey.peerMac.bytes, mac_addr, CDF_MAC_ADDR_SIZE);
5700 }
5701 setKey.keyLength = key_Len;
5702 pKeyPtr = setKey.Key;
5703 memcpy(pKeyPtr, key, key_Len);
5704
5705 hddLog(CDF_TRACE_LEVEL_INFO, "%s: WAPI KEY LENGTH:0x%04x",
5706 __func__, key_Len);
5707 for (n = 0; n < key_Len; n++)
5708 hddLog(CDF_TRACE_LEVEL_INFO, "%s WAPI KEY Data[%d]:%02x ",
5709 __func__, n, setKey.Key[n]);
5710
5711 pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_SETTING_KEY;
5712 if (isConnected) {
5713 status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter),
5714 pAdapter->sessionId, &setKey, &roamId);
5715 }
5716 if (status != 0) {
5717 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
5718 "[%4d] sme_roam_set_key returned ERROR status= %d",
5719 __LINE__, status);
5720 pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE;
5721 }
5722}
5723#endif /* FEATURE_WLAN_WAPI */
5724
5725uint8_t *wlan_hdd_cfg80211_get_ie_ptr(const uint8_t *ies_ptr, int length,
5726 uint8_t eid)
5727{
5728 int left = length;
5729 uint8_t *ptr = (uint8_t *)ies_ptr;
5730 uint8_t elem_id, elem_len;
5731
5732 while (left >= 2) {
5733 elem_id = ptr[0];
5734 elem_len = ptr[1];
5735 left -= 2;
5736 if (elem_len > left) {
5737 hddLog(CDF_TRACE_LEVEL_FATAL,
5738 FL("Invalid IEs eid = %d elem_len=%d left=%d"),
5739 eid, elem_len, left);
5740 return NULL;
5741 }
5742 if (elem_id == eid) {
5743 return ptr;
5744 }
5745
5746 left -= elem_len;
5747 ptr += (elem_len + 2);
5748 }
5749 return NULL;
5750}
5751
5752/*
5753 * FUNCTION: wlan_hdd_validate_operation_channel
5754 * called by wlan_hdd_cfg80211_start_bss() and
5755 * wlan_hdd_set_channel()
5756 * This function validates whether given channel is part of valid
5757 * channel list.
5758 */
5759CDF_STATUS wlan_hdd_validate_operation_channel(hdd_adapter_t *pAdapter,
5760 int channel)
5761{
5762
5763 uint32_t num_ch = 0;
5764 u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN];
5765 u32 indx = 0;
5766 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
5767 uint8_t fValidChannel = false, count = 0;
5768 struct hdd_config *hdd_pConfig_ini = (WLAN_HDD_GET_CTX(pAdapter))->config;
5769
5770 num_ch = WNI_CFG_VALID_CHANNEL_LIST_LEN;
5771
5772 if (hdd_pConfig_ini->sapAllowAllChannel) {
5773 /* Validate the channel */
5774 for (count = RF_CHAN_1; count <= RF_CHAN_165; count++) {
Amar Singhal7a1726a2015-10-14 16:28:11 -07005775 if (channel == CDS_CHANNEL_NUM(count)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005776 fValidChannel = true;
5777 break;
5778 }
5779 }
5780 if (fValidChannel != true) {
5781 hddLog(CDF_TRACE_LEVEL_ERROR,
5782 "%s: Invalid Channel [%d]", __func__, channel);
5783 return CDF_STATUS_E_FAILURE;
5784 }
5785 } else {
5786 if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST,
5787 valid_ch, &num_ch)) {
5788 hddLog(CDF_TRACE_LEVEL_ERROR,
5789 "%s: failed to get valid channel list",
5790 __func__);
5791 return CDF_STATUS_E_FAILURE;
5792 }
5793 for (indx = 0; indx < num_ch; indx++) {
5794 if (channel == valid_ch[indx]) {
5795 break;
5796 }
5797 }
5798
5799 if (indx >= num_ch) {
5800 hddLog(CDF_TRACE_LEVEL_ERROR,
5801 "%s: Invalid Channel [%d]", __func__, channel);
5802 return CDF_STATUS_E_FAILURE;
5803 }
5804 }
5805 return CDF_STATUS_SUCCESS;
5806
5807}
5808
5809#ifdef DHCP_SERVER_OFFLOAD
5810static void wlan_hdd_set_dhcp_server_offload(hdd_adapter_t *pHostapdAdapter)
5811{
5812 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
5813 tpSirDhcpSrvOffloadInfo pDhcpSrvInfo;
5814 uint8_t numEntries = 0;
5815 uint8_t srv_ip[IPADDR_NUM_ENTRIES];
5816 uint8_t num;
5817 uint32_t temp;
5818 pDhcpSrvInfo = cdf_mem_malloc(sizeof(*pDhcpSrvInfo));
5819 if (NULL == pDhcpSrvInfo) {
5820 hddLog(CDF_TRACE_LEVEL_ERROR,
5821 "%s: could not allocate tDhcpSrvOffloadInfo!", __func__);
5822 return;
5823 }
5824 cdf_mem_zero(pDhcpSrvInfo, sizeof(*pDhcpSrvInfo));
5825 pDhcpSrvInfo->vdev_id = pHostapdAdapter->sessionId;
5826 pDhcpSrvInfo->dhcpSrvOffloadEnabled = true;
5827 pDhcpSrvInfo->dhcpClientNum = pHddCtx->config->dhcpMaxNumClients;
5828 hdd_string_to_u8_array(pHddCtx->config->dhcpServerIP,
5829 srv_ip, &numEntries, IPADDR_NUM_ENTRIES);
5830 if (numEntries != IPADDR_NUM_ENTRIES) {
5831 hddLog(CDF_TRACE_LEVEL_ERROR,
5832 "%s: incorrect IP address (%s) assigned for DHCP server!",
5833 __func__, pHddCtx->config->dhcpServerIP);
5834 goto end;
5835 }
5836 if ((srv_ip[0] >= 224) && (srv_ip[0] <= 239)) {
5837 hddLog(CDF_TRACE_LEVEL_ERROR,
5838 "%s: invalid IP address (%s)! It could NOT be multicast IP address!",
5839 __func__, pHddCtx->config->dhcpServerIP);
5840 goto end;
5841 }
5842 if (srv_ip[IPADDR_NUM_ENTRIES - 1] >= 100) {
5843 hddLog(CDF_TRACE_LEVEL_ERROR,
5844 "%s: invalid IP address (%s)! The last field must be less than 100!",
5845 __func__, pHddCtx->config->dhcpServerIP);
5846 goto end;
5847 }
5848 for (num = 0; num < numEntries; num++) {
5849 temp = srv_ip[num];
5850 pDhcpSrvInfo->dhcpSrvIP |= (temp << (8 * num));
5851 }
5852 if (CDF_STATUS_SUCCESS !=
5853 sme_set_dhcp_srv_offload(pHddCtx->hHal, pDhcpSrvInfo)) {
5854 hddLog(CDF_TRACE_LEVEL_ERROR,
5855 "%s: sme_setDHCPSrvOffload fail!", __func__);
5856 goto end;
5857 }
5858 hddLog(CDF_TRACE_LEVEL_INFO_HIGH,
5859 "%s: enable DHCP Server offload successfully!", __func__);
5860end:
5861 cdf_mem_free(pDhcpSrvInfo);
5862 return;
5863}
5864#endif /* DHCP_SERVER_OFFLOAD */
5865
5866static int __wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy,
5867 struct net_device *dev,
5868 struct bss_parameters *params)
5869{
5870 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
5871 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
5872 int ret = 0;
5873 CDF_STATUS cdf_ret_status;
5874
5875 ENTER();
5876
Peng Xuf5d60c82015-10-02 17:17:03 -07005877 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005878 hddLog(LOGE, FL("Command not allowed in FTM mode"));
5879 return -EINVAL;
5880 }
5881
5882 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
5883 TRACE_CODE_HDD_CFG80211_CHANGE_BSS,
5884 pAdapter->sessionId, params->ap_isolate));
5885 hddLog(LOG1, FL("Device_mode %s(%d), ap_isolate = %d"),
5886 hdd_device_mode_to_string(pAdapter->device_mode),
5887 pAdapter->device_mode, params->ap_isolate);
5888
5889 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
5890 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05305891 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005892 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005893
5894 if (!(pAdapter->device_mode == WLAN_HDD_SOFTAP ||
5895 pAdapter->device_mode == WLAN_HDD_P2P_GO)) {
5896 return -EOPNOTSUPP;
5897 }
5898
5899 /* ap_isolate == -1 means that in change bss, upper layer doesn't
5900 * want to update this parameter */
5901 if (-1 != params->ap_isolate) {
5902 pAdapter->sessionCtx.ap.apDisableIntraBssFwd =
5903 !!params->ap_isolate;
5904
5905 cdf_ret_status = sme_ap_disable_intra_bss_fwd(pHddCtx->hHal,
5906 pAdapter->sessionId,
5907 pAdapter->sessionCtx.
5908 ap.
5909 apDisableIntraBssFwd);
5910 if (!CDF_IS_STATUS_SUCCESS(cdf_ret_status)) {
5911 ret = -EINVAL;
5912 }
5913 }
5914
5915 EXIT();
5916 return ret;
5917}
5918
5919static int
5920wlan_hdd_change_iface_to_adhoc(struct net_device *ndev,
5921 tCsrRoamProfile *pRoamProfile,
5922 enum nl80211_iftype type)
5923{
5924 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
5925 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
5926 struct hdd_config *pConfig = pHddCtx->config;
5927 struct wireless_dev *wdev = ndev->ieee80211_ptr;
5928
5929 pRoamProfile->BSSType = eCSR_BSS_TYPE_START_IBSS;
5930 pRoamProfile->phyMode =
5931 hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode);
5932 pAdapter->device_mode = WLAN_HDD_IBSS;
5933 wdev->iftype = type;
5934
5935 return 0;
5936}
5937
5938static int wlan_hdd_change_iface_to_sta_mode(struct net_device *ndev,
5939 enum nl80211_iftype type)
5940{
5941 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
5942 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
5943 hdd_wext_state_t *wext;
5944 struct wireless_dev *wdev;
5945 CDF_STATUS status;
5946
5947 ENTER();
5948
5949 if (test_bit(ACS_IN_PROGRESS, &pHddCtx->g_event_flags)) {
5950 hddLog(LOG1, FL("ACS is in progress, don't change iface!"));
5951 return 0;
5952 }
5953
5954 wdev = ndev->ieee80211_ptr;
5955 hdd_stop_adapter(pHddCtx, pAdapter, true);
5956 hdd_deinit_adapter(pHddCtx, pAdapter, true);
5957 wdev->iftype = type;
5958 /*Check for sub-string p2p to confirm its a p2p interface */
5959 if (NULL != strnstr(ndev->name, "p2p", 3)) {
5960 pAdapter->device_mode =
5961 (type == NL80211_IFTYPE_STATION) ?
5962 WLAN_HDD_P2P_DEVICE : WLAN_HDD_P2P_CLIENT;
5963 } else {
5964 pAdapter->device_mode =
5965 (type == NL80211_IFTYPE_STATION) ?
5966 WLAN_HDD_INFRA_STATION : WLAN_HDD_P2P_CLIENT;
5967 }
5968
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08005969 memset(&pAdapter->sessionCtx, 0, sizeof(pAdapter->sessionCtx));
5970 hdd_set_station_ops(pAdapter->dev);
5971 status = hdd_init_station_mode(pAdapter);
5972 wext = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
5973 wext->roamProfile.pAddIEScan = pAdapter->scan_info.scanAddIE.addIEdata;
5974 wext->roamProfile.nAddIEScanLength =
5975 pAdapter->scan_info.scanAddIE.length;
5976 EXIT();
5977 return status;
5978}
5979
5980static int wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy,
5981 struct net_device *dev,
5982 struct bss_parameters *params)
5983{
5984 int ret;
5985
5986 cds_ssr_protect(__func__);
5987 ret = __wlan_hdd_cfg80211_change_bss(wiphy, dev, params);
5988 cds_ssr_unprotect(__func__);
5989
5990 return ret;
5991}
5992
5993/* FUNCTION: wlan_hdd_change_country_code_cd
5994 * to wait for contry code completion
5995 */
5996void *wlan_hdd_change_country_code_cb(void *pAdapter)
5997{
5998 hdd_adapter_t *call_back_pAdapter = pAdapter;
5999 complete(&call_back_pAdapter->change_country_code);
6000 return NULL;
6001}
6002
6003/*
6004 * FUNCTION: __wlan_hdd_cfg80211_change_iface
6005 * This function is used to set the interface type (INFRASTRUCTURE/ADHOC)
6006 */
6007static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy,
6008 struct net_device *ndev,
6009 enum nl80211_iftype type,
6010 u32 *flags,
6011 struct vif_params *params)
6012{
6013 struct wireless_dev *wdev;
6014 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
6015 hdd_context_t *pHddCtx;
6016 tCsrRoamProfile *pRoamProfile = NULL;
6017 eCsrRoamBssType LastBSSType;
6018 struct hdd_config *pConfig = NULL;
6019 eMib_dot11DesiredBssType connectedBssType;
6020 unsigned long rc;
6021 CDF_STATUS vstatus;
6022 int status;
6023
6024 ENTER();
6025
Peng Xuf5d60c82015-10-02 17:17:03 -07006026 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006027 hddLog(LOGE, FL("Command not allowed in FTM mode"));
6028 return -EINVAL;
6029 }
6030
6031 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
6032 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306033 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006034 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006035
6036 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
6037 TRACE_CODE_HDD_CFG80211_CHANGE_IFACE,
6038 pAdapter->sessionId, type));
6039
6040 hddLog(CDF_TRACE_LEVEL_INFO, FL("Device_mode = %d, IFTYPE = 0x%x"),
6041 pAdapter->device_mode, type);
6042
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08006043 if (!cds_allow_concurrency(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006044 wlan_hdd_convert_nl_iftype_to_hdd_type(type),
6045 0, HW_MODE_20_MHZ)) {
6046 hddLog(CDF_TRACE_LEVEL_DEBUG,
6047 FL("This concurrency combination is not allowed"));
6048 return -EINVAL;
6049 }
6050
6051 pConfig = pHddCtx->config;
6052 wdev = ndev->ieee80211_ptr;
6053
6054 /* Reset the current device mode bit mask */
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08006055 cds_clear_concurrency_mode(pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006056
6057 hdd_tdls_notify_mode_change(pAdapter, pHddCtx);
6058
6059 if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) ||
6060 (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) ||
Krunal Soni2c68f232015-10-26 20:52:51 -07006061 (pAdapter->device_mode == WLAN_HDD_P2P_DEVICE) ||
6062 (pAdapter->device_mode == WLAN_HDD_IBSS)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006063 hdd_wext_state_t *pWextState =
6064 WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
6065
6066 pRoamProfile = &pWextState->roamProfile;
6067 LastBSSType = pRoamProfile->BSSType;
6068
6069 switch (type) {
6070 case NL80211_IFTYPE_STATION:
6071 case NL80211_IFTYPE_P2P_CLIENT:
6072 vstatus = wlan_hdd_change_iface_to_sta_mode(ndev, type);
6073 if (vstatus != CDF_STATUS_SUCCESS)
6074 return -EINVAL;
6075
6076 hdd_register_tx_flow_control(pAdapter,
6077 hdd_tx_resume_timer_expired_handler,
6078 hdd_tx_resume_cb);
6079
6080 goto done;
6081
6082 case NL80211_IFTYPE_ADHOC:
6083 wlan_hdd_tdls_exit(pAdapter);
Masti, Narayanraddi3d8690c2015-11-02 11:13:42 +05306084 hdd_deregister_tx_flow_control(pAdapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006085 hddLog(LOG1, FL("Setting interface Type to ADHOC"));
6086 wlan_hdd_change_iface_to_adhoc(ndev, pRoamProfile,
6087 type);
6088 break;
6089
6090 case NL80211_IFTYPE_AP:
6091 case NL80211_IFTYPE_P2P_GO:
6092 {
6093 hddLog(CDF_TRACE_LEVEL_INFO_HIGH,
6094 FL("Setting interface Type to %s"),
6095 (type ==
6096 NL80211_IFTYPE_AP) ? "SoftAP" :
6097 "P2pGo");
6098
6099 /* Cancel any remain on channel for GO mode */
6100 if (NL80211_IFTYPE_P2P_GO == type) {
6101 wlan_hdd_cancel_existing_remain_on_channel
6102 (pAdapter);
6103 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006104 hdd_stop_adapter(pHddCtx, pAdapter, true);
6105
6106 /* De-init the adapter */
6107 hdd_deinit_adapter(pHddCtx, pAdapter, true);
6108 memset(&pAdapter->sessionCtx, 0,
6109 sizeof(pAdapter->sessionCtx));
6110 pAdapter->device_mode =
6111 (type ==
6112 NL80211_IFTYPE_AP) ? WLAN_HDD_SOFTAP :
6113 WLAN_HDD_P2P_GO;
6114
6115 /*
6116 * Fw will take care incase of concurrency
6117 */
6118
6119 if ((WLAN_HDD_SOFTAP == pAdapter->device_mode)
6120 && (pConfig->apRandomBssidEnabled)) {
6121 /* To meet Android requirements create a randomized
6122 MAC address of the form 02:1A:11:Fx:xx:xx */
6123 get_random_bytes(&ndev->dev_addr[3], 3);
6124 ndev->dev_addr[0] = 0x02;
6125 ndev->dev_addr[1] = 0x1A;
6126 ndev->dev_addr[2] = 0x11;
6127 ndev->dev_addr[3] |= 0xF0;
6128 memcpy(pAdapter->macAddressCurrent.
6129 bytes, ndev->dev_addr,
6130 CDF_MAC_ADDR_SIZE);
6131 pr_info("wlan: Generated HotSpot BSSID "
6132 MAC_ADDRESS_STR "\n",
6133 MAC_ADDR_ARRAY(ndev->dev_addr));
6134 }
6135
6136 hdd_set_ap_ops(pAdapter->dev);
6137
6138 vstatus = hdd_init_ap_mode(pAdapter);
6139 if (vstatus != CDF_STATUS_SUCCESS) {
6140 hddLog(LOGP,
6141 FL
6142 ("Error initializing the ap mode"));
6143 return -EINVAL;
6144 }
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006145
6146 hdd_register_tx_flow_control(pAdapter,
6147 hdd_softap_tx_resume_timer_expired_handler,
6148 hdd_softap_tx_resume_cb);
6149
6150 /* Interface type changed update in wiphy structure */
6151 if (wdev) {
6152 wdev->iftype = type;
6153 } else {
6154 hddLog(LOGE,
6155 FL("Wireless dev is NULL"));
6156 return -EINVAL;
6157 }
6158 goto done;
6159 }
6160
6161 default:
6162 hddLog(LOGE, FL("Unsupported interface type (%d)"),
6163 type);
6164 return -EOPNOTSUPP;
6165 }
6166 } else if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) ||
6167 (pAdapter->device_mode == WLAN_HDD_P2P_GO)) {
6168 switch (type) {
6169 case NL80211_IFTYPE_STATION:
6170 case NL80211_IFTYPE_P2P_CLIENT:
6171 case NL80211_IFTYPE_ADHOC:
6172 status = wlan_hdd_change_iface_to_sta_mode(ndev, type);
6173 if (status != CDF_STATUS_SUCCESS)
6174 return status;
6175
6176 if ((NL80211_IFTYPE_P2P_CLIENT == type) ||
6177 (NL80211_IFTYPE_STATION == type)) {
6178
6179 hdd_register_tx_flow_control(pAdapter,
6180 hdd_tx_resume_timer_expired_handler,
6181 hdd_tx_resume_cb);
6182 }
6183 goto done;
6184
6185 case NL80211_IFTYPE_AP:
6186 case NL80211_IFTYPE_P2P_GO:
6187 wdev->iftype = type;
6188 pAdapter->device_mode = (type == NL80211_IFTYPE_AP) ?
6189 WLAN_HDD_SOFTAP : WLAN_HDD_P2P_GO;
6190
6191 hdd_register_tx_flow_control(pAdapter,
6192 hdd_softap_tx_resume_timer_expired_handler,
6193 hdd_softap_tx_resume_cb);
6194 goto done;
6195
6196 default:
6197 hddLog(LOGE, FL("Unsupported interface type(%d)"),
6198 type);
6199 return -EOPNOTSUPP;
6200 }
6201 } else {
6202 hddLog(LOGE, FL("Unsupported device mode(%d)"),
6203 pAdapter->device_mode);
6204 return -EOPNOTSUPP;
6205 }
6206
6207 if (LastBSSType != pRoamProfile->BSSType) {
6208 /* Interface type changed update in wiphy structure */
6209 wdev->iftype = type;
6210
6211 /* The BSS mode changed, We need to issue disconnect
6212 if connected or in IBSS disconnect state */
6213 if (hdd_conn_get_connected_bss_type
6214 (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), &connectedBssType)
6215 || (eCSR_BSS_TYPE_START_IBSS == LastBSSType)) {
6216 /* Need to issue a disconnect to CSR. */
6217 INIT_COMPLETION(pAdapter->disconnect_comp_var);
6218 if (CDF_STATUS_SUCCESS ==
6219 sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter),
6220 pAdapter->sessionId,
6221 eCSR_DISCONNECT_REASON_UNSPECIFIED)) {
6222 rc = wait_for_completion_timeout(&pAdapter->
6223 disconnect_comp_var,
6224 msecs_to_jiffies
6225 (WLAN_WAIT_TIME_DISCONNECT));
6226 if (!rc) {
6227 hddLog(LOGE,
6228 FL
6229 ("Wait on disconnect_comp_var failed"));
6230 }
6231 }
6232 }
6233 }
6234
6235done:
6236 /* Set bitmask based on updated value */
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08006237 cds_set_concurrency_mode(pAdapter->device_mode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006238
6239#ifdef WLAN_FEATURE_LPSS
6240 wlan_hdd_send_all_scan_intf_info(pHddCtx);
6241#endif
6242
6243 EXIT();
6244 return 0;
6245}
6246
6247/*
6248 * FUNCTION: wlan_hdd_cfg80211_change_iface
6249 * wrapper function to protect the actual implementation from SSR.
6250 */
6251static int wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy,
6252 struct net_device *ndev,
6253 enum nl80211_iftype type,
6254 u32 *flags,
6255 struct vif_params *params)
6256{
6257 int ret;
6258
6259 cds_ssr_protect(__func__);
6260 ret =
6261 __wlan_hdd_cfg80211_change_iface(wiphy, ndev, type, flags, params);
6262 cds_ssr_unprotect(__func__);
6263
6264 return ret;
6265}
6266
6267#ifdef FEATURE_WLAN_TDLS
6268static bool wlan_hdd_is_duplicate_channel(uint8_t *arr,
6269 int index, uint8_t match)
6270{
6271 int i;
6272 for (i = 0; i < index; i++) {
6273 if (arr[i] == match)
6274 return true;
6275 }
6276 return false;
6277}
6278#endif
6279
6280/**
6281 * __wlan_hdd_change_station() - change station
6282 * @wiphy: Pointer to the wiphy structure
6283 * @dev: Pointer to the net device.
6284 * @mac: bssid
6285 * @params: Pointer to station parameters
6286 *
6287 * Return: 0 for success, error number on failure.
6288 */
6289#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
6290static int __wlan_hdd_change_station(struct wiphy *wiphy,
6291 struct net_device *dev,
6292 const uint8_t *mac,
6293 struct station_parameters *params)
6294#else
6295static int __wlan_hdd_change_station(struct wiphy *wiphy,
6296 struct net_device *dev,
6297 uint8_t *mac,
6298 struct station_parameters *params)
6299#endif
6300{
6301 CDF_STATUS status = CDF_STATUS_SUCCESS;
6302 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
6303 hdd_context_t *pHddCtx;
6304 hdd_station_ctx_t *pHddStaCtx;
6305 struct cdf_mac_addr STAMacAddress;
6306#ifdef FEATURE_WLAN_TDLS
6307 tCsrStaParams StaParams = { 0 };
6308 uint8_t isBufSta = 0;
6309 uint8_t isOffChannelSupported = 0;
6310#endif
6311 int ret;
6312
6313 ENTER();
6314
Peng Xuf5d60c82015-10-02 17:17:03 -07006315 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006316 hddLog(LOGE, FL("Command not allowed in FTM mode"));
6317 return -EINVAL;
6318 }
6319
6320 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
6321 TRACE_CODE_HDD_CHANGE_STATION,
6322 pAdapter->sessionId, params->listen_interval));
6323
6324 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
6325 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306326 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006327 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006328
6329 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
6330
6331 cdf_mem_copy(STAMacAddress.bytes, mac, CDF_MAC_ADDR_SIZE);
6332
6333 if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) ||
6334 (pAdapter->device_mode == WLAN_HDD_P2P_GO)) {
6335 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
6336 status =
6337 hdd_softap_change_sta_state(pAdapter,
6338 &STAMacAddress,
6339 ol_txrx_peer_state_auth);
6340
6341 if (status != CDF_STATUS_SUCCESS) {
6342 hddLog(CDF_TRACE_LEVEL_INFO,
6343 FL
6344 ("Not able to change TL state to AUTHENTICATED"));
6345 return -EINVAL;
6346 }
6347 }
6348 } else if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) ||
6349 (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) {
6350#ifdef FEATURE_WLAN_TDLS
6351 if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
6352 StaParams.capability = params->capability;
6353 StaParams.uapsd_queues = params->uapsd_queues;
6354 StaParams.max_sp = params->max_sp;
6355
6356 /* Convert (first channel , number of channels) tuple to
6357 * the total list of channels. This goes with the assumption
6358 * that if the first channel is < 14, then the next channels
6359 * are an incremental of 1 else an incremental of 4 till the number
6360 * of channels.
6361 */
6362 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
6363 "%s: params->supported_channels_len: %d",
6364 __func__, params->supported_channels_len);
6365 if (0 != params->supported_channels_len) {
6366 int i = 0, j = 0, k = 0, no_of_channels = 0;
6367 int num_unique_channels;
6368 int next;
6369 for (i = 0;
6370 i < params->supported_channels_len
6371 && j < SIR_MAC_MAX_SUPP_CHANNELS; i += 2) {
6372 int wifi_chan_index;
6373 if (!wlan_hdd_is_duplicate_channel
6374 (StaParams.supported_channels, j,
6375 params->supported_channels[i])) {
6376 StaParams.
6377 supported_channels[j] =
6378 params->
6379 supported_channels[i];
6380 } else {
6381 continue;
6382 }
6383 wifi_chan_index =
6384 ((StaParams.supported_channels[j] <=
6385 HDD_CHANNEL_14) ? 1 : 4);
6386 no_of_channels =
6387 params->supported_channels[i + 1];
6388
6389 CDF_TRACE(CDF_MODULE_ID_HDD,
6390 CDF_TRACE_LEVEL_INFO,
6391 "%s: i: %d, j: %d, k: %d, StaParams.supported_channels[%d]: %d, wifi_chan_index: %d, no_of_channels: %d",
6392 __func__, i, j, k, j,
6393 StaParams.
6394 supported_channels[j],
6395 wifi_chan_index,
6396 no_of_channels);
6397 for (k = 1; k <= no_of_channels &&
6398 j < SIR_MAC_MAX_SUPP_CHANNELS - 1;
6399 k++) {
6400 next =
6401 StaParams.
6402 supported_channels[j] +
6403 wifi_chan_index;
6404 if (!wlan_hdd_is_duplicate_channel(StaParams.supported_channels, j + 1, next)) {
6405 StaParams.
6406 supported_channels[j
6407 +
6408 1]
6409 = next;
6410 } else {
6411 continue;
6412 }
6413 CDF_TRACE(CDF_MODULE_ID_HDD,
6414 CDF_TRACE_LEVEL_INFO,
6415 "%s: i: %d, j: %d, k: %d, StaParams.supported_channels[%d]: %d",
6416 __func__, i, j, k,
6417 j + 1,
6418 StaParams.
6419 supported_channels[j +
6420 1]);
6421 j += 1;
6422 }
6423 }
6424 num_unique_channels = j + 1;
6425 CDF_TRACE(CDF_MODULE_ID_HDD,
6426 CDF_TRACE_LEVEL_INFO,
6427 "%s: Unique Channel List", __func__);
6428 for (i = 0; i < num_unique_channels; i++) {
6429 CDF_TRACE(CDF_MODULE_ID_HDD,
6430 CDF_TRACE_LEVEL_INFO,
6431 "%s: StaParams.supported_channels[%d]: %d,",
6432 __func__, i,
6433 StaParams.
6434 supported_channels[i]);
6435 }
6436 if (MAX_CHANNEL < num_unique_channels)
6437 num_unique_channels = MAX_CHANNEL;
6438 StaParams.supported_channels_len =
6439 num_unique_channels;
6440 CDF_TRACE(CDF_MODULE_ID_HDD,
6441 CDF_TRACE_LEVEL_INFO,
6442 "%s: After removing duplcates StaParams.supported_channels_len: %d",
6443 __func__,
6444 StaParams.supported_channels_len);
6445 }
6446 cdf_mem_copy(StaParams.supported_oper_classes,
6447 params->supported_oper_classes,
6448 params->supported_oper_classes_len);
6449 StaParams.supported_oper_classes_len =
6450 params->supported_oper_classes_len;
6451
6452 if (0 != params->ext_capab_len)
6453 cdf_mem_copy(StaParams.extn_capability,
6454 params->ext_capab,
6455 sizeof(StaParams.extn_capability));
6456
6457 if (NULL != params->ht_capa) {
6458 StaParams.htcap_present = 1;
6459 cdf_mem_copy(&StaParams.HTCap, params->ht_capa,
6460 sizeof(tSirHTCap));
6461 }
6462
6463 StaParams.supported_rates_len =
6464 params->supported_rates_len;
6465
6466 /* Note : The Maximum sizeof supported_rates sent by the Supplicant is 32.
6467 * The supported_rates array , for all the structures propogating till Add Sta
6468 * to the firmware has to be modified , if the supplicant (ieee80211) is
6469 * modified to send more rates.
6470 */
6471
6472 /* To avoid Data Currption , set to max length to SIR_MAC_MAX_SUPP_RATES
6473 */
6474 if (StaParams.supported_rates_len >
6475 SIR_MAC_MAX_SUPP_RATES)
6476 StaParams.supported_rates_len =
6477 SIR_MAC_MAX_SUPP_RATES;
6478
6479 if (0 != StaParams.supported_rates_len) {
6480 int i = 0;
6481 cdf_mem_copy(StaParams.supported_rates,
6482 params->supported_rates,
6483 StaParams.supported_rates_len);
6484 CDF_TRACE(CDF_MODULE_ID_HDD,
6485 CDF_TRACE_LEVEL_INFO,
6486 "Supported Rates with Length %d",
6487 StaParams.supported_rates_len);
6488 for (i = 0; i < StaParams.supported_rates_len;
6489 i++)
6490 CDF_TRACE(CDF_MODULE_ID_HDD,
6491 CDF_TRACE_LEVEL_INFO,
6492 "[%d]: %0x", i,
6493 StaParams.supported_rates[i]);
6494 }
6495
6496 if (NULL != params->vht_capa) {
6497 StaParams.vhtcap_present = 1;
6498 cdf_mem_copy(&StaParams.VHTCap,
6499 params->vht_capa,
6500 sizeof(tSirVHTCap));
6501 }
6502
6503 if (0 != params->ext_capab_len) {
6504 /*Define A Macro : TODO Sunil */
6505 if ((1 << 4) & StaParams.extn_capability[3]) {
6506 isBufSta = 1;
6507 }
6508 /* TDLS Channel Switching Support */
6509 if ((1 << 6) & StaParams.extn_capability[3]) {
6510 isOffChannelSupported = 1;
6511 }
6512 }
6513
6514 status = wlan_hdd_tdls_set_peer_caps(pAdapter, mac,
6515 &StaParams,
6516 isBufSta,
6517 isOffChannelSupported);
6518 if (CDF_STATUS_SUCCESS != status) {
6519 hddLog(CDF_TRACE_LEVEL_ERROR,
6520 FL
6521 ("wlan_hdd_tdls_set_peer_caps failed!"));
6522 return -EINVAL;
6523 }
6524
6525 status =
6526 wlan_hdd_tdls_add_station(wiphy, dev, mac, 1,
6527 &StaParams);
6528 if (CDF_STATUS_SUCCESS != status) {
6529 hddLog(CDF_TRACE_LEVEL_ERROR,
6530 FL("wlan_hdd_tdls_add_station failed!"));
6531 return -EINVAL;
6532 }
6533 }
6534#endif
6535 }
6536 EXIT();
6537 return ret;
6538}
6539
6540/**
6541 * wlan_hdd_change_station() - cfg80211 change station handler function
6542 * @wiphy: Pointer to the wiphy structure
6543 * @dev: Pointer to the net device.
6544 * @mac: bssid
6545 * @params: Pointer to station parameters
6546 *
6547 * This is the cfg80211 change station handler function which invokes
6548 * the internal function @__wlan_hdd_change_station with
6549 * SSR protection.
6550 *
6551 * Return: 0 for success, error number on failure.
6552 */
6553#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) || defined(WITH_BACKPORTS)
6554static int wlan_hdd_change_station(struct wiphy *wiphy,
6555 struct net_device *dev,
6556 const u8 *mac,
6557 struct station_parameters *params)
6558#else
6559static int wlan_hdd_change_station(struct wiphy *wiphy,
6560 struct net_device *dev,
6561 u8 *mac,
6562 struct station_parameters *params)
6563#endif
6564{
6565 int ret;
6566
6567 cds_ssr_protect(__func__);
6568 ret = __wlan_hdd_change_station(wiphy, dev, mac, params);
6569 cds_ssr_unprotect(__func__);
6570
6571 return ret;
6572}
6573
6574/*
6575 * FUNCTION: __wlan_hdd_cfg80211_add_key
6576 * This function is used to initialize the key information
6577 */
6578static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy,
6579 struct net_device *ndev,
6580 u8 key_index, bool pairwise,
6581 const u8 *mac_addr,
6582 struct key_params *params)
6583{
6584 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
6585 tCsrRoamSetKey setKey;
6586 int status;
6587 uint32_t roamId = 0xFF;
6588#ifndef WLAN_FEATURE_MBSSID
6589 v_CONTEXT_t p_cds_context = (WLAN_HDD_GET_CTX(pAdapter))->pcds_context;
6590#endif
6591 hdd_hostapd_state_t *pHostapdState;
6592 CDF_STATUS cdf_ret_status;
6593 hdd_context_t *pHddCtx;
6594 hdd_ap_ctx_t *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter);
6595
6596 ENTER();
6597
Peng Xuf5d60c82015-10-02 17:17:03 -07006598 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006599 hddLog(LOGE, FL("Command not allowed in FTM mode"));
6600 return -EINVAL;
6601 }
6602
6603 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
6604 TRACE_CODE_HDD_CFG80211_ADD_KEY,
6605 pAdapter->sessionId, params->key_len));
6606 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
6607 status = wlan_hdd_validate_context(pHddCtx);
6608
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306609 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006610 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006611
6612 hddLog(LOG1, FL("Device_mode %s(%d)"),
6613 hdd_device_mode_to_string(pAdapter->device_mode),
6614 pAdapter->device_mode);
6615
6616 if (CSR_MAX_NUM_KEY <= key_index) {
6617 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Invalid key index %d",
6618 __func__, key_index);
6619
6620 return -EINVAL;
6621 }
6622
6623 if (CSR_MAX_KEY_LEN < params->key_len) {
6624 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: Invalid key length %d",
6625 __func__, params->key_len);
6626
6627 return -EINVAL;
6628 }
6629
6630 hddLog(CDF_TRACE_LEVEL_INFO,
6631 "%s: called with key index = %d & key length %d",
6632 __func__, key_index, params->key_len);
6633
6634 /*extract key idx, key len and key */
6635 cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey));
6636 setKey.keyId = key_index;
6637 setKey.keyLength = params->key_len;
6638 cdf_mem_copy(&setKey.Key[0], params->key, params->key_len);
6639
6640 switch (params->cipher) {
6641 case WLAN_CIPHER_SUITE_WEP40:
6642 setKey.encType = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY;
6643 break;
6644
6645 case WLAN_CIPHER_SUITE_WEP104:
6646 setKey.encType = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY;
6647 break;
6648
6649 case WLAN_CIPHER_SUITE_TKIP:
6650 {
6651 u8 *pKey = &setKey.Key[0];
6652 setKey.encType = eCSR_ENCRYPT_TYPE_TKIP;
6653
6654 cdf_mem_zero(pKey, CSR_MAX_KEY_LEN);
6655
6656 /*Supplicant sends the 32bytes key in this order
6657
6658 |--------------|----------|----------|
6659 | Tk1 |TX-MIC | RX Mic |
6660 |||--------------|----------|----------|
6661 <---16bytes---><--8bytes--><--8bytes-->
6662
6663 */
6664 /*Sme expects the 32 bytes key to be in the below order
6665
6666 |--------------|----------|----------|
6667 | Tk1 |RX-MIC | TX Mic |
6668 |||--------------|----------|----------|
6669 <---16bytes---><--8bytes--><--8bytes-->
6670 */
6671 /* Copy the Temporal Key 1 (TK1) */
6672 cdf_mem_copy(pKey, params->key, 16);
6673
6674 /*Copy the rx mic first */
6675 cdf_mem_copy(&pKey[16], &params->key[24], 8);
6676
6677 /*Copy the tx mic */
6678 cdf_mem_copy(&pKey[24], &params->key[16], 8);
6679
6680 break;
6681 }
6682
6683 case WLAN_CIPHER_SUITE_CCMP:
6684 setKey.encType = eCSR_ENCRYPT_TYPE_AES;
6685 break;
6686
6687#ifdef FEATURE_WLAN_WAPI
6688 case WLAN_CIPHER_SUITE_SMS4:
6689 {
6690 cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey));
6691 wlan_hdd_cfg80211_set_key_wapi(pAdapter, key_index,
6692 mac_addr, params->key,
6693 params->key_len);
6694 return 0;
6695 }
6696#endif
6697
6698#ifdef FEATURE_WLAN_ESE
6699 case WLAN_CIPHER_SUITE_KRK:
6700 setKey.encType = eCSR_ENCRYPT_TYPE_KRK;
6701 break;
6702#ifdef WLAN_FEATURE_ROAM_OFFLOAD
6703 case WLAN_CIPHER_SUITE_BTK:
6704 setKey.encType = eCSR_ENCRYPT_TYPE_BTK;
6705 break;
6706#endif
6707#endif
6708
6709#ifdef WLAN_FEATURE_11W
6710 case WLAN_CIPHER_SUITE_AES_CMAC:
6711 setKey.encType = eCSR_ENCRYPT_TYPE_AES_CMAC;
6712 break;
6713#endif
6714
6715 default:
6716 hddLog(CDF_TRACE_LEVEL_ERROR, "%s: unsupported cipher type %u",
6717 __func__, params->cipher);
6718 return -EOPNOTSUPP;
6719 }
6720
6721 hddLog(CDF_TRACE_LEVEL_INFO_MED, "%s: encryption type %d",
6722 __func__, setKey.encType);
6723
6724 if (!pairwise) {
6725 /* set group key */
6726 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
6727 "%s- %d: setting Broadcast key", __func__, __LINE__);
6728 setKey.keyDirection = eSIR_RX_ONLY;
6729 cdf_set_macaddr_broadcast(&setKey.peerMac);
6730 } else {
6731 /* set pairwise key */
6732 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_INFO,
6733 "%s- %d: setting pairwise key", __func__, __LINE__);
6734 setKey.keyDirection = eSIR_TX_RX;
6735 cdf_mem_copy(setKey.peerMac.bytes, mac_addr, CDF_MAC_ADDR_SIZE);
6736 }
6737 if ((WLAN_HDD_IBSS == pAdapter->device_mode) && !pairwise) {
6738 /* if a key is already installed, block all subsequent ones */
6739 if (pAdapter->sessionCtx.station.ibss_enc_key_installed) {
6740 hddLog(CDF_TRACE_LEVEL_INFO_MED,
6741 "%s: IBSS key installed already", __func__);
6742 return 0;
6743 }
6744
6745 setKey.keyDirection = eSIR_TX_RX;
6746 /*Set the group key */
6747 status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter),
6748 pAdapter->sessionId, &setKey, &roamId);
6749
6750 if (0 != status) {
6751 hddLog(CDF_TRACE_LEVEL_ERROR,
6752 "%s: sme_roam_set_key failed, returned %d",
6753 __func__, status);
6754 return -EINVAL;
6755 }
6756 /*Save the keys here and call sme_roam_set_key for setting
6757 the PTK after peer joins the IBSS network */
6758 cdf_mem_copy(&pAdapter->sessionCtx.station.ibss_enc_key,
6759 &setKey, sizeof(tCsrRoamSetKey));
6760
6761 pAdapter->sessionCtx.station.ibss_enc_key_installed = 1;
6762 return status;
6763 }
6764 if ((pAdapter->device_mode == WLAN_HDD_SOFTAP) ||
6765 (pAdapter->device_mode == WLAN_HDD_P2P_GO)) {
6766 pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
6767 if (pHostapdState->bssState == BSS_START) {
6768#ifdef WLAN_FEATURE_MBSSID
6769 status =
6770 wlansap_set_key_sta(WLAN_HDD_GET_SAP_CTX_PTR
6771 (pAdapter), &setKey);
6772#else
6773 status = wlansap_set_key_sta(p_cds_context, &setKey);
6774#endif
6775 if (status != CDF_STATUS_SUCCESS) {
6776 CDF_TRACE(CDF_MODULE_ID_HDD,
6777 CDF_TRACE_LEVEL_ERROR,
6778 "[%4d] wlansap_set_key_sta returned ERROR status= %d",
6779 __LINE__, status);
6780 }
6781 }
6782
6783 /* Save the key in ap ctx for use on START_BASS and restart */
6784 if (pairwise ||
6785 eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == setKey.encType ||
6786 eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == setKey.encType)
6787 cdf_mem_copy(&ap_ctx->wepKey[key_index], &setKey,
6788 sizeof(tCsrRoamSetKey));
6789 else
6790 cdf_mem_copy(&ap_ctx->groupKey, &setKey,
6791 sizeof(tCsrRoamSetKey));
6792
6793 } else if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) ||
6794 (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) {
6795 hdd_wext_state_t *pWextState =
6796 WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
6797 hdd_station_ctx_t *pHddStaCtx =
6798 WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
6799
6800 if (!pairwise) {
6801 /* set group key */
6802 if (pHddStaCtx->roam_info.deferKeyComplete) {
6803 CDF_TRACE(CDF_MODULE_ID_HDD,
6804 CDF_TRACE_LEVEL_INFO,
6805 "%s- %d: Perform Set key Complete",
6806 __func__, __LINE__);
6807 hdd_perform_roam_set_key_complete(pAdapter);
6808 }
6809 }
6810
6811 pWextState->roamProfile.Keys.KeyLength[key_index] =
6812 (u8) params->key_len;
6813
6814 pWextState->roamProfile.Keys.defaultIndex = key_index;
6815
6816 cdf_mem_copy(&pWextState->roamProfile.Keys.
6817 KeyMaterial[key_index][0], params->key,
6818 params->key_len);
6819
6820 pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_SETTING_KEY;
6821
6822 hddLog(LOG2,
6823 FL("Set key for peerMac "MAC_ADDRESS_STR" direction %d"),
6824 MAC_ADDR_ARRAY(setKey.peerMac.bytes),
6825 setKey.keyDirection);
6826
6827#ifdef WLAN_FEATURE_VOWIFI_11R
6828 /* The supplicant may attempt to set the PTK once pre-authentication
6829 is done. Save the key in the UMAC and include it in the ADD BSS
6830 request */
6831 cdf_ret_status = sme_ft_update_key(WLAN_HDD_GET_HAL_CTX(pAdapter),
6832 pAdapter->sessionId, &setKey);
6833 if (cdf_ret_status == CDF_STATUS_FT_PREAUTH_KEY_SUCCESS) {
6834 hddLog(CDF_TRACE_LEVEL_INFO_MED,
6835 "%s: Update PreAuth Key success", __func__);
6836 return 0;
6837 } else if (cdf_ret_status == CDF_STATUS_FT_PREAUTH_KEY_FAILED) {
6838 hddLog(CDF_TRACE_LEVEL_ERROR,
6839 "%s: Update PreAuth Key failed", __func__);
6840 return -EINVAL;
6841 }
6842#endif /* WLAN_FEATURE_VOWIFI_11R */
6843
6844 /* issue set key request to SME */
6845 status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter),
6846 pAdapter->sessionId, &setKey, &roamId);
6847
6848 if (0 != status) {
6849 hddLog(CDF_TRACE_LEVEL_ERROR,
6850 "%s: sme_roam_set_key failed, returned %d",
6851 __func__, status);
6852 pHddStaCtx->roam_info.roamingState =
6853 HDD_ROAM_STATE_NONE;
6854 return -EINVAL;
6855 }
6856
6857 /* in case of IBSS as there was no information available about WEP keys during
6858 * IBSS join, group key intialized with NULL key, so re-initialize group key
6859 * with correct value*/
6860 if ((eCSR_BSS_TYPE_START_IBSS ==
6861 pWextState->roamProfile.BSSType)
6862 &&
6863 !((IW_AUTH_KEY_MGMT_802_1X ==
6864 (pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X))
6865 && (eCSR_AUTH_TYPE_OPEN_SYSTEM ==
6866 pHddStaCtx->conn_info.authType)
6867 )
6868 && ((WLAN_CIPHER_SUITE_WEP40 == params->cipher)
6869 || (WLAN_CIPHER_SUITE_WEP104 == params->cipher)
6870 )
6871 ) {
6872 setKey.keyDirection = eSIR_RX_ONLY;
6873 cdf_set_macaddr_broadcast(&setKey.peerMac);
6874
6875 hddLog(LOG2,
6876 FL("Set key peerMac "MAC_ADDRESS_STR" direction %d"),
6877 MAC_ADDR_ARRAY(setKey.peerMac.bytes),
6878 setKey.keyDirection);
6879
6880 status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter),
6881 pAdapter->sessionId, &setKey,
6882 &roamId);
6883
6884 if (0 != status) {
6885 hddLog(CDF_TRACE_LEVEL_ERROR,
6886 "%s: sme_roam_set_key failed for group key (IBSS), returned %d",
6887 __func__, status);
6888 pHddStaCtx->roam_info.roamingState =
6889 HDD_ROAM_STATE_NONE;
6890 return -EINVAL;
6891 }
6892 }
6893 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05306894 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006895 return 0;
6896}
6897
6898static int wlan_hdd_cfg80211_add_key(struct wiphy *wiphy,
6899 struct net_device *ndev,
6900 u8 key_index, bool pairwise,
6901 const u8 *mac_addr,
6902 struct key_params *params)
6903{
6904 int ret;
6905 cds_ssr_protect(__func__);
6906 ret = __wlan_hdd_cfg80211_add_key(wiphy, ndev, key_index, pairwise,
6907 mac_addr, params);
6908 cds_ssr_unprotect(__func__);
6909
6910 return ret;
6911}
6912
6913/*
6914 * FUNCTION: __wlan_hdd_cfg80211_get_key
6915 * This function is used to get the key information
6916 */
6917static int __wlan_hdd_cfg80211_get_key(struct wiphy *wiphy,
6918 struct net_device *ndev,
6919 u8 key_index, bool pairwise,
6920 const u8 *mac_addr, void *cookie,
6921 void (*callback)(void *cookie,
6922 struct key_params *)
6923 )
6924{
6925 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
6926 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
6927 tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile);
6928 struct key_params params;
6929
6930 ENTER();
6931
Peng Xuf5d60c82015-10-02 17:17:03 -07006932 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08006933 hddLog(LOGE, FL("Command not allowed in FTM mode"));
6934 return -EINVAL;
6935 }
6936
6937 hddLog(LOG1, FL("Device_mode %s(%d)"),
6938 hdd_device_mode_to_string(pAdapter->device_mode),
6939 pAdapter->device_mode);
6940
6941 memset(&params, 0, sizeof(params));
6942
6943 if (CSR_MAX_NUM_KEY <= key_index) {
6944 hddLog(CDF_TRACE_LEVEL_ERROR, FL("invalid key index %d"),
6945 key_index);
6946 return -EINVAL;
6947 }
6948
6949 switch (pRoamProfile->EncryptionType.encryptionType[0]) {
6950 case eCSR_ENCRYPT_TYPE_NONE:
6951 params.cipher = IW_AUTH_CIPHER_NONE;
6952 break;
6953
6954 case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
6955 case eCSR_ENCRYPT_TYPE_WEP40:
6956 params.cipher = WLAN_CIPHER_SUITE_WEP40;
6957 break;
6958
6959 case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
6960 case eCSR_ENCRYPT_TYPE_WEP104:
6961 params.cipher = WLAN_CIPHER_SUITE_WEP104;
6962 break;
6963
6964 case eCSR_ENCRYPT_TYPE_TKIP:
6965 params.cipher = WLAN_CIPHER_SUITE_TKIP;
6966 break;
6967
6968 case eCSR_ENCRYPT_TYPE_AES:
6969 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
6970 break;
6971
6972 default:
6973 params.cipher = IW_AUTH_CIPHER_NONE;
6974 break;
6975 }
6976
6977 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
6978 TRACE_CODE_HDD_CFG80211_GET_KEY,
6979 pAdapter->sessionId, params.cipher));
6980
6981 params.key_len = pRoamProfile->Keys.KeyLength[key_index];
6982 params.seq_len = 0;
6983 params.seq = NULL;
6984 params.key = &pRoamProfile->Keys.KeyMaterial[key_index][0];
6985 callback(cookie, &params);
6986
6987 EXIT();
6988 return 0;
6989}
6990
6991static int wlan_hdd_cfg80211_get_key(struct wiphy *wiphy,
6992 struct net_device *ndev,
6993 u8 key_index, bool pairwise,
6994 const u8 *mac_addr, void *cookie,
6995 void (*callback)(void *cookie,
6996 struct key_params *)
6997 )
6998{
6999 int ret;
7000
7001 cds_ssr_protect(__func__);
7002 ret = __wlan_hdd_cfg80211_get_key(wiphy, ndev, key_index, pairwise,
7003 mac_addr, cookie, callback);
7004 cds_ssr_unprotect(__func__);
7005
7006 return ret;
7007}
7008
7009/**
7010 * __wlan_hdd_cfg80211_del_key() - Delete the encryption key for station
7011 * @wiphy: wiphy interface context
7012 * @ndev: pointer to net device
7013 * @key_index: Key index used in 802.11 frames
7014 * @unicast: true if it is unicast key
7015 * @multicast: true if it is multicast key
7016 *
7017 * This function is required for cfg80211_ops API.
7018 * It is used to delete the key information
7019 * Underlying hardware implementation does not have API to delete the
7020 * encryption key. It is automatically deleted when the peer is
7021 * removed. Hence this function currently does nothing.
7022 * Future implementation may interprete delete key operation to
7023 * replacing the key with a random junk value, effectively making it
7024 * useless.
7025 *
7026 * Return: status code, always 0.
7027 */
7028
7029static int __wlan_hdd_cfg80211_del_key(struct wiphy *wiphy,
7030 struct net_device *ndev,
7031 u8 key_index,
7032 bool pairwise, const u8 *mac_addr)
7033{
7034 EXIT();
7035 return 0;
7036}
7037
7038/**
7039 * wlan_hdd_cfg80211_del_key() - cfg80211 delete key handler function
7040 * @wiphy: Pointer to wiphy structure.
7041 * @dev: Pointer to net_device structure.
7042 * @key_index: key index
7043 * @pairwise: pairwise
7044 * @mac_addr: mac address
7045 *
7046 * This is the cfg80211 delete key handler function which invokes
7047 * the internal function @__wlan_hdd_cfg80211_del_key with
7048 * SSR protection.
7049 *
7050 * Return: 0 for success, error number on failure.
7051 */
7052static int wlan_hdd_cfg80211_del_key(struct wiphy *wiphy,
7053 struct net_device *dev,
7054 u8 key_index,
7055 bool pairwise, const u8 *mac_addr)
7056{
7057 int ret;
7058
7059 cds_ssr_protect(__func__);
7060 ret = __wlan_hdd_cfg80211_del_key(wiphy, dev, key_index,
7061 pairwise, mac_addr);
7062 cds_ssr_unprotect(__func__);
7063
7064 return ret;
7065}
7066
7067/*
7068 * FUNCTION: __wlan_hdd_cfg80211_set_default_key
7069 * This function is used to set the default tx key index
7070 */
7071static int __wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy,
7072 struct net_device *ndev,
7073 u8 key_index,
7074 bool unicast, bool multicast)
7075{
7076 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
7077 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
7078 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
7079 hdd_context_t *pHddCtx;
7080 int status;
7081
7082 ENTER();
7083
Peng Xuf5d60c82015-10-02 17:17:03 -07007084 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007085 hddLog(LOGE, FL("Command not allowed in FTM mode"));
7086 return -EINVAL;
7087 }
7088
7089 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
7090 TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY,
7091 pAdapter->sessionId, key_index));
7092
7093 hddLog(LOG1, FL("Device_mode %s(%d) key_index = %d"),
7094 hdd_device_mode_to_string(pAdapter->device_mode),
7095 pAdapter->device_mode, key_index);
7096
7097 if (CSR_MAX_NUM_KEY <= key_index) {
7098 hddLog(LOGE, FL("Invalid key index %d"), key_index);
7099 return -EINVAL;
7100 }
7101
7102 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
7103 status = wlan_hdd_validate_context(pHddCtx);
7104
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307105 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007106 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007107
7108 if ((pAdapter->device_mode == WLAN_HDD_INFRA_STATION) ||
7109 (pAdapter->device_mode == WLAN_HDD_P2P_CLIENT)) {
7110 if ((eCSR_ENCRYPT_TYPE_TKIP !=
7111 pHddStaCtx->conn_info.ucEncryptionType) &&
7112 (eCSR_ENCRYPT_TYPE_AES !=
7113 pHddStaCtx->conn_info.ucEncryptionType)) {
7114 /* If default key index is not same as previous one,
7115 * then update the default key index */
7116
7117 tCsrRoamSetKey setKey;
7118 uint32_t roamId = 0xFF;
7119 tCsrKeys *Keys = &pWextState->roamProfile.Keys;
7120
7121 hddLog(LOG2, FL("Default tx key index %d"), key_index);
7122
7123 Keys->defaultIndex = (u8) key_index;
7124 cdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey));
7125 setKey.keyId = key_index;
7126 setKey.keyLength = Keys->KeyLength[key_index];
7127
7128 cdf_mem_copy(&setKey.Key[0],
7129 &Keys->KeyMaterial[key_index][0],
7130 Keys->KeyLength[key_index]);
7131
7132 setKey.keyDirection = eSIR_TX_RX;
7133
7134 cdf_copy_macaddr(&setKey.peerMac,
7135 &pHddStaCtx->conn_info.bssId);
7136
7137 if (Keys->KeyLength[key_index] == CSR_WEP40_KEY_LEN &&
7138 pWextState->roamProfile.EncryptionType.
7139 encryptionType[0] == eCSR_ENCRYPT_TYPE_WEP104) {
7140 /* In the case of dynamic wep supplicant hardcodes DWEP type
7141 * to eCSR_ENCRYPT_TYPE_WEP104 even though ap is configured for
7142 * WEP-40 encryption. In this canse the key length is 5 but the
7143 * encryption type is 104 hence checking the key langht(5) and
7144 * encryption type(104) and switching encryption type to 40*/
7145 pWextState->roamProfile.EncryptionType.
7146 encryptionType[0] = eCSR_ENCRYPT_TYPE_WEP40;
7147 pWextState->roamProfile.mcEncryptionType.
7148 encryptionType[0] = eCSR_ENCRYPT_TYPE_WEP40;
7149 }
7150
7151 setKey.encType =
7152 pWextState->roamProfile.EncryptionType.
7153 encryptionType[0];
7154
7155 /* Issue set key request */
7156 status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter),
7157 pAdapter->sessionId, &setKey,
7158 &roamId);
7159
7160 if (0 != status) {
7161 hddLog(LOGE,
7162 FL("sme_roam_set_key failed, returned %d"),
7163 status);
7164 return -EINVAL;
7165 }
7166 }
7167 } else if (WLAN_HDD_SOFTAP == pAdapter->device_mode) {
7168 /* In SoftAp mode setting key direction for default mode */
7169 if ((eCSR_ENCRYPT_TYPE_TKIP !=
7170 pWextState->roamProfile.EncryptionType.encryptionType[0])
7171 && (eCSR_ENCRYPT_TYPE_AES !=
7172 pWextState->roamProfile.EncryptionType.
7173 encryptionType[0])) {
7174 /* Saving key direction for default key index to TX default */
7175 hdd_ap_ctx_t *pAPCtx =
7176 WLAN_HDD_GET_AP_CTX_PTR(pAdapter);
7177 pAPCtx->wepKey[key_index].keyDirection =
7178 eSIR_TX_DEFAULT;
7179 }
7180 }
7181
7182 EXIT();
7183 return status;
7184}
7185
7186static int wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy,
7187 struct net_device *ndev,
7188 u8 key_index,
7189 bool unicast, bool multicast)
7190{
7191 int ret;
7192 cds_ssr_protect(__func__);
7193 ret =
7194 __wlan_hdd_cfg80211_set_default_key(wiphy, ndev, key_index, unicast,
7195 multicast);
7196 cds_ssr_unprotect(__func__);
7197
7198 return ret;
7199}
7200
7201/**
7202 * wlan_hdd_cfg80211_update_bss_list() - update bss list to NL80211
7203 * @pAdapter: Pointer to adapter
7204 * @pRoamInfo: Pointer to roam info
7205 *
7206 * Return: struct cfg80211_bss pointer
7207 */
7208struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_list(hdd_adapter_t *pAdapter,
7209 tCsrRoamInfo *pRoamInfo)
7210{
7211 struct net_device *dev = pAdapter->dev;
7212 struct wireless_dev *wdev = dev->ieee80211_ptr;
7213 struct wiphy *wiphy = wdev->wiphy;
7214 tSirBssDescription *pBssDesc = pRoamInfo->pBssDesc;
7215 int chan_no;
7216 unsigned int freq;
7217 struct ieee80211_channel *chan;
7218 struct cfg80211_bss *bss = NULL;
7219
7220 ENTER();
7221
7222 if (NULL == pBssDesc) {
7223 hddLog(LOGE, FL("pBssDesc is NULL"));
7224 return bss;
7225 }
7226
7227 if (NULL == pRoamInfo->pProfile) {
7228 hddLog(LOGE, FL("Roam profile is NULL"));
7229 return bss;
7230 }
7231
7232 chan_no = pBssDesc->channelId;
7233
7234 if (chan_no <= ARRAY_SIZE(hdd_channels_2_4_ghz)) {
7235 freq =
7236 ieee80211_channel_to_frequency(chan_no,
7237 IEEE80211_BAND_2GHZ);
7238 } else {
7239 freq =
7240 ieee80211_channel_to_frequency(chan_no,
7241 IEEE80211_BAND_5GHZ);
7242 }
7243
7244 chan = __ieee80211_get_channel(wiphy, freq);
7245
7246 if (!chan) {
7247 hddLog(LOGE, FL("chan pointer is NULL"));
7248 return NULL;
7249 }
7250
7251 bss = cfg80211_get_bss(wiphy, chan, pBssDesc->bssId,
7252 &pRoamInfo->pProfile->SSIDs.SSIDList->SSID.
7253 ssId[0],
7254 pRoamInfo->pProfile->SSIDs.SSIDList->SSID.length,
7255 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
7256 if (bss == NULL) {
7257 hddLog(LOGE, FL("BSS not present"));
7258 } else {
7259 hddLog(LOG1, FL("cfg80211_unlink_bss called for BSSID "
7260 MAC_ADDRESS_STR),
7261 MAC_ADDR_ARRAY(pBssDesc->bssId));
7262 cfg80211_unlink_bss(wiphy, bss);
7263 }
7264 return bss;
7265}
7266
7267/**
7268 * wlan_hdd_cfg80211_inform_bss_frame() - inform bss details to NL80211
7269 * @pAdapter: Pointer to adapter
7270 * @bss_desc: Pointer to bss descriptor
7271 *
7272 * This function is used to inform the BSS details to nl80211 interface.
7273 *
7274 * Return: struct cfg80211_bss pointer
7275 */
7276static struct cfg80211_bss *
7277wlan_hdd_cfg80211_inform_bss_frame(hdd_adapter_t *pAdapter,
7278 tSirBssDescription *bss_desc)
7279{
7280 /*
7281 * cfg80211_inform_bss() is not updating ie field of bss entry, if entry
7282 * already exists in bss data base of cfg80211 for that particular BSS
7283 * ID. Using cfg80211_inform_bss_frame to update the bss entry instead
7284 * of cfg80211_inform_bss, But this call expects mgmt packet as input.
7285 * As of now there is no possibility to get the mgmt(probe response)
7286 * frame from PE, converting bss_desc to ieee80211_mgmt(probe response)
7287 * and passing to cfg80211_inform_bss_frame.
7288 */
7289 struct net_device *dev = pAdapter->dev;
7290 struct wireless_dev *wdev = dev->ieee80211_ptr;
7291 struct wiphy *wiphy = wdev->wiphy;
7292 int chan_no = bss_desc->channelId;
7293#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS
7294 qcom_ie_age *qie_age = NULL;
7295 int ie_length =
7296 GET_IE_LEN_IN_BSS_DESC(bss_desc->length) + sizeof(qcom_ie_age);
7297#else
7298 int ie_length = GET_IE_LEN_IN_BSS_DESC(bss_desc->length);
7299#endif
7300 const char *ie =
7301 ((ie_length != 0) ? (const char *)&bss_desc->ieFields : NULL);
7302 unsigned int freq;
7303 struct ieee80211_channel *chan;
7304 struct ieee80211_mgmt *mgmt = NULL;
7305 struct cfg80211_bss *bss_status = NULL;
7306 size_t frame_len = sizeof(struct ieee80211_mgmt) + ie_length;
7307 int rssi = 0;
7308 hdd_context_t *pHddCtx;
7309 int status;
7310#ifdef CONFIG_CNSS
7311 struct timespec ts;
7312#endif
Deepak Dhamdhere68929ec2015-08-05 15:16:35 -07007313 struct hdd_config *cfg_param;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007314
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307315 ENTER();
7316
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007317 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
7318 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307319 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007320 return NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007321
Deepak Dhamdhere68929ec2015-08-05 15:16:35 -07007322 cfg_param = pHddCtx->config;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007323 mgmt = kzalloc((sizeof(struct ieee80211_mgmt) + ie_length), GFP_KERNEL);
7324 if (!mgmt) {
7325 hddLog(LOGE, FL("memory allocation failed"));
7326 return NULL;
7327 }
7328
7329 memcpy(mgmt->bssid, bss_desc->bssId, ETH_ALEN);
7330
7331#ifdef CONFIG_CNSS
7332 /* Android does not want the timestamp from the frame.
7333 Instead it wants a monotonic increasing value */
7334 cnss_get_monotonic_boottime(&ts);
7335 mgmt->u.probe_resp.timestamp =
7336 ((u64) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
7337#else
7338 /* keep old behavior for non-open source (for now) */
7339 memcpy(&mgmt->u.probe_resp.timestamp, bss_desc->timeStamp,
7340 sizeof(bss_desc->timeStamp));
7341
7342#endif
7343
7344 mgmt->u.probe_resp.beacon_int = bss_desc->beaconInterval;
7345 mgmt->u.probe_resp.capab_info = bss_desc->capabilityInfo;
7346
7347#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS
7348 /* GPS Requirement: need age ie per entry. Using vendor specific. */
7349 /* Assuming this is the last IE, copy at the end */
7350 ie_length -= sizeof(qcom_ie_age);
7351 qie_age = (qcom_ie_age *) (mgmt->u.probe_resp.variable + ie_length);
7352 qie_age->element_id = QCOM_VENDOR_IE_ID;
7353 qie_age->len = QCOM_VENDOR_IE_AGE_LEN;
7354 qie_age->oui_1 = QCOM_OUI1;
7355 qie_age->oui_2 = QCOM_OUI2;
7356 qie_age->oui_3 = QCOM_OUI3;
7357 qie_age->type = QCOM_VENDOR_IE_AGE_TYPE;
7358 qie_age->age =
7359 cdf_mc_timer_get_system_ticks() - bss_desc->nReceivedTime;
7360 qie_age->tsf_delta = bss_desc->tsf_delta;
7361#endif
7362
7363 memcpy(mgmt->u.probe_resp.variable, ie, ie_length);
7364 if (bss_desc->fProbeRsp) {
7365 mgmt->frame_control |=
7366 (u16) (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP);
7367 } else {
7368 mgmt->frame_control |=
7369 (u16) (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
7370 }
7371
7372 if (chan_no <= ARRAY_SIZE(hdd_channels_2_4_ghz) &&
7373 (wiphy->bands[IEEE80211_BAND_2GHZ] != NULL)) {
7374 freq =
7375 ieee80211_channel_to_frequency(chan_no,
7376 IEEE80211_BAND_2GHZ);
7377 } else if ((chan_no > ARRAY_SIZE(hdd_channels_2_4_ghz))
7378 && (wiphy->bands[IEEE80211_BAND_5GHZ] != NULL)) {
7379 freq =
7380 ieee80211_channel_to_frequency(chan_no,
7381 IEEE80211_BAND_5GHZ);
7382 } else {
7383 hddLog(LOGE, FL("Invalid chan_no %d"), chan_no);
7384 kfree(mgmt);
7385 return NULL;
7386 }
7387
7388 chan = __ieee80211_get_channel(wiphy, freq);
7389 /* When the band is changed on the fly using the GUI, three things are done
7390 * 1. scan abort
7391 * 2. flush scan results from cache
7392 * 3. update the band with the new band user specified (refer to the
7393 * hdd_set_band_helper function) as part of the scan abort, message will be
7394 * queued to PE and we proceed with flushing and changinh the band.
7395 * PE will stop the scanning further and report back the results what ever
7396 * it had till now by calling the call back function.
7397 * if the time between update band and scandone call back is sufficient
7398 * enough the band change reflects in SME, SME validates the channels
7399 * and discards the channels correponding to previous band and calls back
7400 * with zero bss results. but if the time between band update and scan done
7401 * callback is very small then band change will not reflect in SME and SME
7402 * reports to HDD all the channels correponding to previous band.this is due
7403 * to race condition.but those channels are invalid to the new band and so
7404 * this function __ieee80211_get_channel will return NULL.Each time we
7405 * report scan result with this pointer null warning kernel trace is printed.
7406 * if the scan results contain large number of APs continuosly kernel
7407 * warning trace is printed and it will lead to apps watch dog bark.
7408 * So drop the bss and continue to next bss.
7409 */
7410 if (chan == NULL) {
7411 hddLog(LOGE, FL("chan pointer is NULL"));
7412 kfree(mgmt);
7413 return NULL;
7414 }
7415
Deepak Dhamdhere68929ec2015-08-05 15:16:35 -07007416 /* Based on .ini configuration, raw rssi can be reported for bss.
7417 * Raw rssi is typically used for estimating power.
7418 */
7419
7420 rssi = (cfg_param->inform_bss_rssi_raw) ? bss_desc->rssi_raw :
7421 bss_desc->rssi;
7422
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007423 /* Supplicant takes the signal strength in terms of mBm(100*dBm) */
Deepak Dhamdhere68929ec2015-08-05 15:16:35 -07007424 rssi = CDF_MIN(rssi, 0) * 100;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007425
7426 hddLog(LOG1, FL("BSSID: " MAC_ADDRESS_STR " Channel:%d RSSI:%d"),
7427 MAC_ADDR_ARRAY(mgmt->bssid), chan->center_freq,
7428 (int)(rssi / 100));
7429
7430 bss_status =
7431 cfg80211_inform_bss_frame(wiphy, chan, mgmt, frame_len, rssi,
7432 GFP_KERNEL);
7433 kfree(mgmt);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307434 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007435 return bss_status;
7436}
7437
7438/**
7439 * wlan_hdd_cfg80211_update_bss_db() - update bss database of CF80211
7440 * @pAdapter: Pointer to adapter
7441 * @pRoamInfo: Pointer to roam info
7442 *
7443 * This function is used to update the BSS data base of CFG8011
7444 *
7445 * Return: struct cfg80211_bss pointer
7446 */
7447struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter,
7448 tCsrRoamInfo *pRoamInfo)
7449{
7450 tCsrRoamConnectedProfile roamProfile;
7451 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
7452 struct cfg80211_bss *bss = NULL;
7453
7454 ENTER();
7455
7456 memset(&roamProfile, 0, sizeof(tCsrRoamConnectedProfile));
7457 sme_roam_get_connect_profile(hHal, pAdapter->sessionId, &roamProfile);
7458
7459 if (NULL != roamProfile.pBssDesc) {
7460 bss = wlan_hdd_cfg80211_inform_bss_frame(pAdapter,
7461 roamProfile.pBssDesc);
7462
7463 if (NULL == bss)
7464 hddLog(LOG1,
7465 FL("wlan_hdd_cfg80211_inform_bss_frame returned NULL"));
7466
7467 sme_roam_free_connect_profile(hHal, &roamProfile);
7468 } else {
7469 hddLog(LOGE, FL("roamProfile.pBssDesc is NULL"));
7470 }
7471 EXIT();
7472 return bss;
7473}
7474/**
7475 * wlan_hdd_cfg80211_update_bss() - update bss
7476 * @wiphy: Pointer to wiphy
7477 * @pAdapter: Pointer to adapter
7478 * @scan_time: scan request timestamp
7479 *
7480 * Return: zero if success, non-zero otherwise
7481 */
7482int wlan_hdd_cfg80211_update_bss(struct wiphy *wiphy,
7483 hdd_adapter_t *pAdapter,
7484 uint32_t scan_time)
7485{
7486 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
7487 tCsrScanResultInfo *pScanResult;
7488 CDF_STATUS status = 0;
7489 tScanResultHandle pResult;
7490 struct cfg80211_bss *bss_status = NULL;
7491 hdd_context_t *pHddCtx;
7492 int ret;
7493
7494 ENTER();
7495
7496 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
7497 TRACE_CODE_HDD_CFG80211_UPDATE_BSS,
7498 NO_SESSION, pAdapter->sessionId));
7499
7500 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
7501 ret = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307502 if (0 != ret)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007503 return ret;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007504
7505 /* start getting scan results and populate cgf80211 BSS database */
7506 status = sme_scan_get_result(hHal, pAdapter->sessionId, NULL, &pResult);
7507
7508 /* no scan results */
7509 if (NULL == pResult) {
7510 hddLog(LOGE, FL("No scan result Status %d"), status);
7511 return status;
7512 }
7513
7514 pScanResult = sme_scan_result_get_first(hHal, pResult);
7515
7516 while (pScanResult) {
7517 /*
7518 * - cfg80211_inform_bss() is not updating ie field of bss
7519 * entry if entry already exists in bss data base of cfg80211
7520 * for that particular BSS ID. Using cfg80211_inform_bss_frame
7521 * to update thebss entry instead of cfg80211_inform_bss,
7522 * But this call expects mgmt packet as input. As of now
7523 * there is no possibility to get the mgmt(probe response)
7524 * frame from PE, converting bss_desc to
7525 * ieee80211_mgmt(probe response) and passing to c
7526 * fg80211_inform_bss_frame.
7527 * - Update BSS only if beacon timestamp is later than
7528 * scan request timestamp.
7529 */
7530 if ((scan_time == 0) ||
7531 (scan_time <
7532 pScanResult->BssDescriptor.nReceivedTime)) {
7533 bss_status =
7534 wlan_hdd_cfg80211_inform_bss_frame(pAdapter,
7535 &pScanResult->BssDescriptor);
7536
7537 if (NULL == bss_status) {
7538 hdd_info("NULL returned by cfg80211_inform_bss_frame");
7539 } else {
7540 cfg80211_put_bss(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007541 wiphy,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007542 bss_status);
7543 }
7544 } else {
7545 hdd_info("BSSID: " MAC_ADDRESS_STR " Skipped",
7546 MAC_ADDR_ARRAY(pScanResult->BssDescriptor.bssId));
7547 }
7548 pScanResult = sme_scan_result_get_next(hHal, pResult);
7549 }
7550
7551 sme_scan_result_purge(hHal, pResult);
7552 /*
7553 * For SAP mode, scan is invoked by hostapd during SAP start
7554 * if hostapd is restarted, we need to flush previous scan
7555 * result so that it will reflect environment change
7556 */
7557 if (pAdapter->device_mode == WLAN_HDD_SOFTAP
7558#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
7559 && pHddCtx->skip_acs_scan_status != eSAP_SKIP_ACS_SCAN
7560#endif
7561 )
7562 sme_scan_flush_result(hHal);
7563
7564 EXIT();
7565 return 0;
7566}
7567
Amar Singhal01098f72015-10-08 11:55:32 -07007568#ifdef FEATURE_WLAN_LFR
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007569/**
7570 * wlan_hdd_cfg80211_pmksa_candidate_notify() - notify a new PMSKA candidate
7571 * @pAdapter: Pointer to adapter
7572 * @pRoamInfo: Pointer to roam info
7573 * @index: Index
7574 * @preauth: Preauth flag
7575 *
7576 * This function is used to notify the supplicant of a new PMKSA candidate.
7577 *
7578 * Return: 0 for success, non-zero for failure
7579 */
7580int wlan_hdd_cfg80211_pmksa_candidate_notify(hdd_adapter_t *pAdapter,
7581 tCsrRoamInfo *pRoamInfo,
7582 int index, bool preauth)
7583{
7584#ifdef FEATURE_WLAN_OKC
7585 struct net_device *dev = pAdapter->dev;
7586 hdd_context_t *pHddCtx = (hdd_context_t *) pAdapter->pHddCtx;
7587
7588 ENTER();
7589 hddLog(LOG1, FL("is going to notify supplicant of:"));
7590
7591 if (NULL == pRoamInfo) {
7592 hddLog(LOGP, FL("pRoamInfo is NULL"));
7593 return -EINVAL;
7594 }
7595
7596 if (true == hdd_is_okc_mode_enabled(pHddCtx)) {
7597 hddLog(LOG1, MAC_ADDRESS_STR,
7598 MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes));
7599 cfg80211_pmksa_candidate_notify(dev, index,
7600 pRoamInfo->bssid.bytes,
7601 preauth, GFP_KERNEL);
7602 }
7603#endif /* FEATURE_WLAN_OKC */
7604 return 0;
7605}
7606#endif /* FEATURE_WLAN_LFR */
7607
7608#ifdef FEATURE_WLAN_LFR_METRICS
7609/**
7610 * wlan_hdd_cfg80211_roam_metrics_preauth() - roam metrics preauth
7611 * @pAdapter: Pointer to adapter
7612 * @pRoamInfo: Pointer to roam info
7613 *
7614 * 802.11r/LFR metrics reporting function to report preauth initiation
7615 *
7616 * Return: CDF status
7617 */
7618#define MAX_LFR_METRICS_EVENT_LENGTH 100
7619CDF_STATUS wlan_hdd_cfg80211_roam_metrics_preauth(hdd_adapter_t *pAdapter,
7620 tCsrRoamInfo *pRoamInfo)
7621{
7622 unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1];
7623 union iwreq_data wrqu;
7624
7625 ENTER();
7626
7627 if (NULL == pAdapter) {
7628 hddLog(LOGE, FL("pAdapter is NULL!"));
7629 return CDF_STATUS_E_FAILURE;
7630 }
7631
7632 /* create the event */
7633 memset(&wrqu, 0, sizeof(wrqu));
7634 memset(metrics_notification, 0, sizeof(metrics_notification));
7635
7636 wrqu.data.pointer = metrics_notification;
7637 wrqu.data.length = scnprintf(metrics_notification,
7638 sizeof(metrics_notification),
7639 "QCOM: LFR_PREAUTH_INIT " MAC_ADDRESS_STR,
7640 MAC_ADDR_ARRAY(pRoamInfo->bssid));
7641
7642 wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu,
7643 metrics_notification);
7644
7645 EXIT();
7646
7647 return CDF_STATUS_SUCCESS;
7648}
7649
7650/**
7651 * wlan_hdd_cfg80211_roam_metrics_handover() - roam metrics hand over
7652 * @pAdapter: Pointer to adapter
7653 * @pRoamInfo: Pointer to roam info
7654 * @preauth_status: Preauth status
7655 *
7656 * 802.11r/LFR metrics reporting function to report handover initiation
7657 *
7658 * Return: CDF status
7659 */
7660CDF_STATUS
7661wlan_hdd_cfg80211_roam_metrics_preauth_status(hdd_adapter_t *pAdapter,
7662 tCsrRoamInfo *pRoamInfo,
7663 bool preauth_status)
7664{
7665 unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1];
7666 union iwreq_data wrqu;
7667
7668 ENTER();
7669
7670 if (NULL == pAdapter) {
7671 hddLog(LOGE, FL("pAdapter is NULL!"));
7672 return CDF_STATUS_E_FAILURE;
7673 }
7674
7675 /* create the event */
7676 memset(&wrqu, 0, sizeof(wrqu));
7677 memset(metrics_notification, 0, sizeof(metrics_notification));
7678
7679 scnprintf(metrics_notification, sizeof(metrics_notification),
7680 "QCOM: LFR_PREAUTH_STATUS " MAC_ADDRESS_STR,
7681 MAC_ADDR_ARRAY(pRoamInfo->bssid));
7682
7683 if (1 == preauth_status)
7684 strlcat(metrics_notification, " true",
7685 sizeof(metrics_notification));
7686 else
7687 strlcat(metrics_notification, " false",
7688 sizeof(metrics_notification));
7689
7690 wrqu.data.pointer = metrics_notification;
7691 wrqu.data.length = strlen(metrics_notification);
7692
7693 wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu,
7694 metrics_notification);
7695
7696 EXIT();
7697
7698 return CDF_STATUS_SUCCESS;
7699}
7700
7701/**
7702 * wlan_hdd_cfg80211_roam_metrics_handover() - roam metrics hand over
7703 * @pAdapter: Pointer to adapter
7704 * @pRoamInfo: Pointer to roam info
7705 *
7706 * 802.11r/LFR metrics reporting function to report handover initiation
7707 *
7708 * Return: CDF status
7709 */
7710CDF_STATUS wlan_hdd_cfg80211_roam_metrics_handover(hdd_adapter_t *pAdapter,
7711 tCsrRoamInfo *pRoamInfo)
7712{
7713 unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1];
7714 union iwreq_data wrqu;
7715
7716 ENTER();
7717
7718 if (NULL == pAdapter) {
7719 hddLog(LOGE, FL("pAdapter is NULL!"));
7720 return CDF_STATUS_E_FAILURE;
7721 }
7722
7723 /* create the event */
7724 memset(&wrqu, 0, sizeof(wrqu));
7725 memset(metrics_notification, 0, sizeof(metrics_notification));
7726
7727 wrqu.data.pointer = metrics_notification;
7728 wrqu.data.length = scnprintf(metrics_notification,
7729 sizeof(metrics_notification),
7730 "QCOM: LFR_PREAUTH_HANDOVER "
7731 MAC_ADDRESS_STR,
7732 MAC_ADDR_ARRAY(pRoamInfo->bssid));
7733
7734 wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu,
7735 metrics_notification);
7736
7737 EXIT();
7738
7739 return CDF_STATUS_SUCCESS;
7740}
7741#endif
7742
7743/**
7744 * hdd_select_cbmode() - select channel bonding mode
7745 * @pAdapter: Pointer to adapter
7746 * @operatingChannel: Operating channel
7747 *
7748 * Return: none
7749 */
7750void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel)
7751{
7752 uint8_t iniDot11Mode = (WLAN_HDD_GET_CTX(pAdapter))->config->dot11Mode;
7753 eHddDot11Mode hddDot11Mode = iniDot11Mode;
7754 chan_params_t ch_params;
7755 ch_params.ch_width =
7756 (WLAN_HDD_GET_CTX(pAdapter))->config->vhtChannelWidth;
7757
7758 hddLog(LOG1, FL("Channel Bonding Mode Selected is %u"), iniDot11Mode);
7759 switch (iniDot11Mode) {
7760 case eHDD_DOT11_MODE_AUTO:
7761 case eHDD_DOT11_MODE_11ac:
7762 case eHDD_DOT11_MODE_11ac_ONLY:
7763#ifdef WLAN_FEATURE_11AC
7764 if (sme_is_feature_supported_by_fw(DOT11AC))
7765 hddDot11Mode = eHDD_DOT11_MODE_11ac;
7766 else
7767 hddDot11Mode = eHDD_DOT11_MODE_11n;
7768#else
7769 hddDot11Mode = eHDD_DOT11_MODE_11n;
7770#endif
7771 break;
7772 case eHDD_DOT11_MODE_11n:
7773 case eHDD_DOT11_MODE_11n_ONLY:
7774 hddDot11Mode = eHDD_DOT11_MODE_11n;
7775 break;
7776 default:
7777 hddDot11Mode = iniDot11Mode;
7778 break;
7779 }
7780 /* This call decides required channel bonding mode */
7781 sme_set_ch_params((WLAN_HDD_GET_CTX(pAdapter)->hHal),
7782 hdd_cfg_xlate_to_csr_phy_mode(hddDot11Mode),
7783 operationChannel, 0,
7784 &ch_params);
7785}
7786
7787
7788/*
7789 * FUNCTION: wlan_hdd_cfg80211_connect_start
7790 * wlan_hdd_cfg80211_connect_start() - start connection
7791 * @pAdapter: Pointer to adapter
7792 * @ssid: Pointer ot ssid
7793 * @ssid_len: Length of ssid
7794 * @bssid: Pointer to bssid
7795 * @operatingChannel: Operating channel
7796 *
7797 * This function is used to start the association process
7798 *
7799 * Return: 0 for success, non-zero for failure
7800 */
7801int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter,
7802 const u8 *ssid, size_t ssid_len,
7803 const u8 *bssid_hint, const u8 *bssid,
7804 u8 operatingChannel)
7805{
7806 int status = 0;
7807 hdd_wext_state_t *pWextState;
7808 hdd_context_t *pHddCtx;
7809 uint32_t roamId;
7810 tCsrRoamProfile *pRoamProfile;
7811 eCsrAuthType RSNAuthType;
7812 tSmeConfigParams *sme_config;
7813
7814 ENTER();
7815
7816 pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
7817 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
7818
7819 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05307820 if (status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007821 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007822
7823 if (SIR_MAC_MAX_SSID_LENGTH < ssid_len) {
7824 hddLog(LOGE, FL("wrong SSID len"));
7825 return -EINVAL;
7826 }
7827
7828 pRoamProfile = &pWextState->roamProfile;
7829
7830 if (pRoamProfile) {
7831 hdd_station_ctx_t *pHddStaCtx;
7832 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
7833
7834 if (HDD_WMM_USER_MODE_NO_QOS ==
7835 (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) {
7836 /*QoS not enabled in cfg file */
7837 pRoamProfile->uapsd_mask = 0;
7838 } else {
7839 /*QoS enabled, update uapsd mask from cfg file */
7840 pRoamProfile->uapsd_mask =
7841 (WLAN_HDD_GET_CTX(pAdapter))->config->UapsdMask;
7842 }
7843
7844 pRoamProfile->SSIDs.numOfSSIDs = 1;
7845 pRoamProfile->SSIDs.SSIDList->SSID.length = ssid_len;
7846 cdf_mem_zero(pRoamProfile->SSIDs.SSIDList->SSID.ssId,
7847 sizeof(pRoamProfile->SSIDs.SSIDList->SSID.ssId));
7848 cdf_mem_copy((void *)(pRoamProfile->SSIDs.SSIDList->SSID.ssId),
7849 ssid, ssid_len);
7850
7851 if (bssid) {
7852 pRoamProfile->BSSIDs.numOfBSSIDs = 1;
7853 cdf_mem_copy((void *)(pRoamProfile->BSSIDs.bssid),
7854 bssid, CDF_MAC_ADDR_SIZE);
7855 /* Save BSSID in seperate variable as well, as RoamProfile
7856 BSSID is getting zeroed out in the association process. And in
7857 case of join failure we should send valid BSSID to supplicant
7858 */
7859 cdf_mem_copy((void *)(pWextState->req_bssId.bytes),
7860 bssid, CDF_MAC_ADDR_SIZE);
7861 } else if (bssid_hint) {
7862 pRoamProfile->BSSIDs.numOfBSSIDs = 1;
7863 cdf_mem_copy((void *)(pRoamProfile->BSSIDs.bssid),
7864 bssid_hint, CDF_MAC_ADDR_SIZE);
7865 /* Save BSSID in separate variable as well, as
7866 RoamProfile BSSID is getting zeroed out in the
7867 association process. And in case of join failure
7868 we should send valid BSSID to supplicant
7869 */
7870 cdf_mem_copy((void *)(pWextState->req_bssId.bytes),
7871 bssid_hint, CDF_MAC_ADDR_SIZE);
7872 hddLog(LOGW, FL(" bssid_hint "MAC_ADDRESS_STR),
7873 MAC_ADDR_ARRAY(bssid_hint));
7874 } else {
7875 cdf_mem_zero((void *)(pRoamProfile->BSSIDs.bssid),
7876 CDF_MAC_ADDR_SIZE);
7877 }
7878
7879 hddLog(LOG1, FL("Connect to SSID: %.*s operating Channel: %u"),
7880 pRoamProfile->SSIDs.SSIDList->SSID.length,
7881 pRoamProfile->SSIDs.SSIDList->SSID.ssId,
7882 operatingChannel);
7883
7884 if ((IW_AUTH_WPA_VERSION_WPA == pWextState->wpaVersion) ||
7885 (IW_AUTH_WPA_VERSION_WPA2 == pWextState->wpaVersion)) {
7886 /*set gen ie */
7887 hdd_set_genie_to_csr(pAdapter, &RSNAuthType);
7888 /*set auth */
7889 hdd_set_csr_auth_type(pAdapter, RSNAuthType);
7890 }
7891#ifdef FEATURE_WLAN_WAPI
7892 if (pAdapter->wapi_info.nWapiMode) {
7893 hddLog(LOG1,
7894 FL("Setting WAPI AUTH Type and Encryption Mode values"));
7895 switch (pAdapter->wapi_info.wapiAuthMode) {
7896 case WAPI_AUTH_MODE_PSK:
7897 {
7898 hddLog(LOG1,
7899 FL("WAPI AUTH TYPE: PSK: %d"),
7900 pAdapter->wapi_info.wapiAuthMode);
7901 pRoamProfile->AuthType.authType[0] =
7902 eCSR_AUTH_TYPE_WAPI_WAI_PSK;
7903 break;
7904 }
7905 case WAPI_AUTH_MODE_CERT:
7906 {
7907 hddLog(LOG1,
7908 FL("WAPI AUTH TYPE: CERT: %d"),
7909 pAdapter->wapi_info.wapiAuthMode);
7910 pRoamProfile->AuthType.authType[0] =
7911 eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE;
7912 break;
7913 }
7914 } /* End of switch */
7915 if (pAdapter->wapi_info.wapiAuthMode ==
7916 WAPI_AUTH_MODE_PSK
7917 || pAdapter->wapi_info.wapiAuthMode ==
7918 WAPI_AUTH_MODE_CERT) {
7919 hddLog(LOG1,
7920 FL("WAPI PAIRWISE/GROUP ENCRYPTION: WPI"));
7921 pRoamProfile->AuthType.numEntries = 1;
7922 pRoamProfile->EncryptionType.numEntries = 1;
7923 pRoamProfile->EncryptionType.encryptionType[0] =
7924 eCSR_ENCRYPT_TYPE_WPI;
7925 pRoamProfile->mcEncryptionType.numEntries = 1;
7926 pRoamProfile->mcEncryptionType.
7927 encryptionType[0] = eCSR_ENCRYPT_TYPE_WPI;
7928 }
7929 }
7930#endif /* FEATURE_WLAN_WAPI */
7931#ifdef WLAN_FEATURE_GTK_OFFLOAD
7932 /* Initializing gtkOffloadReqParams */
7933 if ((WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
7934 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) {
7935 memset(&pHddStaCtx->gtkOffloadReqParams, 0,
7936 sizeof(tSirGtkOffloadParams));
7937 pHddStaCtx->gtkOffloadReqParams.ulFlags =
7938 GTK_OFFLOAD_DISABLE;
7939 }
7940#endif
7941 pRoamProfile->csrPersona = pAdapter->device_mode;
7942
7943 if (operatingChannel) {
7944 pRoamProfile->ChannelInfo.ChannelList =
7945 &operatingChannel;
7946 pRoamProfile->ChannelInfo.numOfChannels = 1;
7947 } else {
7948 pRoamProfile->ChannelInfo.ChannelList = NULL;
7949 pRoamProfile->ChannelInfo.numOfChannels = 0;
7950 }
7951 if ((WLAN_HDD_IBSS == pAdapter->device_mode)
7952 && operatingChannel) {
7953 /*
7954 * Need to post the IBSS power save parameters
7955 * to WMA. WMA will configure this parameters
7956 * to firmware if power save is enabled by the
7957 * firmware.
7958 */
7959 status = hdd_set_ibss_power_save_params(pAdapter);
7960
7961 if (CDF_STATUS_SUCCESS != status) {
7962 hddLog(LOGE,
7963 FL("Set IBSS Power Save Params Failed"));
7964 return -EINVAL;
7965 }
7966 hdd_select_cbmode(pAdapter, operatingChannel);
7967 }
7968
7969 if (pHddCtx->config->policy_manager_enabled &&
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08007970 (true == cds_is_connection_in_progress())) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08007971 hdd_err("Connection refused: conn in progress");
7972 return -EINVAL;
7973 }
7974
7975 /* change conn_state to connecting before sme_roam_connect(), because sme_roam_connect()
7976 * has a direct path to call hdd_sme_roam_callback(), which will change the conn_state
7977 * If direct path, conn_state will be accordingly changed to NotConnected or Associated
7978 * by either hdd_association_completion_handler() or hdd_dis_connect_handler() in sme_RoamCallback()
7979 * if sme_RomConnect is to be queued, Connecting state will remain until it is completed.
7980 */
7981 if (WLAN_HDD_INFRA_STATION == pAdapter->device_mode ||
7982 WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) {
7983 hddLog(LOG1,
7984 FL("Set HDD connState to eConnectionState_Connecting"));
7985 hdd_conn_set_connection_state(pAdapter,
7986 eConnectionState_Connecting);
7987 }
7988
7989 /* After 8-way handshake supplicant should give the scan command
7990 * in that it update the additional IEs, But because of scan
7991 * enhancements, the supplicant is not issuing the scan command now.
7992 * So the unicast frames which are sent from the host are not having
7993 * the additional IEs. If it is P2P CLIENT and there is no additional
7994 * IE present in roamProfile, then use the addtional IE form scan_info
7995 */
7996
7997 if ((pAdapter->device_mode == WLAN_HDD_P2P_CLIENT) &&
7998 (!pRoamProfile->pAddIEScan)) {
7999 pRoamProfile->pAddIEScan =
8000 &pAdapter->scan_info.scanAddIE.addIEdata[0];
8001 pRoamProfile->nAddIEScanLength =
8002 pAdapter->scan_info.scanAddIE.length;
8003 }
8004 /*
8005 * When policy manager is enabled from ini file, we shouldn't
8006 * check for other concurrency rules.
8007 */
8008 if (!pHddCtx->config->policy_manager_enabled) {
Tushnim Bhattacharyya4adb3682016-01-07 15:07:12 -08008009 cds_handle_conc_rule1(pAdapter, pRoamProfile);
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08008010 if (true != cds_handle_conc_rule2(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008011 pAdapter, pRoamProfile, &roamId))
8012 return 0;
8013 }
8014
8015 sme_config = cdf_mem_malloc(sizeof(*sme_config));
8016 if (!sme_config) {
8017 hdd_err("unable to allocate sme_config");
8018 return -ENOMEM;
8019 }
8020 cdf_mem_zero(sme_config, sizeof(*sme_config));
8021 sme_get_config_param(pHddCtx->hHal, sme_config);
8022 /* These values are not sessionized. So, any change in these SME
8023 * configs on an older or parallel interface will affect the
8024 * cb mode. So, restoring the default INI params before starting
8025 * interfaces such as sta, cli etc.,
8026 */
8027 sme_config->csrConfig.channelBondingMode5GHz =
8028 pHddCtx->config->nChannelBondingMode5GHz;
8029 sme_config->csrConfig.channelBondingMode24GHz =
8030 pHddCtx->config->nChannelBondingMode24GHz;
8031 sme_update_config(pHddCtx->hHal, sme_config);
8032 cdf_mem_free(sme_config);
8033
8034 status = sme_roam_connect(WLAN_HDD_GET_HAL_CTX(pAdapter),
8035 pAdapter->sessionId, pRoamProfile,
8036 &roamId);
8037
8038 if ((CDF_STATUS_SUCCESS != status) &&
8039 (WLAN_HDD_INFRA_STATION == pAdapter->device_mode ||
8040 WLAN_HDD_P2P_CLIENT == pAdapter->device_mode)) {
8041 hddLog(LOGE,
8042 FL("sme_roam_connect (session %d) failed with "
8043 "status %d. -> NotConnected"),
8044 pAdapter->sessionId, status);
8045 /* change back to NotAssociated */
8046 hdd_conn_set_connection_state(pAdapter,
8047 eConnectionState_NotConnected);
8048 }
8049
8050 pRoamProfile->ChannelInfo.ChannelList = NULL;
8051 pRoamProfile->ChannelInfo.numOfChannels = 0;
8052
8053 } else {
8054 hddLog(LOGE, FL("No valid Roam profile"));
8055 return -EINVAL;
8056 }
8057 EXIT();
8058 return status;
8059}
8060
8061/**
8062 * wlan_hdd_cfg80211_set_auth_type() - set auth type
8063 * @pAdapter: Pointer to adapter
8064 * @auth_type: Auth type
8065 *
8066 * This function is used to set the authentication type (OPEN/SHARED).
8067 *
8068 * Return: 0 for success, non-zero for failure
8069 */
8070static int wlan_hdd_cfg80211_set_auth_type(hdd_adapter_t *pAdapter,
8071 enum nl80211_auth_type auth_type)
8072{
8073 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
8074 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
8075
8076 ENTER();
8077
8078 /*set authentication type */
8079 switch (auth_type) {
8080 case NL80211_AUTHTYPE_AUTOMATIC:
8081 hddLog(LOG1,
8082 FL("set authentication type to AUTOSWITCH"));
8083 pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_AUTOSWITCH;
8084 break;
8085
8086 case NL80211_AUTHTYPE_OPEN_SYSTEM:
8087#ifdef WLAN_FEATURE_VOWIFI_11R
8088 case NL80211_AUTHTYPE_FT:
8089#endif /* WLAN_FEATURE_VOWIFI_11R */
8090 hddLog(LOG1,
8091 FL("set authentication type to OPEN"));
8092 pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM;
8093 break;
8094
8095 case NL80211_AUTHTYPE_SHARED_KEY:
8096 hddLog(LOG1,
8097 FL("set authentication type to SHARED"));
8098 pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_SHARED_KEY;
8099 break;
8100#ifdef FEATURE_WLAN_ESE
8101 case NL80211_AUTHTYPE_NETWORK_EAP:
8102 hddLog(LOG1,
8103 FL("set authentication type to CCKM WPA"));
8104 pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_CCKM_WPA;
8105 break;
8106#endif
8107
8108 default:
8109 hddLog(LOGE,
8110 FL("Unsupported authentication type %d"), auth_type);
8111 pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_UNKNOWN;
8112 return -EINVAL;
8113 }
8114
8115 pWextState->roamProfile.AuthType.authType[0] =
8116 pHddStaCtx->conn_info.authType;
8117 return 0;
8118}
8119
8120/**
8121 * wlan_hdd_set_akm_suite() - set key management type
8122 * @pAdapter: Pointer to adapter
8123 * @key_mgmt: Key management type
8124 *
8125 * This function is used to set the key mgmt type(PSK/8021x).
8126 *
8127 * Return: 0 for success, non-zero for failure
8128 */
8129static int wlan_hdd_set_akm_suite(hdd_adapter_t *pAdapter, u32 key_mgmt)
8130{
8131 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
8132
8133 ENTER();
8134
8135#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
8136#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
8137 /*set key mgmt type */
8138 switch (key_mgmt) {
8139 case WLAN_AKM_SUITE_PSK:
8140 case WLAN_AKM_SUITE_PSK_SHA256:
8141#ifdef WLAN_FEATURE_VOWIFI_11R
8142 case WLAN_AKM_SUITE_FT_PSK:
8143#endif
8144 hddLog(LOG1, FL("setting key mgmt type to PSK"));
8145 pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_PSK;
8146 break;
8147
8148 case WLAN_AKM_SUITE_8021X_SHA256:
8149 case WLAN_AKM_SUITE_8021X:
8150#ifdef WLAN_FEATURE_VOWIFI_11R
8151 case WLAN_AKM_SUITE_FT_8021X:
8152#endif
8153 hddLog(LOG1,
8154 FL("setting key mgmt type to 8021x"));
8155 pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X;
8156 break;
8157#ifdef FEATURE_WLAN_ESE
8158#define WLAN_AKM_SUITE_CCKM 0x00409600 /* Should be in ieee802_11_defs.h */
8159#define IW_AUTH_KEY_MGMT_CCKM 8 /* Should be in linux/wireless.h */
8160 case WLAN_AKM_SUITE_CCKM:
8161 hddLog(LOG1,
8162 FL("setting key mgmt type to CCKM"));
8163 pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_CCKM;
8164 break;
8165#endif
8166#ifndef WLAN_AKM_SUITE_OSEN
8167#define WLAN_AKM_SUITE_OSEN 0x506f9a01 /* Should be in ieee802_11_defs.h */
8168#endif
8169 case WLAN_AKM_SUITE_OSEN:
8170 hddLog(LOG1,
8171 FL("setting key mgmt type to OSEN"));
8172 pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X;
8173 break;
8174
8175 default:
8176 hddLog(LOGE,
8177 FL("Unsupported key mgmt type %d"), key_mgmt);
8178 return -EINVAL;
8179
8180 }
8181 return 0;
8182}
8183
8184/**
8185 * wlan_hdd_cfg80211_set_cipher() - set encryption type
8186 * @pAdapter: Pointer to adapter
8187 * @cipher: Cipher type
8188 * @ucast: Unicast flag
8189 *
8190 * This function is used to set the encryption type
8191 * (NONE/WEP40/WEP104/TKIP/CCMP).
8192 *
8193 * Return: 0 for success, non-zero for failure
8194 */
8195static int wlan_hdd_cfg80211_set_cipher(hdd_adapter_t *pAdapter,
8196 u32 cipher, bool ucast)
8197{
8198 eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE;
8199 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
8200 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
8201
8202 ENTER();
8203
8204 if (!cipher) {
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08008205 hdd_info("received cipher %d - considering none", cipher);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008206 encryptionType = eCSR_ENCRYPT_TYPE_NONE;
8207 } else {
8208
8209 /*set encryption method */
8210 switch (cipher) {
8211 case IW_AUTH_CIPHER_NONE:
8212 encryptionType = eCSR_ENCRYPT_TYPE_NONE;
8213 break;
8214
8215 case WLAN_CIPHER_SUITE_WEP40:
8216 encryptionType = eCSR_ENCRYPT_TYPE_WEP40;
8217 break;
8218
8219 case WLAN_CIPHER_SUITE_WEP104:
8220 encryptionType = eCSR_ENCRYPT_TYPE_WEP104;
8221 break;
8222
8223 case WLAN_CIPHER_SUITE_TKIP:
8224 encryptionType = eCSR_ENCRYPT_TYPE_TKIP;
8225 break;
8226
8227 case WLAN_CIPHER_SUITE_CCMP:
8228 encryptionType = eCSR_ENCRYPT_TYPE_AES;
8229 break;
8230#ifdef FEATURE_WLAN_WAPI
8231 case WLAN_CIPHER_SUITE_SMS4:
8232 encryptionType = eCSR_ENCRYPT_TYPE_WPI;
8233 break;
8234#endif
8235
8236#ifdef FEATURE_WLAN_ESE
8237 case WLAN_CIPHER_SUITE_KRK:
8238 encryptionType = eCSR_ENCRYPT_TYPE_KRK;
8239 break;
8240#ifdef WLAN_FEATURE_ROAM_OFFLOAD
8241 case WLAN_CIPHER_SUITE_BTK:
8242 encryptionType = eCSR_ENCRYPT_TYPE_BTK;
8243 break;
8244#endif
8245#endif
8246 default:
8247 hddLog(LOGE,
8248 FL("Unsupported cipher type %d"), cipher);
8249 return -EOPNOTSUPP;
8250 }
8251 }
8252
8253 if (ucast) {
8254 hddLog(LOG1,
8255 FL("setting unicast cipher type to %d"), encryptionType);
8256 pHddStaCtx->conn_info.ucEncryptionType = encryptionType;
8257 pWextState->roamProfile.EncryptionType.numEntries = 1;
8258 pWextState->roamProfile.EncryptionType.encryptionType[0] =
8259 encryptionType;
8260 } else {
8261 hddLog(LOG1,
8262 FL("setting mcast cipher type to %d"), encryptionType);
8263 pHddStaCtx->conn_info.mcEncryptionType = encryptionType;
8264 pWextState->roamProfile.mcEncryptionType.numEntries = 1;
8265 pWextState->roamProfile.mcEncryptionType.encryptionType[0] =
8266 encryptionType;
8267 }
8268
8269 return 0;
8270}
8271
8272/**
8273 * wlan_hdd_cfg80211_set_ie() - set IEs
8274 * @pAdapter: Pointer to adapter
8275 * @ie: Pointer ot ie
8276 * @ie: IE length
8277 *
8278 * Return: 0 for success, non-zero for failure
8279 */
8280int wlan_hdd_cfg80211_set_ie(hdd_adapter_t *pAdapter, const uint8_t *ie,
8281 size_t ie_len)
8282{
8283 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
8284 const uint8_t *genie = ie;
8285 uint16_t remLen = ie_len;
8286#ifdef FEATURE_WLAN_WAPI
8287 uint32_t akmsuite[MAX_NUM_AKM_SUITES];
8288 u16 *tmp;
8289 uint16_t akmsuiteCount;
8290 int *akmlist;
8291#endif
8292 ENTER();
8293
8294 /* clear previous assocAddIE */
8295 pWextState->assocAddIE.length = 0;
8296 pWextState->roamProfile.bWPSAssociation = false;
8297 pWextState->roamProfile.bOSENAssociation = false;
8298
8299 while (remLen >= 2) {
8300 uint16_t eLen = 0;
8301 uint8_t elementId;
8302 elementId = *genie++;
8303 eLen = *genie++;
8304 remLen -= 2;
8305
8306 hddLog(LOG1, FL("IE[0x%X], LEN[%d]"), elementId, eLen);
8307
8308 switch (elementId) {
8309 case DOT11F_EID_WPA:
8310 if (4 > eLen) { /* should have at least OUI which is 4 bytes so extra 2 bytes not needed */
8311 hddLog(LOGE, FL("Invalid WPA IE"));
8312 return -EINVAL;
8313 } else if (0 ==
8314 memcmp(&genie[0], "\x00\x50\xf2\x04", 4)) {
8315 uint16_t curAddIELen =
8316 pWextState->assocAddIE.length;
8317 hddLog(LOG1,
8318 FL("Set WPS IE(len %d)"), eLen + 2);
8319
8320 if (SIR_MAC_MAX_ADD_IE_LENGTH <
8321 (pWextState->assocAddIE.length + eLen)) {
8322 hddLog(LOGE,
8323 FL("Cannot accommodate assocAddIE. Need bigger buffer space"));
8324 CDF_ASSERT(0);
8325 return -ENOMEM;
8326 }
8327 /* WSC IE is saved to Additional IE ; it should be accumulated to handle WPS IE + P2P IE */
8328 memcpy(pWextState->assocAddIE.addIEdata +
8329 curAddIELen, genie - 2, eLen + 2);
8330 pWextState->assocAddIE.length += eLen + 2;
8331
8332 pWextState->roamProfile.bWPSAssociation = true;
8333 pWextState->roamProfile.pAddIEAssoc =
8334 pWextState->assocAddIE.addIEdata;
8335 pWextState->roamProfile.nAddIEAssocLength =
8336 pWextState->assocAddIE.length;
8337 } else if (0 == memcmp(&genie[0], "\x00\x50\xf2", 3)) {
8338 hddLog(LOG1,
8339 FL("Set WPA IE (len %d)"), eLen + 2);
8340 memset(pWextState->WPARSNIE, 0,
8341 MAX_WPA_RSN_IE_LEN);
8342 memcpy(pWextState->WPARSNIE, genie - 2,
8343 (eLen + 2));
8344 pWextState->roamProfile.pWPAReqIE =
8345 pWextState->WPARSNIE;
8346 pWextState->roamProfile.nWPAReqIELength = eLen + 2; /* ie_len; */
8347 } else if ((0 == memcmp(&genie[0], P2P_OUI_TYPE,
8348 P2P_OUI_TYPE_SIZE))) {
8349 uint16_t curAddIELen =
8350 pWextState->assocAddIE.length;
8351 hddLog(LOG1,
8352 FL("Set P2P IE(len %d)"), eLen + 2);
8353
8354 if (SIR_MAC_MAX_ADD_IE_LENGTH <
8355 (pWextState->assocAddIE.length + eLen)) {
8356 hddLog(LOGE,
8357 FL("Cannot accommodate assocAddIE Need bigger buffer space"));
8358 CDF_ASSERT(0);
8359 return -ENOMEM;
8360 }
8361 /* P2P IE is saved to Additional IE ; it should be accumulated to handle WPS IE + P2P IE */
8362 memcpy(pWextState->assocAddIE.addIEdata +
8363 curAddIELen, genie - 2, eLen + 2);
8364 pWextState->assocAddIE.length += eLen + 2;
8365
8366 pWextState->roamProfile.pAddIEAssoc =
8367 pWextState->assocAddIE.addIEdata;
8368 pWextState->roamProfile.nAddIEAssocLength =
8369 pWextState->assocAddIE.length;
8370 }
8371#ifdef WLAN_FEATURE_WFD
8372 else if ((0 == memcmp(&genie[0], WFD_OUI_TYPE,
8373 WFD_OUI_TYPE_SIZE)) &&
8374 /* Consider WFD IE, only for P2P Client */
8375 (WLAN_HDD_P2P_CLIENT ==
8376 pAdapter->device_mode)) {
8377 uint16_t curAddIELen =
8378 pWextState->assocAddIE.length;
8379 hddLog(LOG1,
8380 FL("Set WFD IE(len %d)"), eLen + 2);
8381
8382 if (SIR_MAC_MAX_ADD_IE_LENGTH <
8383 (pWextState->assocAddIE.length + eLen)) {
8384 hddLog(LOGE,
8385 FL("Cannot accommodate assocAddIE Need bigger buffer space"));
8386 CDF_ASSERT(0);
8387 return -ENOMEM;
8388 }
8389 /* WFD IE is saved to Additional IE ; it should
8390 * be accumulated to handle WPS IE + P2P IE +
8391 * WFD IE */
8392 memcpy(pWextState->assocAddIE.addIEdata +
8393 curAddIELen, genie - 2, eLen + 2);
8394 pWextState->assocAddIE.length += eLen + 2;
8395
8396 pWextState->roamProfile.pAddIEAssoc =
8397 pWextState->assocAddIE.addIEdata;
8398 pWextState->roamProfile.nAddIEAssocLength =
8399 pWextState->assocAddIE.length;
8400 }
8401#endif
8402 /* Appending HS 2.0 Indication Element in Assiciation Request */
8403 else if ((0 == memcmp(&genie[0], HS20_OUI_TYPE,
8404 HS20_OUI_TYPE_SIZE))) {
8405 uint16_t curAddIELen =
8406 pWextState->assocAddIE.length;
8407 hddLog(LOG1,
8408 FL("Set HS20 IE(len %d)"), eLen + 2);
8409
8410 if (SIR_MAC_MAX_ADD_IE_LENGTH <
8411 (pWextState->assocAddIE.length + eLen)) {
8412 hddLog(LOGE,
8413 FL("Cannot accommodate assocAddIE Need bigger buffer space"));
8414 CDF_ASSERT(0);
8415 return -ENOMEM;
8416 }
8417 memcpy(pWextState->assocAddIE.addIEdata +
8418 curAddIELen, genie - 2, eLen + 2);
8419 pWextState->assocAddIE.length += eLen + 2;
8420
8421 pWextState->roamProfile.pAddIEAssoc =
8422 pWextState->assocAddIE.addIEdata;
8423 pWextState->roamProfile.nAddIEAssocLength =
8424 pWextState->assocAddIE.length;
8425 }
8426 /* Appending OSEN Information Element in Assiciation Request */
8427 else if ((0 == memcmp(&genie[0], OSEN_OUI_TYPE,
8428 OSEN_OUI_TYPE_SIZE))) {
8429 uint16_t curAddIELen =
8430 pWextState->assocAddIE.length;
8431 hddLog(LOG1,
8432 FL("Set OSEN IE(len %d)"), eLen + 2);
8433
8434 if (SIR_MAC_MAX_ADD_IE_LENGTH <
8435 (pWextState->assocAddIE.length + eLen)) {
8436 hddLog(LOGE,
8437 FL("Cannot accommodate assocAddIE Need bigger buffer space"));
8438 CDF_ASSERT(0);
8439 return -ENOMEM;
8440 }
8441 memcpy(pWextState->assocAddIE.addIEdata +
8442 curAddIELen, genie - 2, eLen + 2);
8443 pWextState->assocAddIE.length += eLen + 2;
8444
8445 pWextState->roamProfile.bOSENAssociation = true;
8446 pWextState->roamProfile.pAddIEAssoc =
8447 pWextState->assocAddIE.addIEdata;
8448 pWextState->roamProfile.nAddIEAssocLength =
8449 pWextState->assocAddIE.length;
8450 } else {
8451 uint16_t add_ie_len =
8452 pWextState->assocAddIE.length;
8453
8454 hdd_info("Set OSEN IE(len %d)", eLen + 2);
8455
8456 if (SIR_MAC_MAX_ADD_IE_LENGTH <
8457 (pWextState->assocAddIE.length + eLen)) {
8458 hdd_err("Cannot accommodate assocAddIE Need bigger buffer space");
8459 CDF_ASSERT(0);
8460 return -ENOMEM;
8461 }
8462
8463 memcpy(pWextState->assocAddIE.addIEdata +
8464 add_ie_len, genie - 2, eLen + 2);
8465 pWextState->assocAddIE.length += eLen + 2;
8466
8467 pWextState->roamProfile.pAddIEAssoc =
8468 pWextState->assocAddIE.addIEdata;
8469 pWextState->roamProfile.nAddIEAssocLength =
8470 pWextState->assocAddIE.length;
8471 }
8472 break;
8473 case DOT11F_EID_RSN:
8474 hddLog(LOG1, FL("Set RSN IE(len %d)"), eLen + 2);
8475 memset(pWextState->WPARSNIE, 0, MAX_WPA_RSN_IE_LEN);
8476 memcpy(pWextState->WPARSNIE, genie - 2,
8477 (eLen + 2));
8478 pWextState->roamProfile.pRSNReqIE =
8479 pWextState->WPARSNIE;
8480 pWextState->roamProfile.nRSNReqIELength = eLen + 2; /* ie_len; */
8481 break;
8482 /*
8483 * Appending Extended Capabilities with Interworking bit set
8484 * in Assoc Req.
8485 *
8486 * In assoc req this EXT Cap will only be taken into account if
8487 * interworkingService bit is set to 1. Currently
8488 * driver is only interested in interworkingService capability
8489 * from supplicant. If in future any other EXT Cap info is
8490 * required from supplicat, it needs to be handled while
8491 * sending Assoc Req in LIM.
8492 */
8493 case DOT11F_EID_EXTCAP:
8494 {
8495 uint16_t curAddIELen =
8496 pWextState->assocAddIE.length;
8497 hddLog(LOG1,
8498 FL("Set Extended CAPS IE(len %d)"), eLen + 2);
8499
8500 if (SIR_MAC_MAX_ADD_IE_LENGTH <
8501 (pWextState->assocAddIE.length + eLen)) {
8502 hddLog(LOGE, FL("Cannot accommodate assocAddIE Need bigger buffer space"));
8503 CDF_ASSERT(0);
8504 return -ENOMEM;
8505 }
8506 memcpy(pWextState->assocAddIE.addIEdata +
8507 curAddIELen, genie - 2, eLen + 2);
8508 pWextState->assocAddIE.length += eLen + 2;
8509
8510 pWextState->roamProfile.pAddIEAssoc =
8511 pWextState->assocAddIE.addIEdata;
8512 pWextState->roamProfile.nAddIEAssocLength =
8513 pWextState->assocAddIE.length;
8514 break;
8515 }
8516#ifdef FEATURE_WLAN_WAPI
8517 case WLAN_EID_WAPI:
8518 /* Setting WAPI Mode to ON=1 */
8519 pAdapter->wapi_info.nWapiMode = 1;
8520 hddLog(LOG1,
8521 FL("WAPI MODE IS %u"), pAdapter->wapi_info.nWapiMode);
8522 tmp = (u16 *) ie;
8523 tmp = tmp + 2; /* Skip element Id and Len, Version */
8524 akmsuiteCount = WPA_GET_LE16(tmp);
8525 tmp = tmp + 1;
8526 akmlist = (int *)(tmp);
8527 if (akmsuiteCount <= MAX_NUM_AKM_SUITES) {
8528 memcpy(akmsuite, akmlist, (4 * akmsuiteCount));
8529 } else {
8530 hddLog(LOGE,
8531 FL("Invalid akmSuite count"));
8532 CDF_ASSERT(0);
8533 return -EINVAL;
8534 }
8535
8536 if (WAPI_PSK_AKM_SUITE == akmsuite[0]) {
8537 hddLog(LOG1,
8538 FL("WAPI AUTH MODE SET TO PSK"));
8539 pAdapter->wapi_info.wapiAuthMode =
8540 WAPI_AUTH_MODE_PSK;
8541 }
8542 if (WAPI_CERT_AKM_SUITE == akmsuite[0]) {
8543 hddLog(LOG1,
8544 FL("WAPI AUTH MODE SET TO CERTIFICATE"));
8545 pAdapter->wapi_info.wapiAuthMode =
8546 WAPI_AUTH_MODE_CERT;
8547 }
8548 break;
8549#endif
8550 default:
8551 hddLog(LOGE,
8552 FL("Set UNKNOWN IE %X"), elementId);
8553 /* when Unknown IE is received we should break and continue
8554 * to the next IE in the buffer instead we were returning
8555 * so changing this to break */
8556 break;
8557 }
8558 genie += eLen;
8559 remLen -= eLen;
8560 }
8561 EXIT();
8562 return 0;
8563}
8564
8565/**
8566 * hdd_is_wpaie_present() - check for WPA ie
8567 * @ie: Pointer to ie
8568 * @ie_len: Ie length
8569 *
8570 * Parse the received IE to find the WPA IE
8571 *
8572 * Return: true if wpa ie is found else false
8573 */
8574static bool hdd_is_wpaie_present(const uint8_t *ie, uint8_t ie_len)
8575{
8576 uint8_t eLen = 0;
8577 uint16_t remLen = ie_len;
8578 uint8_t elementId = 0;
8579
8580 while (remLen >= 2) {
8581 elementId = *ie++;
8582 eLen = *ie++;
8583 remLen -= 2;
8584 if (eLen > remLen) {
8585 hddLog(CDF_TRACE_LEVEL_ERROR,
8586 "%s: IE length is wrong %d", __func__, eLen);
8587 return false;
8588 }
8589 if ((elementId == DOT11F_EID_WPA) && (remLen > 5)) {
8590 /* OUI - 0x00 0X50 0XF2
8591 * WPA Information Element - 0x01
8592 * WPA version - 0x01
8593 */
8594 if (0 == memcmp(&ie[0], "\x00\x50\xf2\x01\x01", 5))
8595 return true;
8596 }
8597 ie += eLen;
8598 remLen -= eLen;
8599 }
8600 return false;
8601}
8602
8603/**
8604 * wlan_hdd_cfg80211_set_privacy() - set security parameters during connection
8605 * @pAdapter: Pointer to adapter
8606 * @req: Pointer to security parameters
8607 *
8608 * Return: 0 for success, non-zero for failure
8609 */
8610int wlan_hdd_cfg80211_set_privacy(hdd_adapter_t *pAdapter,
8611 struct cfg80211_connect_params *req)
8612{
8613 int status = 0;
8614 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
8615 ENTER();
8616
8617 /*set wpa version */
8618 pWextState->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED;
8619
8620 if (req->crypto.wpa_versions) {
8621 if (NL80211_WPA_VERSION_1 == req->crypto.wpa_versions) {
8622 pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA;
8623 } else if (NL80211_WPA_VERSION_2 == req->crypto.wpa_versions) {
8624 pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA2;
8625 }
8626 }
8627
8628 hddLog(LOG1, FL("set wpa version to %d"), pWextState->wpaVersion);
8629
8630 /*set authentication type */
8631 status = wlan_hdd_cfg80211_set_auth_type(pAdapter, req->auth_type);
8632
8633 if (0 > status) {
8634 hddLog(LOGE, FL("failed to set authentication type "));
8635 return status;
8636 }
8637
8638 /*set key mgmt type */
8639 if (req->crypto.n_akm_suites) {
8640 status =
8641 wlan_hdd_set_akm_suite(pAdapter, req->crypto.akm_suites[0]);
8642 if (0 > status) {
8643 hddLog(LOGE, FL("failed to set akm suite"));
8644 return status;
8645 }
8646 }
8647
8648 /*set pairwise cipher type */
8649 if (req->crypto.n_ciphers_pairwise) {
8650 status = wlan_hdd_cfg80211_set_cipher(pAdapter,
8651 req->crypto.
8652 ciphers_pairwise[0],
8653 true);
8654 if (0 > status) {
8655 hddLog(LOGE, FL("failed to set unicast cipher type"));
8656 return status;
8657 }
8658 } else {
8659 /*Reset previous cipher suite to none */
8660 status = wlan_hdd_cfg80211_set_cipher(pAdapter, 0, true);
8661 if (0 > status) {
8662 hddLog(LOGE, FL("failed to set unicast cipher type"));
8663 return status;
8664 }
8665 }
8666
8667 /*set group cipher type */
8668 status =
8669 wlan_hdd_cfg80211_set_cipher(pAdapter, req->crypto.cipher_group,
8670 false);
8671
8672 if (0 > status) {
8673 hddLog(LOGE, FL("failed to set mcast cipher type"));
8674 return status;
8675 }
8676#ifdef WLAN_FEATURE_11W
8677 pWextState->roamProfile.MFPEnabled = (req->mfp == NL80211_MFP_REQUIRED);
8678#endif
8679
8680 /*parse WPA/RSN IE, and set the correspoing fileds in Roam profile */
8681 if (req->ie_len) {
8682 status =
8683 wlan_hdd_cfg80211_set_ie(pAdapter, req->ie, req->ie_len);
8684 if (0 > status) {
8685 hddLog(LOGE, FL("failed to parse the WPA/RSN IE"));
8686 return status;
8687 }
8688 }
8689
8690 /*incase of WEP set default key information */
8691 if (req->key && req->key_len) {
8692 if ((WLAN_CIPHER_SUITE_WEP40 == req->crypto.ciphers_pairwise[0])
8693 || (WLAN_CIPHER_SUITE_WEP104 ==
8694 req->crypto.ciphers_pairwise[0])
8695 ) {
8696 if (IW_AUTH_KEY_MGMT_802_1X
8697 ==
8698 (pWextState->
8699 authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) {
8700 hddLog(LOGE,
8701 FL("Dynamic WEP not supported"));
8702 return -EOPNOTSUPP;
8703 } else {
8704 u8 key_len = req->key_len;
8705 u8 key_idx = req->key_idx;
8706
8707 if ((eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES >=
8708 key_len)
8709 && (CSR_MAX_NUM_KEY > key_idx)
8710 ) {
8711 hddLog(LOG1,
8712 FL("setting default wep key, key_idx = %hu key_len %hu"),
8713 key_idx, key_len);
8714 cdf_mem_copy(&pWextState->roamProfile.
8715 Keys.
8716 KeyMaterial[key_idx][0],
8717 req->key, key_len);
8718 pWextState->roamProfile.Keys.
8719 KeyLength[key_idx] = (u8) key_len;
8720 pWextState->roamProfile.Keys.
8721 defaultIndex = (u8) key_idx;
8722 }
8723 }
8724 }
8725 }
8726
8727 return status;
8728}
8729
8730/**
8731 * wlan_hdd_try_disconnect() - try disconnnect from previous connection
8732 * @pAdapter: Pointer to adapter
8733 *
8734 * This function is used to disconnect from previous connection
8735 *
8736 * Return: 0 for success, non-zero for failure
8737 */
8738static int wlan_hdd_try_disconnect(hdd_adapter_t *pAdapter)
8739{
8740 unsigned long rc;
8741 hdd_station_ctx_t *pHddStaCtx;
8742 eMib_dot11DesiredBssType connectedBssType;
8743
8744 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
8745
8746 hdd_conn_get_connected_bss_type(pHddStaCtx, &connectedBssType);
8747
8748 if ((eMib_dot11DesiredBssType_independent == connectedBssType) ||
Abhishek Singh03f992e2016-01-07 18:07:06 +05308749 (eConnectionState_Associated == pHddStaCtx->conn_info.connState) ||
8750 (eConnectionState_Connecting == pHddStaCtx->conn_info.connState) ||
8751 (eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState)) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008752 hdd_conn_set_connection_state(pAdapter,
8753 eConnectionState_Disconnecting);
8754 /* Issue disconnect to CSR */
8755 INIT_COMPLETION(pAdapter->disconnect_comp_var);
8756 if (CDF_STATUS_SUCCESS ==
8757 sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter),
8758 pAdapter->sessionId,
8759 eCSR_DISCONNECT_REASON_UNSPECIFIED)) {
8760 rc = wait_for_completion_timeout(&pAdapter->
8761 disconnect_comp_var,
8762 msecs_to_jiffies
8763 (WLAN_WAIT_TIME_DISCONNECT));
8764 if (!rc) {
8765 hddLog(LOGE,
8766 FL("Sme disconnect event timed out session Id %d staDebugState %d"),
8767 pAdapter->sessionId,
8768 pHddStaCtx->staDebugState);
8769 return -EALREADY;
8770 }
8771 }
8772 } else if (eConnectionState_Disconnecting ==
8773 pHddStaCtx->conn_info.connState) {
8774 rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var,
8775 msecs_to_jiffies
8776 (WLAN_WAIT_TIME_DISCONNECT));
8777 if (!rc) {
8778 hddLog(LOGE,
8779 FL("Disconnect event timed out session Id %d staDebugState %d"),
8780 pAdapter->sessionId, pHddStaCtx->staDebugState);
8781 return -EALREADY;
8782 }
8783 }
8784
8785 return 0;
8786}
8787
8788/**
8789 * __wlan_hdd_cfg80211_connect() - cfg80211 connect api
8790 * @wiphy: Pointer to wiphy
8791 * @dev: Pointer to network device
8792 * @req: Pointer to cfg80211 connect request
8793 *
8794 * This function is used to start the association process
8795 *
8796 * Return: 0 for success, non-zero for failure
8797 */
8798static int __wlan_hdd_cfg80211_connect(struct wiphy *wiphy,
8799 struct net_device *ndev,
8800 struct cfg80211_connect_params *req)
8801{
8802 int status;
Sreelakshmi Konamki6bd8a2e2015-11-03 16:30:32 +05308803 u16 channel;
8804#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
8805 const u8 *bssid_hint = req->bssid_hint;
8806#else
8807 const u8 *bssid_hint = NULL;
8808#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008809 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev);
8810 hdd_context_t *pHddCtx;
8811
8812 ENTER();
8813
Peng Xuf5d60c82015-10-02 17:17:03 -07008814 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008815 hddLog(LOGE, FL("Command not allowed in FTM mode"));
8816 return -EINVAL;
8817 }
8818
8819 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
8820 TRACE_CODE_HDD_CFG80211_CONNECT,
8821 pAdapter->sessionId, pAdapter->device_mode));
8822 hddLog(LOG1, FL("Device_mode %s(%d)"),
8823 hdd_device_mode_to_string(pAdapter->device_mode),
8824 pAdapter->device_mode);
8825
8826 if (pAdapter->device_mode != WLAN_HDD_INFRA_STATION &&
8827 pAdapter->device_mode != WLAN_HDD_P2P_CLIENT) {
8828 hddLog(LOGE, FL("Device_mode %s(%d) is not supported"),
8829 hdd_device_mode_to_string(pAdapter->device_mode),
8830 pAdapter->device_mode);
8831 return -EINVAL;
8832 }
8833
8834 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
8835 if (!pHddCtx) {
8836 hddLog(LOGE, FL("HDD context is null"));
8837 return -EINVAL;
8838 }
8839
8840 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05308841 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008842 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008843 if (req->channel) {
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08008844 if (!cds_allow_concurrency(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008845 cds_convert_device_mode_to_hdd_type(
8846 pAdapter->device_mode),
8847 req->channel->hw_value, HW_MODE_20_MHZ)) {
8848 hdd_err("This concurrency combination is not allowed");
8849 return -ECONNREFUSED;
8850 }
8851 } else {
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08008852 if (!cds_allow_concurrency(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008853 cds_convert_device_mode_to_hdd_type(
8854 pAdapter->device_mode), 0, HW_MODE_20_MHZ)) {
8855 hdd_err("This concurrency combination is not allowed");
8856 return -ECONNREFUSED;
8857 }
8858 }
8859#if defined(FEATURE_WLAN_LFR)
8860 wlan_hdd_disable_roaming(pAdapter);
8861#endif
8862
8863 /*Try disconnecting if already in connected state */
8864 status = wlan_hdd_try_disconnect(pAdapter);
8865 if (0 > status) {
8866 hddLog(LOGE,
8867 FL("Failed to disconnect the existing connection"));
8868 return -EALREADY;
8869 }
8870
8871 /*initialise security parameters */
8872 status = wlan_hdd_cfg80211_set_privacy(pAdapter, req);
8873
8874 if (0 > status) {
8875 hddLog(LOGE,
8876 FL("failed to set security params"));
8877 return status;
8878 }
8879
Sreelakshmi Konamki6bd8a2e2015-11-03 16:30:32 +05308880 if (req->channel)
8881 channel = req->channel->hw_value;
8882 else
8883 channel = 0;
8884 status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid,
8885 req->ssid_len, req->bssid,
8886 bssid_hint, channel);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008887 if (0 > status) {
8888 hddLog(LOGE, FL("connect failed"));
8889 return status;
8890 }
8891 EXIT();
8892 return status;
8893}
8894
8895/**
8896 * wlan_hdd_cfg80211_connect() - cfg80211 connect api
8897 * @wiphy: Pointer to wiphy
8898 * @dev: Pointer to network device
8899 * @req: Pointer to cfg80211 connect request
8900 *
8901 * Return: 0 for success, non-zero for failure
8902 */
8903static int wlan_hdd_cfg80211_connect(struct wiphy *wiphy,
8904 struct net_device *ndev,
8905 struct cfg80211_connect_params *req)
8906{
8907 int ret;
8908 cds_ssr_protect(__func__);
8909 ret = __wlan_hdd_cfg80211_connect(wiphy, ndev, req);
8910 cds_ssr_unprotect(__func__);
8911
8912 return ret;
8913}
8914
8915/**
8916 * wlan_hdd_disconnect() - hdd disconnect api
8917 * @pAdapter: Pointer to adapter
8918 * @reason: Disconnect reason code
8919 *
8920 * This function is used to issue a disconnect request to SME
8921 *
8922 * Return: 0 for success, non-zero for failure
8923 */
8924int wlan_hdd_disconnect(hdd_adapter_t *pAdapter, u16 reason)
8925{
8926 int status, result = 0;
8927 unsigned long rc;
8928 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
8929 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
8930
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05308931 ENTER();
8932
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008933 status = wlan_hdd_validate_context(pHddCtx);
8934
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05308935 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008936 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008937
8938 /*stop tx queues */
8939 hddLog(LOG1, FL("Disabling queues"));
8940 wlan_hdd_netif_queue_control(pAdapter, WLAN_NETIF_TX_DISABLE_N_CARRIER,
8941 WLAN_CONTROL_PATH);
8942 hddLog(LOG1,
8943 FL("Set HDD connState to eConnectionState_Disconnecting"));
8944 pHddStaCtx->conn_info.connState = eConnectionState_Disconnecting;
8945 INIT_COMPLETION(pAdapter->disconnect_comp_var);
8946
8947 /*issue disconnect */
8948
8949 status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter),
8950 pAdapter->sessionId, reason);
Abhishek Singhacfdc922015-12-30 17:31:21 +05308951 /*
8952 * Wait here instead of returning directly, this will block the next
8953 * connect command and allow processing of the scan for ssid and
8954 * the previous connect command in CSR. Else we might hit some
8955 * race conditions leading to SME and HDD out of sync.
8956 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008957 if (CDF_STATUS_CMD_NOT_QUEUED == status) {
8958 hddLog(LOG1, FL("status = %d, already disconnected"),
8959 (int)status);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08008960 } else if (0 != status) {
8961 hddLog(LOGE,
8962 FL("csr_roam_disconnect failure, returned %d"),
8963 (int)status);
8964 pHddStaCtx->staDebugState = status;
8965 result = -EINVAL;
8966 goto disconnected;
8967 }
8968 rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var,
8969 msecs_to_jiffies
8970 (WLAN_WAIT_TIME_DISCONNECT));
8971
8972 if (!rc) {
8973 hddLog(LOGE,
8974 FL("Failed to disconnect, timed out"));
8975 result = -ETIMEDOUT;
8976 }
8977disconnected:
8978 hddLog(LOG1,
8979 FL("Set HDD connState to eConnectionState_NotConnected"));
8980 hdd_conn_set_connection_state(pAdapter, eConnectionState_NotConnected);
8981#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
8982 /* Sending disconnect event to userspace for kernel version < 3.11
8983 * is handled by __cfg80211_disconnect call to __cfg80211_disconnected
8984 */
8985 hddLog(LOG1, FL("Send disconnected event to userspace"));
8986 cfg80211_disconnected(pAdapter->dev, WLAN_REASON_UNSPECIFIED,
8987 NULL, 0, GFP_KERNEL);
8988#endif
8989
8990 return result;
8991}
8992
8993/**
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08008994 * hdd_ieee80211_reason_code_to_str() - return string conversion of reason code
8995 * @reason: ieee80211 reason code.
8996 *
8997 * This utility function helps log string conversion of reason code.
8998 *
8999 * Return: string conversion of reason code, if match found;
9000 * "Unknown" otherwise.
9001 */
9002static const char *hdd_ieee80211_reason_code_to_str(uint16_t reason)
9003{
9004 switch (reason) {
9005 CASE_RETURN_STRING(WLAN_REASON_UNSPECIFIED);
9006 CASE_RETURN_STRING(WLAN_REASON_PREV_AUTH_NOT_VALID);
9007 CASE_RETURN_STRING(WLAN_REASON_DEAUTH_LEAVING);
9008 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
9009 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_AP_BUSY);
9010 CASE_RETURN_STRING(WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
9011 CASE_RETURN_STRING(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
9012 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_STA_HAS_LEFT);
9013 CASE_RETURN_STRING(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH);
9014 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_BAD_POWER);
9015 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_BAD_SUPP_CHAN);
9016 CASE_RETURN_STRING(WLAN_REASON_INVALID_IE);
9017 CASE_RETURN_STRING(WLAN_REASON_MIC_FAILURE);
9018 CASE_RETURN_STRING(WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT);
9019 CASE_RETURN_STRING(WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT);
9020 CASE_RETURN_STRING(WLAN_REASON_IE_DIFFERENT);
9021 CASE_RETURN_STRING(WLAN_REASON_INVALID_GROUP_CIPHER);
9022 CASE_RETURN_STRING(WLAN_REASON_INVALID_PAIRWISE_CIPHER);
9023 CASE_RETURN_STRING(WLAN_REASON_INVALID_AKMP);
9024 CASE_RETURN_STRING(WLAN_REASON_UNSUPP_RSN_VERSION);
9025 CASE_RETURN_STRING(WLAN_REASON_INVALID_RSN_IE_CAP);
9026 CASE_RETURN_STRING(WLAN_REASON_IEEE8021X_FAILED);
9027 CASE_RETURN_STRING(WLAN_REASON_CIPHER_SUITE_REJECTED);
9028 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_UNSPECIFIED_QOS);
9029 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH);
9030 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_LOW_ACK);
9031 CASE_RETURN_STRING(WLAN_REASON_DISASSOC_QAP_EXCEED_TXOP);
9032 CASE_RETURN_STRING(WLAN_REASON_QSTA_LEAVE_QBSS);
9033 CASE_RETURN_STRING(WLAN_REASON_QSTA_NOT_USE);
9034 CASE_RETURN_STRING(WLAN_REASON_QSTA_REQUIRE_SETUP);
9035 CASE_RETURN_STRING(WLAN_REASON_QSTA_TIMEOUT);
9036 CASE_RETURN_STRING(WLAN_REASON_QSTA_CIPHER_NOT_SUPP);
9037 CASE_RETURN_STRING(WLAN_REASON_MESH_PEER_CANCELED);
9038 CASE_RETURN_STRING(WLAN_REASON_MESH_MAX_PEERS);
9039 CASE_RETURN_STRING(WLAN_REASON_MESH_CONFIG);
9040 CASE_RETURN_STRING(WLAN_REASON_MESH_CLOSE);
9041 CASE_RETURN_STRING(WLAN_REASON_MESH_MAX_RETRIES);
9042 CASE_RETURN_STRING(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
9043 CASE_RETURN_STRING(WLAN_REASON_MESH_INVALID_GTK);
9044 CASE_RETURN_STRING(WLAN_REASON_MESH_INCONSISTENT_PARAM);
9045 CASE_RETURN_STRING(WLAN_REASON_MESH_INVALID_SECURITY);
9046 CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_ERROR);
9047 CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_NOFORWARD);
9048 CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE);
9049 CASE_RETURN_STRING(WLAN_REASON_MAC_EXISTS_IN_MBSS);
9050 CASE_RETURN_STRING(WLAN_REASON_MESH_CHAN_REGULATORY);
9051 CASE_RETURN_STRING(WLAN_REASON_MESH_CHAN);
9052 default:
9053 return "Unknown";
9054 }
9055}
9056
9057/**
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009058 * __wlan_hdd_cfg80211_disconnect() - cfg80211 disconnect api
9059 * @wiphy: Pointer to wiphy
9060 * @dev: Pointer to network device
9061 * @reason: Disconnect reason code
9062 *
9063 * This function is used to issue a disconnect request to SME
9064 *
9065 * Return: 0 for success, non-zero for failure
9066 */
9067static int __wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy,
9068 struct net_device *dev, u16 reason)
9069{
9070 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
9071 int status;
9072 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
9073 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
9074#ifdef FEATURE_WLAN_TDLS
9075 uint8_t staIdx;
9076#endif
9077
9078 ENTER();
9079
Peng Xuf5d60c82015-10-02 17:17:03 -07009080 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009081 hddLog(LOGE, FL("Command not allowed in FTM mode"));
9082 return -EINVAL;
9083 }
9084
9085 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
9086 TRACE_CODE_HDD_CFG80211_DISCONNECT,
9087 pAdapter->sessionId, reason));
9088 hddLog(LOG1, FL("Device_mode %s(%d) reason code(%d)"),
9089 hdd_device_mode_to_string(pAdapter->device_mode),
9090 pAdapter->device_mode, reason);
9091
9092 status = wlan_hdd_validate_context(pHddCtx);
9093
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05309094 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009095 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009096
9097 /* Issue disconnect request to SME, if station is in connected state */
9098 if ((pHddStaCtx->conn_info.connState == eConnectionState_Associated) ||
9099 (pHddStaCtx->conn_info.connState == eConnectionState_Connecting)) {
9100 eCsrRoamDisconnectReason reasonCode =
9101 eCSR_DISCONNECT_REASON_UNSPECIFIED;
9102 hdd_scaninfo_t *pScanInfo;
9103
9104 switch (reason) {
9105 case WLAN_REASON_MIC_FAILURE:
9106 reasonCode = eCSR_DISCONNECT_REASON_MIC_ERROR;
9107 break;
9108
9109 case WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY:
9110 case WLAN_REASON_DISASSOC_AP_BUSY:
9111 case WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA:
9112 reasonCode = eCSR_DISCONNECT_REASON_DISASSOC;
9113 break;
9114
9115 case WLAN_REASON_PREV_AUTH_NOT_VALID:
9116 case WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA:
9117 reasonCode = eCSR_DISCONNECT_REASON_DEAUTH;
9118 break;
9119
9120 case WLAN_REASON_DEAUTH_LEAVING:
9121 reasonCode =
9122 pHddCtx->config->
9123 gEnableDeauthToDisassocMap ?
9124 eCSR_DISCONNECT_REASON_STA_HAS_LEFT :
9125 eCSR_DISCONNECT_REASON_DEAUTH;
9126 break;
9127 case WLAN_REASON_DISASSOC_STA_HAS_LEFT:
9128 reasonCode = eCSR_DISCONNECT_REASON_STA_HAS_LEFT;
9129 break;
9130 default:
9131 reasonCode = eCSR_DISCONNECT_REASON_UNSPECIFIED;
9132 break;
9133 }
9134 hddLog(LOG1,
9135 FL("convert to internal reason %d to reasonCode %d"),
9136 reason, reasonCode);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009137 pScanInfo = &pAdapter->scan_info;
9138 if (pScanInfo->mScanPending) {
9139 hddLog(LOG1,
9140 FL("Disconnect is in progress, Aborting Scan"));
9141 hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId,
9142 eCSR_SCAN_ABORT_DEFAULT);
9143 }
9144#ifdef FEATURE_WLAN_TDLS
9145 /* First clean up the tdls peers if any */
9146 for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; staIdx++) {
9147 if ((pHddCtx->tdlsConnInfo[staIdx].sessionId ==
9148 pAdapter->sessionId)
9149 && (pHddCtx->tdlsConnInfo[staIdx].staId)) {
9150 uint8_t *mac;
9151 mac =
9152 pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes;
9153 hddLog(LOG1,
9154 "%s: call sme_delete_tdls_peer_sta staId %d sessionId %d "
9155 MAC_ADDRESS_STR, __func__,
9156 pHddCtx->tdlsConnInfo[staIdx].staId,
9157 pAdapter->sessionId,
9158 MAC_ADDR_ARRAY(mac));
9159 sme_delete_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX
9160 (pAdapter),
9161 pAdapter->sessionId, mac);
9162 }
9163 }
9164#endif
9165 hddLog(LOG1, FL("Disconnecting with reasoncode:%u"),
9166 reasonCode);
Srinivas Girigowdaf2599dd2015-11-16 18:20:46 -08009167 hdd_info("Disconnect request from user space with reason: %s",
9168 hdd_ieee80211_reason_code_to_str(reason));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009169 status = wlan_hdd_disconnect(pAdapter, reasonCode);
9170 if (0 != status) {
9171 hddLog(LOGE,
9172 FL("failure, returned %d"), status);
9173 return -EINVAL;
9174 }
9175 } else {
9176 hddLog(LOGE,
9177 FL("unexpected cfg disconnect called while in state (%d)"),
9178 pHddStaCtx->conn_info.connState);
9179 }
9180
9181 return status;
9182}
9183
9184/**
9185 * wlan_hdd_cfg80211_disconnect() - cfg80211 disconnect api
9186 * @wiphy: Pointer to wiphy
9187 * @dev: Pointer to network device
9188 * @reason: Disconnect reason code
9189 *
9190 * Return: 0 for success, non-zero for failure
9191 */
9192static int wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy,
9193 struct net_device *dev, u16 reason)
9194{
9195 int ret;
9196 cds_ssr_protect(__func__);
9197 ret = __wlan_hdd_cfg80211_disconnect(wiphy, dev, reason);
9198 cds_ssr_unprotect(__func__);
9199
9200 return ret;
9201}
9202
9203/**
9204 * wlan_hdd_cfg80211_set_privacy_ibss() - set ibss privacy
9205 * @pAdapter: Pointer to adapter
9206 * @param: Pointer to IBSS parameters
9207 *
9208 * This function is used to initialize the security settings in IBSS mode
9209 *
9210 * Return: 0 for success, non-zero for failure
9211 */
9212static int wlan_hdd_cfg80211_set_privacy_ibss(hdd_adapter_t *pAdapter,
9213 struct cfg80211_ibss_params
9214 *params)
9215{
9216 int status = 0;
9217 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
9218 eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE;
9219 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
9220
9221 ENTER();
9222
9223 pWextState->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED;
9224 cdf_mem_zero(&pHddStaCtx->ibss_enc_key, sizeof(tCsrRoamSetKey));
9225 pHddStaCtx->ibss_enc_key_installed = 0;
9226
9227 if (params->ie_len && (NULL != params->ie)) {
9228 if (wlan_hdd_cfg80211_get_ie_ptr(params->ie,
9229 params->ie_len, WLAN_EID_RSN)) {
9230 pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA2;
9231 encryptionType = eCSR_ENCRYPT_TYPE_AES;
9232 } else if (hdd_is_wpaie_present(params->ie, params->ie_len)) {
9233 tDot11fIEWPA dot11WPAIE;
9234 tHalHandle halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
9235 u8 *ie;
9236
9237 memset(&dot11WPAIE, 0, sizeof(dot11WPAIE));
9238 ie = wlan_hdd_cfg80211_get_ie_ptr(params->ie,
9239 params->ie_len,
9240 DOT11F_EID_WPA);
9241 if (NULL != ie) {
9242 pWextState->wpaVersion =
9243 IW_AUTH_WPA_VERSION_WPA;
9244 /* Unpack the WPA IE */
9245 /* Skip past the EID byte and length byte - and four byte WiFi OUI */
9246 dot11f_unpack_ie_wpa((tpAniSirGlobal) halHandle,
9247 &ie[2 + 4],
9248 ie[1] - 4, &dot11WPAIE);
9249 /*Extract the multicast cipher, the encType for unicast
9250 cipher for wpa-none is none */
9251 encryptionType =
9252 hdd_translate_wpa_to_csr_encryption_type
9253 (dot11WPAIE.multicast_cipher);
9254 }
9255 }
9256
9257 status =
9258 wlan_hdd_cfg80211_set_ie(pAdapter, params->ie,
9259 params->ie_len);
9260
9261 if (0 > status) {
9262 hddLog(LOGE, FL("failed to parse WPA/RSN IE"));
9263 return status;
9264 }
9265 }
9266
9267 pWextState->roamProfile.AuthType.authType[0] =
9268 pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM;
9269
9270 if (params->privacy) {
9271 /* Security enabled IBSS, At this time there is no information
9272 * available about the security paramters, so initialise the
9273 * encryption type to eCSR_ENCRYPT_TYPE_WEP40_STATICKEY.
9274 * The correct security parameters will be updated later in
9275 * wlan_hdd_cfg80211_add_key Hal expects encryption type to be
9276 * set inorder enable privacy bit in beacons
9277 */
9278
9279 encryptionType = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY;
9280 }
9281 hddLog(LOG2, FL("encryptionType=%d"), encryptionType);
9282 pHddStaCtx->conn_info.ucEncryptionType = encryptionType;
9283 pWextState->roamProfile.EncryptionType.numEntries = 1;
9284 pWextState->roamProfile.EncryptionType.encryptionType[0] =
9285 encryptionType;
9286 return status;
9287}
9288
9289/**
9290 * __wlan_hdd_cfg80211_join_ibss() - join ibss
9291 * @wiphy: Pointer to wiphy
9292 * @dev: Pointer to network device
9293 * @param: Pointer to IBSS join parameters
9294 *
9295 * This function is used to create/join an IBSS network
9296 *
9297 * Return: 0 for success, non-zero for failure
9298 */
9299static int __wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy,
9300 struct net_device *dev,
9301 struct cfg80211_ibss_params *params)
9302{
9303 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
9304 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
9305 tCsrRoamProfile *pRoamProfile;
9306 int status;
9307 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
9308 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
9309 struct cdf_mac_addr bssid;
9310 u8 channelNum = 0;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009311
9312 ENTER();
9313
Peng Xuf5d60c82015-10-02 17:17:03 -07009314 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009315 hddLog(LOGE, FL("Command not allowed in FTM mode"));
9316 return -EINVAL;
9317 }
9318
9319 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
9320 TRACE_CODE_HDD_CFG80211_JOIN_IBSS,
9321 pAdapter->sessionId, pAdapter->device_mode));
9322 hddLog(LOG1, FL("Device_mode %s(%d)"),
9323 hdd_device_mode_to_string(pAdapter->device_mode),
9324 pAdapter->device_mode);
9325
9326 status = wlan_hdd_validate_context(pHddCtx);
9327
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05309328 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009329 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009330
9331 if (NULL !=
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009332 params->chandef.chan)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009333 {
9334 uint32_t numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN;
9335 uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN];
9336 tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
9337 int indx;
9338
9339 /* Get channel number */
9340 channelNum = ieee80211_frequency_to_channel(
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009341 params->
9342 chandef.
9343 chan->
9344 center_freq);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009345
9346 if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST,
9347 validChan, &numChans)) {
9348 hddLog(LOGE, FL("No valid channel list"));
9349 return -EOPNOTSUPP;
9350 }
9351
9352 for (indx = 0; indx < numChans; indx++) {
9353 if (channelNum == validChan[indx]) {
9354 break;
9355 }
9356 }
9357 if (indx >= numChans) {
9358 hddLog(LOGE,
9359 FL("Not valid Channel %d"), channelNum);
9360 return -EINVAL;
9361 }
9362 }
9363
Tushnim Bhattacharyyaca50b322015-12-28 17:14:36 -08009364 if (!cds_allow_concurrency(CDS_IBSS_MODE, channelNum,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009365 HW_MODE_20_MHZ)) {
9366 hdd_err("This concurrency combination is not allowed");
9367 return -ECONNREFUSED;
9368 }
9369 if (pHddCtx->config->policy_manager_enabled) {
Chandrasekaran, Manishekareceb8112015-11-16 15:38:53 +05309370 status = cdf_reset_connection_update();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009371 if (!CDF_IS_STATUS_SUCCESS(status))
9372 hdd_err("ERR: clear event failed");
9373
Chandrasekaran, Manishekaref70c0d2015-10-20 19:54:55 +05309374 status = cds_current_connections_update(pAdapter->sessionId,
9375 channelNum,
9376 CDS_UPDATE_REASON_JOIN_IBSS);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009377 if (CDF_STATUS_E_FAILURE == status) {
9378 hdd_err("ERROR: connections update failed!!");
9379 return -EINVAL;
9380 }
9381
9382 if (CDF_STATUS_SUCCESS == status) {
Chandrasekaran, Manishekareceb8112015-11-16 15:38:53 +05309383 status = cdf_wait_for_connection_update();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009384 if (!CDF_IS_STATUS_SUCCESS(status)) {
9385 hdd_err("ERROR: cdf wait for event failed!!");
9386 return -EINVAL;
9387 }
9388 }
9389 }
9390
9391 /*Try disconnecting if already in connected state */
9392 status = wlan_hdd_try_disconnect(pAdapter);
9393 if (0 > status) {
9394 hddLog(LOGE,
9395 FL("Failed to disconnect the existing IBSS connection"));
9396 return -EALREADY;
9397 }
9398
9399 pRoamProfile = &pWextState->roamProfile;
9400
9401 if (eCSR_BSS_TYPE_START_IBSS != pRoamProfile->BSSType) {
9402 hddLog(LOGE,
9403 FL("Interface type is not set to IBSS"));
9404 return -EINVAL;
9405 }
9406
9407 /* enable selected protection checks in IBSS mode */
9408 pRoamProfile->cfg_protection = IBSS_CFG_PROTECTION_ENABLE_MASK;
9409
9410 if (CDF_STATUS_E_FAILURE == sme_cfg_set_int(pHddCtx->hHal,
9411 WNI_CFG_IBSS_ATIM_WIN_SIZE,
9412 pHddCtx->config->
9413 ibssATIMWinSize)) {
9414 hddLog(LOGE,
9415 FL("Could not pass on WNI_CFG_IBSS_ATIM_WIN_SIZE to CCM"));
9416 }
9417
9418 /* BSSID is provided by upper layers hence no need to AUTO generate */
9419 if (NULL != params->bssid) {
9420 if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_IBSS_AUTO_BSSID, 0)
9421 == CDF_STATUS_E_FAILURE) {
9422 hddLog(LOGE,
9423 FL("ccmCfgStInt failed for WNI_CFG_IBSS_AUTO_BSSID"));
9424 return -EIO;
9425 }
9426 cdf_mem_copy(bssid.bytes, params->bssid, CDF_MAC_ADDR_SIZE);
9427 } else if (pHddCtx->config->isCoalesingInIBSSAllowed == 0) {
9428 if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_IBSS_AUTO_BSSID, 0)
9429 == CDF_STATUS_E_FAILURE) {
9430 hddLog(LOGE,
9431 FL("ccmCfgStInt failed for WNI_CFG_IBSS_AUTO_BSSID"));
9432 return -EIO;
9433 }
9434 cdf_copy_macaddr(&bssid, &pHddCtx->config->IbssBssid);
9435 }
9436 if ((params->beacon_interval > CFG_BEACON_INTERVAL_MIN)
9437 && (params->beacon_interval <= CFG_BEACON_INTERVAL_MAX))
9438 pRoamProfile->beaconInterval = params->beacon_interval;
9439 else {
9440 pRoamProfile->beaconInterval = CFG_BEACON_INTERVAL_DEFAULT;
9441 hddLog(LOG2,
9442 FL("input beacon interval %d TU is invalid, use default %d TU"),
9443 params->beacon_interval, pRoamProfile->beaconInterval);
9444 }
9445
9446 /* Set Channel */
9447 if (channelNum) {
9448 /* Set the Operational Channel */
9449 hddLog(LOG2, FL("set channel %d"), channelNum);
9450 pRoamProfile->ChannelInfo.numOfChannels = 1;
9451 pHddStaCtx->conn_info.operationChannel = channelNum;
9452 pRoamProfile->ChannelInfo.ChannelList =
9453 &pHddStaCtx->conn_info.operationChannel;
9454 }
9455
9456 /* Initialize security parameters */
9457 status = wlan_hdd_cfg80211_set_privacy_ibss(pAdapter, params);
9458 if (status < 0) {
9459 hddLog(LOGE,
9460 FL("failed to set security parameters"));
9461 return status;
9462 }
9463
9464 /* Issue connect start */
9465 status = wlan_hdd_cfg80211_connect_start(pAdapter, params->ssid,
9466 params->ssid_len,
9467 bssid.bytes,
9468 NULL,
9469 pHddStaCtx->conn_info.
9470 operationChannel);
9471
9472 if (0 > status) {
9473 hddLog(LOGE, FL("connect failed"));
9474 return status;
9475 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05309476 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009477 return 0;
9478}
9479
9480/**
9481 * wlan_hdd_cfg80211_join_ibss() - join ibss
9482 * @wiphy: Pointer to wiphy
9483 * @dev: Pointer to network device
9484 * @param: Pointer to IBSS join parameters
9485 *
9486 * This function is used to create/join an IBSS network
9487 *
9488 * Return: 0 for success, non-zero for failure
9489 */
9490static int wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy,
9491 struct net_device *dev,
9492 struct cfg80211_ibss_params *params)
9493{
9494 int ret = 0;
9495
9496 cds_ssr_protect(__func__);
9497 ret = __wlan_hdd_cfg80211_join_ibss(wiphy, dev, params);
9498 cds_ssr_unprotect(__func__);
9499
9500 return ret;
9501}
9502
9503/**
9504 * __wlan_hdd_cfg80211_leave_ibss() - leave ibss
9505 * @wiphy: Pointer to wiphy
9506 * @dev: Pointer to network device
9507 *
9508 * This function is used to leave an IBSS network
9509 *
9510 * Return: 0 for success, non-zero for failure
9511 */
9512static int __wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy,
9513 struct net_device *dev)
9514{
9515 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
9516 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
9517 tCsrRoamProfile *pRoamProfile;
9518 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
9519 int status;
9520 CDF_STATUS hal_status;
Chandrasekaran, Manishekar12a818a2015-12-18 11:44:56 +05309521 unsigned long rc;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009522
9523 ENTER();
9524
Peng Xuf5d60c82015-10-02 17:17:03 -07009525 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009526 hddLog(LOGE, FL("Command not allowed in FTM mode"));
9527 return -EINVAL;
9528 }
9529
9530 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
9531 TRACE_CODE_HDD_CFG80211_LEAVE_IBSS,
9532 pAdapter->sessionId,
9533 eCSR_DISCONNECT_REASON_IBSS_LEAVE));
9534 status = wlan_hdd_validate_context(pHddCtx);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05309535 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009536 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009537
9538 hddLog(LOG1, FL("Device_mode %s(%d)"),
9539 hdd_device_mode_to_string(pAdapter->device_mode),
9540 pAdapter->device_mode);
9541 if (NULL == pWextState) {
9542 hddLog(LOGE, FL("Data Storage Corruption"));
9543 return -EIO;
9544 }
9545
9546 pRoamProfile = &pWextState->roamProfile;
9547
9548 /* Issue disconnect only if interface type is set to IBSS */
9549 if (eCSR_BSS_TYPE_START_IBSS != pRoamProfile->BSSType) {
9550 hddLog(LOGE,
9551 FL("BSS Type is not set to IBSS"));
9552 return -EINVAL;
9553 }
9554
9555 /* Issue Disconnect request */
9556 INIT_COMPLETION(pAdapter->disconnect_comp_var);
9557 hal_status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter),
9558 pAdapter->sessionId,
9559 eCSR_DISCONNECT_REASON_IBSS_LEAVE);
9560 if (!CDF_IS_STATUS_SUCCESS(hal_status)) {
9561 hddLog(LOGE,
9562 FL("sme_roam_disconnect failed hal_status(%d)"),
9563 hal_status);
9564 return -EAGAIN;
9565 }
Chandrasekaran, Manishekar12a818a2015-12-18 11:44:56 +05309566
9567 /* wait for mc thread to cleanup and then return to upper stack
9568 * so by the time upper layer calls the change interface, we are
9569 * all set to proceed further
9570 */
9571 rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var,
9572 msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
9573 if (!rc) {
9574 hdd_err("Failed to disconnect, timed out");
9575 return -ETIMEDOUT;
9576 }
9577
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05309578 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009579 return 0;
9580}
9581
9582/**
9583 * wlan_hdd_cfg80211_leave_ibss() - leave ibss
9584 * @wiphy: Pointer to wiphy
9585 * @dev: Pointer to network device
9586 *
9587 * This function is used to leave an IBSS network
9588 *
9589 * Return: 0 for success, non-zero for failure
9590 */
9591static int wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy,
9592 struct net_device *dev)
9593{
9594 int ret = 0;
9595
9596 cds_ssr_protect(__func__);
9597 ret = __wlan_hdd_cfg80211_leave_ibss(wiphy, dev);
9598 cds_ssr_unprotect(__func__);
9599
9600 return ret;
9601}
9602
9603/**
9604 * __wlan_hdd_cfg80211_set_wiphy_params() - set wiphy parameters
9605 * @wiphy: Pointer to wiphy
9606 * @changed: Parameters changed
9607 *
9608 * This function is used to set the phy parameters. RTS Threshold/FRAG
9609 * Threshold/Retry Count etc.
9610 *
9611 * Return: 0 for success, non-zero for failure
9612 */
9613static int __wlan_hdd_cfg80211_set_wiphy_params(struct wiphy *wiphy,
9614 u32 changed)
9615{
9616 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
9617 tHalHandle hHal = pHddCtx->hHal;
9618 int status;
9619
9620 ENTER();
9621
Peng Xuf5d60c82015-10-02 17:17:03 -07009622 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009623 hddLog(LOGE, FL("Command not allowed in FTM mode"));
9624 return -EINVAL;
9625 }
9626
9627 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
9628 TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS,
9629 NO_SESSION, wiphy->rts_threshold));
9630 status = wlan_hdd_validate_context(pHddCtx);
9631
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05309632 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009633 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009634
9635 if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
9636 u32 rts_threshold = (wiphy->rts_threshold == -1) ?
9637 WNI_CFG_RTS_THRESHOLD_STAMAX : wiphy->rts_threshold;
9638
9639 if ((WNI_CFG_RTS_THRESHOLD_STAMIN > rts_threshold) ||
9640 (WNI_CFG_RTS_THRESHOLD_STAMAX < rts_threshold)) {
9641 hddLog(LOGE,
9642 FL("Invalid RTS Threshold value %u"),
9643 rts_threshold);
9644 return -EINVAL;
9645 }
9646
9647 if (0 != sme_cfg_set_int(hHal, WNI_CFG_RTS_THRESHOLD,
9648 rts_threshold)) {
9649 hddLog(LOGE,
9650 FL("sme_cfg_set_int failed for rts_threshold value %u"),
9651 rts_threshold);
9652 return -EIO;
9653 }
9654
9655 hddLog(LOG2, FL("set rts threshold %u"), rts_threshold);
9656 }
9657
9658 if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
9659 u16 frag_threshold = (wiphy->frag_threshold == -1) ?
9660 WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX :
9661 wiphy->frag_threshold;
9662
9663 if ((WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN > frag_threshold) ||
9664 (WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX < frag_threshold)) {
9665 hddLog(LOGE,
9666 FL("Invalid frag_threshold value %hu"),
9667 frag_threshold);
9668 return -EINVAL;
9669 }
9670
9671 if (0 != sme_cfg_set_int(hHal, WNI_CFG_FRAGMENTATION_THRESHOLD,
9672 frag_threshold)) {
9673 hddLog(LOGE,
9674 FL("sme_cfg_set_int failed for frag_threshold value %hu"),
9675 frag_threshold);
9676 return -EIO;
9677 }
9678
9679 hddLog(LOG2, FL("set frag threshold %hu"), frag_threshold);
9680 }
9681
9682 if ((changed & WIPHY_PARAM_RETRY_SHORT)
9683 || (changed & WIPHY_PARAM_RETRY_LONG)) {
9684 u8 retry_value = (changed & WIPHY_PARAM_RETRY_SHORT) ?
9685 wiphy->retry_short : wiphy->retry_long;
9686
9687 if ((WNI_CFG_LONG_RETRY_LIMIT_STAMIN > retry_value) ||
9688 (WNI_CFG_LONG_RETRY_LIMIT_STAMAX < retry_value)) {
9689 hddLog(LOGE,
9690 FL("Invalid Retry count %hu"), retry_value);
9691 return -EINVAL;
9692 }
9693
9694 if (changed & WIPHY_PARAM_RETRY_SHORT) {
9695 if (0 != sme_cfg_set_int(hHal,
9696 WNI_CFG_LONG_RETRY_LIMIT,
9697 retry_value)) {
9698 hddLog(LOGE,
9699 FL("sme_cfg_set_int failed for long retry count %hu"),
9700 retry_value);
9701 return -EIO;
9702 }
9703 hddLog(LOG2,
9704 FL("set long retry count %hu"), retry_value);
9705 } else if (changed & WIPHY_PARAM_RETRY_SHORT) {
9706 if (0 != sme_cfg_set_int(hHal,
9707 WNI_CFG_SHORT_RETRY_LIMIT,
9708 retry_value)) {
9709 hddLog(LOGE,
9710 FL("sme_cfg_set_int failed for short retry count %hu"),
9711 retry_value);
9712 return -EIO;
9713 }
9714 hddLog(LOG2,
9715 FL("set short retry count %hu"), retry_value);
9716 }
9717 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05309718 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009719 return 0;
9720}
9721
9722/**
9723 * wlan_hdd_cfg80211_set_wiphy_params() - set wiphy parameters
9724 * @wiphy: Pointer to wiphy
9725 * @changed: Parameters changed
9726 *
9727 * Return: 0 for success, non-zero for failure
9728 */
9729static int wlan_hdd_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
9730{
9731 int ret;
9732
9733 cds_ssr_protect(__func__);
9734 ret = __wlan_hdd_cfg80211_set_wiphy_params(wiphy, changed);
9735 cds_ssr_unprotect(__func__);
9736
9737 return ret;
9738}
9739
9740/**
9741 * __wlan_hdd_set_default_mgmt_key() - dummy implementation of set default mgmt
9742 * key
9743 * @wiphy: Pointer to wiphy
9744 * @dev: Pointer to network device
9745 * @key_index: Key index
9746 *
9747 * Return: 0
9748 */
9749static int __wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy,
9750 struct net_device *netdev,
9751 u8 key_index)
9752{
9753 ENTER();
9754 return 0;
9755}
9756
9757/**
9758 * wlan_hdd_set_default_mgmt_key() - SSR wrapper for
9759 * wlan_hdd_set_default_mgmt_key
9760 * @wiphy: pointer to wiphy
9761 * @netdev: pointer to net_device structure
9762 * @key_index: key index
9763 *
9764 * Return: 0 on success, error number on failure
9765 */
9766static int wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy,
9767 struct net_device *netdev,
9768 u8 key_index)
9769{
9770 int ret;
9771
9772 cds_ssr_protect(__func__);
9773 ret = __wlan_hdd_set_default_mgmt_key(wiphy, netdev, key_index);
9774 cds_ssr_unprotect(__func__);
9775
9776 return ret;
9777}
9778
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009779/**
9780 * __wlan_hdd_set_txq_params() - dummy implementation of set tx queue params
9781 * @wiphy: Pointer to wiphy
9782 * @dev: Pointer to network device
9783 * @params: Pointer to tx queue parameters
9784 *
9785 * Return: 0
9786 */
9787static int __wlan_hdd_set_txq_params(struct wiphy *wiphy,
9788 struct net_device *dev,
9789 struct ieee80211_txq_params *params)
9790{
9791 ENTER();
9792 return 0;
9793}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009794
9795/**
9796 * wlan_hdd_set_txq_params() - SSR wrapper for wlan_hdd_set_txq_params
9797 * @wiphy: pointer to wiphy
9798 * @netdev: pointer to net_device structure
9799 * @params: pointer to ieee80211_txq_params
9800 *
9801 * Return: 0 on success, error number on failure
9802 */
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009803static int wlan_hdd_set_txq_params(struct wiphy *wiphy,
9804 struct net_device *dev,
9805 struct ieee80211_txq_params *params)
9806{
9807 int ret;
9808
9809 cds_ssr_protect(__func__);
9810 ret = __wlan_hdd_set_txq_params(wiphy, dev, params);
9811 cds_ssr_unprotect(__func__);
9812
9813 return ret;
9814}
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009815
9816/**
9817 * __wlan_hdd_cfg80211_del_station() - delete station v2
9818 * @wiphy: Pointer to wiphy
9819 * @param: Pointer to delete station parameter
9820 *
9821 * Return: 0 for success, non-zero for failure
9822 */
9823static
9824int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
9825 struct net_device *dev,
9826 struct tagCsrDelStaParams *pDelStaParams)
9827{
9828 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
9829 hdd_context_t *pHddCtx;
9830 CDF_STATUS cdf_status = CDF_STATUS_E_FAILURE;
9831 hdd_hostapd_state_t *hapd_state;
9832 int status;
9833 uint8_t staId;
9834 uint8_t *mac;
9835
9836 ENTER();
9837
Peng Xuf5d60c82015-10-02 17:17:03 -07009838 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009839 hddLog(LOGE, FL("Command not allowed in FTM mode"));
9840 return -EINVAL;
9841 }
9842
9843 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
9844 TRACE_CODE_HDD_CFG80211_DEL_STA,
9845 pAdapter->sessionId, pAdapter->device_mode));
9846
9847 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
9848 status = wlan_hdd_validate_context(pHddCtx);
9849
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +05309850 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009851 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009852
9853 mac = (uint8_t *) pDelStaParams->peerMacAddr.bytes;
9854
9855 if ((WLAN_HDD_SOFTAP == pAdapter->device_mode) ||
9856 (WLAN_HDD_P2P_GO == pAdapter->device_mode)) {
9857
9858 hapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
9859 if (!hapd_state) {
9860 hddLog(LOGE, "%s: Hostapd State is Null", __func__);
9861 return 0;
9862 }
9863
9864 if (cdf_is_macaddr_broadcast((struct cdf_mac_addr *) mac)) {
9865 uint16_t i;
9866 for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
9867 if ((pAdapter->aStaInfo[i].isUsed) &&
9868 (!pAdapter->aStaInfo[i].
9869 isDeauthInProgress)) {
9870 cdf_mem_copy(
9871 mac,
9872 pAdapter->aStaInfo[i].
9873 macAddrSTA.bytes,
Srinivas Girigowdad65dc5a2016-01-14 17:08:26 -08009874 CDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08009875 if (hdd_ipa_uc_is_enabled(pHddCtx)) {
9876 hdd_ipa_wlan_evt(pAdapter,
9877 pAdapter->
9878 aStaInfo[i].
9879 ucSTAId,
9880 WLAN_CLIENT_DISCONNECT,
9881 mac);
9882 }
9883 hddLog(LOG1,
9884 FL("Delete STA with MAC::"
9885 MAC_ADDRESS_STR),
9886 MAC_ADDR_ARRAY(mac));
9887
9888 if (pHddCtx->dev_dfs_cac_status ==
9889 DFS_CAC_IN_PROGRESS)
9890 goto fn_end;
9891
9892 cdf_event_reset(&hapd_state->cdf_event);
9893 hdd_softap_sta_disassoc(pAdapter,
9894 mac);
9895 cdf_status =
9896 hdd_softap_sta_deauth(pAdapter,
9897 pDelStaParams);
9898 if (CDF_IS_STATUS_SUCCESS(cdf_status)) {
9899 pAdapter->aStaInfo[i].
9900 isDeauthInProgress = true;
9901 cdf_status =
9902 cdf_wait_single_event(
9903 &hapd_state->cdf_event,
9904 1000);
9905 if (!CDF_IS_STATUS_SUCCESS(
9906 cdf_status))
9907 hddLog(LOGE,
9908 "%s: Deauth wait time expired",
9909 __func__);
9910 }
9911 }
9912 }
9913 } else {
9914 cdf_status =
9915 hdd_softap_get_sta_id(pAdapter,
9916 (struct cdf_mac_addr *) mac,
9917 &staId);
9918 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
9919 hddLog(LOG1,
9920 FL("Skip DEL STA as this is not used::"
9921 MAC_ADDRESS_STR),
9922 MAC_ADDR_ARRAY(mac));
9923 return -ENOENT;
9924 }
9925
9926 if (hdd_ipa_uc_is_enabled(pHddCtx)) {
9927 hdd_ipa_wlan_evt(pAdapter, staId,
9928 WLAN_CLIENT_DISCONNECT, mac);
9929 }
9930
9931 if (pAdapter->aStaInfo[staId].isDeauthInProgress ==
9932 true) {
9933 hddLog(LOG1,
9934 FL("Skip DEL STA as deauth is in progress::"
9935 MAC_ADDRESS_STR),
9936 MAC_ADDR_ARRAY(mac));
9937 return -ENOENT;
9938 }
9939
9940 pAdapter->aStaInfo[staId].isDeauthInProgress = true;
9941
9942 hddLog(LOG1,
9943 FL("Delete STA with MAC::" MAC_ADDRESS_STR),
9944 MAC_ADDR_ARRAY(mac));
9945
9946 /* Case: SAP in ACS selected DFS ch and client connected
9947 * Now Radar detected. Then if random channel is another
9948 * DFS ch then new CAC is initiated and no TX allowed.
9949 * So do not send any mgmt frames as it will timeout
9950 * during CAC.
9951 */
9952
9953 if (pHddCtx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS)
9954 goto fn_end;
9955
9956 cdf_event_reset(&hapd_state->cdf_event);
9957 hdd_softap_sta_disassoc(pAdapter, mac);
9958 cdf_status = hdd_softap_sta_deauth(pAdapter,
9959 pDelStaParams);
9960 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
9961 pAdapter->aStaInfo[staId].isDeauthInProgress =
9962 false;
9963 hddLog(LOG1,
9964 FL("STA removal failed for ::"
9965 MAC_ADDRESS_STR),
9966 MAC_ADDR_ARRAY(mac));
9967 return -ENOENT;
9968 } else {
9969 cdf_status = cdf_wait_single_event(
9970 &hapd_state->cdf_event,
9971 1000);
9972 if (!CDF_IS_STATUS_SUCCESS(cdf_status))
9973 hddLog(LOGE,
9974 "%s: Deauth wait time expired",
9975 __func__);
9976 }
9977 }
9978 }
9979
9980fn_end:
9981 EXIT();
9982 return 0;
9983}
9984
9985#ifdef CFG80211_DEL_STA_V2
9986/**
9987 * wlan_hdd_cfg80211_del_station() - delete station v2
9988 * @wiphy: Pointer to wiphy
9989 * @param: Pointer to delete station parameter
9990 *
9991 * Return: 0 for success, non-zero for failure
9992 */
9993int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
9994 struct net_device *dev,
9995 struct station_del_parameters *param)
9996#else
9997/**
9998 * wlan_hdd_cfg80211_del_station() - delete station
9999 * @wiphy: Pointer to wiphy
10000 * @mac: Pointer to station mac address
10001 *
10002 * Return: 0 for success, non-zero for failure
10003 */
10004#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
10005int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
10006 struct net_device *dev,
10007 const uint8_t *mac)
10008#else
10009int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
10010 struct net_device *dev,
10011 uint8_t *mac)
10012#endif
10013#endif
10014{
10015 int ret;
10016 struct tagCsrDelStaParams delStaParams;
10017
10018 cds_ssr_protect(__func__);
10019#ifdef CFG80211_DEL_STA_V2
10020 if (NULL == param) {
10021 hddLog(LOGE, FL("Invalid argumet passed"));
10022 return -EINVAL;
10023 }
10024 wlansap_populate_del_sta_params(param->mac, param->reason_code,
10025 param->subtype, &delStaParams);
10026#else
10027 wlansap_populate_del_sta_params(mac, eSIR_MAC_DEAUTH_LEAVING_BSS_REASON,
10028 (SIR_MAC_MGMT_DEAUTH >> 4),
10029 &delStaParams);
10030#endif
10031 ret = __wlan_hdd_cfg80211_del_station(wiphy, dev, &delStaParams);
10032 cds_ssr_unprotect(__func__);
10033
10034 return ret;
10035}
10036
10037/**
10038 * __wlan_hdd_cfg80211_add_station() - add station
10039 * @wiphy: Pointer to wiphy
10040 * @mac: Pointer to station mac address
10041 * @pmksa: Pointer to add station parameter
10042 *
10043 * Return: 0 for success, non-zero for failure
10044 */
10045static int __wlan_hdd_cfg80211_add_station(struct wiphy *wiphy,
10046 struct net_device *dev,
10047 const uint8_t *mac,
10048 struct station_parameters *params)
10049{
10050 int status = -EPERM;
10051#ifdef FEATURE_WLAN_TDLS
10052 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
10053 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
10054 u32 mask, set;
10055
10056 ENTER();
10057
Peng Xuf5d60c82015-10-02 17:17:03 -070010058 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010059 hddLog(LOGE, FL("Command not allowed in FTM mode"));
10060 return -EINVAL;
10061 }
10062
10063 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
10064 TRACE_CODE_HDD_CFG80211_ADD_STA,
10065 pAdapter->sessionId, params->listen_interval));
10066
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010067 if (0 != wlan_hdd_validate_context(pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010068 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010069
10070 mask = params->sta_flags_mask;
10071
10072 set = params->sta_flags_set;
10073
10074 hddLog(LOG1, FL("mask 0x%x set 0x%x " MAC_ADDRESS_STR), mask, set,
10075 MAC_ADDR_ARRAY(mac));
10076
10077 if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
10078 if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) {
10079 status =
10080 wlan_hdd_tdls_add_station(wiphy, dev, mac, 0, NULL);
10081 }
10082 }
10083#endif
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010084 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010085 return status;
10086}
10087
10088/**
10089 * wlan_hdd_cfg80211_add_station() - add station
10090 * @wiphy: Pointer to wiphy
10091 * @mac: Pointer to station mac address
10092 * @pmksa: Pointer to add station parameter
10093 *
10094 * Return: 0 for success, non-zero for failure
10095 */
10096#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0))
10097static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy,
10098 struct net_device *dev,
10099 const uint8_t *mac,
10100 struct station_parameters *params)
10101#else
10102static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy,
10103 struct net_device *dev, uint8_t *mac,
10104 struct station_parameters *params)
10105#endif
10106{
10107 int ret;
10108
10109 cds_ssr_protect(__func__);
10110 ret = __wlan_hdd_cfg80211_add_station(wiphy, dev, mac, params);
10111 cds_ssr_unprotect(__func__);
10112
10113 return ret;
10114}
10115
10116#ifdef FEATURE_WLAN_LFR
10117/**
10118 * __wlan_hdd_cfg80211_set_pmksa() - set pmksa
10119 * @wiphy: Pointer to wiphy
10120 * @dev: Pointer to network device
10121 * @pmksa: Pointer to set pmksa parameter
10122 *
10123 * Return: 0 for success, non-zero for failure
10124 */
10125static int __wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy,
10126 struct net_device *dev,
10127 struct cfg80211_pmksa *pmksa)
10128{
10129 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
10130 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
10131 tHalHandle halHandle;
10132 CDF_STATUS result = CDF_STATUS_SUCCESS;
10133 int status;
10134 tPmkidCacheInfo pmk_id;
10135
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010136 ENTER();
10137
Peng Xuf5d60c82015-10-02 17:17:03 -070010138 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010139 hddLog(LOGE, FL("Command not allowed in FTM mode"));
10140 return -EINVAL;
10141 }
10142
10143 if (!pmksa) {
10144 hddLog(LOGE, FL("pmksa is NULL"));
10145 return -EINVAL;
10146 }
10147
10148 if (!pmksa->bssid || !pmksa->pmkid) {
10149 hddLog(LOGE, FL("pmksa->bssid(%p) or pmksa->pmkid(%p) is NULL"),
10150 pmksa->bssid, pmksa->pmkid);
10151 return -EINVAL;
10152 }
10153
10154 hddLog(LOGW, FL("set PMKSA for " MAC_ADDRESS_STR),
10155 MAC_ADDR_ARRAY(pmksa->bssid));
10156
10157 status = wlan_hdd_validate_context(pHddCtx);
10158
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010159 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010160 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010161
10162 halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
10163
Srinivas Girigowdad65dc5a2016-01-14 17:08:26 -080010164 cdf_mem_copy(pmk_id.BSSID.bytes, pmksa->bssid, CDF_MAC_ADDR_SIZE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010165 cdf_mem_copy(pmk_id.PMKID, pmksa->pmkid, CSR_RSN_PMKID_SIZE);
10166
10167 /* Add to the PMKSA ID Cache in CSR */
10168 result = sme_roam_set_pmkid_cache(halHandle, pAdapter->sessionId,
10169 &pmk_id, 1, false);
10170
10171 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
10172 TRACE_CODE_HDD_CFG80211_SET_PMKSA,
10173 pAdapter->sessionId, result));
10174
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010175 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010176 return CDF_IS_STATUS_SUCCESS(result) ? 0 : -EINVAL;
10177}
10178
10179/**
10180 * wlan_hdd_cfg80211_set_pmksa() - set pmksa
10181 * @wiphy: Pointer to wiphy
10182 * @dev: Pointer to network device
10183 * @pmksa: Pointer to set pmksa parameter
10184 *
10185 * Return: 0 for success, non-zero for failure
10186 */
10187static int wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy,
10188 struct net_device *dev,
10189 struct cfg80211_pmksa *pmksa)
10190{
10191 int ret;
10192
10193 cds_ssr_protect(__func__);
10194 ret = __wlan_hdd_cfg80211_set_pmksa(wiphy, dev, pmksa);
10195 cds_ssr_unprotect(__func__);
10196
10197 return ret;
10198}
10199
10200/**
10201 * __wlan_hdd_cfg80211_del_pmksa() - delete pmksa
10202 * @wiphy: Pointer to wiphy
10203 * @dev: Pointer to network device
10204 * @pmksa: Pointer to pmksa parameter
10205 *
10206 * Return: 0 for success, non-zero for failure
10207 */
10208static int __wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy,
10209 struct net_device *dev,
10210 struct cfg80211_pmksa *pmksa)
10211{
10212 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
10213 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
10214 tHalHandle halHandle;
10215 int status = 0;
10216
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010217 ENTER();
10218
Peng Xuf5d60c82015-10-02 17:17:03 -070010219 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010220 hddLog(LOGE, FL("Command not allowed in FTM mode"));
10221 return -EINVAL;
10222 }
10223
10224 if (!pmksa) {
10225 hddLog(LOGE, FL("pmksa is NULL"));
10226 return -EINVAL;
10227 }
10228
10229 if (!pmksa->bssid) {
10230 hddLog(LOGE, FL("pmksa->bssid is NULL"));
10231 return -EINVAL;
10232 }
10233
10234 hddLog(CDF_TRACE_LEVEL_DEBUG, FL("Deleting PMKSA for " MAC_ADDRESS_STR),
10235 MAC_ADDR_ARRAY(pmksa->bssid));
10236
10237 status = wlan_hdd_validate_context(pHddCtx);
10238
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010239 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010240 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010241
10242 halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
10243
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +053010244 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
10245 TRACE_CODE_HDD_CFG80211_DEL_PMKSA,
10246 pAdapter->sessionId, 0));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010247 /* Delete the PMKID CSR cache */
10248 if (CDF_STATUS_SUCCESS !=
10249 sme_roam_del_pmkid_from_cache(halHandle,
10250 pAdapter->sessionId, pmksa->bssid,
10251 false)) {
10252 hddLog(LOGE, FL("Failed to delete PMKSA for " MAC_ADDRESS_STR),
10253 MAC_ADDR_ARRAY(pmksa->bssid));
10254 status = -EINVAL;
10255 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010256 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010257 return status;
10258}
10259
10260/**
10261 * wlan_hdd_cfg80211_del_pmksa() - delete pmksa
10262 * @wiphy: Pointer to wiphy
10263 * @dev: Pointer to network device
10264 * @pmksa: Pointer to pmksa parameter
10265 *
10266 * Return: 0 for success, non-zero for failure
10267 */
10268static int wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy,
10269 struct net_device *dev,
10270 struct cfg80211_pmksa *pmksa)
10271{
10272 int ret;
10273
10274 cds_ssr_protect(__func__);
10275 ret = __wlan_hdd_cfg80211_del_pmksa(wiphy, dev, pmksa);
10276 cds_ssr_unprotect(__func__);
10277
10278 return ret;
10279
10280}
10281
10282/**
10283 * __wlan_hdd_cfg80211_flush_pmksa() - flush pmksa
10284 * @wiphy: Pointer to wiphy
10285 * @dev: Pointer to network device
10286 *
10287 * Return: 0 for success, non-zero for failure
10288 */
10289static int __wlan_hdd_cfg80211_flush_pmksa(struct wiphy *wiphy,
10290 struct net_device *dev)
10291{
10292 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
10293 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
10294 tHalHandle halHandle;
10295 int status = 0;
10296
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010297 ENTER();
10298
Peng Xuf5d60c82015-10-02 17:17:03 -070010299 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010300 hddLog(LOGE, FL("Command not allowed in FTM mode"));
10301 return -EINVAL;
10302 }
10303
10304 hddLog(LOGW, FL("Flushing PMKSA"));
10305
10306 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
10307 status = wlan_hdd_validate_context(pHddCtx);
10308
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010309 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010310 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010311
10312 /* Retrieve halHandle */
10313 halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter);
10314
10315 /* Flush the PMKID cache in CSR */
10316 if (CDF_STATUS_SUCCESS !=
10317 sme_roam_del_pmkid_from_cache(halHandle, pAdapter->sessionId, NULL,
10318 true)) {
10319 hddLog(LOGE, FL("Cannot flush PMKIDCache"));
10320 status = -EINVAL;
10321 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010322 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010323 return status;
10324}
10325
10326/**
10327 * wlan_hdd_cfg80211_flush_pmksa() - flush pmksa
10328 * @wiphy: Pointer to wiphy
10329 * @dev: Pointer to network device
10330 *
10331 * Return: 0 for success, non-zero for failure
10332 */
10333static int wlan_hdd_cfg80211_flush_pmksa(struct wiphy *wiphy,
10334 struct net_device *dev)
10335{
10336 int ret;
10337
10338 cds_ssr_protect(__func__);
10339 ret = __wlan_hdd_cfg80211_flush_pmksa(wiphy, dev);
10340 cds_ssr_unprotect(__func__);
10341
10342 return ret;
10343}
10344#endif
10345
10346#if defined(WLAN_FEATURE_VOWIFI_11R) && defined(KERNEL_SUPPORT_11R_CFG80211)
10347/**
10348 * __wlan_hdd_cfg80211_update_ft_ies() - update fast transition ies
10349 * @wiphy: Pointer to wiphy
10350 * @dev: Pointer to network device
10351 * @ftie: Pointer to fast transition ie parameter
10352 *
10353 * Return: 0 for success, non-zero for failure
10354 */
10355static int
10356__wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy,
10357 struct net_device *dev,
10358 struct cfg80211_update_ft_ies_params *ftie)
10359{
10360 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
10361 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
10362 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
10363 int status;
10364
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010365 ENTER();
10366
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010367 status = wlan_hdd_validate_context(hdd_ctx);
10368 if (status)
10369 return status;
10370
Peng Xuf5d60c82015-10-02 17:17:03 -070010371 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010372 hddLog(LOGE, FL("Command not allowed in FTM mode"));
10373 return -EINVAL;
10374 }
10375
10376 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
10377 TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES,
10378 pAdapter->sessionId, pHddStaCtx->conn_info.connState));
10379 /* Added for debug on reception of Re-assoc Req. */
10380 if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
10381 hddLog(LOGE,
10382 FL("Called with Ie of length = %zu when not associated"),
10383 ftie->ie_len);
10384 hddLog(LOGE, FL("Should be Re-assoc Req IEs"));
10385 }
10386#ifdef WLAN_FEATURE_VOWIFI_11R_DEBUG
10387 hddLog(LOG1, FL("%s called with Ie of length = %zu"), __func__,
10388 ftie->ie_len);
10389#endif
10390
10391 /* Pass the received FT IEs to SME */
10392 sme_set_ft_ies(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId,
10393 (const u8 *)ftie->ie, ftie->ie_len);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010394 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010395 return 0;
10396}
10397
10398/**
10399 * wlan_hdd_cfg80211_update_ft_ies() - update fast transition ies
10400 * @wiphy: Pointer to wiphy
10401 * @dev: Pointer to network device
10402 * @ftie: Pointer to fast transition ie parameter
10403 *
10404 * Return: 0 for success, non-zero for failure
10405 */
10406static int
10407wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy,
10408 struct net_device *dev,
10409 struct cfg80211_update_ft_ies_params *ftie)
10410{
10411 int ret;
10412
10413 cds_ssr_protect(__func__);
10414 ret = __wlan_hdd_cfg80211_update_ft_ies(wiphy, dev, ftie);
10415 cds_ssr_unprotect(__func__);
10416
10417 return ret;
10418}
10419#endif
10420
10421#ifdef WLAN_FEATURE_GTK_OFFLOAD
10422/**
10423 * wlan_hdd_cfg80211_update_replay_counter_callback() - replay counter callback
10424 * @callbackContext: Callback context
10425 * @pGtkOffloadGetInfoRsp: Pointer to gtk offload response parameter
10426 *
10427 * Callback rountine called upon receiving response for get offload info
10428 *
10429 * Return: none
10430 */
10431void wlan_hdd_cfg80211_update_replay_counter_callback(void *callbackContext,
10432 tpSirGtkOffloadGetInfoRspParams
10433 pGtkOffloadGetInfoRsp)
10434{
10435 hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext;
10436 uint8_t tempReplayCounter[8];
10437 hdd_station_ctx_t *pHddStaCtx;
10438
10439 ENTER();
10440
10441 if (NULL == pAdapter) {
10442 hddLog(LOGE, FL("HDD adapter is Null"));
10443 return;
10444 }
10445
10446 if (NULL == pGtkOffloadGetInfoRsp) {
10447 hddLog(LOGE, FL("pGtkOffloadGetInfoRsp is Null"));
10448 return;
10449 }
10450
10451 if (CDF_STATUS_SUCCESS != pGtkOffloadGetInfoRsp->ulStatus) {
10452 hddLog(LOGE, FL("wlan Failed to get replay counter value"));
10453 return;
10454 }
10455
10456 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
10457 /* Update replay counter */
10458 pHddStaCtx->gtkOffloadReqParams.ullKeyReplayCounter =
10459 pGtkOffloadGetInfoRsp->ullKeyReplayCounter;
10460
10461 {
10462 /* changing from little to big endian since supplicant
10463 * works on big endian format
10464 */
10465 int i;
10466 uint8_t *p =
10467 (uint8_t *) &pGtkOffloadGetInfoRsp->ullKeyReplayCounter;
10468
10469 for (i = 0; i < 8; i++) {
10470 tempReplayCounter[7 - i] = (uint8_t) p[i];
10471 }
10472 }
10473
10474 /* Update replay counter to NL */
Srinivas Girigowda2213b1d2015-11-20 17:10:11 -080010475 cfg80211_gtk_rekey_notify(pAdapter->dev,
10476 pGtkOffloadGetInfoRsp->bssid.bytes,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010477 tempReplayCounter, GFP_KERNEL);
10478}
10479
10480/**
10481 * __wlan_hdd_cfg80211_set_rekey_data() - set rekey data
10482 * @wiphy: Pointer to wiphy
10483 * @dev: Pointer to network device
10484 * @data: Pointer to rekey data
10485 *
10486 * This function is used to offload GTK rekeying job to the firmware.
10487 *
10488 * Return: 0 for success, non-zero for failure
10489 */
10490int __wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy,
10491 struct net_device *dev,
10492 struct cfg80211_gtk_rekey_data *data)
10493{
10494 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
10495 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
10496 hdd_station_ctx_t *pHddStaCtx;
10497 tHalHandle hHal;
10498 int result;
10499 tSirGtkOffloadParams hddGtkOffloadReqParams;
10500 CDF_STATUS status = CDF_STATUS_E_FAILURE;
10501
10502 ENTER();
10503
Peng Xuf5d60c82015-10-02 17:17:03 -070010504 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010505 hddLog(LOGE, FL("Command not allowed in FTM mode"));
10506 return -EINVAL;
10507 }
10508
10509 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
10510 TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA,
10511 pAdapter->sessionId, pAdapter->device_mode));
10512
10513 result = wlan_hdd_validate_context(pHddCtx);
10514
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010515 if (0 != result)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010516 return result;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010517
10518 pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
10519 hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
10520 if (NULL == hHal) {
10521 hddLog(LOGE, FL("HAL context is Null!!!"));
10522 return -EAGAIN;
10523 }
10524
10525 pHddStaCtx->gtkOffloadReqParams.ulFlags = GTK_OFFLOAD_ENABLE;
10526 memcpy(pHddStaCtx->gtkOffloadReqParams.aKCK, data->kck,
10527 NL80211_KCK_LEN);
10528 memcpy(pHddStaCtx->gtkOffloadReqParams.aKEK, data->kek,
10529 NL80211_KEK_LEN);
Srinivas Girigowda2213b1d2015-11-20 17:10:11 -080010530 cdf_copy_macaddr(&pHddStaCtx->gtkOffloadReqParams.bssid,
10531 &pHddStaCtx->conn_info.bssId);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010532 {
10533 /* changing from big to little endian since driver
10534 * works on little endian format
10535 */
10536 uint8_t *p =
10537 (uint8_t *) &pHddStaCtx->gtkOffloadReqParams.
10538 ullKeyReplayCounter;
10539 int i;
10540
10541 for (i = 0; i < 8; i++) {
10542 p[7 - i] = data->replay_ctr[i];
10543 }
10544 }
10545
10546 if (true == pHddCtx->hdd_wlan_suspended) {
10547 /* if wlan is suspended, enable GTK offload directly from here */
10548 memcpy(&hddGtkOffloadReqParams,
10549 &pHddStaCtx->gtkOffloadReqParams,
10550 sizeof(tSirGtkOffloadParams));
10551 status =
10552 sme_set_gtk_offload(hHal, &hddGtkOffloadReqParams,
10553 pAdapter->sessionId);
10554
10555 if (CDF_STATUS_SUCCESS != status) {
10556 hddLog(LOGE, FL("sme_set_gtk_offload failed, status(%d)"),
10557 status);
10558 return -EINVAL;
10559 }
10560 hddLog(LOG1, FL("sme_set_gtk_offload successful"));
10561 } else {
10562 hddLog(LOG1,
10563 FL("wlan not suspended GTKOffload request is stored"));
10564 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010565 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010566 return result;
10567}
10568
10569/**
10570 * wlan_hdd_cfg80211_set_rekey_data() - set rekey data
10571 * @wiphy: Pointer to wiphy
10572 * @dev: Pointer to network device
10573 * @data: Pointer to rekey data
10574 *
10575 * This function is used to offload GTK rekeying job to the firmware.
10576 *
10577 * Return: 0 for success, non-zero for failure
10578 */
10579int wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy,
10580 struct net_device *dev,
10581 struct cfg80211_gtk_rekey_data *data)
10582{
10583 int ret;
10584
10585 cds_ssr_protect(__func__);
10586 ret = __wlan_hdd_cfg80211_set_rekey_data(wiphy, dev, data);
10587 cds_ssr_unprotect(__func__);
10588
10589 return ret;
10590}
10591#endif /*WLAN_FEATURE_GTK_OFFLOAD */
10592
10593/**
10594 * __wlan_hdd_cfg80211_set_mac_acl() - set access control policy
10595 * @wiphy: Pointer to wiphy
10596 * @dev: Pointer to network device
10597 * @param: Pointer to access control parameter
10598 *
10599 * Return: 0 for success, non-zero for failure
10600 */
10601static int __wlan_hdd_cfg80211_set_mac_acl(struct wiphy *wiphy,
10602 struct net_device *dev,
10603 const struct cfg80211_acl_data *params)
10604{
10605 int i;
10606 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
10607 hdd_hostapd_state_t *pHostapdState;
10608 tsap_Config_t *pConfig;
10609 v_CONTEXT_t p_cds_context = NULL;
10610 hdd_context_t *pHddCtx;
10611 int status;
10612 CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
10613
10614 ENTER();
10615
Peng Xuf5d60c82015-10-02 17:17:03 -070010616 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010617 hddLog(LOGE, FL("Command not allowed in FTM mode"));
10618 return -EINVAL;
10619 }
10620
10621 if (NULL == params) {
10622 hddLog(LOGE, FL("params is Null"));
10623 return -EINVAL;
10624 }
10625
10626 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
10627 status = wlan_hdd_validate_context(pHddCtx);
10628
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010629 if (0 != status)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010630 return status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010631
10632 p_cds_context = pHddCtx->pcds_context;
10633 pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
10634
10635 if (NULL == pHostapdState) {
10636 hddLog(LOGE, FL("pHostapdState is Null"));
10637 return -EINVAL;
10638 }
10639
10640 hddLog(LOGE, "acl policy: = %d no acl entries = %d", params->acl_policy,
10641 params->n_acl_entries);
10642
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +053010643 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
10644 TRACE_CODE_HDD_CFG80211_SET_MAC_ACL,
10645 pAdapter->sessionId, pAdapter->device_mode));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010646 if (WLAN_HDD_SOFTAP == pAdapter->device_mode) {
10647 pConfig = &pAdapter->sessionCtx.ap.sapConfig;
10648
10649 /* default value */
10650 pConfig->num_accept_mac = 0;
10651 pConfig->num_deny_mac = 0;
10652
10653 /**
10654 * access control policy
10655 * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are
10656 * listed in hostapd.deny file.
10657 * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow stations which are
10658 * listed in hostapd.accept file.
10659 */
10660 if (NL80211_ACL_POLICY_DENY_UNLESS_LISTED == params->acl_policy) {
10661 pConfig->SapMacaddr_acl = eSAP_DENY_UNLESS_ACCEPTED;
10662 } else if (NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED ==
10663 params->acl_policy) {
10664 pConfig->SapMacaddr_acl = eSAP_ACCEPT_UNLESS_DENIED;
10665 } else {
10666 hddLog(LOGE, FL("Acl Policy : %d is not supported"),
10667 params->acl_policy);
10668 return -ENOTSUPP;
10669 }
10670
10671 if (eSAP_DENY_UNLESS_ACCEPTED == pConfig->SapMacaddr_acl) {
10672 pConfig->num_accept_mac = params->n_acl_entries;
10673 for (i = 0; i < params->n_acl_entries; i++) {
10674 hddLog(LOG1,
10675 FL("** Add ACL MAC entry %i in WhiletList :"
10676 MAC_ADDRESS_STR), i,
10677 MAC_ADDR_ARRAY(
10678 params->mac_addrs[i].addr));
10679
10680 cdf_mem_copy(&pConfig->accept_mac[i],
10681 params->mac_addrs[i].addr,
10682 sizeof(qcmacaddr));
10683 }
10684 } else if (eSAP_ACCEPT_UNLESS_DENIED == pConfig->SapMacaddr_acl) {
10685 pConfig->num_deny_mac = params->n_acl_entries;
10686 for (i = 0; i < params->n_acl_entries; i++) {
10687 hddLog(LOG1,
10688 FL("** Add ACL MAC entry %i in BlackList :"
10689 MAC_ADDRESS_STR), i,
10690 MAC_ADDR_ARRAY(
10691 params->mac_addrs[i].addr));
10692
10693 cdf_mem_copy(&pConfig->deny_mac[i],
10694 params->mac_addrs[i].addr,
10695 sizeof(qcmacaddr));
10696 }
10697 }
10698#ifdef WLAN_FEATURE_MBSSID
10699 cdf_status =
10700 wlansap_set_mac_acl(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter),
10701 pConfig);
10702#else
10703 cdf_status = wlansap_set_mac_acl(p_cds_context, pConfig);
10704#endif
10705 if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
10706 hddLog(LOGE, FL("SAP Set Mac Acl fail"));
10707 return -EINVAL;
10708 }
10709 } else {
10710 hddLog(LOG1, FL("Invalid device_mode %s(%d)"),
10711 hdd_device_mode_to_string(pAdapter->device_mode),
10712 pAdapter->device_mode);
10713 return -EINVAL;
10714 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010715 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010716 return 0;
10717}
10718
10719/**
10720 * wlan_hdd_cfg80211_set_mac_acl() - SSR wrapper for
10721 * __wlan_hdd_cfg80211_set_mac_acl
10722 * @wiphy: pointer to wiphy structure
10723 * @dev: pointer to net_device
10724 * @params: pointer to cfg80211_acl_data
10725 *
10726 * Return; 0 on success, error number otherwise
10727 */
10728static int
10729wlan_hdd_cfg80211_set_mac_acl(struct wiphy *wiphy,
10730 struct net_device *dev,
10731 const struct cfg80211_acl_data *params)
10732{
10733 int ret;
10734
10735 cds_ssr_protect(__func__);
10736 ret = __wlan_hdd_cfg80211_set_mac_acl(wiphy, dev, params);
10737 cds_ssr_unprotect(__func__);
10738
10739 return ret;
10740}
10741
10742#ifdef WLAN_NL80211_TESTMODE
10743#ifdef FEATURE_WLAN_LPHB
10744/**
10745 * wlan_hdd_cfg80211_lphb_ind_handler() - handle low power heart beat indication
10746 * @pHddCtx: Pointer to hdd context
10747 * @lphbInd: Pointer to low power heart beat indication parameter
10748 *
10749 * Return: none
10750 */
10751void wlan_hdd_cfg80211_lphb_ind_handler(void *pHddCtx, tSirLPHBInd *lphbInd)
10752{
10753 struct sk_buff *skb;
10754
10755 hddLog(LOGE, FL("LPHB indication arrived"));
10756
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010757 if (0 != wlan_hdd_validate_context((hdd_context_t *) pHddCtx))
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010758 return;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010759
10760 if (NULL == lphbInd) {
10761 hddLog(LOGE, FL("invalid argument lphbInd"));
10762 return;
10763 }
10764
10765 skb = cfg80211_testmode_alloc_event_skb(((hdd_context_t *) pHddCtx)->
10766 wiphy, sizeof(tSirLPHBInd),
10767 GFP_ATOMIC);
10768 if (!skb) {
10769 hddLog(LOGE, FL("LPHB timeout, NL buffer alloc fail"));
10770 return;
10771 }
10772
10773 if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_CMD, WLAN_HDD_TM_CMD_WLAN_HB)) {
10774 hddLog(LOGE, FL("WLAN_HDD_TM_ATTR_CMD put fail"));
10775 goto nla_put_failure;
10776 }
10777 if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_TYPE, lphbInd->protocolType)) {
10778 hddLog(LOGE, FL("WLAN_HDD_TM_ATTR_TYPE put fail"));
10779 goto nla_put_failure;
10780 }
10781 if (nla_put(skb, WLAN_HDD_TM_ATTR_DATA, sizeof(tSirLPHBInd), lphbInd)) {
10782 hddLog(LOGE, FL("WLAN_HDD_TM_ATTR_DATA put fail"));
10783 goto nla_put_failure;
10784 }
10785 cfg80211_testmode_event(skb, GFP_ATOMIC);
10786 return;
10787
10788nla_put_failure:
10789 hddLog(LOGE, FL("NLA Put fail"));
10790 kfree_skb(skb);
10791
10792 return;
10793}
10794#endif /* FEATURE_WLAN_LPHB */
10795
10796/**
10797 * __wlan_hdd_cfg80211_testmode() - test mode
10798 * @wiphy: Pointer to wiphy
10799 * @data: Data pointer
10800 * @len: Data length
10801 *
10802 * Return: 0 for success, non-zero for failure
10803 */
10804static int __wlan_hdd_cfg80211_testmode(struct wiphy *wiphy,
10805 void *data, int len)
10806{
10807 struct nlattr *tb[WLAN_HDD_TM_ATTR_MAX + 1];
10808 int err;
10809 hdd_context_t *pHddCtx = wiphy_priv(wiphy);
10810
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010811 ENTER();
10812
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010813 err = wlan_hdd_validate_context(pHddCtx);
10814 if (err)
10815 return err;
10816
10817 err = nla_parse(tb, WLAN_HDD_TM_ATTR_MAX, data,
10818 len, wlan_hdd_tm_policy);
10819 if (err) {
10820 hddLog(LOGE, FL("Testmode INV ATTR"));
10821 return err;
10822 }
10823
10824 if (!tb[WLAN_HDD_TM_ATTR_CMD]) {
10825 hddLog(LOGE, FL("Testmode INV CMD"));
10826 return -EINVAL;
10827 }
10828
Sreelakshmi Konamki6744cff2015-09-07 12:10:39 +053010829 MTRACE(cdf_trace(CDF_MODULE_ID_HDD,
10830 TRACE_CODE_HDD_CFG80211_TESTMODE,
10831 NO_SESSION, nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010832 switch (nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])) {
10833#ifdef FEATURE_WLAN_LPHB
10834 /* Low Power Heartbeat configuration request */
10835 case WLAN_HDD_TM_CMD_WLAN_HB:
10836 {
10837 int buf_len;
10838 void *buf;
10839 tSirLPHBReq *hb_params = NULL;
10840 tSirLPHBReq *hb_params_temp = NULL;
10841 CDF_STATUS smeStatus;
10842
10843 if (!tb[WLAN_HDD_TM_ATTR_DATA]) {
10844 hddLog(LOGE, FL("Testmode INV DATA"));
10845 return -EINVAL;
10846 }
10847
10848 buf = nla_data(tb[WLAN_HDD_TM_ATTR_DATA]);
10849 buf_len = nla_len(tb[WLAN_HDD_TM_ATTR_DATA]);
10850
10851 hb_params_temp = (tSirLPHBReq *) buf;
10852 if ((hb_params_temp->cmd == LPHB_SET_TCP_PARAMS_INDID)
10853 && (hb_params_temp->params.lphbTcpParamReq.
10854 timePeriodSec == 0))
10855 return -EINVAL;
10856
10857 hb_params =
10858 (tSirLPHBReq *) cdf_mem_malloc(sizeof(tSirLPHBReq));
10859 if (NULL == hb_params) {
10860 hddLog(LOGE, FL("Request Buffer Alloc Fail"));
10861 return -ENOMEM;
10862 }
10863
10864 cdf_mem_copy(hb_params, buf, buf_len);
10865 smeStatus =
10866 sme_lphb_config_req((tHalHandle) (pHddCtx->hHal),
10867 hb_params,
10868 wlan_hdd_cfg80211_lphb_ind_handler);
10869 if (CDF_STATUS_SUCCESS != smeStatus) {
10870 hddLog(LOGE, "LPHB Config Fail, disable");
10871 cdf_mem_free(hb_params);
10872 }
10873 return 0;
10874 }
10875#endif /* FEATURE_WLAN_LPHB */
10876
10877#if defined(QCA_WIFI_FTM)
10878 case WLAN_HDD_TM_CMD_WLAN_FTM:
10879 {
10880 int buf_len;
10881 void *buf;
10882 CDF_STATUS status;
10883 if (!tb[WLAN_HDD_TM_ATTR_DATA]) {
10884 hddLog(LOGE,
10885 FL
10886 ("WLAN_HDD_TM_ATTR_DATA attribute is invalid"));
10887 return -EINVAL;
10888 }
10889
10890 buf = nla_data(tb[WLAN_HDD_TM_ATTR_DATA]);
10891 buf_len = nla_len(tb[WLAN_HDD_TM_ATTR_DATA]);
10892
10893 pr_info("****FTM Tx cmd len = %d*****\n", buf_len);
10894
10895 status = wlan_hdd_ftm_testmode_cmd(buf, buf_len);
10896
10897 if (status != CDF_STATUS_SUCCESS)
10898 err = -EBUSY;
10899 break;
10900 }
10901#endif
10902
10903 default:
10904 hddLog(LOGE, FL("command %d not supported"),
10905 nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD]));
10906 return -EOPNOTSUPP;
10907 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053010908 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080010909 return err;
10910}
10911
10912/**
10913 * wlan_hdd_cfg80211_testmode() - test mode
10914 * @wiphy: Pointer to wiphy
10915 * @dev: Pointer to network device
10916 * @data: Data pointer
10917 * @len: Data length
10918 *
10919 * Return: 0 for success, non-zero for failure
10920 */
10921static int wlan_hdd_cfg80211_testmode(struct wiphy *wiphy,
10922#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
10923 struct wireless_dev *wdev,
10924#endif
10925 void *data, int len)
10926{
10927 int ret;
10928
10929 cds_ssr_protect(__func__);
10930 ret = __wlan_hdd_cfg80211_testmode(wiphy, data, len);
10931 cds_ssr_unprotect(__func__);
10932
10933 return ret;
10934}
10935
10936#if defined(QCA_WIFI_FTM)
10937/**
10938 * wlan_hdd_testmode_rx_event() - test mode rx event handler
10939 * @buf: Pointer to buffer
10940 * @buf_len: Buffer length
10941 *
10942 * Return: none
10943 */
10944void wlan_hdd_testmode_rx_event(void *buf, size_t buf_len)
10945{
10946 struct sk_buff *skb;
10947 hdd_context_t *hdd_ctx;
10948
10949 if (!buf || !buf_len) {
10950 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
10951 "%s: buf or buf_len invalid, buf = %p buf_len = %zu",
10952 __func__, buf, buf_len);
10953 return;
10954 }
10955
10956 hdd_ctx = cds_get_context(CDF_MODULE_ID_HDD);
10957 if (!hdd_ctx) {
10958 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
10959 "%s: hdd context invalid", __func__);
10960 return;
10961 }
10962
10963 skb = cfg80211_testmode_alloc_event_skb(hdd_ctx->wiphy,
10964 buf_len, GFP_KERNEL);
10965 if (!skb) {
10966 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
10967 "%s: failed to allocate testmode rx skb!", __func__);
10968 return;
10969 }
10970
10971 if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_CMD, WLAN_HDD_TM_CMD_WLAN_FTM) ||
10972 nla_put(skb, WLAN_HDD_TM_ATTR_DATA, buf_len, buf))
10973 goto nla_put_failure;
10974
10975 pr_info("****FTM Rx cmd len = %zu*****\n", buf_len);
10976
10977 cfg80211_testmode_event(skb, GFP_KERNEL);
10978 return;
10979
10980nla_put_failure:
10981 kfree_skb(skb);
10982 CDF_TRACE(CDF_MODULE_ID_HDD, CDF_TRACE_LEVEL_ERROR,
10983 "%s: nla_put failed on testmode rx skb!", __func__);
10984}
10985#endif
10986#endif /* CONFIG_NL80211_TESTMODE */
10987
10988#ifdef QCA_HT_2040_COEX
10989/**
10990 * __wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth
10991 * @wiphy: Pointer to wiphy
10992 * @dev: Pointer to network device
10993 * @chandef: Pointer to channel definition parameter
10994 *
10995 * Return: 0 for success, non-zero for failure
10996 */
10997static int
10998__wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy,
10999 struct net_device *dev,
11000 struct cfg80211_chan_def *chandef)
11001{
11002 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
11003 hdd_context_t *pHddCtx;
11004 CDF_STATUS status;
11005 tSmeConfigParams sme_config;
11006 bool cbModeChange;
11007
Peng Xuf5d60c82015-10-02 17:17:03 -070011008 if (CDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080011009 hddLog(LOGE, FL("Command not allowed in FTM mode"));
11010 return -EINVAL;
11011 }
11012
11013 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
11014 status = wlan_hdd_validate_context(pHddCtx);
11015
11016 if (0 != status) {
11017 hddLog(LOGE, FL("HDD context is not valid"));
11018 return status;
11019 }
11020
11021 cdf_mem_zero(&sme_config, sizeof(tSmeConfigParams));
11022 sme_get_config_param(pHddCtx->hHal, &sme_config);
11023 switch (chandef->width) {
11024 case NL80211_CHAN_WIDTH_20:
11025 if (sme_config.csrConfig.channelBondingMode24GHz !=
11026 eCSR_INI_SINGLE_CHANNEL_CENTERED) {
11027 sme_config.csrConfig.channelBondingMode24GHz =
11028 eCSR_INI_SINGLE_CHANNEL_CENTERED;
11029 sme_update_config(pHddCtx->hHal, &sme_config);
11030 cbModeChange = true;
11031 }
11032 break;
11033
11034 case NL80211_CHAN_WIDTH_40:
11035 if (sme_config.csrConfig.channelBondingMode24GHz ==
11036 eCSR_INI_SINGLE_CHANNEL_CENTERED) {
11037 if (NL80211_CHAN_HT40MINUS ==
11038 cfg80211_get_chandef_type(chandef))
11039 sme_config.csrConfig.channelBondingMode24GHz =
11040 eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY;
11041 else
11042 sme_config.csrConfig.channelBondingMode24GHz =
11043 eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY;
11044 sme_update_config(pHddCtx->hHal, &sme_config);
11045 cbModeChange = true;
11046 }
11047 break;
11048
11049 default:
11050 hddLog(LOGE, FL("Error!!! Invalid HT20/40 mode !"));
11051 return -EINVAL;
11052 }
11053
11054 if (!cbModeChange)
11055 return 0;
11056
11057 if (WLAN_HDD_SOFTAP != pAdapter->device_mode)
11058 return 0;
11059
11060 hddLog(LOG1, FL("Channel bonding changed to %d"),
11061 sme_config.csrConfig.channelBondingMode24GHz);
11062
11063 /* Change SAP ht2040 mode */
11064 status = hdd_set_sap_ht2040_mode(pAdapter,
11065 cfg80211_get_chandef_type(chandef));
11066 if (status != CDF_STATUS_SUCCESS) {
11067 hddLog(LOGE, FL("Error!!! Cannot set SAP HT20/40 mode!"));
11068 return -EINVAL;
11069 }
11070
11071 return 0;
11072}
11073
11074/**
11075 * wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth
11076 * @wiphy: Pointer to wiphy
11077 * @dev: Pointer to network device
11078 * @chandef: Pointer to channel definition parameter
11079 *
11080 * Return: 0 for success, non-zero for failure
11081 */
11082static int
11083wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy,
11084 struct net_device *dev,
11085 struct cfg80211_chan_def *chandef)
11086{
11087 int ret;
11088
11089 cds_ssr_protect(__func__);
11090 ret = __wlan_hdd_cfg80211_set_ap_channel_width(wiphy, dev, chandef);
11091 cds_ssr_unprotect(__func__);
11092
11093 return ret;
11094}
11095#endif
11096
Abhishek Singh1bdb1572015-10-16 16:24:19 +053011097#ifdef CHANNEL_SWITCH_SUPPORTED
11098/**
11099 * __wlan_hdd_cfg80211_channel_switch()- function to switch
11100 * channel in SAP/GO
11101 * @wiphy: wiphy pointer
11102 * @dev: dev pointer.
11103 * @csa_params: Change channel params
11104 *
11105 * This function is called to switch channel in SAP/GO
11106 *
11107 * Return: 0 if success else return non zero
11108 */
11109static int __wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy,
11110 struct net_device *dev,
11111 struct cfg80211_csa_settings *csa_params)
11112{
11113 hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
11114 hdd_context_t *hdd_ctx;
11115 uint8_t channel;
11116 uint16_t freq;
11117 int ret;
Chandrasekaran, Manishekara74bb022016-01-12 18:37:43 +053011118 phy_ch_width ch_width;
Abhishek Singh1bdb1572015-10-16 16:24:19 +053011119
11120 hddLog(LOG1, FL("Set Freq %d"),
11121 csa_params->chandef.chan->center_freq);
11122
11123 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
11124 ret = wlan_hdd_validate_context(hdd_ctx);
11125
11126 if (0 != ret)
11127 return ret;
11128
11129 if ((WLAN_HDD_P2P_GO != adapter->device_mode) &&
11130 (WLAN_HDD_SOFTAP != adapter->device_mode))
11131 return -ENOTSUPP;
11132
11133 freq = csa_params->chandef.chan->center_freq;
11134 channel = cds_freq_to_chan(freq);
11135
Chandrasekaran, Manishekara74bb022016-01-12 18:37:43 +053011136 ch_width = hdd_map_nl_chan_width(csa_params->chandef.width);
11137
11138 ret = hdd_softap_set_channel_change(dev, channel, ch_width);
Abhishek Singh1bdb1572015-10-16 16:24:19 +053011139 return ret;
11140}
11141
11142/**
11143 * wlan_hdd_cfg80211_channel_switch()- function to switch
11144 * channel in SAP/GO
11145 * @wiphy: wiphy pointer
11146 * @dev: dev pointer.
11147 * @csa_params: Change channel params
11148 *
11149 * This function is called to switch channel in SAP/GO
11150 *
11151 * Return: 0 if success else return non zero
11152 */
11153static int wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy,
11154 struct net_device *dev,
11155 struct cfg80211_csa_settings *csa_params)
11156{
11157 int ret;
11158
11159 cds_ssr_protect(__func__);
11160 ret = __wlan_hdd_cfg80211_channel_switch(wiphy, dev, csa_params);
11161 cds_ssr_unprotect(__func__);
11162 return ret;
11163}
11164#endif
11165
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080011166/**
11167 * wlan_hdd_convert_nl_iftype_to_hdd_type() - provides the type
11168 * translation from NL to policy manager type
11169 * @type: Generic connection mode type defined in NL
11170 *
11171 *
11172 * This function provides the type translation
11173 *
11174 * Return: cds_con_mode enum
11175 */
11176enum cds_con_mode wlan_hdd_convert_nl_iftype_to_hdd_type(
11177 enum nl80211_iftype type)
11178{
11179 enum cds_con_mode mode = CDS_MAX_NUM_OF_MODE;
11180 switch (type) {
11181 case NL80211_IFTYPE_STATION:
11182 mode = CDS_STA_MODE;
11183 break;
11184 case NL80211_IFTYPE_P2P_CLIENT:
11185 mode = CDS_P2P_CLIENT_MODE;
11186 break;
11187 case NL80211_IFTYPE_P2P_GO:
11188 mode = CDS_P2P_GO_MODE;
11189 break;
11190 case NL80211_IFTYPE_AP:
11191 mode = CDS_SAP_MODE;
11192 break;
11193 case NL80211_IFTYPE_ADHOC:
11194 mode = CDS_IBSS_MODE;
11195 break;
11196 default:
11197 hddLog(LOGE, FL("Unsupported interface type (%d)"),
11198 type);
11199 }
11200 return mode;
11201}
11202
11203/**
11204 * struct cfg80211_ops - cfg80211_ops
11205 *
11206 * @add_virtual_intf: Add virtual interface
11207 * @del_virtual_intf: Delete virtual interface
11208 * @change_virtual_intf: Change virtual interface
11209 * @change_station: Change station
11210 * @add_beacon: Add beacon in sap mode
11211 * @del_beacon: Delete beacon in sap mode
11212 * @set_beacon: Set beacon in sap mode
11213 * @start_ap: Start ap
11214 * @change_beacon: Change beacon
11215 * @stop_ap: Stop ap
11216 * @change_bss: Change bss
11217 * @add_key: Add key
11218 * @get_key: Get key
11219 * @del_key: Delete key
11220 * @set_default_key: Set default key
11221 * @set_channel: Set channel
11222 * @scan: Scan
11223 * @connect: Connect
11224 * @disconnect: Disconnect
11225 * @join_ibss = Join ibss
11226 * @leave_ibss = Leave ibss
11227 * @set_wiphy_params = Set wiphy params
11228 * @set_tx_power = Set tx power
11229 * @get_tx_power = get tx power
11230 * @remain_on_channel = Remain on channel
11231 * @cancel_remain_on_channel = Cancel remain on channel
11232 * @mgmt_tx = Tx management frame
11233 * @mgmt_tx_cancel_wait = Cancel management tx wait
11234 * @set_default_mgmt_key = Set default management key
11235 * @set_txq_params = Set tx queue parameters
11236 * @get_station = Get station
11237 * @set_power_mgmt = Set power management
11238 * @del_station = Delete station
11239 * @add_station = Add station
11240 * @set_pmksa = Set pmksa
11241 * @del_pmksa = Delete pmksa
11242 * @flush_pmksa = Flush pmksa
11243 * @update_ft_ies = Update FT IEs
11244 * @tdls_mgmt = Tdls management
11245 * @tdls_oper = Tdls operation
11246 * @set_rekey_data = Set rekey data
11247 * @sched_scan_start = Scheduled scan start
11248 * @sched_scan_stop = Scheduled scan stop
11249 * @resume = Resume wlan
11250 * @suspend = Suspend wlan
11251 * @set_mac_acl = Set mac acl
11252 * @testmode_cmd = Test mode command
11253 * @set_ap_chanwidth = Set AP channel bandwidth
11254 * @dump_survey = Dump survey
11255 * @key_mgmt_set_pmk = Set pmk key management
11256 */
11257static struct cfg80211_ops wlan_hdd_cfg80211_ops = {
11258 .add_virtual_intf = wlan_hdd_add_virtual_intf,
11259 .del_virtual_intf = wlan_hdd_del_virtual_intf,
11260 .change_virtual_intf = wlan_hdd_cfg80211_change_iface,
11261 .change_station = wlan_hdd_change_station,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080011262 .start_ap = wlan_hdd_cfg80211_start_ap,
11263 .change_beacon = wlan_hdd_cfg80211_change_beacon,
11264 .stop_ap = wlan_hdd_cfg80211_stop_ap,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080011265 .change_bss = wlan_hdd_cfg80211_change_bss,
11266 .add_key = wlan_hdd_cfg80211_add_key,
11267 .get_key = wlan_hdd_cfg80211_get_key,
11268 .del_key = wlan_hdd_cfg80211_del_key,
11269 .set_default_key = wlan_hdd_cfg80211_set_default_key,
11270 .scan = wlan_hdd_cfg80211_scan,
11271 .connect = wlan_hdd_cfg80211_connect,
11272 .disconnect = wlan_hdd_cfg80211_disconnect,
11273 .join_ibss = wlan_hdd_cfg80211_join_ibss,
11274 .leave_ibss = wlan_hdd_cfg80211_leave_ibss,
11275 .set_wiphy_params = wlan_hdd_cfg80211_set_wiphy_params,
11276 .set_tx_power = wlan_hdd_cfg80211_set_txpower,
11277 .get_tx_power = wlan_hdd_cfg80211_get_txpower,
11278 .remain_on_channel = wlan_hdd_cfg80211_remain_on_channel,
11279 .cancel_remain_on_channel = wlan_hdd_cfg80211_cancel_remain_on_channel,
11280 .mgmt_tx = wlan_hdd_mgmt_tx,
11281 .mgmt_tx_cancel_wait = wlan_hdd_cfg80211_mgmt_tx_cancel_wait,
11282 .set_default_mgmt_key = wlan_hdd_set_default_mgmt_key,
11283 .set_txq_params = wlan_hdd_set_txq_params,
11284 .get_station = wlan_hdd_cfg80211_get_station,
11285 .set_power_mgmt = wlan_hdd_cfg80211_set_power_mgmt,
11286 .del_station = wlan_hdd_cfg80211_del_station,
11287 .add_station = wlan_hdd_cfg80211_add_station,
11288#ifdef FEATURE_WLAN_LFR
11289 .set_pmksa = wlan_hdd_cfg80211_set_pmksa,
11290 .del_pmksa = wlan_hdd_cfg80211_del_pmksa,
11291 .flush_pmksa = wlan_hdd_cfg80211_flush_pmksa,
11292#endif
11293#if defined(WLAN_FEATURE_VOWIFI_11R) && defined(KERNEL_SUPPORT_11R_CFG80211)
11294 .update_ft_ies = wlan_hdd_cfg80211_update_ft_ies,
11295#endif
11296#ifdef FEATURE_WLAN_TDLS
11297 .tdls_mgmt = wlan_hdd_cfg80211_tdls_mgmt,
11298 .tdls_oper = wlan_hdd_cfg80211_tdls_oper,
11299#endif
11300#ifdef WLAN_FEATURE_GTK_OFFLOAD
11301 .set_rekey_data = wlan_hdd_cfg80211_set_rekey_data,
11302#endif /* WLAN_FEATURE_GTK_OFFLOAD */
11303#ifdef FEATURE_WLAN_SCAN_PNO
11304 .sched_scan_start = wlan_hdd_cfg80211_sched_scan_start,
11305 .sched_scan_stop = wlan_hdd_cfg80211_sched_scan_stop,
11306#endif /*FEATURE_WLAN_SCAN_PNO */
11307 .resume = wlan_hdd_cfg80211_resume_wlan,
11308 .suspend = wlan_hdd_cfg80211_suspend_wlan,
11309 .set_mac_acl = wlan_hdd_cfg80211_set_mac_acl,
11310#ifdef WLAN_NL80211_TESTMODE
11311 .testmode_cmd = wlan_hdd_cfg80211_testmode,
11312#endif
11313#ifdef QCA_HT_2040_COEX
11314 .set_ap_chanwidth = wlan_hdd_cfg80211_set_ap_channel_width,
11315#endif
11316 .dump_survey = wlan_hdd_cfg80211_dump_survey,
Abhishek Singh1bdb1572015-10-16 16:24:19 +053011317#ifdef CHANNEL_SWITCH_SUPPORTED
11318 .channel_switch = wlan_hdd_cfg80211_channel_switch,
11319#endif
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080011320};