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