WIFI: fix ap62x8 cts test fail issue [1/5]
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.1.579.77.41.1.cn / wl_cfgvendor.c
CommitLineData
010c3a89
RC
1/*
2 * Linux cfg80211 Vendor Extension Code
3 *
4 * Copyright (C) 1999-2017, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: wl_cfgvendor.c 710862 2017-07-14 07:43:59Z $
28 */
29
30/*
31 * New vendor interface additon to nl80211/cfg80211 to allow vendors
32 * to implement proprietary features over the cfg80211 stack.
33*/
34
35#include <typedefs.h>
36#include <linuxver.h>
37#include <osl.h>
38#include <linux/kernel.h>
39#include <linux/vmalloc.h>
40
41#include <bcmutils.h>
42#include <bcmwifi_channels.h>
43#include <bcmendian.h>
44#include <ethernet.h>
45#include <802.11.h>
46#include <linux/if_arp.h>
47#include <asm/uaccess.h>
48
49#include <dngl_stats.h>
50#include <dhd.h>
51#include <dhd_debug.h>
52#include <dhdioctl.h>
53#include <wlioctl.h>
54#include <wlioctl_utils.h>
55#include <dhd_cfg80211.h>
56#ifdef PNO_SUPPORT
57#include <dhd_pno.h>
58#endif /* PNO_SUPPORT */
59#ifdef RTT_SUPPORT
60#include <dhd_rtt.h>
61#endif /* RTT_SUPPORT */
62
63#include <ethernet.h>
64#include <linux/kernel.h>
65#include <linux/kthread.h>
66#include <linux/netdevice.h>
67#include <linux/sched.h>
68#include <linux/etherdevice.h>
69#include <linux/wireless.h>
70#include <linux/ieee80211.h>
71#include <linux/wait.h>
72#include <net/cfg80211.h>
73#include <net/rtnetlink.h>
74
75#include <wlioctl.h>
76#include <wldev_common.h>
77#include <wl_cfg80211.h>
78#include <wl_cfgp2p.h>
79#include <wl_android.h>
80#include <wl_cfgvendor.h>
81#ifdef PROP_TXSTATUS
82#include <dhd_wlfc.h>
83#endif
84#include <brcm_nl80211.h>
85
86#ifdef STAT_REPORT
87#include <wl_statreport.h>
88#endif
89
90#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
91
92/*
93 * This API is to be used for asynchronous vendor events. This
94 * shouldn't be used in response to a vendor command from its
95 * do_it handler context (instead wl_cfgvendor_send_cmd_reply should
96 * be used).
97 */
98int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
99 struct net_device *dev, int event_id, const void *data, int len)
100{
101 u16 kflags;
102 struct sk_buff *skb;
103
104 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
105
106 /* Alloc the SKB for vendor_event */
107#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
108 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
109 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len, event_id, kflags);
110#else
111 skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
112#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
113 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
114 if (!skb) {
115 WL_ERR(("skb alloc failed"));
116 return -ENOMEM;
117 }
118
119 /* Push the data to the skb */
120 nla_put_nohdr(skb, len, data);
121
122 cfg80211_vendor_event(skb, kflags);
123
124 return 0;
125}
126
127static int
128wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
129 struct net_device *dev, const void *data, int len)
130{
131 struct sk_buff *skb;
132
133 /* Alloc the SKB for vendor_event */
134 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
135 if (unlikely(!skb)) {
136 WL_ERR(("skb alloc failed"));
137 return -ENOMEM;
138 }
139
140 /* Push the data to the skb */
141 nla_put_nohdr(skb, len, data);
142
143 return cfg80211_vendor_cmd_reply(skb);
144}
145
146static int
147wl_cfgvendor_get_feature_set(struct wiphy *wiphy,
148 struct wireless_dev *wdev, const void *data, int len)
149{
150 int err = 0;
151 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
152 int reply;
153
154 reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg));
155
156 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
157 &reply, sizeof(int));
158 if (unlikely(err))
159 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
160
161 return err;
162}
163
164static int
165wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
166 struct wireless_dev *wdev, const void *data, int len)
167{
168 int err = 0;
169 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
170 struct sk_buff *skb;
171 int reply;
172 int mem_needed, i;
173
174 mem_needed = VENDOR_REPLY_OVERHEAD +
175 (ATTRIBUTE_U32_LEN * MAX_FEATURE_SET_CONCURRRENT_GROUPS) + ATTRIBUTE_U32_LEN;
176
177 /* Alloc the SKB for vendor_event */
178 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
179 if (unlikely(!skb)) {
180 WL_ERR(("skb alloc failed"));
181 err = -ENOMEM;
182 goto exit;
183 }
184
185 nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, MAX_FEATURE_SET_CONCURRRENT_GROUPS);
186 for (i = 0; i < MAX_FEATURE_SET_CONCURRRENT_GROUPS; i++) {
187 reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), i);
188 if (reply != WIFI_FEATURE_INVALID) {
189 nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply);
190 }
191 }
192
193 err = cfg80211_vendor_cmd_reply(skb);
194
195 if (unlikely(err)) {
196 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
197 }
198exit:
199 return err;
200}
201
202static int
203wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy,
204 struct wireless_dev *wdev, const void *data, int len)
205{
206 int err = 0;
207 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
208 int type;
209 uint8 random_mac_oui[DOT11_OUI_LEN];
210
211 type = nla_type(data);
212
213 if (type == ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI) {
214 memcpy(random_mac_oui, nla_data(data), DOT11_OUI_LEN);
215
216 err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), random_mac_oui);
217
218 if (unlikely(err))
219 WL_ERR(("Bad OUI, could not set:%d \n", err));
220
221 } else {
222 err = -1;
223 }
224
225 return err;
226}
227#ifdef CUSTOM_FORCE_NODFS_FLAG
228static int
229wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy,
230 struct wireless_dev *wdev, const void *data, int len)
231{
232 int err = 0;
233 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
234 int type;
235 u32 nodfs;
236
237 type = nla_type(data);
238 if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) {
239 nodfs = nla_get_u32(data);
240 err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs);
241 } else {
242 err = -1;
243 }
244 return err;
245}
246#endif /* CUSTOM_FORCE_NODFS_FLAG */
247
248static int
249wl_cfgvendor_set_country(struct wiphy *wiphy,
250 struct wireless_dev *wdev, const void *data, int len)
251{
252 int err = BCME_ERROR, rem, type;
253 char country_code[WLC_CNTRY_BUF_SZ] = {0};
254 const struct nlattr *iter;
dfb0f3ae 255
010c3a89
RC
256 nla_for_each_attr(iter, data, len, rem) {
257 type = nla_type(iter);
258 switch (type) {
259 case ANDR_WIFI_ATTRIBUTE_COUNTRY:
260 memcpy(country_code, nla_data(iter),
261 MIN(nla_len(iter), WLC_CNTRY_BUF_SZ));
262 break;
263 default:
264 WL_ERR(("Unknown type: %d\n", type));
265 return err;
266 }
267 }
268
269 err = wldev_set_country(wdev->netdev, country_code, true, true, -1);
270 if (err < 0) {
271 WL_ERR(("Set country failed ret:%d\n", err));
272 }
273
274 return err;
275}
276
277#ifdef GSCAN_SUPPORT
278int
279wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
280 struct net_device *dev, void *data, int len, wl_vendor_event_t event)
281{
282 u16 kflags;
283 const void *ptr;
284 struct sk_buff *skb;
285 int malloc_len, total, iter_cnt_to_send, cnt;
286 gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
287
288 total = len/sizeof(wifi_gscan_result_t);
289 while (total > 0) {
290 malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD;
291 if (malloc_len > NLMSG_DEFAULT_SIZE) {
292 malloc_len = NLMSG_DEFAULT_SIZE;
293 }
294 iter_cnt_to_send =
295 (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t);
296 total = total - iter_cnt_to_send;
297
298 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
299
300 /* Alloc the SKB for vendor_event */
301#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
302 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
303 skb = cfg80211_vendor_event_alloc(wiphy, NULL, malloc_len, event, kflags);
304#else
305 skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags);
306#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
307 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
308 if (!skb) {
309 WL_ERR(("skb alloc failed"));
310 return -ENOMEM;
311 }
312
313 while (cache && iter_cnt_to_send) {
314 ptr = (const void *) &cache->results[cache->tot_consumed];
315
316 if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) {
317 cnt = iter_cnt_to_send;
318 } else {
319 cnt = (cache->tot_count - cache->tot_consumed);
320 }
321
322 iter_cnt_to_send -= cnt;
323 cache->tot_consumed += cnt;
324 /* Push the data to the skb */
325 nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
326 if (cache->tot_consumed == cache->tot_count) {
327 cache = cache->next;
328 }
329
330 }
331
332 cfg80211_vendor_event(skb, kflags);
333 }
334
335 return 0;
336}
337
338
339static int
340wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
341 struct wireless_dev *wdev, const void *data, int len)
342{
343 int err = 0;
344 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
345 dhd_pno_gscan_capabilities_t *reply = NULL;
346 uint32 reply_len = 0;
347
348
349 reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
350 DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
351 if (!reply) {
352 WL_ERR(("Could not get capabilities\n"));
353 err = -EINVAL;
354 return err;
355 }
356
357 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
358 reply, reply_len);
359
360 if (unlikely(err)) {
361 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
362 }
363
364 kfree(reply);
365 return err;
366}
367
368static int
369wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
370 struct wireless_dev *wdev, const void *data, int len)
371{
372 int err = 0;
373 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
374 gscan_results_cache_t *results, *iter;
375 uint32 reply_len, is_done = 1;
376 int32 mem_needed, num_results_iter;
377 wifi_gscan_result_t *ptr;
378 uint16 num_scan_ids, num_results;
379 struct sk_buff *skb;
380 struct nlattr *scan_hdr, *complete_flag;
381
382 err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
383 if (err != BCME_OK)
384 return -EBUSY;
385
386 err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
387 if (err != BCME_OK) {
388 WL_ERR(("Can't obtain lock to access batch results %d\n", err));
389 return -EBUSY;
390 }
391 results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
392 DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
393
394 if (!results) {
395 WL_ERR(("No results to send %d\n", err));
396 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
397 results, 0);
398
399 if (unlikely(err))
400 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
401 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
402 return err;
403 }
404 num_scan_ids = reply_len & 0xFFFF;
405 num_results = (reply_len & 0xFFFF0000) >> 16;
406 mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
407 (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
408 VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
409
410 if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
411 mem_needed = (int32)NLMSG_DEFAULT_SIZE;
412 }
413
414 WL_TRACE(("is_done %d mem_needed %d max_mem %d\n", is_done, mem_needed,
415 (int)NLMSG_DEFAULT_SIZE));
416 /* Alloc the SKB for vendor_event */
417 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
418 if (unlikely(!skb)) {
419 WL_ERR(("skb alloc failed"));
420 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
421 return -ENOMEM;
422 }
423 iter = results;
424 complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,
425 sizeof(is_done));
426 mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
427
428 while (iter) {
429 num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN);
430 num_results_iter /= (int32)sizeof(wifi_gscan_result_t);
431 if (num_results_iter <= 0 ||
432 ((iter->tot_count - iter->tot_consumed) > num_results_iter)) {
433 break;
434 }
435 scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
436 /* no more room? we are done then (for now) */
437 if (scan_hdr == NULL) {
438 is_done = 0;
439 break;
440 }
441 nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
442 nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
443 nla_put_u32(skb, GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK, iter->scan_ch_bucket);
444
445 num_results_iter = iter->tot_count - iter->tot_consumed;
446
447 nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
448 if (num_results_iter) {
449 ptr = &iter->results[iter->tot_consumed];
450 iter->tot_consumed += num_results_iter;
451 nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
452 num_results_iter * sizeof(wifi_gscan_result_t), ptr);
453 }
454 nla_nest_end(skb, scan_hdr);
455 mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
456 (num_results_iter * sizeof(wifi_gscan_result_t));
457 iter = iter->next;
458 }
459 /* Returns TRUE if all result consumed */
460 is_done = dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
461 memcpy(nla_data(complete_flag), &is_done, sizeof(is_done));
462 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
463 return cfg80211_vendor_cmd_reply(skb);
464}
465
466static int
467wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
468 struct wireless_dev *wdev, const void *data, int len)
469{
470 int err = 0;
471 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
472 int type, tmp = len;
473 int run = 0xFF;
474 int flush = 0;
475 const struct nlattr *iter;
476
477 nla_for_each_attr(iter, data, len, tmp) {
478 type = nla_type(iter);
479 if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
480 run = nla_get_u32(iter);
481 else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
482 flush = nla_get_u32(iter);
483 }
484
485 if (run != 0xFF) {
486 err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
487
488 if (unlikely(err)) {
489 WL_ERR(("Could not run gscan:%d \n", err));
490 }
491 return err;
492 } else {
493 return -EINVAL;
494 }
495
496
497}
498
499static int
500wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
501 struct wireless_dev *wdev, const void *data, int len)
502{
503 int err = 0;
504 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
505 int type;
506 bool real_time = FALSE;
507
508 type = nla_type(data);
509
510 if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
511 real_time = nla_get_u32(data);
512
513 err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
514
515 if (unlikely(err)) {
516 WL_ERR(("Could not run gscan:%d \n", err));
517 }
518
519 } else {
520 err = -EINVAL;
521 }
522
523 return err;
524}
525
526static int
527wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev,
528 gscan_scan_params_t *scan_param, int num)
529{
530 struct dhd_pno_gscan_channel_bucket *ch_bucket;
531 int k = 0;
532 int type, err = 0, rem;
533 const struct nlattr *cur, *next;
534
535 nla_for_each_nested(cur, prev, rem) {
536 type = nla_type(cur);
537 ch_bucket = scan_param->channel_bucket;
538 switch (type) {
539 case GSCAN_ATTRIBUTE_BUCKET_ID:
540 break;
541 case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
542 if (nla_len(cur) != sizeof(uint32)) {
543 err = -EINVAL;
544 goto exit;
545 }
546
547 ch_bucket[num].bucket_freq_multiple =
548 nla_get_u32(cur) / MSEC_PER_SEC;
549 break;
550 case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
551 if (nla_len(cur) != sizeof(uint32)) {
552 err = -EINVAL;
553 goto exit;
554 }
555 ch_bucket[num].num_channels = nla_get_u32(cur);
556 if (ch_bucket[num].num_channels >
557 GSCAN_MAX_CHANNELS_IN_BUCKET) {
558 WL_ERR(("channel range:%d,bucket:%d\n",
559 ch_bucket[num].num_channels,
560 num));
561 err = -EINVAL;
562 goto exit;
563 }
564 break;
565 case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
566 nla_for_each_nested(next, cur, rem) {
567 if (k >= GSCAN_MAX_CHANNELS_IN_BUCKET)
568 break;
569 if (nla_len(next) != sizeof(uint32)) {
570 err = -EINVAL;
571 goto exit;
572 }
573 ch_bucket[num].chan_list[k] = nla_get_u32(next);
574 k++;
575 }
576 break;
577 case GSCAN_ATTRIBUTE_BUCKETS_BAND:
578 if (nla_len(cur) != sizeof(uint32)) {
579 err = -EINVAL;
580 goto exit;
581 }
582 ch_bucket[num].band = (uint16)nla_get_u32(cur);
583 break;
584 case GSCAN_ATTRIBUTE_REPORT_EVENTS:
585 if (nla_len(cur) != sizeof(uint32)) {
586 err = -EINVAL;
587 goto exit;
588 }
589 ch_bucket[num].report_flag = (uint8)nla_get_u32(cur);
590 break;
591 case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT:
592 if (nla_len(cur) != sizeof(uint32)) {
593 err = -EINVAL;
594 goto exit;
595 }
596 ch_bucket[num].repeat = (uint16)nla_get_u32(cur);
597 break;
598 case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD:
599 if (nla_len(cur) != sizeof(uint32)) {
600 err = -EINVAL;
601 goto exit;
602 }
603 ch_bucket[num].bucket_max_multiple =
604 nla_get_u32(cur) / MSEC_PER_SEC;
605 break;
606 default:
607 WL_ERR(("unknown attr type:%d\n", type));
608 err = -EINVAL;
609 goto exit;
610 }
611 }
612
613exit:
614 return err;
615}
616
617static int
618wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, struct wireless_dev *wdev,
619 const void *data, int len)
620{
621 int err = 0;
622 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
623 gscan_scan_params_t *scan_param;
624 int j = 0;
625 int type, tmp;
626 const struct nlattr *iter;
627
628 scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL);
629 if (!scan_param) {
630 WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
631 err = -EINVAL;
632 return err;
633
634 }
635
636 scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
637 nla_for_each_attr(iter, data, len, tmp) {
638 type = nla_type(iter);
639
640 if (j >= GSCAN_MAX_CH_BUCKETS) {
641 break;
642 }
643
644 switch (type) {
645 case GSCAN_ATTRIBUTE_BASE_PERIOD:
646 if (nla_len(iter) != sizeof(uint32)) {
647 err = -EINVAL;
648 goto exit;
649 }
650 scan_param->scan_fr = nla_get_u32(iter) / MSEC_PER_SEC;
651 break;
652 case GSCAN_ATTRIBUTE_NUM_BUCKETS:
653 if (nla_len(iter) != sizeof(uint32)) {
654 err = -EINVAL;
655 goto exit;
656 }
657 scan_param->nchannel_buckets = nla_get_u32(iter);
658 if (scan_param->nchannel_buckets >=
659 GSCAN_MAX_CH_BUCKETS) {
660 WL_ERR(("ncha_buck out of range %d\n",
661 scan_param->nchannel_buckets));
662 err = -EINVAL;
663 goto exit;
664 }
665 break;
666 case GSCAN_ATTRIBUTE_CH_BUCKET_1:
667 case GSCAN_ATTRIBUTE_CH_BUCKET_2:
668 case GSCAN_ATTRIBUTE_CH_BUCKET_3:
669 case GSCAN_ATTRIBUTE_CH_BUCKET_4:
670 case GSCAN_ATTRIBUTE_CH_BUCKET_5:
671 case GSCAN_ATTRIBUTE_CH_BUCKET_6:
672 case GSCAN_ATTRIBUTE_CH_BUCKET_7:
673 err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j);
674 if (err < 0) {
675 WL_ERR(("set_scan_cfg_buck error:%d\n", err));
676 goto exit;
677 }
678 j++;
679 break;
680 default:
681 WL_ERR(("Unknown type %d\n", type));
682 err = -EINVAL;
683 goto exit;
684 }
685 }
686
687 err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
688 DHD_PNO_SCAN_CFG_ID, scan_param, FALSE);
689
690 if (err < 0) {
691 WL_ERR(("Could not set GSCAN scan cfg\n"));
692 err = -EINVAL;
693 }
694
695exit:
696 kfree(scan_param);
697 return err;
698
699}
700
701static int
702wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
703 struct wireless_dev *wdev, const void *data, int len)
704{
705 int err = 0;
706 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
707 gscan_hotlist_scan_params_t *hotlist_params;
708 int tmp, tmp1, tmp2, type, j = 0, dummy;
709 const struct nlattr *outer, *inner = NULL, *iter;
710 bool flush = FALSE;
711 struct bssid_t *pbssid;
712
713 BCM_REFERENCE(dummy);
714
715 if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) {
716 WL_ERR(("buffer length :%d wrong - bail out.\n", len));
717 return -EINVAL;
718 }
719
720 hotlist_params = kzalloc(sizeof(*hotlist_params)
721 + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)),
722 GFP_KERNEL);
723
724 if (!hotlist_params) {
725 WL_ERR(("Cannot Malloc memory.\n"));
726 return -ENOMEM;
727 }
728
729 hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
730
731 nla_for_each_attr(iter, data, len, tmp2) {
732 type = nla_type(iter);
733 switch (type) {
734 case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
735 pbssid = hotlist_params->bssid;
736 nla_for_each_nested(outer, iter, tmp) {
737 nla_for_each_nested(inner, outer, tmp1) {
738 type = nla_type(inner);
739
740 switch (type) {
741 case GSCAN_ATTRIBUTE_BSSID:
742 if (nla_len(inner) != sizeof(pbssid[j].macaddr)) {
743 WL_ERR(("type:%d length:%d not matching.\n",
744 type, nla_len(inner)));
745 err = -EINVAL;
746 goto exit;
747 }
748 memcpy(
749 &(pbssid[j].macaddr),
750 nla_data(inner),
751 sizeof(pbssid[j].macaddr));
752 break;
753 case GSCAN_ATTRIBUTE_RSSI_LOW:
754 if (nla_len(inner) != sizeof(uint8)) {
755 WL_ERR(("type:%d length:%d not matching.\n",
756 type, nla_len(inner)));
757 err = -EINVAL;
758 goto exit;
759 }
760 pbssid[j].rssi_reporting_threshold =
761 (int8)nla_get_u8(inner);
762 break;
763 case GSCAN_ATTRIBUTE_RSSI_HIGH:
764 if (nla_len(inner) != sizeof(uint8)) {
765 WL_ERR(("type:%d length:%d not matching.\n",
766 type, nla_len(inner)));
767 err = -EINVAL;
768 goto exit;
769 }
770 dummy = (int8)nla_get_u8(inner);
771 break;
772 default:
773 WL_ERR(("ATTR unknown %d\n", type));
774 err = -EINVAL;
775 goto exit;
776 }
777 }
778 if (++j >= PFN_SWC_MAX_NUM_APS) {
779 WL_ERR(("cap hotlist max:%d\n", j));
780 break;
781 }
782 }
783 hotlist_params->nbssid = j;
784 break;
785 case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
786 if (nla_len(iter) != sizeof(uint8)) {
787 WL_ERR(("type:%d length:%d not matching.\n",
788 type, nla_len(inner)));
789 err = -EINVAL;
790 goto exit;
791 }
792 flush = nla_get_u8(iter);
793 break;
794 case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
795 if (nla_len(iter) != sizeof(uint32)) {
796 WL_ERR(("type:%d length:%d not matching.\n",
797 type, nla_len(inner)));
798 err = -EINVAL;
799 goto exit;
800 }
801 hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter);
802 break;
803 default:
804 WL_ERR(("Unknown type %d\n", type));
805 err = -EINVAL;
806 goto exit;
807 }
808
809 }
810
811 if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
812 DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
813 WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err));
814 err = -EINVAL;
815 goto exit;
816 }
817exit:
818 kfree(hotlist_params);
819 return err;
820}
821
822static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy,
823 struct wireless_dev *wdev, const void *data, int len)
824{
825 int err = 0;
826 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
827 dhd_pno_ssid_t *ssid_elem;
828 int tmp, tmp1, tmp2, type = 0, num = 0;
829 const struct nlattr *outer, *inner, *iter;
830 uint8 flush = FALSE, i = 0;
831 wl_pfn_ssid_params_t params;
832
833 nla_for_each_attr(iter, data, len, tmp2) {
834 type = nla_type(iter);
835 switch (type) {
836 case GSCAN_ATTRIBUTE_EPNO_SSID_LIST:
837 nla_for_each_nested(outer, iter, tmp) {
838 ssid_elem = (dhd_pno_ssid_t *)
839 dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
840 DHD_PNO_GET_NEW_EPNO_SSID_ELEM,
841 NULL, &num);
842 if (!ssid_elem) {
843 WL_ERR(("Failed to get SSID LIST buffer\n"));
844 err = -ENOMEM;
845 goto exit;
846 }
847 i++;
848 nla_for_each_nested(inner, outer, tmp1) {
849 type = nla_type(inner);
850
851 switch (type) {
852 case GSCAN_ATTRIBUTE_EPNO_SSID:
853 memcpy(ssid_elem->SSID,
854 nla_data(inner),
855 DOT11_MAX_SSID_LEN);
856 break;
857 case GSCAN_ATTRIBUTE_EPNO_SSID_LEN:
858 ssid_elem->SSID_len =
859 nla_get_u32(inner);
860 if (ssid_elem->SSID_len >
861 DOT11_MAX_SSID_LEN) {
862 WL_ERR(("SSID too"
863 "long %d\n",
864 ssid_elem->SSID_len));
865 err = -EINVAL;
866 goto exit;
867 }
868 break;
869 case GSCAN_ATTRIBUTE_EPNO_FLAGS:
870 ssid_elem->flags =
871 nla_get_u32(inner);
872 ssid_elem->hidden =
873 ((ssid_elem->flags &
874 DHD_EPNO_HIDDEN_SSID) != 0);
875 break;
876 case GSCAN_ATTRIBUTE_EPNO_AUTH:
877 ssid_elem->wpa_auth =
878 nla_get_u32(inner);
879 break;
880 }
881 }
882 if (!ssid_elem->SSID_len) {
883 WL_ERR(("Broadcast SSID is illegal for ePNO\n"));
884 err = -EINVAL;
885 goto exit;
886 }
887 dhd_pno_translate_epno_fw_flags(&ssid_elem->flags);
888 dhd_pno_set_epno_auth_flag(&ssid_elem->wpa_auth);
889 }
890 break;
891 case GSCAN_ATTRIBUTE_EPNO_SSID_NUM:
892 num = nla_get_u8(iter);
893 break;
894 case GSCAN_ATTRIBUTE_EPNO_FLUSH:
895 flush = (bool)nla_get_u32(iter);
896 /* Flush attribute is expected before any ssid attribute */
897 if (i && flush) {
898 WL_ERR(("Bad attributes\n"));
899 err = -EINVAL;
900 goto exit;
901 }
902 /* Need to flush driver and FW cfg */
903 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
904 DHD_PNO_EPNO_CFG_ID, NULL, flush);
905 dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
906 break;
907 case GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR:
908 params.min5G_rssi = nla_get_s8(iter);
909 break;
910 case GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR:
911 params.min2G_rssi = nla_get_s8(iter);
912 break;
913 case GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX:
914 params.init_score_max = nla_get_s16(iter);
915 break;
916 case GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS:
917 params.cur_bssid_bonus = nla_get_s16(iter);
918 break;
919 case GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS:
920 params.same_ssid_bonus = nla_get_s16(iter);
921 break;
922 case GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS:
923 params.secure_bonus = nla_get_s16(iter);
924 break;
925 case GSCAN_ATTRIBUTE_EPNO_5G_BONUS:
926 params.band_5g_bonus = nla_get_s16(iter);
927 break;
928 default:
929 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
930 err = -EINVAL;
931 goto exit;
932 }
933 }
934 if (i != num) {
935 WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__,
936 num, i));
937 err = -EINVAL;
938 }
939exit:
940 /* Flush all configs if error condition */
941 if (err < 0) {
942 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
943 DHD_PNO_EPNO_CFG_ID, NULL, TRUE);
944 dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
945 } else if (type != GSCAN_ATTRIBUTE_EPNO_FLUSH) {
946 /* If the last attribute was FLUSH, nothing else to do */
947 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
948 DHD_PNO_EPNO_PARAMS_ID, &params, FALSE);
949 err = dhd_dev_set_epno(bcmcfg_to_prmry_ndev(cfg));
950 }
951 return err;
952}
953
954static int
955wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
956 struct wireless_dev *wdev, const void *data, int len)
957{
958 int err = 0, tmp, type;
959 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
960 gscan_batch_params_t batch_param;
961 const struct nlattr *iter;
962
963 batch_param.mscan = batch_param.bestn = 0;
964 batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
965
966 nla_for_each_attr(iter, data, len, tmp) {
967 type = nla_type(iter);
968
969 switch (type) {
970 case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
971 batch_param.bestn = nla_get_u32(iter);
972 break;
973 case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
974 batch_param.mscan = nla_get_u32(iter);
975 break;
976 case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
977 batch_param.buffer_threshold = nla_get_u32(iter);
978 break;
979 default:
980 WL_ERR(("Unknown type %d\n", type));
981 break;
982 }
983 }
984
985 if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
986 DHD_PNO_BATCH_SCAN_CFG_ID, &batch_param, FALSE) < 0) {
987 WL_ERR(("Could not set batch cfg\n"));
988 err = -EINVAL;
989 return err;
990 }
991
992 return err;
993}
994
995#endif /* GSCAN_SUPPORT */
996#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
997static int
998wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
999 struct wireless_dev *wdev, const void *data, int len)
1000{
1001 int err = 0, type, band;
1002 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1003 uint16 *reply = NULL;
1004 uint32 reply_len = 0, num_channels, mem_needed;
1005 struct sk_buff *skb;
1006
1007 type = nla_type(data);
1008
1009 if (type == GSCAN_ATTRIBUTE_BAND) {
1010 band = nla_get_u32(data);
1011 } else {
1012 return -EINVAL;
1013 }
1014
1015 reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
1016 DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
1017
1018 if (!reply) {
1019 WL_ERR(("Could not get channel list\n"));
1020 err = -EINVAL;
1021 return err;
1022 }
1023 num_channels = reply_len/ sizeof(uint32);
1024 mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
1025
1026 /* Alloc the SKB for vendor_event */
1027 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1028 if (unlikely(!skb)) {
1029 WL_ERR(("skb alloc failed"));
1030 err = -ENOMEM;
1031 goto exit;
1032 }
1033
1034 nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
1035 nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
1036
1037 err = cfg80211_vendor_cmd_reply(skb);
1038
1039 if (unlikely(err)) {
1040 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1041 }
1042exit:
1043 kfree(reply);
1044 return err;
1045}
1046#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
1047
1048#ifdef RSSI_MONITOR_SUPPORT
1049static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy,
1050 struct wireless_dev *wdev, const void *data, int len)
1051{
1052 int err = 0, tmp, type, start = 0;
1053 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1054 int8 max_rssi = 0, min_rssi = 0;
1055 const struct nlattr *iter;
1056
1057 nla_for_each_attr(iter, data, len, tmp) {
1058 type = nla_type(iter);
1059 switch (type) {
1060 case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI:
1061 max_rssi = (int8) nla_get_u32(iter);
1062 break;
1063 case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI:
1064 min_rssi = (int8) nla_get_u32(iter);
1065 break;
1066 case RSSI_MONITOR_ATTRIBUTE_START:
1067 start = nla_get_u32(iter);
1068 }
1069 }
1070
1071 if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
1072 start, max_rssi, min_rssi) < 0) {
1073 WL_ERR(("Could not set rssi monitor cfg\n"));
1074 err = -EINVAL;
1075 }
1076 return err;
1077}
1078#endif /* RSSI_MONITOR_SUPPORT */
1079
1080#ifdef DHDTCPACK_SUPPRESS
1081static int wl_cfgvendor_set_tcpack_sup_mode(struct wiphy *wiphy,
1082 struct wireless_dev *wdev, const void *data, int len)
1083{
1084 int err = 0, tmp, type;
1085 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1086 struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1087 uint8 enable = 0;
1088 const struct nlattr *iter;
1089
1090 nla_for_each_attr(iter, data, len, tmp) {
1091 type = nla_type(iter);
1092 if (type == ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE) {
1093 enable = (int8)nla_get_u32(iter);
1094 }
1095 }
1096
1097 if (dhd_dev_set_tcpack_sup_mode_cfg(ndev, enable) < 0) {
1098 WL_ERR(("Could not set TCP Ack Suppress mode cfg\n"));
1099 err = -EINVAL;
1100 }
1101 return err;
1102}
1103#endif /* DHDTCPACK_SUPPRESS */
1104
1105#ifdef DHD_WAKE_STATUS
1106static int
1107wl_cfgvendor_get_wake_reason_stats(struct wiphy *wiphy,
1108 struct wireless_dev *wdev, const void *data, int len)
1109{
1110 struct net_device *ndev = wdev_to_ndev(wdev);
1111 wake_counts_t *pwake_count_info;
1112 int ret, mem_needed;
1113#if defined(DHD_WAKE_EVENT_STATUS) && defined(DHD_DEBUG)
1114 int flowid;
1115#endif /* DHD_WAKE_EVENT_STATUS && DHD_DEBUG */
1116 struct sk_buff *skb;
1117 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
1118
1119 WL_DBG(("Recv get wake status info cmd.\n"));
1120
1121 pwake_count_info = dhd_get_wakecount(dhdp);
1122 mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 20) +
1123 (WLC_E_LAST * sizeof(uint));
1124
1125 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1126 if (unlikely(!skb)) {
1127 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
1128 return -ENOMEM;
1129 goto exit;
1130 }
1131#ifdef DHD_WAKE_EVENT_STATUS
1132 WL_ERR(("pwake_count_info->rcwake %d\n", pwake_count_info->rcwake));
1133 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, pwake_count_info->rcwake);
1134 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED, WLC_E_LAST);
1135 nla_put(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE, (WLC_E_LAST * sizeof(uint)),
1136 pwake_count_info->rc_event);
1137#ifdef DHD_DEBUG
1138 for (flowid = 0; flowid < WLC_E_LAST; flowid++) {
1139 if (pwake_count_info->rc_event[flowid] != 0) {
1140 WL_ERR((" %s = %u\n", bcmevent_get_name(flowid),
1141 pwake_count_info->rc_event[flowid]));
1142 }
1143 }
1144#endif /* DHD_DEBUG */
1145#endif /* DHD_WAKE_EVENT_STATUS */
1146#ifdef DHD_WAKE_RX_STATUS
1147 WL_ERR(("pwake_count_info->rxwake %d\n", pwake_count_info->rxwake));
1148 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE, pwake_count_info->rxwake);
1149 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT, pwake_count_info->rx_ucast);
1150 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT, pwake_count_info->rx_mcast);
1151 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT, pwake_count_info->rx_bcast);
1152 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT, pwake_count_info->rx_arp);
1153 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT, pwake_count_info->rx_icmpv6);
1154 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA, pwake_count_info->rx_icmpv6_ra);
1155 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA, pwake_count_info->rx_icmpv6_na);
1156 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS, pwake_count_info->rx_icmpv6_ns);
1157 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
1158 pwake_count_info->rx_multi_ipv4);
1159 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
1160 pwake_count_info->rx_multi_ipv6);
1161 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT,
1162 pwake_count_info->rx_multi_other);
1163#endif /* #ifdef DHD_WAKE_RX_STATUS */
1164 ret = cfg80211_vendor_cmd_reply(skb);
1165 if (unlikely(ret)) {
1166 WL_ERR(("Vendor cmd reply for -get wake status failed:%d \n", ret));
1167 }
1168exit:
1169 return ret;
1170}
1171#endif /* DHD_WAKE_STATUS */
1172
1173#ifdef RTT_SUPPORT
1174void
1175wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
1176{
1177 struct wireless_dev *wdev = (struct wireless_dev *)ctx;
1178 struct wiphy *wiphy;
1179 struct sk_buff *skb;
1180 uint32 evt_complete = 0;
1181 gfp_t kflags;
1182 rtt_result_t *rtt_result;
1183 rtt_results_header_t *rtt_header;
1184 struct list_head *rtt_cache_list;
1185 struct nlattr *rtt_nl_hdr;
1186 wiphy = wdev->wiphy;
1187
1188 WL_DBG(("In\n"));
1189 /* Push the data to the skb */
1190 if (!rtt_data) {
1191 WL_ERR(("rtt_data is NULL\n"));
1192 return;
1193 }
1194 rtt_cache_list = (struct list_head *)rtt_data;
1195 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1196 if (list_empty(rtt_cache_list)) {
1197#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1198 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1199 skb = cfg80211_vendor_event_alloc(wiphy, NULL, 100,
1200 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1201#else
1202 skb = cfg80211_vendor_event_alloc(wiphy, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags);
1203#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1204 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1205 if (!skb) {
1206 WL_ERR(("skb alloc failed"));
1207 return;
1208 }
1209 evt_complete = 1;
1210 nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1211 cfg80211_vendor_event(skb, kflags);
1212 return;
1213 }
1214#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1215#pragma GCC diagnostic push
1216#pragma GCC diagnostic ignored "-Wcast-qual"
1217#endif
1218 list_for_each_entry(rtt_header, rtt_cache_list, list) {
1219 /* Alloc the SKB for vendor_event */
1220#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1221 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1222 skb = cfg80211_vendor_event_alloc(wiphy, NULL, rtt_header->result_tot_len + 100,
1223 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1224#else
1225 skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100,
1226 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1227#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1228 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1229 if (!skb) {
1230 WL_ERR(("skb alloc failed"));
1231 return;
1232 }
1233 if (list_is_last(&rtt_header->list, rtt_cache_list)) {
1234 evt_complete = 1;
1235 }
1236 nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1237 rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET);
1238 if (!rtt_nl_hdr) {
1239 WL_ERR(("rtt_nl_hdr is NULL\n"));
1240 break;
1241 }
1242 nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &rtt_header->peer_mac);
1243 nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt);
1244 list_for_each_entry(rtt_result, &rtt_header->result_list, list) {
1245 nla_put(skb, RTT_ATTRIBUTE_RESULT,
1246 rtt_result->report_len, &rtt_result->report);
1247 }
1248 nla_nest_end(skb, rtt_nl_hdr);
1249 cfg80211_vendor_event(skb, kflags);
1250 }
1251#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1252#pragma GCC diagnostic pop
1253#endif
1254}
1255
1256static int
1257wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1258 const void *data, int len) {
1259 int err = 0, rem, rem1, rem2, type;
1260 int target_cnt;
1261 rtt_config_params_t rtt_param;
1262 rtt_target_info_t* rtt_target = NULL;
1263 const struct nlattr *iter, *iter1, *iter2;
1264 int8 eabuf[ETHER_ADDR_STR_LEN];
1265 int8 chanbuf[CHANSPEC_STR_LEN];
1266 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1267 rtt_capabilities_t capability;
1268
1269 memset(&rtt_param, 0, sizeof(rtt_param));
1270
1271 WL_DBG(("In\n"));
1272 err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
1273 if (err < 0) {
1274 WL_ERR(("failed to register rtt_noti_callback\n"));
1275 goto exit;
1276 }
1277 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1278 if (err < 0) {
1279 WL_ERR(("failed to get the capability\n"));
1280 goto exit;
1281 }
1282
1283 if (len <= 0) {
1284 WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
1285 err = BCME_ERROR;
1286 goto exit;
1287 }
1288 nla_for_each_attr(iter, data, len, rem) {
1289 type = nla_type(iter);
1290 switch (type) {
1291 case RTT_ATTRIBUTE_TARGET_CNT:
1292 target_cnt = nla_get_u8(iter);
1293 if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) {
1294 WL_ERR(("target_cnt is not valid : %d\n",
1295 target_cnt));
1296 err = BCME_RANGE;
1297 goto exit;
1298 }
1299 rtt_param.rtt_target_cnt = target_cnt;
1300
1301 rtt_param.target_info = kzalloc(TARGET_INFO_SIZE(target_cnt), GFP_KERNEL);
1302 if (rtt_param.target_info == NULL) {
1303 WL_ERR(("failed to allocate target info for (%d)\n", target_cnt));
1304 err = BCME_NOMEM;
1305 goto exit;
1306 }
1307 break;
1308 case RTT_ATTRIBUTE_TARGET_INFO:
1309 /* Added this variable for safe check to avoid crash
1310 * incase the caller did not respect the order
1311 */
1312 if (rtt_param.target_info == NULL) {
1313 WL_ERR(("rtt_target_info is NULL\n"));
1314 err = BCME_NOMEM;
1315 goto exit;
1316 }
1317 rtt_target = rtt_param.target_info;
1318 nla_for_each_nested(iter1, iter, rem1) {
1319 nla_for_each_nested(iter2, iter1, rem2) {
1320 type = nla_type(iter2);
1321 switch (type) {
1322 case RTT_ATTRIBUTE_TARGET_MAC:
1323 memcpy(&rtt_target->addr, nla_data(iter2),
1324 ETHER_ADDR_LEN);
1325 break;
1326 case RTT_ATTRIBUTE_TARGET_TYPE:
1327 rtt_target->type = nla_get_u8(iter2);
1328 if (rtt_target->type == RTT_INVALID ||
1329 (rtt_target->type == RTT_ONE_WAY &&
1330 !capability.rtt_one_sided_supported)) {
1331 WL_ERR(("doesn't support RTT type"
1332 " : %d\n",
1333 rtt_target->type));
1334 err = -EINVAL;
1335 goto exit;
1336 }
1337 break;
1338 case RTT_ATTRIBUTE_TARGET_PEER:
1339 rtt_target->peer = nla_get_u8(iter2);
1340 break;
1341 case RTT_ATTRIBUTE_TARGET_CHAN:
1342 memcpy(&rtt_target->channel, nla_data(iter2),
1343 sizeof(rtt_target->channel));
1344 break;
1345 case RTT_ATTRIBUTE_TARGET_PERIOD:
1346 rtt_target->burst_period = nla_get_u32(iter2);
1347 if (rtt_target->burst_period < 32) {
1348 /* 100ms unit */
1349 rtt_target->burst_period *= 100;
1350 } else {
1351 WL_ERR(("%d value must in (0-31)\n",
1352 rtt_target->burst_period));
1353 err = EINVAL;
1354 goto exit;
1355 }
1356 break;
1357 case RTT_ATTRIBUTE_TARGET_NUM_BURST:
1358 rtt_target->num_burst = nla_get_u32(iter2);
1359 if (rtt_target->num_burst > 16) {
1360 WL_ERR(("%d value must in (0-15)\n",
1361 rtt_target->num_burst));
1362 err = -EINVAL;
1363 goto exit;
1364 }
1365 rtt_target->num_burst = BIT(rtt_target->num_burst);
1366 break;
1367 case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST:
1368 rtt_target->num_frames_per_burst =
1369 nla_get_u32(iter2);
1370 break;
1371 case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM:
1372 rtt_target->num_retries_per_ftm =
1373 nla_get_u32(iter2);
1374 break;
1375 case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR:
1376 rtt_target->num_retries_per_ftmr =
1377 nla_get_u32(iter2);
1378 if (rtt_target->num_retries_per_ftmr > 3) {
1379 WL_ERR(("%d value must in (0-3)\n",
1380 rtt_target->num_retries_per_ftmr));
1381 err = -EINVAL;
1382 goto exit;
1383 }
1384 break;
1385 case RTT_ATTRIBUTE_TARGET_LCI:
1386 rtt_target->LCI_request = nla_get_u8(iter2);
1387 break;
1388 case RTT_ATTRIBUTE_TARGET_LCR:
1389 rtt_target->LCI_request = nla_get_u8(iter2);
1390 break;
1391 case RTT_ATTRIBUTE_TARGET_BURST_DURATION:
1392 if ((nla_get_u32(iter2) > 1 &&
1393 nla_get_u32(iter2) < 12)) {
1394 rtt_target->burst_duration =
1395 dhd_rtt_idx_to_burst_duration(
1396 nla_get_u32(iter2));
1397 } else if (nla_get_u32(iter2) == 15) {
1398 /* use default value */
1399 rtt_target->burst_duration = 0;
1400 } else {
1401 WL_ERR(("%d value must in (2-11) or 15\n",
1402 nla_get_u32(iter2)));
1403 err = -EINVAL;
1404 goto exit;
1405 }
1406 break;
1407 case RTT_ATTRIBUTE_TARGET_BW:
1408 rtt_target->bw = nla_get_u8(iter2);
1409 break;
1410 case RTT_ATTRIBUTE_TARGET_PREAMBLE:
1411 rtt_target->preamble = nla_get_u8(iter2);
1412 break;
1413 }
1414 }
1415 /* convert to chanspec value */
1416 rtt_target->chanspec =
1417 dhd_rtt_convert_to_chspec(rtt_target->channel);
1418 if (rtt_target->chanspec == 0) {
1419 WL_ERR(("Channel is not valid \n"));
1420 err = -EINVAL;
1421 goto exit;
1422 }
1423 WL_INFORM(("Target addr %s, Channel : %s for RTT \n",
1424 bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr,
1425 eabuf),
1426 wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
1427 rtt_target++;
1428 }
1429 break;
1430 }
1431 }
1432 WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
1433 if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
1434 WL_ERR(("Could not set RTT configuration\n"));
1435 err = -EINVAL;
1436 }
1437exit:
1438 /* free the target info list */
1439 if (rtt_param.target_info) {
1440 kfree(rtt_param.target_info);
1441 rtt_param.target_info = NULL;
1442 }
1443 return err;
1444}
1445
1446static int
1447wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1448 const void *data, int len)
1449{
1450 int err = 0, rem, type, target_cnt = 0;
1451 int target_cnt_chk = 0;
1452 const struct nlattr *iter;
1453 struct ether_addr *mac_list = NULL, *mac_addr = NULL;
1454 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1455
1456 if (len <= 0) {
1457 WL_ERR(("Length of nlattr is not valid len : %d\n", len));
1458 err = -EINVAL;
1459 goto exit;
1460 }
1461 nla_for_each_attr(iter, data, len, rem) {
1462 type = nla_type(iter);
1463 switch (type) {
1464 case RTT_ATTRIBUTE_TARGET_CNT:
1465 if (mac_list != NULL) {
1466 WL_ERR(("mac_list is not NULL\n"));
1467 err = -EINVAL;
1468 goto exit;
1469 }
1470 target_cnt = nla_get_u8(iter);
1471 if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) {
1472 mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN,
1473 GFP_KERNEL);
1474 if (mac_list == NULL) {
1475 WL_ERR(("failed to allocate mem for mac list\n"));
1476 err = -EINVAL;
1477 goto exit;
1478 }
1479 mac_addr = &mac_list[0];
1480 } else {
1481 /* cancel the current whole RTT process */
1482 goto cancel;
1483 }
1484 break;
1485 case RTT_ATTRIBUTE_TARGET_MAC:
1486 if (mac_addr) {
1487 memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN);
1488 target_cnt_chk++;
1489 if (target_cnt_chk > target_cnt) {
1490 WL_ERR(("over target count\n"));
1491 err = -EINVAL;
1492 goto exit;
1493 }
1494 break;
1495 } else {
1496 WL_ERR(("mac_list is NULL\n"));
1497 err = -EINVAL;
1498 goto exit;
1499 }
1500 }
1501 }
1502cancel:
1503 if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
1504 WL_ERR(("Could not cancel RTT configuration\n"));
1505 err = -EINVAL;
1506 }
1507
1508exit:
1509 if (mac_list) {
1510 kfree(mac_list);
1511 }
1512 return err;
1513}
1514
1515static int
1516wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
1517 const void *data, int len)
1518{
1519 int err = 0;
1520 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1521 rtt_capabilities_t capability;
1522
1523 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1524 if (unlikely(err)) {
1525 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1526 goto exit;
1527 }
1528 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
1529 &capability, sizeof(capability));
1530
1531 if (unlikely(err)) {
1532 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1533 }
1534exit:
1535 return err;
1536}
1537static int
1538get_responder_info(struct bcm_cfg80211 *cfg,
1539 struct wifi_rtt_responder *responder_info)
1540{
1541 int err = 0;
1542 rtt_capabilities_t capability;
1543 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1544 if (unlikely(err)) {
1545 WL_ERR(("Could not get responder capability:%d \n", err));
1546 return err;
1547 }
1548 if (capability.preamble_support & RTT_PREAMBLE_VHT) {
1549 responder_info->preamble |= RTT_PREAMBLE_VHT;
1550 }
1551 if (capability.preamble_support & RTT_PREAMBLE_HT) {
1552 responder_info->preamble |= RTT_PREAMBLE_HT;
1553 }
1554 err = dhd_dev_rtt_avail_channel(bcmcfg_to_prmry_ndev(cfg), &(responder_info->channel));
1555 if (unlikely(err)) {
1556 WL_ERR(("Could not get available channel:%d \n", err));
1557 return err;
1558 }
1559 return err;
1560}
1561static int
1562wl_cfgvendor_rtt_get_responder_info(struct wiphy *wiphy, struct wireless_dev *wdev,
1563 const void *data, int len)
1564{
1565 int err = 0;
1566 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1567 wifi_rtt_responder_t responder_info;
1568
1569 WL_DBG(("Recv -get_avail_ch command \n"));
1570
1571 memset(&responder_info, 0, sizeof(responder_info));
1572 err = get_responder_info(cfg, &responder_info);
1573 if (unlikely(err)) {
1574 WL_ERR(("Failed to get responder info:%d \n", err));
1575 return err;
1576 }
1577 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
1578 &responder_info, sizeof(responder_info));
1579
1580 if (unlikely(err)) {
1581 WL_ERR(("Vendor cmd reply for -get_avail_ch failed ret:%d \n", err));
1582 }
1583 return err;
1584}
1585
1586static int
1587wl_cfgvendor_rtt_set_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
1588 const void *data, int len)
1589{
1590 int err = 0;
1591 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1592 struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1593 wifi_rtt_responder_t responder_info;
1594
1595 WL_DBG(("Recv rtt -enable_resp cmd.\n"));
1596
1597 memset(&responder_info, 0, sizeof(responder_info));
1598
1599 /*
1600 *Passing channel as NULL until implementation
1601 *to get chan info from upper layers is donex
1602 */
1603 err = dhd_dev_rtt_enable_responder(ndev, NULL);
1604 if (unlikely(err)) {
1605 WL_ERR(("Could not enable responder ret:%d \n", err));
1606 goto done;
1607 }
1608 err = get_responder_info(cfg, &responder_info);
1609 if (unlikely(err)) {
1610 WL_ERR(("Failed to get responder info:%d \n", err));
1611 dhd_dev_rtt_cancel_responder(ndev);
1612 goto done;
1613 }
1614done:
1615 err = wl_cfgvendor_send_cmd_reply(wiphy, ndev,
1616 &responder_info, sizeof(responder_info));
1617
1618 if (unlikely(err)) {
1619 WL_ERR(("Vendor cmd reply for -enable_resp failed ret:%d \n", err));
1620 }
1621 return err;
1622}
1623
1624static int
1625wl_cfgvendor_rtt_cancel_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
1626 const void *data, int len)
1627{
1628 int err = 0;
1629 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1630
1631 WL_DBG(("Recv rtt -cancel_resp cmd \n"));
1632
1633 err = dhd_dev_rtt_cancel_responder(bcmcfg_to_prmry_ndev(cfg));
1634 if (unlikely(err)) {
1635 WL_ERR(("Vendor cmd -cancel_resp failed ret:%d \n", err));
1636 }
1637 return err;
1638}
1639#endif /* RTT_SUPPORT */
1640
1641#ifdef GSCAN_SUPPORT
1642static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy,
1643 struct wireless_dev *wdev, const void *data, int len)
1644{
1645 int err = -EINVAL;
1646 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1647 int type;
1648 uint32 lazy_roam_enable_flag;
1649
1650 type = nla_type(data);
1651
1652 if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) {
1653 lazy_roam_enable_flag = nla_get_u32(data);
1654
1655 err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg),
1656 lazy_roam_enable_flag);
1657
1658 if (unlikely(err))
1659 WL_ERR(("Could not enable lazy roam:%d \n", err));
1660
1661 }
1662 return err;
1663}
1664
1665static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy,
1666 struct wireless_dev *wdev, const void *data, int len)
1667{
1668 int err = 0, tmp, type;
1669 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1670 wlc_roam_exp_params_t roam_param;
1671 const struct nlattr *iter;
1672
1673 memset(&roam_param, 0, sizeof(roam_param));
1674
1675 nla_for_each_attr(iter, data, len, tmp) {
1676 type = nla_type(iter);
1677
1678 switch (type) {
1679 case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD:
1680 roam_param.a_band_boost_threshold = nla_get_u32(iter);
1681 break;
1682 case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD:
1683 roam_param.a_band_penalty_threshold = nla_get_u32(iter);
1684 break;
1685 case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR:
1686 roam_param.a_band_boost_factor = nla_get_u32(iter);
1687 break;
1688 case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR:
1689 roam_param.a_band_penalty_factor = nla_get_u32(iter);
1690 break;
1691 case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST:
1692 roam_param.a_band_max_boost = nla_get_u32(iter);
1693 break;
1694 case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS:
1695 roam_param.cur_bssid_boost = nla_get_u32(iter);
1696 break;
1697 case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER:
1698 roam_param.alert_roam_trigger_threshold = nla_get_u32(iter);
1699 break;
1700 }
1701 }
1702
1703 if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) {
1704 WL_ERR(("Could not set batch cfg\n"));
1705 err = -EINVAL;
1706 }
1707 return err;
1708}
1709
1710/* small helper function */
1711static wl_bssid_pref_cfg_t *
1712create_bssid_pref_cfg(uint32 num)
1713{
1714 uint32 mem_needed;
1715 wl_bssid_pref_cfg_t *bssid_pref;
1716
1717 mem_needed = sizeof(wl_bssid_pref_cfg_t);
1718 if (num)
1719 mem_needed += (num - 1) * sizeof(wl_bssid_pref_list_t);
1720 bssid_pref = (wl_bssid_pref_cfg_t *) kmalloc(mem_needed, GFP_KERNEL);
1721 return bssid_pref;
1722}
1723
1724static int
1725wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy,
1726 struct wireless_dev *wdev, const void *data, int len)
1727{
1728 int err = 0;
1729 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1730 wl_bssid_pref_cfg_t *bssid_pref = NULL;
1731 wl_bssid_pref_list_t *bssids;
1732 int tmp, tmp1, tmp2, type;
1733 const struct nlattr *outer, *inner, *iter;
1734 uint32 flush = 0, i = 0, num = 0;
1735
1736 /* Assumption: NUM attribute must come first */
1737 nla_for_each_attr(iter, data, len, tmp2) {
1738 type = nla_type(iter);
1739 switch (type) {
1740 case GSCAN_ATTRIBUTE_NUM_BSSID:
1741 num = nla_get_u32(iter);
1742 if (num > MAX_BSSID_PREF_LIST_NUM) {
1743 WL_ERR(("Too many Preferred BSSIDs!\n"));
1744 err = -EINVAL;
1745 goto exit;
1746 }
1747 break;
1748 case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH:
1749 flush = nla_get_u32(iter);
1750 break;
1751 case GSCAN_ATTRIBUTE_BSSID_PREF_LIST:
1752 if (!num)
1753 return -EINVAL;
1754 if ((bssid_pref = create_bssid_pref_cfg(num)) == NULL) {
1755 WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__));
1756 err = -ENOMEM;
1757 goto exit;
1758 }
1759 bssid_pref->count = num;
1760 bssids = bssid_pref->bssids;
1761 nla_for_each_nested(outer, iter, tmp) {
1762 if (i >= num) {
1763 WL_ERR(("CFGs don't seem right!\n"));
1764 err = -EINVAL;
1765 goto exit;
1766 }
1767 nla_for_each_nested(inner, outer, tmp1) {
1768 type = nla_type(inner);
1769 switch (type) {
1770 case GSCAN_ATTRIBUTE_BSSID_PREF:
1771 memcpy(&(bssids[i].bssid),
1772 nla_data(inner), ETHER_ADDR_LEN);
1773 /* not used for now */
1774 bssids[i].flags = 0;
1775 break;
1776 case GSCAN_ATTRIBUTE_RSSI_MODIFIER:
1777 bssids[i].rssi_factor =
1778 (int8) nla_get_u32(inner);
1779 break;
1780 }
1781 }
1782 i++;
1783 }
1784 break;
1785 default:
1786 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1787 break;
1788 }
1789 }
1790
1791 if (!bssid_pref) {
1792 /* What if only flush is desired? */
1793 if (flush) {
1794 if ((bssid_pref = create_bssid_pref_cfg(0)) == NULL) {
1795 WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__));
1796 err = -ENOMEM;
1797 goto exit;
1798 }
1799 bssid_pref->count = 0;
1800 } else {
1801 err = -EINVAL;
1802 goto exit;
1803 }
1804 }
1805 err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg),
1806 bssid_pref, flush);
1807exit:
1808 kfree(bssid_pref);
1809 return err;
1810}
1811
1812static int
1813wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy,
1814 struct wireless_dev *wdev, const void *data, int len)
1815{
1816 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1817 maclist_t *blacklist = NULL;
1818 int err = 0;
1819 int type, tmp;
1820 const struct nlattr *iter;
1821 uint32 mem_needed = 0, flush = 0, i = 0, num = 0;
1822
1823 /* Assumption: NUM attribute must come first */
1824 nla_for_each_attr(iter, data, len, tmp) {
1825 type = nla_type(iter);
1826 switch (type) {
1827 case GSCAN_ATTRIBUTE_NUM_BSSID:
1828 num = nla_get_u32(iter);
1829 if (num > MAX_BSSID_BLACKLIST_NUM) {
1830 WL_ERR(("Too many Blacklist BSSIDs!\n"));
1831 err = -EINVAL;
1832 goto exit;
1833 }
1834 break;
1835 case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH:
1836 flush = nla_get_u32(iter);
1837 break;
1838 case GSCAN_ATTRIBUTE_BLACKLIST_BSSID:
1839 if (num) {
1840 if (!blacklist) {
1841 mem_needed = sizeof(maclist_t) +
1842 sizeof(struct ether_addr) * (num - 1);
1843 blacklist = (maclist_t *)
1844 kmalloc(mem_needed, GFP_KERNEL);
1845 if (!blacklist) {
1846 WL_ERR(("%s: Can't malloc %d bytes\n",
1847 __FUNCTION__, mem_needed));
1848 err = -ENOMEM;
1849 goto exit;
1850 }
1851 blacklist->count = num;
1852 }
1853 if (i >= num) {
1854 WL_ERR(("CFGs don't seem right!\n"));
1855 err = -EINVAL;
1856 goto exit;
1857 }
1858 memcpy(&(blacklist->ea[i]),
1859 nla_data(iter), ETHER_ADDR_LEN);
1860 i++;
1861 }
1862 break;
1863 default:
1864 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1865 break;
1866 }
1867 }
1868 err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg),
1869 blacklist, mem_needed, flush);
1870exit:
1871 kfree(blacklist);
1872 return err;
1873}
1874
1875static int
1876wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy,
1877 struct wireless_dev *wdev, const void *data, int len)
1878{
1879 int err = 0;
1880 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1881 wl_ssid_whitelist_t *ssid_whitelist = NULL;
1882 wlc_ssid_t *ssid_elem;
1883 int tmp, tmp2, mem_needed = 0, type;
1884 const struct nlattr *inner, *iter;
1885 uint32 flush = 0, i = 0, num = 0;
1886
1887 /* Assumption: NUM attribute must come first */
1888 nla_for_each_attr(iter, data, len, tmp2) {
1889 type = nla_type(iter);
1890 switch (type) {
1891 case GSCAN_ATTRIBUTE_NUM_WL_SSID:
1892 num = nla_get_u32(iter);
1893 if (num > MAX_SSID_WHITELIST_NUM) {
1894 WL_ERR(("Too many WL SSIDs!\n"));
1895 err = -EINVAL;
1896 goto exit;
1897 }
1898 mem_needed = sizeof(wl_ssid_whitelist_t);
1899 if (num)
1900 mem_needed += (num - 1) * sizeof(ssid_info_t);
1901 ssid_whitelist = (wl_ssid_whitelist_t *)
1902 kzalloc(mem_needed, GFP_KERNEL);
1903 if (ssid_whitelist == NULL) {
1904 WL_ERR(("%s: Can't malloc %d bytes\n",
1905 __FUNCTION__, mem_needed));
1906 err = -ENOMEM;
1907 goto exit;
1908 }
1909 ssid_whitelist->ssid_count = num;
1910 break;
1911 case GSCAN_ATTRIBUTE_WL_SSID_FLUSH:
1912 flush = nla_get_u32(iter);
1913 break;
1914 case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM:
1915 if (!num || !ssid_whitelist) {
1916 WL_ERR(("num ssid is not set!\n"));
1917 return -EINVAL;
1918 }
1919 if (i >= num) {
1920 WL_ERR(("CFGs don't seem right!\n"));
1921 err = -EINVAL;
1922 goto exit;
1923 }
1924 ssid_elem = &ssid_whitelist->ssids[i];
1925 nla_for_each_nested(inner, iter, tmp) {
1926 type = nla_type(inner);
1927 switch (type) {
1928 case GSCAN_ATTRIBUTE_WHITELIST_SSID:
1929 memcpy(ssid_elem->SSID,
1930 nla_data(inner),
1931 DOT11_MAX_SSID_LEN);
1932 break;
1933 case GSCAN_ATTRIBUTE_WL_SSID_LEN:
1934 ssid_elem->SSID_len = (uint8)
1935 nla_get_u32(inner);
1936 break;
1937 }
1938 }
1939 i++;
1940 break;
1941 default:
1942 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1943 break;
1944 }
1945 }
1946
1947 err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg),
1948 ssid_whitelist, mem_needed, flush);
1949exit:
1950 kfree(ssid_whitelist);
1951 return err;
1952}
1953#endif /* GSCAN_SUPPORT */
1954
1955static int
1956wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
1957 struct wireless_dev *wdev, const void *data, int len)
1958{
1959 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1960 int ret = 0;
1961 int ret_len = 0, payload = 0, msglen;
1962 const struct bcm_nlmsg_hdr *nlioc = data;
1963 void *buf = NULL, *cur;
1964 int maxmsglen = PAGE_SIZE - 0x100;
1965 struct sk_buff *reply;
1966
1967 WL_ERR(("entry: cmd = %d\n", nlioc->cmd));
1968
1969 len -= sizeof(struct bcm_nlmsg_hdr);
1970 ret_len = nlioc->len;
1971 if (ret_len > 0 || len > 0) {
1972 if (len > DHD_IOCTL_MAXLEN) {
1973 WL_ERR(("oversize input buffer %d\n", len));
1974 len = DHD_IOCTL_MAXLEN;
1975 }
1976 if (ret_len > DHD_IOCTL_MAXLEN) {
1977 WL_ERR(("oversize return buffer %d\n", ret_len));
1978 ret_len = DHD_IOCTL_MAXLEN;
1979 }
1980 payload = max(ret_len, len) + 1;
1981 buf = vzalloc(payload);
1982 if (!buf) {
1983 return -ENOMEM;
1984 }
1985#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1986#pragma GCC diagnostic push
1987#pragma GCC diagnostic ignored "-Wcast-qual"
1988#endif
1989 memcpy(buf, (void *)((char *)nlioc + nlioc->offset), len);
1990#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1991#pragma GCC diagnostic pop
1992#endif
1993 *((char *)buf + len) = '\0';
1994 }
1995
1996 ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf);
1997 if (ret) {
1998 WL_ERR(("dhd_cfgvendor returned error %d", ret));
1999 vfree(buf);
2000 return ret;
2001 }
2002 cur = buf;
2003 while (ret_len > 0) {
2004 msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len;
2005 ret_len -= msglen;
2006 payload = msglen + sizeof(msglen);
2007 reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
2008 if (!reply) {
2009 WL_ERR(("Failed to allocate reply msg\n"));
2010 ret = -ENOMEM;
2011 break;
2012 }
2013
2014 if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
2015 nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
2016 kfree_skb(reply);
2017 ret = -ENOBUFS;
2018 break;
2019 }
2020
2021 ret = cfg80211_vendor_cmd_reply(reply);
2022 if (ret) {
2023 WL_ERR(("testmode reply failed:%d\n", ret));
2024 break;
2025 }
2026 cur = (void *)((char *)cur + msglen);
2027 }
2028
2029 return ret;
2030}
2031
2032struct net_device *
2033wl_cfgvendor_get_ndev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
2034 const void *data, unsigned long int *out_addr)
2035{
2036 char *pos, *pos1;
2037 char ifname[IFNAMSIZ + 1] = {0};
2038 struct net_info *iter, *next;
2039 struct net_device *ndev = NULL;
2040 *out_addr = (unsigned long int) data; /* point to command str by default */
2041
2042 /* check whether ifname=<ifname> is provided in the command */
2043 pos = strstr(data, "ifname=");
2044 if (pos) {
2045 pos += strlen("ifname=");
2046 pos1 = strstr(pos, " ");
2047 if (!pos1) {
2048 WL_ERR(("command format error \n"));
2049 return NULL;
2050 }
2051 memcpy(ifname, pos, (pos1 - pos));
2052#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2053#pragma GCC diagnostic push
2054#pragma GCC diagnostic ignored "-Wcast-qual"
2055#endif
2056 for_each_ndev(cfg, iter, next) {
2057 if (iter->ndev) {
2058 if (strncmp(iter->ndev->name, ifname,
2059 strlen(iter->ndev->name)) == 0) {
2060 /* matching ifname found */
2061 WL_DBG(("matching interface (%s) found ndev:%p \n",
2062 iter->ndev->name, iter->ndev));
2063 *out_addr = (unsigned long int)(pos1 + 1);
2064 /* Returns the command portion after ifname=<name> */
2065 return iter->ndev;
2066 }
2067 }
2068 }
2069#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2070#pragma GCC diagnostic pop
2071#endif
2072 WL_ERR(("Couldn't find ifname:%s in the netinfo list \n",
2073 ifname));
2074 return NULL;
2075 }
2076
2077 /* If ifname=<name> arg is not provided, use default ndev */
2078 ndev = wdev->netdev ? wdev->netdev : bcmcfg_to_prmry_ndev(cfg);
2079 WL_DBG(("Using default ndev (%s) \n", ndev->name));
2080 return ndev;
2081}
2082
2083/* Max length for the reply buffer. For BRCM_ATTR_DRIVER_CMD, the reply
2084 * would be a formatted string and reply buf would be the size of the
2085 * string.
2086 */
2087#define WL_DRIVER_PRIV_CMD_LEN 512
2088static int
2089wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy,
2090 struct wireless_dev *wdev, const void *data, int len)
2091{
2092 const struct nlattr *iter;
2093 int err = 0;
2094 int data_len = 0, cmd_len = 0, tmp = 0, type = 0;
2095 struct net_device *ndev = wdev->netdev;
2096 char *reply_buf = NULL;
2097 char *cmd = NULL;
2098 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2099 int bytes_written;
2100 struct net_device *net = NULL;
2101 unsigned long int cmd_out = 0;
2102 u32 reply_len = WL_DRIVER_PRIV_CMD_LEN;
2103
2104
2105 WL_DBG(("%s: Enter \n", __func__));
2106
2107 /* hold wake lock */
2108 net_os_wake_lock(ndev);
2109
2110 nla_for_each_attr(iter, data, len, tmp) {
2111 type = nla_type(iter);
2112 cmd = nla_data(iter);
2113 cmd_len = nla_len(iter);
2114
2115 WL_DBG(("%s: type: %d cmd_len:%d cmd_ptr:%p \n", __func__, type, cmd_len, cmd));
2116 if (!cmd || !cmd_len) {
2117 WL_ERR(("Invalid cmd data \n"));
2118 err = -EINVAL;
2119 goto exit;
2120 }
2121
2122 if (type == BRCM_ATTR_DRIVER_CMD) {
2123 if (cmd_len >= WL_DRIVER_PRIV_CMD_LEN) {
2124 WL_ERR(("Unexpected command length. Ignore the command\n"));
2125 err = -EINVAL;
2126 goto exit;
2127 }
2128 net = wl_cfgvendor_get_ndev(cfg, wdev, cmd, &cmd_out);
2129 if (!cmd_out || !net) {
2130 err = -ENODEV;
2131 goto exit;
2132 }
2133 cmd = (char *)cmd_out;
2134 reply_buf = kzalloc(reply_len, GFP_KERNEL);
2135 if (!reply_buf) {
2136 WL_ERR(("memory alloc failed for %u \n", cmd_len));
2137 err = -ENOMEM;
2138 goto exit;
2139 }
2140 memcpy(reply_buf, cmd, cmd_len);
2141 WL_DBG(("vendor_command: %s len: %u \n", cmd, cmd_len));
2142 bytes_written = wl_handle_private_cmd(net, reply_buf, reply_len);
2143 WL_DBG(("bytes_written: %d \n", bytes_written));
2144 if (bytes_written == 0) {
2145 snprintf(reply_buf, reply_len, "%s", "OK");
2146 data_len = strlen("OK");
2147 } else if (bytes_written > 0) {
2148 data_len = bytes_written > reply_len ?
2149 reply_len : bytes_written;
2150 } else {
2151 /* -ve return value. Propagate the error back */
2152 err = bytes_written;
2153 goto exit;
2154 }
2155 break;
2156 }
2157 }
2158
2159 if ((data_len > 0) && reply_buf) {
2160 err = wl_cfgvendor_send_cmd_reply(wiphy, wdev->netdev,
2161 reply_buf, data_len+1);
2162 if (unlikely(err))
2163 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2164 else
2165 WL_DBG(("Vendor Command reply sent successfully!\n"));
2166 } else {
2167 /* No data to be sent back as reply */
2168 WL_ERR(("Vendor_cmd: No reply expected. data_len:%u reply_buf %p \n",
2169 data_len, reply_buf));
2170 }
2171
2172exit:
2173 if (reply_buf)
2174 kfree(reply_buf);
2175 net_os_wake_unlock(ndev);
2176 return err;
2177}
2178
2179
2180#ifdef LINKSTAT_SUPPORT
2181#define NUM_RATE 32
2182#define NUM_PEER 1
2183#define NUM_CHAN 11
2184#define HEADER_SIZE sizeof(ver_len)
2185static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy,
2186 struct wireless_dev *wdev, const void *data, int len)
2187{
2188 static char iovar_buf[WLC_IOCTL_MAXLEN];
2189 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2190 int err = 0, i;
2191 wifi_radio_stat *radio;
2192 wifi_radio_stat_h radio_h;
2193 wl_wme_cnt_t *wl_wme_cnt;
2194 wl_cnt_ge40mcst_v1_t *macstat_cnt;
2195 wl_cnt_wlc_t *wlc_cnt;
2196 scb_val_t scbval;
2197 char *output = NULL;
2198 char *outdata = NULL;
2199 wifi_rate_stat_v1 *p_wifi_rate_stat_v1 = NULL;
2200 wifi_rate_stat *p_wifi_rate_stat = NULL;
2201 uint total_len = 0;
2202 wifi_iface_stat iface;
2203 wlc_rev_info_t revinfo;
2204#ifdef CONFIG_COMPAT
2205 compat_wifi_iface_stat compat_iface;
ccd15baf
RC
2206#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2207 int compat_task_state = in_compat_syscall();
2208#else
010c3a89 2209 int compat_task_state = is_compat_task();
ccd15baf 2210#endif
010c3a89
RC
2211#endif /* CONFIG_COMPAT */
2212
2213 WL_INFORM(("%s: Enter \n", __func__));
2214 RETURN_EIO_IF_NOT_UP(cfg);
2215
2216 /* Get the device rev info */
2217 memset(&revinfo, 0, sizeof(revinfo));
2218 err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_REVINFO, &revinfo,
2219 sizeof(revinfo));
2220 if (err != BCME_OK) {
2221 goto exit;
2222 }
2223
2224 outdata = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
2225 if (outdata == NULL) {
2226 WL_ERR(("%s: alloc failed\n", __func__));
2227 return -ENOMEM;
2228 }
2229
2230 memset(&scbval, 0, sizeof(scb_val_t));
2231 memset(outdata, 0, WLC_IOCTL_MAXLEN);
2232 output = outdata;
2233
2234 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0,
2235 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2236 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
2237 WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wifi_radio_stat)));
2238 goto exit;
2239 }
2240 radio = (wifi_radio_stat *)iovar_buf;
2241
2242 memset(&radio_h, 0, sizeof(wifi_radio_stat_h));
2243 radio_h.on_time = radio->on_time;
2244 radio_h.tx_time = radio->tx_time;
2245 radio_h.rx_time = radio->rx_time;
2246 radio_h.on_time_scan = radio->on_time_scan;
2247 radio_h.on_time_nbd = radio->on_time_nbd;
2248 radio_h.on_time_gscan = radio->on_time_gscan;
2249 radio_h.on_time_roam_scan = radio->on_time_roam_scan;
2250 radio_h.on_time_pno_scan = radio->on_time_pno_scan;
2251 radio_h.on_time_hs20 = radio->on_time_hs20;
2252 radio_h.num_channels = NUM_CHAN;
2253
2254 memcpy(output, &radio_h, sizeof(wifi_radio_stat_h));
2255
2256 output += sizeof(wifi_radio_stat_h);
2257 output += (NUM_CHAN * sizeof(wifi_channel_stat));
2258
2259 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "wme_counters", NULL, 0,
2260 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2261 if (unlikely(err)) {
2262 WL_ERR(("error (%d)\n", err));
2263 goto exit;
2264 }
2265 wl_wme_cnt = (wl_wme_cnt_t *)iovar_buf;
2266
2267 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].ac, WIFI_AC_VO);
2268 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].tx_mpdu, wl_wme_cnt->tx[AC_VO].packets);
2269 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].rx_mpdu, wl_wme_cnt->rx[AC_VO].packets);
2270 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].mpdu_lost,
2271 wl_wme_cnt->tx_failed[WIFI_AC_VO].packets);
2272
2273 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].ac, WIFI_AC_VI);
2274 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].tx_mpdu, wl_wme_cnt->tx[AC_VI].packets);
2275 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].rx_mpdu, wl_wme_cnt->rx[AC_VI].packets);
2276 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].mpdu_lost,
2277 wl_wme_cnt->tx_failed[WIFI_AC_VI].packets);
2278
2279 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].ac, WIFI_AC_BE);
2280 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu, wl_wme_cnt->tx[AC_BE].packets);
2281 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu, wl_wme_cnt->rx[AC_BE].packets);
2282 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost,
2283 wl_wme_cnt->tx_failed[WIFI_AC_BE].packets);
2284
2285 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].ac, WIFI_AC_BK);
2286 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].tx_mpdu, wl_wme_cnt->tx[AC_BK].packets);
2287 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].rx_mpdu, wl_wme_cnt->rx[AC_BK].packets);
2288 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].mpdu_lost,
2289 wl_wme_cnt->tx_failed[WIFI_AC_BK].packets);
2290
2291
2292 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0,
2293 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2294 if (unlikely(err)) {
2295 WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_cnt_wlc_t)));
2296 goto exit;
2297 }
2298
2299 CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MAXLEN);
2300
2301#ifdef STAT_REPORT
2302 wl_stat_report_gather(cfg, iovar_buf);
2303#endif
2304
2305 /* Translate traditional (ver <= 10) counters struct to new xtlv type struct */
2306 err = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WLC_IOCTL_MAXLEN, revinfo.corerev);
2307 if (err != BCME_OK) {
2308 WL_ERR(("%s wl_cntbuf_to_xtlv_format ERR %d\n",
2309 __FUNCTION__, err));
2310 goto exit;
2311 }
2312
2313 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
2314 WL_ERR(("%s wlc_cnt NULL!\n", __FUNCTION__));
2315 err = BCME_ERROR;
2316 goto exit;
2317 }
2318
2319 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, wlc_cnt->txretry);
2320
2321 if ((macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
2322 ((wl_cnt_info_t *)iovar_buf)->datalen,
2323 WL_CNT_XTLV_CNTV_LE10_UCODE, NULL,
2324 BCM_XTLV_OPTION_ALIGN32)) == NULL) {
d964ce36 2325 if ((macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
010c3a89
RC
2326 ((wl_cnt_info_t *)iovar_buf)->datalen,
2327 WL_CNT_XTLV_GE40_UCODE_V1, NULL,
d964ce36 2328 BCM_XTLV_OPTION_ALIGN32)) == NULL) {
2329 macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
2330 ((wl_cnt_info_t *)iovar_buf)->datalen,
2331 WL_CNT_XTLV_LT40_UCODE_V1, NULL,
010c3a89 2332 BCM_XTLV_OPTION_ALIGN32);
d964ce36 2333 }
010c3a89
RC
2334 }
2335
2336 if (macstat_cnt == NULL) {
2337 printf("wlmTxGetAckedPackets: macstat_cnt NULL!\n");
2338 err = BCME_ERROR;
2339 goto exit;
2340 }
2341
2342 err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval);
2343 if (unlikely(err)) {
2344 WL_ERR(("get_rssi error (%d)\n", err));
2345 goto exit;
2346 }
2347
2348 COMPAT_ASSIGN_VALUE(iface, beacon_rx, macstat_cnt->rxbeaconmbss);
2349 COMPAT_ASSIGN_VALUE(iface, rssi_mgmt, scbval.val);
2350 COMPAT_ASSIGN_VALUE(iface, num_peers, NUM_PEER);
2351 COMPAT_ASSIGN_VALUE(iface, peer_info->num_rate, NUM_RATE);
2352
2353#ifdef CONFIG_COMPAT
2354 if (compat_task_state) {
2355 memcpy(output, &compat_iface, sizeof(compat_iface));
2356 output += (sizeof(compat_iface) - sizeof(wifi_rate_stat));
2357 } else
2358#endif /* CONFIG_COMPAT */
2359 {
2360 memcpy(output, &iface, sizeof(iface));
2361 output += (sizeof(iface) - sizeof(wifi_rate_stat));
2362 }
2363
2364 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0,
2365 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2366 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
2367 WL_ERR(("error (%d) - size = %zu\n", err, NUM_RATE*sizeof(wifi_rate_stat)));
2368 goto exit;
2369 }
2370 for (i = 0; i < NUM_RATE; i++) {
2371 p_wifi_rate_stat =
2372 (wifi_rate_stat *)(iovar_buf + i*sizeof(wifi_rate_stat));
2373 p_wifi_rate_stat_v1 = (wifi_rate_stat_v1 *)output;
2374 p_wifi_rate_stat_v1->rate.preamble = p_wifi_rate_stat->rate.preamble;
2375 p_wifi_rate_stat_v1->rate.nss = p_wifi_rate_stat->rate.nss;
2376 p_wifi_rate_stat_v1->rate.bw = p_wifi_rate_stat->rate.bw;
2377 p_wifi_rate_stat_v1->rate.rateMcsIdx = p_wifi_rate_stat->rate.rateMcsIdx;
2378 p_wifi_rate_stat_v1->rate.reserved = p_wifi_rate_stat->rate.reserved;
2379 p_wifi_rate_stat_v1->rate.bitrate = p_wifi_rate_stat->rate.bitrate;
2380 p_wifi_rate_stat_v1->tx_mpdu = p_wifi_rate_stat->tx_mpdu;
2381 p_wifi_rate_stat_v1->rx_mpdu = p_wifi_rate_stat->rx_mpdu;
2382 p_wifi_rate_stat_v1->mpdu_lost = p_wifi_rate_stat->mpdu_lost;
2383 p_wifi_rate_stat_v1->retries = p_wifi_rate_stat->retries;
2384 p_wifi_rate_stat_v1->retries_short = p_wifi_rate_stat->retries_short;
2385 p_wifi_rate_stat_v1->retries_long = p_wifi_rate_stat->retries_long;
2386 output = (char *) &(p_wifi_rate_stat_v1->retries_long);
2387 output += sizeof(p_wifi_rate_stat_v1->retries_long);
2388 }
2389
2390 total_len = sizeof(wifi_radio_stat_h) +
2391 NUM_CHAN * sizeof(wifi_channel_stat);
2392
2393#ifdef CONFIG_COMPAT
2394 if (compat_task_state) {
2395 total_len += sizeof(compat_wifi_iface_stat);
2396 } else
2397#endif /* CONFIG_COMPAT */
2398 {
2399 total_len += sizeof(wifi_iface_stat);
2400 }
2401
2402 total_len = total_len - sizeof(wifi_peer_info) +
2403 NUM_PEER * (sizeof(wifi_peer_info) - sizeof(wifi_rate_stat_v1) +
2404 NUM_RATE * sizeof(wifi_rate_stat_v1));
2405
2406 if (total_len > WLC_IOCTL_MAXLEN) {
2407 WL_ERR(("Error! total_len:%d is unexpected value\n", total_len));
2408 err = BCME_BADLEN;
2409 goto exit;
2410 }
2411 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2412 outdata,
2413 total_len);
2414
2415 if (unlikely(err))
2416 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2417
2418exit:
2419 if (outdata) {
2420 kfree(outdata);
2421 }
2422 return err;
2423}
2424#endif /* LINKSTAT_SUPPORT */
2425
2426#ifdef DEBUGABILITY
2427static int wl_cfgvendor_dbg_start_logging(struct wiphy *wiphy,
2428 struct wireless_dev *wdev, const void *data, int len)
2429{
2430 int ret = BCME_OK, rem, type;
2431 char ring_name[DBGRING_NAME_MAX] = {0};
2432 int log_level = 0, flags = 0, time_intval = 0, threshold = 0;
2433 const struct nlattr *iter;
2434 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2435 dhd_pub_t *dhd_pub = cfg->pub;
2436 nla_for_each_attr(iter, data, len, rem) {
2437 type = nla_type(iter);
2438 switch (type) {
2439 case DEBUG_ATTRIBUTE_RING_NAME:
2440 strncpy(ring_name, nla_data(iter),
2441 MIN(sizeof(ring_name) -1, nla_len(iter)));
2442 break;
2443 case DEBUG_ATTRIBUTE_LOG_LEVEL:
2444 log_level = nla_get_u32(iter);
2445 break;
2446 case DEBUG_ATTRIBUTE_RING_FLAGS:
2447 flags = nla_get_u32(iter);
2448 break;
2449 case DEBUG_ATTRIBUTE_LOG_TIME_INTVAL:
2450 time_intval = nla_get_u32(iter);
2451 break;
2452 case DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE:
2453 threshold = nla_get_u32(iter);
2454 break;
2455 default:
2456 WL_ERR(("Unknown type: %d\n", type));
2457 ret = BCME_BADADDR;
2458 goto exit;
2459 }
2460 }
2461
2462 ret = dhd_os_start_logging(dhd_pub, ring_name, log_level, flags, time_intval, threshold);
2463 if (ret < 0) {
2464 WL_ERR(("start_logging is failed ret: %d\n", ret));
2465 }
2466exit:
2467 return ret;
2468}
2469
2470static int wl_cfgvendor_dbg_reset_logging(struct wiphy *wiphy,
2471 struct wireless_dev *wdev, const void *data, int len)
2472{
2473 int ret = BCME_OK;
2474 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2475 dhd_pub_t *dhd_pub = cfg->pub;
2476
2477 ret = dhd_os_reset_logging(dhd_pub);
2478 if (ret < 0) {
2479 WL_ERR(("reset logging is failed ret: %d\n", ret));
2480 }
2481
2482 return ret;
2483}
2484
2485static int
2486wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
2487 struct wireless_dev *wdev, const void *data, int len)
2488{
2489 int ret = BCME_OK;
2490 uint32 alloc_len;
2491 struct sk_buff *skb;
2492 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2493 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
2494
2495 dhdp->memdump_type = DUMP_TYPE_CFG_VENDOR_TRIGGERED;
2496
2497 ret = dhd_os_socram_dump(bcmcfg_to_prmry_ndev(cfg), &alloc_len);
2498 if (ret) {
2499 WL_ERR(("failed to call dhd_os_socram_dump : %d\n", ret));
2500 goto exit;
2501 }
2502 /* Alloc the SKB for vendor_event */
2503 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 100);
2504 if (!skb) {
2505 WL_ERR(("skb allocation is failed\n"));
2506 ret = BCME_NOMEM;
2507 goto exit;
2508 }
2509 nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, alloc_len);
2510
2511 ret = cfg80211_vendor_cmd_reply(skb);
2512
2513 if (ret) {
2514 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2515 }
47fa5ad5 2516 printk("wl_cfgvendor_dbg_trigger_mem_dump ===================ret : %d\n", ret);
010c3a89
RC
2517
2518exit:
2519 return ret;
2520}
2521
2522static int
2523wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
2524 struct wireless_dev *wdev, const void *data, int len)
2525{
2526 int ret = BCME_OK, rem, type;
2527 int buf_len = 0;
2528 uintptr_t user_buf = (uintptr_t)NULL;
2529 const struct nlattr *iter;
2530 char *mem_buf = NULL;
2531 struct sk_buff *skb;
2532 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2533
2534 nla_for_each_attr(iter, data, len, rem) {
2535 type = nla_type(iter);
2536 switch (type) {
2537 case DEBUG_ATTRIBUTE_FW_DUMP_LEN:
2538 /* Check if the iter is valid and
2539 * buffer length is not already initialized.
2540 */
2541 if ((nla_len(iter) == sizeof(uint32)) &&
2542 !buf_len) {
2543 buf_len = nla_get_u32(iter);
2544 } else {
2545 ret = BCME_ERROR;
2546 goto exit;
2547 }
2548 break;
2549 case DEBUG_ATTRIBUTE_FW_DUMP_DATA:
2550 if (nla_len(iter) != sizeof(uint64)) {
2551 WL_ERR(("Invalid len\n"));
2552 ret = BCME_ERROR;
2553 goto exit;
2554 }
2555 user_buf = (uintptr_t)nla_get_u64(iter);
2556 break;
2557 default:
2558 WL_ERR(("Unknown type: %d\n", type));
2559 ret = BCME_ERROR;
2560 goto exit;
2561 }
2562 }
2563 if (buf_len > 0 && user_buf) {
2564 mem_buf = vmalloc(buf_len);
2565 if (!mem_buf) {
2566 WL_ERR(("failed to allocate mem_buf with size : %d\n", buf_len));
2567 ret = BCME_NOMEM;
2568 goto exit;
2569 }
2570 ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf, &buf_len);
2571 if (ret) {
2572 WL_ERR(("failed to get_socram_dump : %d\n", ret));
2573 goto free_mem;
2574 }
2575#ifdef CONFIG_COMPAT
ccd15baf
RC
2576#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2577 if (in_compat_syscall())
2578#else
2579 if (is_compat_task())
2580#endif
2581 {
010c3a89
RC
2582 void * usr_ptr = compat_ptr((uintptr_t) user_buf);
2583 ret = copy_to_user(usr_ptr, mem_buf, buf_len);
2584 if (ret) {
2585 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
2586 goto free_mem;
2587 }
2588 }
2589 else
2590#endif /* CONFIG_COMPAT */
2591 {
2592 ret = copy_to_user((void*)user_buf, mem_buf, buf_len);
2593 if (ret) {
2594 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
2595 goto free_mem;
2596 }
2597 }
2598 /* Alloc the SKB for vendor_event */
2599 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 100);
2600 if (!skb) {
2601 WL_ERR(("skb allocation is failed\n"));
2602 ret = BCME_NOMEM;
2603 goto free_mem;
2604 }
2605 /* Indicate the memdump is succesfully copied */
2606 nla_put(skb, DEBUG_ATTRIBUTE_FW_DUMP_DATA, sizeof(ret), &ret);
2607
2608 ret = cfg80211_vendor_cmd_reply(skb);
2609
2610 if (ret) {
2611 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2612 }
2613 }
2614
2615free_mem:
2616 vfree(mem_buf);
2617exit:
2618 return ret;
2619}
2620
2621static int wl_cfgvendor_dbg_get_version(struct wiphy *wiphy,
2622 struct wireless_dev *wdev, const void *data, int len)
2623{
2624 int ret = BCME_OK, rem, type;
2625 int buf_len = 1024;
2626 bool dhd_ver = FALSE;
2627 char *buf_ptr;
2628 const struct nlattr *iter;
2629 gfp_t kflags;
2630 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2631 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2632 buf_ptr = kzalloc(buf_len, kflags);
2633 if (!buf_ptr) {
2634 WL_ERR(("failed to allocate the buffer for version n"));
2635 ret = BCME_NOMEM;
2636 goto exit;
2637 }
2638 nla_for_each_attr(iter, data, len, rem) {
2639 type = nla_type(iter);
2640 switch (type) {
2641 case DEBUG_ATTRIBUTE_GET_DRIVER:
2642 dhd_ver = TRUE;
2643 break;
2644 case DEBUG_ATTRIBUTE_GET_FW:
2645 dhd_ver = FALSE;
2646 break;
2647 default:
2648 WL_ERR(("Unknown type: %d\n", type));
2649 ret = BCME_ERROR;
2650 goto exit;
2651 }
2652 }
2653 ret = dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg), dhd_ver, &buf_ptr, buf_len);
2654 if (ret < 0) {
2655 WL_ERR(("failed to get the version %d\n", ret));
2656 goto exit;
2657 }
2658 ret = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2659 buf_ptr, strlen(buf_ptr));
2660exit:
2661 kfree(buf_ptr);
2662 return ret;
2663}
2664
2665static int wl_cfgvendor_dbg_get_ring_status(struct wiphy *wiphy,
2666 struct wireless_dev *wdev, const void *data, int len)
2667{
2668 int ret = BCME_OK;
2669 int ring_id, i;
2670 int ring_cnt;
2671 struct sk_buff *skb;
2672 dhd_dbg_ring_status_t dbg_ring_status[DEBUG_RING_ID_MAX];
2673 dhd_dbg_ring_status_t ring_status;
2674 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2675 dhd_pub_t *dhd_pub = cfg->pub;
2676 memset(dbg_ring_status, 0, DBG_RING_STATUS_SIZE * DEBUG_RING_ID_MAX);
2677 ring_cnt = 0;
2678 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
2679 ret = dhd_os_get_ring_status(dhd_pub, ring_id, &ring_status);
2680 if (ret == BCME_NOTFOUND) {
2681 WL_DBG(("The ring (%d) is not found \n", ring_id));
2682 } else if (ret == BCME_OK) {
2683 dbg_ring_status[ring_cnt++] = ring_status;
2684 }
2685 }
2686 /* Alloc the SKB for vendor_event */
2687 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
2688 (DBG_RING_STATUS_SIZE * ring_cnt) + 100);
2689 if (!skb) {
2690 WL_ERR(("skb allocation is failed\n"));
2691 ret = BCME_NOMEM;
2692 goto exit;
2693 }
2694
2695 nla_put_u32(skb, DEBUG_ATTRIBUTE_RING_NUM, ring_cnt);
2696 for (i = 0; i < ring_cnt; i++) {
2697 nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, DBG_RING_STATUS_SIZE,
2698 &dbg_ring_status[i]);
2699 }
2700 ret = cfg80211_vendor_cmd_reply(skb);
2701
2702 if (ret) {
2703 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2704 }
2705exit:
2706 return ret;
2707}
2708
2709static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy,
2710 struct wireless_dev *wdev, const void *data, int len)
2711{
2712 int ret = BCME_OK, rem, type;
2713 char ring_name[DBGRING_NAME_MAX] = {0};
2714 const struct nlattr *iter;
2715 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2716 dhd_pub_t *dhd_pub = cfg->pub;
2717
2718 nla_for_each_attr(iter, data, len, rem) {
2719 type = nla_type(iter);
2720 switch (type) {
2721 case DEBUG_ATTRIBUTE_RING_NAME:
2722 strncpy(ring_name, nla_data(iter),
2723 MIN(sizeof(ring_name) -1, nla_len(iter)));
2724 break;
2725 default:
2726 WL_ERR(("Unknown type: %d\n", type));
2727 return ret;
2728 }
2729 }
2730
2731 ret = dhd_os_trigger_get_ring_data(dhd_pub, ring_name);
2732 if (ret < 0) {
2733 WL_ERR(("trigger_get_data failed ret:%d\n", ret));
2734 }
2735
2736 return ret;
2737}
2738
2739static int wl_cfgvendor_dbg_get_feature(struct wiphy *wiphy,
2740 struct wireless_dev *wdev, const void *data, int len)
2741{
2742 int ret = BCME_OK;
2743 u32 supported_features = 0;
2744 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2745 dhd_pub_t *dhd_pub = cfg->pub;
2746
2747 ret = dhd_os_dbg_get_feature(dhd_pub, &supported_features);
2748 if (ret < 0) {
2749 WL_ERR(("dbg_get_feature failed ret:%d\n", ret));
2750 goto exit;
2751 }
2752 ret = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2753 &supported_features, sizeof(supported_features));
2754 if (ret < 0) {
ccd15baf
RC
2755 WL_ERR(("wl_cfgvendor_send_cmd_reply failed ret:%d\n", ret));
2756 goto exit;
2757 }
010c3a89
RC
2758exit:
2759 return ret;
2760}
2761
2762static void wl_cfgvendor_dbg_ring_send_evt(void *ctx,
2763 const int ring_id, const void *data, const uint32 len,
2764 const dhd_dbg_ring_status_t ring_status)
2765{
2766 struct net_device *ndev = ctx;
2767 struct wiphy *wiphy;
2768 gfp_t kflags;
2769 struct sk_buff *skb;
2770 if (!ndev) {
2771 WL_ERR(("ndev is NULL\n"));
2772 return;
2773 }
2774 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2775 wiphy = ndev->ieee80211_ptr->wiphy;
2776 /* Alloc the SKB for vendor_event */
2777#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2778 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2779 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + 100,
2780 GOOGLE_DEBUG_RING_EVENT, kflags);
2781#else
2782 skb = cfg80211_vendor_event_alloc(wiphy, len + 100,
2783 GOOGLE_DEBUG_RING_EVENT, kflags);
2784#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2785 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2786 if (!skb) {
2787 WL_ERR(("skb alloc failed"));
2788 return;
2789 }
2790 nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, sizeof(ring_status), &ring_status);
2791 nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
2792 cfg80211_vendor_event(skb, kflags);
2793}
2794
2795static void wl_cfgvendor_dbg_send_urgent_evt(void *ctx, const void *data,
2796 const uint32 len, const uint32 fw_len)
2797{
2798 struct net_device *ndev = ctx;
2799 struct wiphy *wiphy;
2800 gfp_t kflags;
2801 struct sk_buff *skb;
2802 if (!ndev) {
2803 WL_ERR(("ndev is NULL\n"));
2804 return;
2805 }
2806 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2807 wiphy = ndev->ieee80211_ptr->wiphy;
2808 /* Alloc the SKB for vendor_event */
2809#if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2810 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2811 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + 100,
2812 GOOGLE_FW_DUMP_EVENT, kflags);
2813#else
2814 skb = cfg80211_vendor_event_alloc(wiphy, len + 100,
2815 GOOGLE_FW_DUMP_EVENT, kflags);
2816#endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2817 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2818 if (!skb) {
2819 WL_ERR(("skb alloc failed"));
2820 return;
2821 }
2822 nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, fw_len);
2823 nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
2824 cfg80211_vendor_event(skb, kflags);
2825}
2826#endif /* DEBUGABILITY */
2827
2828#ifdef DBG_PKT_MON
2829static int wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy *wiphy,
2830 struct wireless_dev *wdev, const void *data, int len)
2831{
2832 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2833 dhd_pub_t *dhd_pub = cfg->pub;
2834 int ret;
2835
2836 ret = dhd_os_dbg_attach_pkt_monitor(dhd_pub);
2837 if (unlikely(ret)) {
2838 WL_ERR(("failed to start pkt fate monitoring, ret=%d", ret));
2839 }
2840
2841 return ret;
2842}
2843
2844typedef int (*dbg_mon_get_pkts_t) (dhd_pub_t *dhdp, void __user *user_buf,
2845 uint16 req_count, uint16 *resp_count);
2846
2847static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy *wiphy,
2848 const void *data, int len, dbg_mon_get_pkts_t dbg_mon_get_pkts)
2849{
2850 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2851 dhd_pub_t *dhd_pub = cfg->pub;
2852 struct sk_buff *skb = NULL;
2853 const struct nlattr *iter;
2854 void __user *user_buf = NULL;
2855 uint16 req_count = 0, resp_count = 0;
2856 int ret, tmp, type, mem_needed;
2857
2858 nla_for_each_attr(iter, data, len, tmp) {
2859 type = nla_type(iter);
2860 switch (type) {
2861 case DEBUG_ATTRIBUTE_PKT_FATE_NUM:
2862 req_count = nla_get_u32(iter);
2863 break;
2864 case DEBUG_ATTRIBUTE_PKT_FATE_DATA:
2865 user_buf = (void __user *)(unsigned long) nla_get_u64(iter);
2866 break;
2867 default:
2868 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
2869 ret = -EINVAL;
2870 goto exit;
2871 }
2872 }
2873
2874 if (!req_count || !user_buf) {
2875 WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n",
2876 __FUNCTION__, user_buf, req_count));
2877 ret = -EINVAL;
2878 goto exit;
2879 }
2880
2881 ret = dbg_mon_get_pkts(dhd_pub, user_buf, req_count, &resp_count);
2882 if (unlikely(ret)) {
2883 WL_ERR(("failed to get packets, ret:%d \n", ret));
2884 goto exit;
2885 }
2886
2887 mem_needed = VENDOR_REPLY_OVERHEAD + ATTRIBUTE_U32_LEN;
2888 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
2889 if (unlikely(!skb)) {
2890 WL_ERR(("skb alloc failed"));
2891 ret = -ENOMEM;
2892 goto exit;
2893 }
2894
2895 nla_put_u32(skb, DEBUG_ATTRIBUTE_PKT_FATE_NUM, resp_count);
2896
2897 ret = cfg80211_vendor_cmd_reply(skb);
2898 if (unlikely(ret)) {
2899 WL_ERR(("vendor Command reply failed ret:%d \n", ret));
2900 }
2901
2902exit:
2903 return ret;
2904}
2905
2906static int wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy *wiphy,
2907 struct wireless_dev *wdev, const void *data, int len)
2908{
2909 int ret;
2910
2911 ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
2912 dhd_os_dbg_monitor_get_tx_pkts);
2913 if (unlikely(ret)) {
2914 WL_ERR(("failed to get tx packets, ret:%d \n", ret));
2915 }
2916
2917 return ret;
2918}
2919
2920static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy *wiphy,
2921 struct wireless_dev *wdev, const void *data, int len)
2922{
2923 int ret;
2924
2925 ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
2926 dhd_os_dbg_monitor_get_rx_pkts);
2927 if (unlikely(ret)) {
2928 WL_ERR(("failed to get rx packets, ret:%d \n", ret));
2929 }
2930
2931 return ret;
2932}
2933#endif /* DBG_PKT_MON */
2934
2935#ifdef KEEP_ALIVE
2936static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
2937 const void *data, int len)
2938{
2939 /* max size of IP packet for keep alive */
2940 const int MKEEP_ALIVE_IP_PKT_MAX = 256;
2941
2942 int ret = BCME_OK, rem, type;
2943 uint8 mkeep_alive_id = 0;
2944 uint8 *ip_pkt = NULL;
2945 uint16 ip_pkt_len = 0;
2946 uint8 src_mac[ETHER_ADDR_LEN];
2947 uint8 dst_mac[ETHER_ADDR_LEN];
2948 uint32 period_msec = 0;
2949 const struct nlattr *iter;
2950 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2951 dhd_pub_t *dhd_pub = cfg->pub;
2952 gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2953
2954 nla_for_each_attr(iter, data, len, rem) {
2955 type = nla_type(iter);
2956 switch (type) {
2957 case MKEEP_ALIVE_ATTRIBUTE_ID:
2958 mkeep_alive_id = nla_get_u8(iter);
2959 break;
2960 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
2961 ip_pkt_len = nla_get_u16(iter);
2962 if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
2963 ret = BCME_BADARG;
2964 goto exit;
2965 }
2966 break;
2967 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
2968 if (!ip_pkt_len) {
2969 ret = BCME_BADARG;
2970 WL_ERR(("ip packet length is 0\n"));
2971 goto exit;
2972 }
2973 ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags);
2974 if (ip_pkt == NULL) {
2975 ret = BCME_NOMEM;
2976 WL_ERR(("Failed to allocate mem for ip packet\n"));
2977 goto exit;
2978 }
2979 memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len);
2980 break;
2981 case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
2982 memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN);
2983 break;
2984 case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
2985 memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN);
2986 break;
2987 case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
2988 period_msec = nla_get_u32(iter);
2989 break;
2990 default:
2991 WL_ERR(("Unknown type: %d\n", type));
2992 ret = BCME_BADARG;
2993 goto exit;
2994 }
2995 }
2996
2997 if (ip_pkt == NULL) {
2998 ret = BCME_BADARG;
2999 WL_ERR(("ip packet is NULL\n"));
3000 goto exit;
3001 }
3002
3003 ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac,
3004 dst_mac, period_msec);
3005 if (ret < 0) {
3006 WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret));
3007 }
3008
3009exit:
3010 if (ip_pkt) {
3011 kfree(ip_pkt);
3012 }
3013
3014 return ret;
3015}
3016
3017static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
3018 const void *data, int len)
3019{
3020 int ret = BCME_OK, rem, type;
3021 uint8 mkeep_alive_id = 0;
3022 const struct nlattr *iter;
3023 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3024 dhd_pub_t *dhd_pub = cfg->pub;
3025
3026 nla_for_each_attr(iter, data, len, rem) {
3027 type = nla_type(iter);
3028 switch (type) {
3029 case MKEEP_ALIVE_ATTRIBUTE_ID:
3030 mkeep_alive_id = nla_get_u8(iter);
3031 break;
3032 default:
3033 WL_ERR(("Unknown type: %d\n", type));
3034 ret = BCME_BADARG;
3035 break;
3036 }
3037 }
3038
3039 ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id);
3040 if (ret < 0) {
3041 WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret));
3042 }
3043
3044 return ret;
3045}
3046#endif /* KEEP_ALIVE */
3047
3048#if defined(PKT_FILTER_SUPPORT) && defined(APF)
3049static int
3050wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy,
3051 struct wireless_dev *wdev, const void *data, int len)
3052{
3053 struct net_device *ndev = wdev_to_ndev(wdev);
3054 struct sk_buff *skb;
3055 int ret, ver, max_len, mem_needed;
3056
3057 /* APF version */
3058 ver = 0;
3059 ret = dhd_dev_apf_get_version(ndev, &ver);
3060 if (unlikely(ret)) {
3061 WL_ERR(("APF get version failed, ret=%d\n", ret));
3062 return ret;
3063 }
3064
3065 /* APF memory size limit */
3066 max_len = 0;
3067 ret = dhd_dev_apf_get_max_len(ndev, &max_len);
3068 if (unlikely(ret)) {
3069 WL_ERR(("APF get maximum length failed, ret=%d\n", ret));
3070 return ret;
3071 }
3072
3073 mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
3074
3075 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
3076 if (unlikely(!skb)) {
3077 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
3078 return -ENOMEM;
3079 }
3080
3081 nla_put_u32(skb, APF_ATTRIBUTE_VERSION, ver);
3082 nla_put_u32(skb, APF_ATTRIBUTE_MAX_LEN, max_len);
3083
3084 ret = cfg80211_vendor_cmd_reply(skb);
3085 if (unlikely(ret)) {
3086 WL_ERR(("vendor command reply failed, ret=%d\n", ret));
3087 }
3088
3089 return ret;
3090}
3091
3092static int
3093wl_cfgvendor_apf_set_filter(struct wiphy *wiphy,
3094 struct wireless_dev *wdev, const void *data, int len)
3095{
3096 struct net_device *ndev = wdev_to_ndev(wdev);
3097 const struct nlattr *iter;
3098 u8 *program = NULL;
3099 u32 program_len = 0;
3100 int ret, tmp, type;
3101 gfp_t kflags;
3102
3103 if (len <= 0) {
3104 WL_ERR(("Invalid len: %d\n", len));
3105 ret = -EINVAL;
3106 goto exit;
3107 }
3108 nla_for_each_attr(iter, data, len, tmp) {
3109 type = nla_type(iter);
3110 switch (type) {
3111 case APF_ATTRIBUTE_PROGRAM_LEN:
3112 /* check if the iter value is valid and program_len
3113 * is not already initialized.
3114 */
3115 if (nla_len(iter) == sizeof(uint32) && !program_len) {
3116 program_len = nla_get_u32(iter);
3117 } else {
3118 ret = -EINVAL;
3119 goto exit;
3120 }
3121
3122 if (program_len > WL_APF_PROGRAM_MAX_SIZE) {
3123 WL_ERR(("program len is more than expected len\n"));
3124 ret = -EINVAL;
3125 goto exit;
3126 }
3127
3128 if (unlikely(!program_len)) {
3129 WL_ERR(("zero program length\n"));
3130 ret = -EINVAL;
3131 goto exit;
3132 }
3133 break;
3134 case APF_ATTRIBUTE_PROGRAM:
3135 if (unlikely(!program_len)) {
3136 WL_ERR(("program len is not set\n"));
3137 ret = -EINVAL;
3138 goto exit;
3139 }
3140 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3141 program = kzalloc(program_len, kflags);
3142 if (unlikely(!program)) {
3143 WL_ERR(("%s: can't allocate %d bytes\n",
3144 __FUNCTION__, program_len));
3145 ret = -ENOMEM;
3146 goto exit;
3147 }
3148 memcpy(program, (u8*)nla_data(iter), program_len);
3149 break;
3150 default:
3151 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
3152 ret = -EINVAL;
3153 goto exit;
3154 }
3155 }
3156
3157 ret = dhd_dev_apf_add_filter(ndev, program, program_len);
3158
3159exit:
3160 if (program) {
3161 kfree(program);
3162 }
3163 return ret;
3164}
3165#endif /* PKT_FILTER_SUPPORT && APF */
3166
3167#ifdef NDO_CONFIG_SUPPORT
3168static int wl_cfgvendor_configure_nd_offload(struct wiphy *wiphy,
3169 struct wireless_dev *wdev, const void *data, int len)
3170{
3171 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3172 const struct nlattr *iter;
3173 int ret = BCME_OK, rem, type;
3174 u8 enable = 0;
3175
3176 nla_for_each_attr(iter, data, len, rem) {
3177 type = nla_type(iter);
3178 switch (type) {
3179 case ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE:
3180 enable = nla_get_u8(iter);
3181 break;
3182 default:
3183 WL_ERR(("Unknown type: %d\n", type));
3184 ret = BCME_BADARG;
3185 goto exit;
3186 }
3187 }
3188
3189 ret = dhd_dev_ndo_cfg(bcmcfg_to_prmry_ndev(cfg), enable);
3190 if (ret < 0) {
3191 WL_ERR(("dhd_dev_ndo_cfg() failed: %d\n", ret));
3192 }
3193
3194exit:
3195 return ret;
3196}
3197#endif /* NDO_CONFIG_SUPPORT */
3198
3199static const struct wiphy_vendor_command wl_vendor_cmds [] = {
3200 {
3201 {
3202 .vendor_id = OUI_BRCM,
3203 .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
3204 },
3205 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3206 .doit = wl_cfgvendor_priv_string_handler
3207 },
3208 {
3209 {
3210 .vendor_id = OUI_BRCM,
3211 .subcmd = BRCM_VENDOR_SCMD_BCM_STR
3212 },
3213 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3214 .doit = wl_cfgvendor_priv_bcm_handler
3215 },
3216#ifdef GSCAN_SUPPORT
3217 {
3218 {
3219 .vendor_id = OUI_GOOGLE,
3220 .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
3221 },
3222 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3223 .doit = wl_cfgvendor_gscan_get_capabilities
3224 },
3225 {
3226 {
3227 .vendor_id = OUI_GOOGLE,
3228 .subcmd = GSCAN_SUBCMD_SET_CONFIG
3229 },
3230 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3231 .doit = wl_cfgvendor_set_scan_cfg
3232 },
3233 {
3234 {
3235 .vendor_id = OUI_GOOGLE,
3236 .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
3237 },
3238 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3239 .doit = wl_cfgvendor_set_batch_scan_cfg
3240 },
3241 {
3242 {
3243 .vendor_id = OUI_GOOGLE,
3244 .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
3245 },
3246 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3247 .doit = wl_cfgvendor_initiate_gscan
3248 },
3249 {
3250 {
3251 .vendor_id = OUI_GOOGLE,
3252 .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
3253 },
3254 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3255 .doit = wl_cfgvendor_enable_full_scan_result
3256 },
3257 {
3258 {
3259 .vendor_id = OUI_GOOGLE,
3260 .subcmd = GSCAN_SUBCMD_SET_HOTLIST
3261 },
3262 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3263 .doit = wl_cfgvendor_hotlist_cfg
3264 },
3265 {
3266 {
3267 .vendor_id = OUI_GOOGLE,
3268 .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
3269 },
3270 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3271 .doit = wl_cfgvendor_gscan_get_batch_results
3272 },
3273#endif /* GSCAN_SUPPORT */
3274#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
3275 {
3276 {
3277 .vendor_id = OUI_GOOGLE,
3278 .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
3279 },
3280 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3281 .doit = wl_cfgvendor_gscan_get_channel_list
3282 },
3283#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
3284#ifdef RTT_SUPPORT
3285 {
3286 {
3287 .vendor_id = OUI_GOOGLE,
3288 .subcmd = RTT_SUBCMD_SET_CONFIG
3289 },
3290 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3291 .doit = wl_cfgvendor_rtt_set_config
3292 },
3293 {
3294 {
3295 .vendor_id = OUI_GOOGLE,
3296 .subcmd = RTT_SUBCMD_CANCEL_CONFIG
3297 },
3298 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3299 .doit = wl_cfgvendor_rtt_cancel_config
3300 },
3301 {
3302 {
3303 .vendor_id = OUI_GOOGLE,
3304 .subcmd = RTT_SUBCMD_GETCAPABILITY
3305 },
3306 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3307 .doit = wl_cfgvendor_rtt_get_capability
3308 },
3309 {
3310 {
3311 .vendor_id = OUI_GOOGLE,
3312 .subcmd = RTT_SUBCMD_GETAVAILCHANNEL
3313 },
3314 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3315 .doit = wl_cfgvendor_rtt_get_responder_info
3316 },
3317 {
3318 {
3319 .vendor_id = OUI_GOOGLE,
3320 .subcmd = RTT_SUBCMD_SET_RESPONDER
3321 },
3322 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3323 .doit = wl_cfgvendor_rtt_set_responder
3324 },
3325 {
3326 {
3327 .vendor_id = OUI_GOOGLE,
3328 .subcmd = RTT_SUBCMD_CANCEL_RESPONDER
3329 },
3330 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3331 .doit = wl_cfgvendor_rtt_cancel_responder
3332 },
3333#endif /* RTT_SUPPORT */
3334 {
3335 {
3336 .vendor_id = OUI_GOOGLE,
3337 .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
3338 },
3339 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3340 .doit = wl_cfgvendor_get_feature_set
3341 },
3342 {
3343 {
3344 .vendor_id = OUI_GOOGLE,
3345 .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
3346 },
3347 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3348 .doit = wl_cfgvendor_get_feature_set_matrix
3349 },
3350 {
3351 {
3352 .vendor_id = OUI_GOOGLE,
3353 .subcmd = ANDR_WIFI_RANDOM_MAC_OUI
3354 },
3355 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3356 .doit = wl_cfgvendor_set_rand_mac_oui
3357 },
3358#ifdef CUSTOM_FORCE_NODFS_FLAG
3359 {
3360 {
3361 .vendor_id = OUI_GOOGLE,
3362 .subcmd = ANDR_WIFI_NODFS_CHANNELS
3363 },
3364 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3365 .doit = wl_cfgvendor_set_nodfs_flag
3366 },
3367#endif /* CUSTOM_FORCE_NODFS_FLAG */
3368 {
3369 {
3370 .vendor_id = OUI_GOOGLE,
3371 .subcmd = ANDR_WIFI_SET_COUNTRY
3372 },
3373 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3374 .doit = wl_cfgvendor_set_country
3375 },
3376#ifdef LINKSTAT_SUPPORT
3377 {
3378 {
3379 .vendor_id = OUI_GOOGLE,
3380 .subcmd = LSTATS_SUBCMD_GET_INFO
3381 },
3382 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3383 .doit = wl_cfgvendor_lstats_get_info
3384 },
3385#endif /* LINKSTAT_SUPPORT */
3386
3387#ifdef GSCAN_SUPPORT
3388 {
3389 {
3390 .vendor_id = OUI_GOOGLE,
3391 .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID
3392 },
3393 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3394 .doit = wl_cfgvendor_epno_cfg
3395
3396 },
3397 {
3398 {
3399 .vendor_id = OUI_GOOGLE,
3400 .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST
3401 },
3402 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3403 .doit = wl_cfgvendor_set_ssid_whitelist
3404
3405 },
3406 {
3407 {
3408 .vendor_id = OUI_GOOGLE,
3409 .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
3410 },
3411 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3412 .doit = wl_cfgvendor_set_lazy_roam_cfg
3413
3414 },
3415 {
3416 {
3417 .vendor_id = OUI_GOOGLE,
3418 .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM
3419 },
3420 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3421 .doit = wl_cfgvendor_enable_lazy_roam
3422
3423 },
3424 {
3425 {
3426 .vendor_id = OUI_GOOGLE,
3427 .subcmd = WIFI_SUBCMD_SET_BSSID_PREF
3428 },
3429 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3430 .doit = wl_cfgvendor_set_bssid_pref
3431
3432 },
3433 {
3434 {
3435 .vendor_id = OUI_GOOGLE,
3436 .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST
3437 },
3438 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3439 .doit = wl_cfgvendor_set_bssid_blacklist
3440 },
3441#endif /* GSCAN_SUPPORT */
3442#ifdef DEBUGABILITY
3443 {
3444 {
3445 .vendor_id = OUI_GOOGLE,
3446 .subcmd = DEBUG_START_LOGGING
3447 },
3448 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3449 .doit = wl_cfgvendor_dbg_start_logging
3450 },
3451 {
3452 {
3453 .vendor_id = OUI_GOOGLE,
3454 .subcmd = DEBUG_RESET_LOGGING
3455 },
3456 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3457 .doit = wl_cfgvendor_dbg_reset_logging
3458 },
3459 {
3460 {
3461 .vendor_id = OUI_GOOGLE,
3462 .subcmd = DEBUG_TRIGGER_MEM_DUMP
3463 },
3464 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3465 .doit = wl_cfgvendor_dbg_trigger_mem_dump
3466 },
3467 {
3468 {
3469 .vendor_id = OUI_GOOGLE,
3470 .subcmd = DEBUG_GET_MEM_DUMP
3471 },
3472 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3473 .doit = wl_cfgvendor_dbg_get_mem_dump
3474 },
3475 {
3476 {
3477 .vendor_id = OUI_GOOGLE,
3478 .subcmd = DEBUG_GET_VER
3479 },
3480 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3481 .doit = wl_cfgvendor_dbg_get_version
3482 },
3483 {
3484 {
3485 .vendor_id = OUI_GOOGLE,
3486 .subcmd = DEBUG_GET_RING_STATUS
3487 },
3488 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3489 .doit = wl_cfgvendor_dbg_get_ring_status
3490 },
3491 {
3492 {
3493 .vendor_id = OUI_GOOGLE,
3494 .subcmd = DEBUG_GET_RING_DATA
3495 },
3496 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3497 .doit = wl_cfgvendor_dbg_get_ring_data
3498 },
3499 {
3500 {
3501 .vendor_id = OUI_GOOGLE,
3502 .subcmd = DEBUG_GET_FEATURE
3503 },
3504 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3505 .doit = wl_cfgvendor_dbg_get_feature
3506 },
3507#endif /* DEBUGABILITY */
3508#ifdef DBG_PKT_MON
3509 {
3510 {
3511 .vendor_id = OUI_GOOGLE,
3512 .subcmd = DEBUG_START_PKT_FATE_MONITORING
3513 },
3514 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3515 .doit = wl_cfgvendor_dbg_start_pkt_fate_monitoring
3516 },
3517 {
3518 {
3519 .vendor_id = OUI_GOOGLE,
3520 .subcmd = DEBUG_GET_TX_PKT_FATES
3521 },
3522 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3523 .doit = wl_cfgvendor_dbg_get_tx_pkt_fates
3524 },
3525 {
3526 {
3527 .vendor_id = OUI_GOOGLE,
3528 .subcmd = DEBUG_GET_RX_PKT_FATES
3529 },
3530 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3531 .doit = wl_cfgvendor_dbg_get_rx_pkt_fates
3532 },
3533#endif /* DBG_PKT_MON */
3534#ifdef KEEP_ALIVE
3535 {
3536 {
3537 .vendor_id = OUI_GOOGLE,
3538 .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
3539 },
3540 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3541 .doit = wl_cfgvendor_start_mkeep_alive
3542 },
3543 {
3544 {
3545 .vendor_id = OUI_GOOGLE,
3546 .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
3547 },
3548 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3549 .doit = wl_cfgvendor_stop_mkeep_alive
3550 },
3551#endif /* KEEP_ALIVE */
3552#if defined(PKT_FILTER_SUPPORT) && defined(APF)
3553 {
3554 {
3555 .vendor_id = OUI_GOOGLE,
3556 .subcmd = APF_SUBCMD_GET_CAPABILITIES
3557 },
3558 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3559 .doit = wl_cfgvendor_apf_get_capabilities
3560 },
3561
3562 {
3563 {
3564 .vendor_id = OUI_GOOGLE,
3565 .subcmd = APF_SUBCMD_SET_FILTER
3566 },
3567 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3568 .doit = wl_cfgvendor_apf_set_filter
3569 },
3570#endif /* PKT_FILTER_SUPPORT && APF */
3571#ifdef NDO_CONFIG_SUPPORT
3572 {
3573 {
3574 .vendor_id = OUI_GOOGLE,
3575 .subcmd = WIFI_SUBCMD_CONFIG_ND_OFFLOAD
3576 },
3577 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3578 .doit = wl_cfgvendor_configure_nd_offload
3579 },
3580#endif /* NDO_CONFIG_SUPPORT */
3581#ifdef RSSI_MONITOR_SUPPORT
3582 {
3583 {
3584 .vendor_id = OUI_GOOGLE,
3585 .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR
3586 },
3587 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3588 .doit = wl_cfgvendor_set_rssi_monitor
3589 },
3590#endif /* RSSI_MONITOR_SUPPORT */
3591#ifdef DHDTCPACK_SUPPRESS
3592 {
3593 {
3594 .vendor_id = OUI_GOOGLE,
3595 .subcmd = WIFI_SUBCMD_CONFIG_TCPACK_SUP
3596 },
3597 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3598 .doit = wl_cfgvendor_set_tcpack_sup_mode
3599 },
3600#endif /* DHDTCPACK_SUPPRESS */
3601#ifdef DHD_WAKE_STATUS
3602 {
3603 {
3604 .vendor_id = OUI_GOOGLE,
3605 .subcmd = DEBUG_GET_WAKE_REASON_STATS
3606 },
3607 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3608 .doit = wl_cfgvendor_get_wake_reason_stats
3609 }
3610#endif /* DHD_WAKE_STATUS */
3611};
3612
3613static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
3614 { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
3615 { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
3616#ifdef GSCAN_SUPPORT
3617 { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
3618 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
3619 { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
3620 { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
3621#endif /* GSCAN_SUPPORT */
3622#ifdef RTT_SUPPORT
3623 { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
3624#endif /* RTT_SUPPORT */
3625#ifdef GSCAN_SUPPORT
3626 { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
3627 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT },
3628 { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
3629#endif /* GSCAN_SUPPORT */
3630 { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
3631 { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
3632#ifdef GSCAN_SUPPORT
3633 { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
3634#endif /* GSCAN_SUPPORT */
3635 { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
3636 { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT },
3637 { OUI_GOOGLE, GOOGLE_NAN_EVENT_ENABLED},
3638 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DISABLED},
3639 { OUI_GOOGLE, GOOGLE_NAN_EVENT_PUBLISH_TERMINATED},
3640 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH},
3641 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH},
3642 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED},
3643 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DE_EVENT},
3644 { OUI_GOOGLE, GOOGLE_NAN_EVENT_FOLLOWUP},
3645 { OUI_GOOGLE, GOOGLE_NAN_EVENT_TCA},
3646#ifdef NAN_DP
3647 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_PATH_OPEN},
3648#endif /* NAN_DP */
3649 { OUI_GOOGLE, GOOGLE_NAN_EVENT_UNKNOWN}
3650};
3651
3652int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd)
3653{
3654
3655 WL_INFORM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
3656 NL80211_CMD_VENDOR));
3657
3658 wiphy->vendor_commands = wl_vendor_cmds;
3659 wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
3660 wiphy->vendor_events = wl_vendor_events;
3661 wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events);
3662
3663#ifdef DEBUGABILITY
3664 dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3665 dhd_os_dbg_register_callback(FW_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3666 dhd_os_dbg_register_callback(DHD_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3667 dhd_os_dbg_register_callback(NAN_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3668 dhd_os_dbg_register_urgent_notifier(dhd, wl_cfgvendor_dbg_send_urgent_evt);
3669#endif /* DEBUGABILITY */
3670
3671 return 0;
3672}
3673
3674int wl_cfgvendor_detach(struct wiphy *wiphy)
3675{
3676 WL_INFORM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
3677
3678 wiphy->vendor_commands = NULL;
3679 wiphy->vendor_events = NULL;
3680 wiphy->n_vendor_commands = 0;
3681 wiphy->n_vendor_events = 0;
3682
3683 return 0;
3684}
3685#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */