2 * Linux cfg80211 Vendor Extension Code
4 * Copyright (C) 1999-2017, Broadcom Corporation
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:
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.
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.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: wl_cfgvendor.c 710862 2017-07-14 07:43:59Z $
31 * New vendor interface additon to nl80211/cfg80211 to allow vendors
32 * to implement proprietary features over the cfg80211 stack.
38 #include <linux/kernel.h>
39 #include <linux/vmalloc.h>
42 #include <bcmwifi_channels.h>
43 #include <bcmendian.h>
46 #include <linux/if_arp.h>
47 #include <asm/uaccess.h>
49 #include <dngl_stats.h>
51 #include <dhd_debug.h>
54 #include <wlioctl_utils.h>
55 #include <dhd_cfg80211.h>
58 #endif /* PNO_SUPPORT */
61 #endif /* RTT_SUPPORT */
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>
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>
84 #include <brcm_nl80211.h>
87 #include <wl_statreport.h>
90 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
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
98 int wl_cfgvendor_send_async_event(struct wiphy
*wiphy
,
99 struct net_device
*dev
, int event_id
, const void *data
, int len
)
104 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
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
);
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) */
115 WL_ERR(("skb alloc failed"));
119 /* Push the data to the skb */
120 nla_put_nohdr(skb
, len
, data
);
122 cfg80211_vendor_event(skb
, kflags
);
128 wl_cfgvendor_send_cmd_reply(struct wiphy
*wiphy
,
129 struct net_device
*dev
, const void *data
, int len
)
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"));
140 /* Push the data to the skb */
141 nla_put_nohdr(skb
, len
, data
);
143 return cfg80211_vendor_cmd_reply(skb
);
147 wl_cfgvendor_get_feature_set(struct wiphy
*wiphy
,
148 struct wireless_dev
*wdev
, const void *data
, int len
)
151 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
154 reply
= dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg
));
156 err
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
157 &reply
, sizeof(int));
159 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
165 wl_cfgvendor_get_feature_set_matrix(struct wiphy
*wiphy
,
166 struct wireless_dev
*wdev
, const void *data
, int len
)
169 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
174 mem_needed
= VENDOR_REPLY_OVERHEAD
+
175 (ATTRIBUTE_U32_LEN
* MAX_FEATURE_SET_CONCURRRENT_GROUPS
) + ATTRIBUTE_U32_LEN
;
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"));
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
);
193 err
= cfg80211_vendor_cmd_reply(skb
);
196 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
203 wl_cfgvendor_set_rand_mac_oui(struct wiphy
*wiphy
,
204 struct wireless_dev
*wdev
, const void *data
, int len
)
207 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
209 uint8 random_mac_oui
[DOT11_OUI_LEN
];
211 type
= nla_type(data
);
213 if (type
== ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI
) {
214 memcpy(random_mac_oui
, nla_data(data
), DOT11_OUI_LEN
);
216 err
= dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg
), random_mac_oui
);
219 WL_ERR(("Bad OUI, could not set:%d \n", err
));
227 #ifdef CUSTOM_FORCE_NODFS_FLAG
229 wl_cfgvendor_set_nodfs_flag(struct wiphy
*wiphy
,
230 struct wireless_dev
*wdev
, const void *data
, int len
)
233 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
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
);
246 #endif /* CUSTOM_FORCE_NODFS_FLAG */
249 wl_cfgvendor_set_country(struct wiphy
*wiphy
,
250 struct wireless_dev
*wdev
, const void *data
, int len
)
252 int err
= BCME_ERROR
, rem
, type
;
253 char country_code
[WLC_CNTRY_BUF_SZ
] = {0};
254 const struct nlattr
*iter
;
256 nla_for_each_attr(iter
, data
, len
, rem
) {
257 type
= nla_type(iter
);
259 case ANDR_WIFI_ATTRIBUTE_COUNTRY
:
260 memcpy(country_code
, nla_data(iter
),
261 MIN(nla_len(iter
), WLC_CNTRY_BUF_SZ
));
264 WL_ERR(("Unknown type: %d\n", type
));
269 err
= wldev_set_country(wdev
->netdev
, country_code
, true, true, -1);
271 WL_ERR(("Set country failed ret:%d\n", err
));
279 wl_cfgvendor_send_hotlist_event(struct wiphy
*wiphy
,
280 struct net_device
*dev
, void *data
, int len
, wl_vendor_event_t event
)
285 int malloc_len
, total
, iter_cnt_to_send
, cnt
;
286 gscan_results_cache_t
*cache
= (gscan_results_cache_t
*)data
;
288 total
= len
/sizeof(wifi_gscan_result_t
);
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
;
295 (malloc_len
- VENDOR_DATA_OVERHEAD
)/sizeof(wifi_gscan_result_t
);
296 total
= total
- iter_cnt_to_send
;
298 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
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
);
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) */
309 WL_ERR(("skb alloc failed"));
313 while (cache
&& iter_cnt_to_send
) {
314 ptr
= (const void *) &cache
->results
[cache
->tot_consumed
];
316 if (iter_cnt_to_send
< (cache
->tot_count
- cache
->tot_consumed
)) {
317 cnt
= iter_cnt_to_send
;
319 cnt
= (cache
->tot_count
- cache
->tot_consumed
);
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
) {
332 cfg80211_vendor_event(skb
, kflags
);
340 wl_cfgvendor_gscan_get_capabilities(struct wiphy
*wiphy
,
341 struct wireless_dev
*wdev
, const void *data
, int len
)
344 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
345 dhd_pno_gscan_capabilities_t
*reply
= NULL
;
346 uint32 reply_len
= 0;
349 reply
= dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg
),
350 DHD_PNO_GET_CAPABILITIES
, NULL
, &reply_len
);
352 WL_ERR(("Could not get capabilities\n"));
357 err
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
361 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
369 wl_cfgvendor_gscan_get_batch_results(struct wiphy
*wiphy
,
370 struct wireless_dev
*wdev
, const void *data
, int len
)
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
;
380 struct nlattr
*scan_hdr
, *complete_flag
;
382 err
= dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg
));
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
));
391 results
= dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg
),
392 DHD_PNO_GET_BATCH_RESULTS
, NULL
, &reply_len
);
395 WL_ERR(("No results to send %d\n", err
));
396 err
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
400 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
401 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg
));
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
;
410 if (mem_needed
> (int32
)NLMSG_DEFAULT_SIZE
) {
411 mem_needed
= (int32
)NLMSG_DEFAULT_SIZE
;
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
));
424 complete_flag
= nla_reserve(skb
, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE
,
426 mem_needed
= mem_needed
- (SCAN_RESULTS_COMPLETE_FLAG_LEN
+ VENDOR_REPLY_OVERHEAD
);
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
)) {
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
) {
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
);
445 num_results_iter
= iter
->tot_count
- iter
->tot_consumed
;
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
);
454 nla_nest_end(skb
, scan_hdr
);
455 mem_needed
-= GSCAN_BATCH_RESULT_HDR_LEN
+
456 (num_results_iter
* sizeof(wifi_gscan_result_t
));
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
);
467 wl_cfgvendor_initiate_gscan(struct wiphy
*wiphy
,
468 struct wireless_dev
*wdev
, const void *data
, int len
)
471 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
475 const struct nlattr
*iter
;
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
);
486 err
= dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg
), run
, flush
);
489 WL_ERR(("Could not run gscan:%d \n", err
));
500 wl_cfgvendor_enable_full_scan_result(struct wiphy
*wiphy
,
501 struct wireless_dev
*wdev
, const void *data
, int len
)
504 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
506 bool real_time
= FALSE
;
508 type
= nla_type(data
);
510 if (type
== GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS
) {
511 real_time
= nla_get_u32(data
);
513 err
= dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg
), real_time
);
516 WL_ERR(("Could not run gscan:%d \n", err
));
527 wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr
*prev
,
528 gscan_scan_params_t
*scan_param
, int num
)
530 struct dhd_pno_gscan_channel_bucket
*ch_bucket
;
532 int type
, err
= 0, rem
;
533 const struct nlattr
*cur
, *next
;
535 nla_for_each_nested(cur
, prev
, rem
) {
536 type
= nla_type(cur
);
537 ch_bucket
= scan_param
->channel_bucket
;
539 case GSCAN_ATTRIBUTE_BUCKET_ID
:
541 case GSCAN_ATTRIBUTE_BUCKET_PERIOD
:
542 if (nla_len(cur
) != sizeof(uint32
)) {
547 ch_bucket
[num
].bucket_freq_multiple
=
548 nla_get_u32(cur
) / MSEC_PER_SEC
;
550 case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS
:
551 if (nla_len(cur
) != sizeof(uint32
)) {
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
,
565 case GSCAN_ATTRIBUTE_BUCKET_CHANNELS
:
566 nla_for_each_nested(next
, cur
, rem
) {
567 if (k
>= GSCAN_MAX_CHANNELS_IN_BUCKET
)
569 if (nla_len(next
) != sizeof(uint32
)) {
573 ch_bucket
[num
].chan_list
[k
] = nla_get_u32(next
);
577 case GSCAN_ATTRIBUTE_BUCKETS_BAND
:
578 if (nla_len(cur
) != sizeof(uint32
)) {
582 ch_bucket
[num
].band
= (uint16
)nla_get_u32(cur
);
584 case GSCAN_ATTRIBUTE_REPORT_EVENTS
:
585 if (nla_len(cur
) != sizeof(uint32
)) {
589 ch_bucket
[num
].report_flag
= (uint8
)nla_get_u32(cur
);
591 case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT
:
592 if (nla_len(cur
) != sizeof(uint32
)) {
596 ch_bucket
[num
].repeat
= (uint16
)nla_get_u32(cur
);
598 case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD
:
599 if (nla_len(cur
) != sizeof(uint32
)) {
603 ch_bucket
[num
].bucket_max_multiple
=
604 nla_get_u32(cur
) / MSEC_PER_SEC
;
607 WL_ERR(("unknown attr type:%d\n", type
));
618 wl_cfgvendor_set_scan_cfg(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
619 const void *data
, int len
)
622 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
623 gscan_scan_params_t
*scan_param
;
626 const struct nlattr
*iter
;
628 scan_param
= kzalloc(sizeof(gscan_scan_params_t
), GFP_KERNEL
);
630 WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
636 scan_param
->scan_fr
= PNO_SCAN_MIN_FW_SEC
;
637 nla_for_each_attr(iter
, data
, len
, tmp
) {
638 type
= nla_type(iter
);
640 if (j
>= GSCAN_MAX_CH_BUCKETS
) {
645 case GSCAN_ATTRIBUTE_BASE_PERIOD
:
646 if (nla_len(iter
) != sizeof(uint32
)) {
650 scan_param
->scan_fr
= nla_get_u32(iter
) / MSEC_PER_SEC
;
652 case GSCAN_ATTRIBUTE_NUM_BUCKETS
:
653 if (nla_len(iter
) != sizeof(uint32
)) {
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
));
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
);
675 WL_ERR(("set_scan_cfg_buck error:%d\n", err
));
681 WL_ERR(("Unknown type %d\n", type
));
687 err
= dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg
),
688 DHD_PNO_SCAN_CFG_ID
, scan_param
, FALSE
);
691 WL_ERR(("Could not set GSCAN scan cfg\n"));
702 wl_cfgvendor_hotlist_cfg(struct wiphy
*wiphy
,
703 struct wireless_dev
*wdev
, const void *data
, int len
)
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
;
711 struct bssid_t
*pbssid
;
713 BCM_REFERENCE(dummy
);
715 if (len
< sizeof(*hotlist_params
) || len
>= WLC_IOCTL_MAXLEN
) {
716 WL_ERR(("buffer length :%d wrong - bail out.\n", len
));
720 hotlist_params
= kzalloc(sizeof(*hotlist_params
)
721 + (sizeof(struct bssid_t
) * (PFN_SWC_MAX_NUM_APS
- 1)),
724 if (!hotlist_params
) {
725 WL_ERR(("Cannot Malloc memory.\n"));
729 hotlist_params
->lost_ap_window
= GSCAN_LOST_AP_WINDOW_DEFAULT
;
731 nla_for_each_attr(iter
, data
, len
, tmp2
) {
732 type
= nla_type(iter
);
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
);
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
)));
749 &(pbssid
[j
].macaddr
),
751 sizeof(pbssid
[j
].macaddr
));
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
)));
760 pbssid
[j
].rssi_reporting_threshold
=
761 (int8
)nla_get_u8(inner
);
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
)));
770 dummy
= (int8
)nla_get_u8(inner
);
773 WL_ERR(("ATTR unknown %d\n", type
));
778 if (++j
>= PFN_SWC_MAX_NUM_APS
) {
779 WL_ERR(("cap hotlist max:%d\n", j
));
783 hotlist_params
->nbssid
= j
;
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
)));
792 flush
= nla_get_u8(iter
);
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
)));
801 hotlist_params
->lost_ap_window
= (uint16
)nla_get_u32(iter
);
804 WL_ERR(("Unknown type %d\n", type
));
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
));
818 kfree(hotlist_params
);
822 static int wl_cfgvendor_epno_cfg(struct wiphy
*wiphy
,
823 struct wireless_dev
*wdev
, const void *data
, int len
)
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
;
833 nla_for_each_attr(iter
, data
, len
, tmp2
) {
834 type
= nla_type(iter
);
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
,
843 WL_ERR(("Failed to get SSID LIST buffer\n"));
848 nla_for_each_nested(inner
, outer
, tmp1
) {
849 type
= nla_type(inner
);
852 case GSCAN_ATTRIBUTE_EPNO_SSID
:
853 memcpy(ssid_elem
->SSID
,
857 case GSCAN_ATTRIBUTE_EPNO_SSID_LEN
:
858 ssid_elem
->SSID_len
=
860 if (ssid_elem
->SSID_len
>
861 DOT11_MAX_SSID_LEN
) {
864 ssid_elem
->SSID_len
));
869 case GSCAN_ATTRIBUTE_EPNO_FLAGS
:
874 DHD_EPNO_HIDDEN_SSID
) != 0);
876 case GSCAN_ATTRIBUTE_EPNO_AUTH
:
877 ssid_elem
->wpa_auth
=
882 if (!ssid_elem
->SSID_len
) {
883 WL_ERR(("Broadcast SSID is illegal for ePNO\n"));
887 dhd_pno_translate_epno_fw_flags(&ssid_elem
->flags
);
888 dhd_pno_set_epno_auth_flag(&ssid_elem
->wpa_auth
);
891 case GSCAN_ATTRIBUTE_EPNO_SSID_NUM
:
892 num
= nla_get_u8(iter
);
894 case GSCAN_ATTRIBUTE_EPNO_FLUSH
:
895 flush
= (bool)nla_get_u32(iter
);
896 /* Flush attribute is expected before any ssid attribute */
898 WL_ERR(("Bad attributes\n"));
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
));
907 case GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR
:
908 params
.min5G_rssi
= nla_get_s8(iter
);
910 case GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR
:
911 params
.min2G_rssi
= nla_get_s8(iter
);
913 case GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX
:
914 params
.init_score_max
= nla_get_s16(iter
);
916 case GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS
:
917 params
.cur_bssid_bonus
= nla_get_s16(iter
);
919 case GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS
:
920 params
.same_ssid_bonus
= nla_get_s16(iter
);
922 case GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS
:
923 params
.secure_bonus
= nla_get_s16(iter
);
925 case GSCAN_ATTRIBUTE_EPNO_5G_BONUS
:
926 params
.band_5g_bonus
= nla_get_s16(iter
);
929 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__
, type
));
935 WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__
,
940 /* Flush all configs if error condition */
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
, ¶ms
, FALSE
);
949 err
= dhd_dev_set_epno(bcmcfg_to_prmry_ndev(cfg
));
955 wl_cfgvendor_set_batch_scan_cfg(struct wiphy
*wiphy
,
956 struct wireless_dev
*wdev
, const void *data
, int len
)
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
;
963 batch_param
.mscan
= batch_param
.bestn
= 0;
964 batch_param
.buffer_threshold
= GSCAN_BATCH_NO_THR_SET
;
966 nla_for_each_attr(iter
, data
, len
, tmp
) {
967 type
= nla_type(iter
);
970 case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN
:
971 batch_param
.bestn
= nla_get_u32(iter
);
973 case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE
:
974 batch_param
.mscan
= nla_get_u32(iter
);
976 case GSCAN_ATTRIBUTE_REPORT_THRESHOLD
:
977 batch_param
.buffer_threshold
= nla_get_u32(iter
);
980 WL_ERR(("Unknown type %d\n", type
));
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"));
995 #endif /* GSCAN_SUPPORT */
996 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
998 wl_cfgvendor_gscan_get_channel_list(struct wiphy
*wiphy
,
999 struct wireless_dev
*wdev
, const void *data
, int len
)
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
;
1007 type
= nla_type(data
);
1009 if (type
== GSCAN_ATTRIBUTE_BAND
) {
1010 band
= nla_get_u32(data
);
1015 reply
= dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg
),
1016 DHD_PNO_GET_CHANNEL_LIST
, &band
, &reply_len
);
1019 WL_ERR(("Could not get channel list\n"));
1023 num_channels
= reply_len
/ sizeof(uint32
);
1024 mem_needed
= reply_len
+ VENDOR_REPLY_OVERHEAD
+ (ATTRIBUTE_U32_LEN
* 2);
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"));
1034 nla_put_u32(skb
, GSCAN_ATTRIBUTE_NUM_CHANNELS
, num_channels
);
1035 nla_put(skb
, GSCAN_ATTRIBUTE_CHANNEL_LIST
, reply_len
, reply
);
1037 err
= cfg80211_vendor_cmd_reply(skb
);
1039 if (unlikely(err
)) {
1040 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
1046 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
1048 #ifdef RSSI_MONITOR_SUPPORT
1049 static int wl_cfgvendor_set_rssi_monitor(struct wiphy
*wiphy
,
1050 struct wireless_dev
*wdev
, const void *data
, int len
)
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
;
1057 nla_for_each_attr(iter
, data
, len
, tmp
) {
1058 type
= nla_type(iter
);
1060 case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI
:
1061 max_rssi
= (int8
) nla_get_u32(iter
);
1063 case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI
:
1064 min_rssi
= (int8
) nla_get_u32(iter
);
1066 case RSSI_MONITOR_ATTRIBUTE_START
:
1067 start
= nla_get_u32(iter
);
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"));
1078 #endif /* RSSI_MONITOR_SUPPORT */
1080 #ifdef DHDTCPACK_SUPPRESS
1081 static int wl_cfgvendor_set_tcpack_sup_mode(struct wiphy
*wiphy
,
1082 struct wireless_dev
*wdev
, const void *data
, int len
)
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
);
1088 const struct nlattr
*iter
;
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
);
1097 if (dhd_dev_set_tcpack_sup_mode_cfg(ndev
, enable
) < 0) {
1098 WL_ERR(("Could not set TCP Ack Suppress mode cfg\n"));
1103 #endif /* DHDTCPACK_SUPPRESS */
1105 #ifdef DHD_WAKE_STATUS
1107 wl_cfgvendor_get_wake_reason_stats(struct wiphy
*wiphy
,
1108 struct wireless_dev
*wdev
, const void *data
, int len
)
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)
1115 #endif /* DHD_WAKE_EVENT_STATUS && DHD_DEBUG */
1116 struct sk_buff
*skb
;
1117 dhd_pub_t
*dhdp
= wl_cfg80211_get_dhdp(ndev
);
1119 WL_DBG(("Recv get wake status info cmd.\n"));
1121 pwake_count_info
= dhd_get_wakecount(dhdp
);
1122 mem_needed
= VENDOR_REPLY_OVERHEAD
+ (ATTRIBUTE_U32_LEN
* 20) +
1123 (WLC_E_LAST
* sizeof(uint
));
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
));
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
);
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
]));
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
));
1171 #endif /* DHD_WAKE_STATUS */
1175 wl_cfgvendor_rtt_evt(void *ctx
, void *rtt_data
)
1177 struct wireless_dev
*wdev
= (struct wireless_dev
*)ctx
;
1178 struct wiphy
*wiphy
;
1179 struct sk_buff
*skb
;
1180 uint32 evt_complete
= 0;
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
;
1189 /* Push the data to the skb */
1191 WL_ERR(("rtt_data is NULL\n"));
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
);
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) */
1206 WL_ERR(("skb alloc failed"));
1210 nla_put_u32(skb
, RTT_ATTRIBUTE_RESULTS_COMPLETE
, evt_complete
);
1211 cfg80211_vendor_event(skb
, kflags
);
1214 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1215 #pragma GCC diagnostic push
1216 #pragma GCC diagnostic ignored "-Wcast-qual"
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
);
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) */
1230 WL_ERR(("skb alloc failed"));
1233 if (list_is_last(&rtt_header
->list
, rtt_cache_list
)) {
1236 nla_put_u32(skb
, RTT_ATTRIBUTE_RESULTS_COMPLETE
, evt_complete
);
1237 rtt_nl_hdr
= nla_nest_start(skb
, RTT_ATTRIBUTE_RESULTS_PER_TARGET
);
1239 WL_ERR(("rtt_nl_hdr is NULL\n"));
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
);
1248 nla_nest_end(skb
, rtt_nl_hdr
);
1249 cfg80211_vendor_event(skb
, kflags
);
1251 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1252 #pragma GCC diagnostic pop
1257 wl_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
;
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
;
1269 memset(&rtt_param
, 0, sizeof(rtt_param
));
1272 err
= dhd_dev_rtt_register_noti_callback(wdev
->netdev
, wdev
, wl_cfgvendor_rtt_evt
);
1274 WL_ERR(("failed to register rtt_noti_callback\n"));
1277 err
= dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg
), &capability
);
1279 WL_ERR(("failed to get the capability\n"));
1284 WL_ERR(("Length of the nlattr is not valid len : %d\n", len
));
1288 nla_for_each_attr(iter
, data
, len
, rem
) {
1289 type
= nla_type(iter
);
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",
1299 rtt_param
.rtt_target_cnt
= target_cnt
;
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
));
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
1312 if (rtt_param
.target_info
== NULL
) {
1313 WL_ERR(("rtt_target_info is NULL\n"));
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
);
1322 case RTT_ATTRIBUTE_TARGET_MAC
:
1323 memcpy(&rtt_target
->addr
, nla_data(iter2
),
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"
1338 case RTT_ATTRIBUTE_TARGET_PEER
:
1339 rtt_target
->peer
= nla_get_u8(iter2
);
1341 case RTT_ATTRIBUTE_TARGET_CHAN
:
1342 memcpy(&rtt_target
->channel
, nla_data(iter2
),
1343 sizeof(rtt_target
->channel
));
1345 case RTT_ATTRIBUTE_TARGET_PERIOD
:
1346 rtt_target
->burst_period
= nla_get_u32(iter2
);
1347 if (rtt_target
->burst_period
< 32) {
1349 rtt_target
->burst_period
*= 100;
1351 WL_ERR(("%d value must in (0-31)\n",
1352 rtt_target
->burst_period
));
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
));
1365 rtt_target
->num_burst
= BIT(rtt_target
->num_burst
);
1367 case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST
:
1368 rtt_target
->num_frames_per_burst
=
1371 case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM
:
1372 rtt_target
->num_retries_per_ftm
=
1375 case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR
:
1376 rtt_target
->num_retries_per_ftmr
=
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
));
1385 case RTT_ATTRIBUTE_TARGET_LCI
:
1386 rtt_target
->LCI_request
= nla_get_u8(iter2
);
1388 case RTT_ATTRIBUTE_TARGET_LCR
:
1389 rtt_target
->LCI_request
= nla_get_u8(iter2
);
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;
1401 WL_ERR(("%d value must in (2-11) or 15\n",
1402 nla_get_u32(iter2
)));
1407 case RTT_ATTRIBUTE_TARGET_BW
:
1408 rtt_target
->bw
= nla_get_u8(iter2
);
1410 case RTT_ATTRIBUTE_TARGET_PREAMBLE
:
1411 rtt_target
->preamble
= nla_get_u8(iter2
);
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"));
1423 WL_INFORM(("Target addr %s, Channel : %s for RTT \n",
1424 bcm_ether_ntoa((const struct ether_addr
*)&rtt_target
->addr
,
1426 wf_chspec_ntoa(rtt_target
->chanspec
, chanbuf
)));
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"));
1438 /* free the target info list */
1439 if (rtt_param
.target_info
) {
1440 kfree(rtt_param
.target_info
);
1441 rtt_param
.target_info
= NULL
;
1447 wl_cfgvendor_rtt_cancel_config(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
1448 const void *data
, int len
)
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
);
1457 WL_ERR(("Length of nlattr is not valid len : %d\n", len
));
1461 nla_for_each_attr(iter
, data
, len
, rem
) {
1462 type
= nla_type(iter
);
1464 case RTT_ATTRIBUTE_TARGET_CNT
:
1465 if (mac_list
!= NULL
) {
1466 WL_ERR(("mac_list is not NULL\n"));
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
,
1474 if (mac_list
== NULL
) {
1475 WL_ERR(("failed to allocate mem for mac list\n"));
1479 mac_addr
= &mac_list
[0];
1481 /* cancel the current whole RTT process */
1485 case RTT_ATTRIBUTE_TARGET_MAC
:
1487 memcpy(mac_addr
++, nla_data(iter
), ETHER_ADDR_LEN
);
1489 if (target_cnt_chk
> target_cnt
) {
1490 WL_ERR(("over target count\n"));
1496 WL_ERR(("mac_list is NULL\n"));
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"));
1516 wl_cfgvendor_rtt_get_capability(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
1517 const void *data
, int len
)
1520 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
1521 rtt_capabilities_t capability
;
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
));
1528 err
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
1529 &capability
, sizeof(capability
));
1531 if (unlikely(err
)) {
1532 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
1538 get_responder_info(struct bcm_cfg80211
*cfg
,
1539 struct wifi_rtt_responder
*responder_info
)
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
));
1548 if (capability
.preamble_support
& RTT_PREAMBLE_VHT
) {
1549 responder_info
->preamble
|= RTT_PREAMBLE_VHT
;
1551 if (capability
.preamble_support
& RTT_PREAMBLE_HT
) {
1552 responder_info
->preamble
|= RTT_PREAMBLE_HT
;
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
));
1562 wl_cfgvendor_rtt_get_responder_info(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
1563 const void *data
, int len
)
1566 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
1567 wifi_rtt_responder_t responder_info
;
1569 WL_DBG(("Recv -get_avail_ch command \n"));
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
));
1577 err
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
1578 &responder_info
, sizeof(responder_info
));
1580 if (unlikely(err
)) {
1581 WL_ERR(("Vendor cmd reply for -get_avail_ch failed ret:%d \n", err
));
1587 wl_cfgvendor_rtt_set_responder(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
1588 const void *data
, int len
)
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
;
1595 WL_DBG(("Recv rtt -enable_resp cmd.\n"));
1597 memset(&responder_info
, 0, sizeof(responder_info
));
1600 *Passing channel as NULL until implementation
1601 *to get chan info from upper layers is donex
1603 err
= dhd_dev_rtt_enable_responder(ndev
, NULL
);
1604 if (unlikely(err
)) {
1605 WL_ERR(("Could not enable responder ret:%d \n", err
));
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
);
1615 err
= wl_cfgvendor_send_cmd_reply(wiphy
, ndev
,
1616 &responder_info
, sizeof(responder_info
));
1618 if (unlikely(err
)) {
1619 WL_ERR(("Vendor cmd reply for -enable_resp failed ret:%d \n", err
));
1625 wl_cfgvendor_rtt_cancel_responder(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
1626 const void *data
, int len
)
1629 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
1631 WL_DBG(("Recv rtt -cancel_resp cmd \n"));
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
));
1639 #endif /* RTT_SUPPORT */
1641 #ifdef GSCAN_SUPPORT
1642 static int wl_cfgvendor_enable_lazy_roam(struct wiphy
*wiphy
,
1643 struct wireless_dev
*wdev
, const void *data
, int len
)
1646 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
1648 uint32 lazy_roam_enable_flag
;
1650 type
= nla_type(data
);
1652 if (type
== GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE
) {
1653 lazy_roam_enable_flag
= nla_get_u32(data
);
1655 err
= dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg
),
1656 lazy_roam_enable_flag
);
1659 WL_ERR(("Could not enable lazy roam:%d \n", err
));
1665 static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy
*wiphy
,
1666 struct wireless_dev
*wdev
, const void *data
, int len
)
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
;
1673 memset(&roam_param
, 0, sizeof(roam_param
));
1675 nla_for_each_attr(iter
, data
, len
, tmp
) {
1676 type
= nla_type(iter
);
1679 case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD
:
1680 roam_param
.a_band_boost_threshold
= nla_get_u32(iter
);
1682 case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD
:
1683 roam_param
.a_band_penalty_threshold
= nla_get_u32(iter
);
1685 case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR
:
1686 roam_param
.a_band_boost_factor
= nla_get_u32(iter
);
1688 case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR
:
1689 roam_param
.a_band_penalty_factor
= nla_get_u32(iter
);
1691 case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST
:
1692 roam_param
.a_band_max_boost
= nla_get_u32(iter
);
1694 case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS
:
1695 roam_param
.cur_bssid_boost
= nla_get_u32(iter
);
1697 case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER
:
1698 roam_param
.alert_roam_trigger_threshold
= nla_get_u32(iter
);
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"));
1710 /* small helper function */
1711 static wl_bssid_pref_cfg_t
*
1712 create_bssid_pref_cfg(uint32 num
)
1715 wl_bssid_pref_cfg_t
*bssid_pref
;
1717 mem_needed
= sizeof(wl_bssid_pref_cfg_t
);
1719 mem_needed
+= (num
- 1) * sizeof(wl_bssid_pref_list_t
);
1720 bssid_pref
= (wl_bssid_pref_cfg_t
*) kmalloc(mem_needed
, GFP_KERNEL
);
1725 wl_cfgvendor_set_bssid_pref(struct wiphy
*wiphy
,
1726 struct wireless_dev
*wdev
, const void *data
, int len
)
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;
1736 /* Assumption: NUM attribute must come first */
1737 nla_for_each_attr(iter
, data
, len
, tmp2
) {
1738 type
= nla_type(iter
);
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"));
1748 case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH
:
1749 flush
= nla_get_u32(iter
);
1751 case GSCAN_ATTRIBUTE_BSSID_PREF_LIST
:
1754 if ((bssid_pref
= create_bssid_pref_cfg(num
)) == NULL
) {
1755 WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__
));
1759 bssid_pref
->count
= num
;
1760 bssids
= bssid_pref
->bssids
;
1761 nla_for_each_nested(outer
, iter
, tmp
) {
1763 WL_ERR(("CFGs don't seem right!\n"));
1767 nla_for_each_nested(inner
, outer
, tmp1
) {
1768 type
= nla_type(inner
);
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;
1776 case GSCAN_ATTRIBUTE_RSSI_MODIFIER
:
1777 bssids
[i
].rssi_factor
=
1778 (int8
) nla_get_u32(inner
);
1786 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__
, type
));
1792 /* What if only flush is desired? */
1794 if ((bssid_pref
= create_bssid_pref_cfg(0)) == NULL
) {
1795 WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__
));
1799 bssid_pref
->count
= 0;
1805 err
= dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg
),
1813 wl_cfgvendor_set_bssid_blacklist(struct wiphy
*wiphy
,
1814 struct wireless_dev
*wdev
, const void *data
, int len
)
1816 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
1817 maclist_t
*blacklist
= NULL
;
1820 const struct nlattr
*iter
;
1821 uint32 mem_needed
= 0, flush
= 0, i
= 0, num
= 0;
1823 /* Assumption: NUM attribute must come first */
1824 nla_for_each_attr(iter
, data
, len
, tmp
) {
1825 type
= nla_type(iter
);
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"));
1835 case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH
:
1836 flush
= nla_get_u32(iter
);
1838 case GSCAN_ATTRIBUTE_BLACKLIST_BSSID
:
1841 mem_needed
= sizeof(maclist_t
) +
1842 sizeof(struct ether_addr
) * (num
- 1);
1843 blacklist
= (maclist_t
*)
1844 kmalloc(mem_needed
, GFP_KERNEL
);
1846 WL_ERR(("%s: Can't malloc %d bytes\n",
1847 __FUNCTION__
, mem_needed
));
1851 blacklist
->count
= num
;
1854 WL_ERR(("CFGs don't seem right!\n"));
1858 memcpy(&(blacklist
->ea
[i
]),
1859 nla_data(iter
), ETHER_ADDR_LEN
);
1864 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__
, type
));
1868 err
= dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg
),
1869 blacklist
, mem_needed
, flush
);
1876 wl_cfgvendor_set_ssid_whitelist(struct wiphy
*wiphy
,
1877 struct wireless_dev
*wdev
, const void *data
, int len
)
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;
1887 /* Assumption: NUM attribute must come first */
1888 nla_for_each_attr(iter
, data
, len
, tmp2
) {
1889 type
= nla_type(iter
);
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"));
1898 mem_needed
= sizeof(wl_ssid_whitelist_t
);
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
));
1909 ssid_whitelist
->ssid_count
= num
;
1911 case GSCAN_ATTRIBUTE_WL_SSID_FLUSH
:
1912 flush
= nla_get_u32(iter
);
1914 case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM
:
1915 if (!num
|| !ssid_whitelist
) {
1916 WL_ERR(("num ssid is not set!\n"));
1920 WL_ERR(("CFGs don't seem right!\n"));
1924 ssid_elem
= &ssid_whitelist
->ssids
[i
];
1925 nla_for_each_nested(inner
, iter
, tmp
) {
1926 type
= nla_type(inner
);
1928 case GSCAN_ATTRIBUTE_WHITELIST_SSID
:
1929 memcpy(ssid_elem
->SSID
,
1931 DOT11_MAX_SSID_LEN
);
1933 case GSCAN_ATTRIBUTE_WL_SSID_LEN
:
1934 ssid_elem
->SSID_len
= (uint8
)
1942 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__
, type
));
1947 err
= dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg
),
1948 ssid_whitelist
, mem_needed
, flush
);
1950 kfree(ssid_whitelist
);
1953 #endif /* GSCAN_SUPPORT */
1956 wl_cfgvendor_priv_string_handler(struct wiphy
*wiphy
,
1957 struct wireless_dev
*wdev
, const void *data
, int len
)
1959 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
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
;
1967 WL_ERR(("entry: cmd = %d\n", nlioc
->cmd
));
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
;
1976 if (ret_len
> DHD_IOCTL_MAXLEN
) {
1977 WL_ERR(("oversize return buffer %d\n", ret_len
));
1978 ret_len
= DHD_IOCTL_MAXLEN
;
1980 payload
= max(ret_len
, len
) + 1;
1981 buf
= vzalloc(payload
);
1985 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1986 #pragma GCC diagnostic push
1987 #pragma GCC diagnostic ignored "-Wcast-qual"
1989 memcpy(buf
, (void *)((char *)nlioc
+ nlioc
->offset
), len
);
1990 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1991 #pragma GCC diagnostic pop
1993 *((char *)buf
+ len
) = '\0';
1996 ret
= dhd_cfgvendor_priv_string_handler(cfg
, wdev
, nlioc
, buf
);
1998 WL_ERR(("dhd_cfgvendor returned error %d", ret
));
2003 while (ret_len
> 0) {
2004 msglen
= nlioc
->len
> maxmsglen
? maxmsglen
: ret_len
;
2006 payload
= msglen
+ sizeof(msglen
);
2007 reply
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, payload
);
2009 WL_ERR(("Failed to allocate reply msg\n"));
2014 if (nla_put(reply
, BCM_NLATTR_DATA
, msglen
, cur
) ||
2015 nla_put_u16(reply
, BCM_NLATTR_LEN
, msglen
)) {
2021 ret
= cfg80211_vendor_cmd_reply(reply
);
2023 WL_ERR(("testmode reply failed:%d\n", ret
));
2026 cur
= (void *)((char *)cur
+ msglen
);
2033 wl_cfgvendor_get_ndev(struct bcm_cfg80211
*cfg
, struct wireless_dev
*wdev
,
2034 const void *data
, unsigned long int *out_addr
)
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 */
2042 /* check whether ifname=<ifname> is provided in the command */
2043 pos
= strstr(data
, "ifname=");
2045 pos
+= strlen("ifname=");
2046 pos1
= strstr(pos
, " ");
2048 WL_ERR(("command format error \n"));
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"
2056 for_each_ndev(cfg
, iter
, next
) {
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> */
2069 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2070 #pragma GCC diagnostic pop
2072 WL_ERR(("Couldn't find ifname:%s in the netinfo list \n",
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
));
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
2087 #define WL_DRIVER_PRIV_CMD_LEN 512
2089 wl_cfgvendor_priv_bcm_handler(struct wiphy
*wiphy
,
2090 struct wireless_dev
*wdev
, const void *data
, int len
)
2092 const struct nlattr
*iter
;
2094 int data_len
= 0, cmd_len
= 0, tmp
= 0, type
= 0;
2095 struct net_device
*ndev
= wdev
->netdev
;
2096 char *reply_buf
= NULL
;
2098 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2100 struct net_device
*net
= NULL
;
2101 unsigned long int cmd_out
= 0;
2102 u32 reply_len
= WL_DRIVER_PRIV_CMD_LEN
;
2105 WL_DBG(("%s: Enter \n", __func__
));
2107 /* hold wake lock */
2108 net_os_wake_lock(ndev
);
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
);
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"));
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"));
2128 net
= wl_cfgvendor_get_ndev(cfg
, wdev
, cmd
, &cmd_out
);
2129 if (!cmd_out
|| !net
) {
2133 cmd
= (char *)cmd_out
;
2134 reply_buf
= kzalloc(reply_len
, GFP_KERNEL
);
2136 WL_ERR(("memory alloc failed for %u \n", cmd_len
));
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
;
2151 /* -ve return value. Propagate the error back */
2152 err
= bytes_written
;
2159 if ((data_len
> 0) && reply_buf
) {
2160 err
= wl_cfgvendor_send_cmd_reply(wiphy
, wdev
->netdev
,
2161 reply_buf
, data_len
+1);
2163 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
2165 WL_DBG(("Vendor Command reply sent successfully!\n"));
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
));
2175 net_os_wake_unlock(ndev
);
2180 #ifdef LINKSTAT_SUPPORT
2184 #define HEADER_SIZE sizeof(ver_len)
2185 static int wl_cfgvendor_lstats_get_info(struct wiphy
*wiphy
,
2186 struct wireless_dev
*wdev
, const void *data
, int len
)
2188 static char iovar_buf
[WLC_IOCTL_MAXLEN
];
2189 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
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
;
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
;
2202 wifi_iface_stat iface
;
2203 wlc_rev_info_t revinfo
;
2204 #ifdef CONFIG_COMPAT
2205 compat_wifi_iface_stat compat_iface
;
2206 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2207 int compat_task_state
= in_compat_syscall();
2209 int compat_task_state
= is_compat_task();
2211 #endif /* CONFIG_COMPAT */
2213 WL_INFORM(("%s: Enter \n", __func__
));
2214 RETURN_EIO_IF_NOT_UP(cfg
);
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
,
2220 if (err
!= BCME_OK
) {
2224 outdata
= (void *)kzalloc(WLC_IOCTL_MAXLEN
, GFP_KERNEL
);
2225 if (outdata
== NULL
) {
2226 WL_ERR(("%s: alloc failed\n", __func__
));
2230 memset(&scbval
, 0, sizeof(scb_val_t
));
2231 memset(outdata
, 0, WLC_IOCTL_MAXLEN
);
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
)));
2240 radio
= (wifi_radio_stat
*)iovar_buf
;
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
;
2254 memcpy(output
, &radio_h
, sizeof(wifi_radio_stat_h
));
2256 output
+= sizeof(wifi_radio_stat_h
);
2257 output
+= (NUM_CHAN
* sizeof(wifi_channel_stat
));
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
));
2265 wl_wme_cnt
= (wl_wme_cnt_t
*)iovar_buf
;
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
);
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
);
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
);
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
);
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
)));
2299 CHK_CNTBUF_DATALEN(iovar_buf
, WLC_IOCTL_MAXLEN
);
2302 wl_stat_report_gather(cfg
, iovar_buf
);
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
));
2313 if (!(wlc_cnt
= GET_WLCCNT_FROM_CNTBUF(iovar_buf
))) {
2314 WL_ERR(("%s wlc_cnt NULL!\n", __FUNCTION__
));
2319 COMPAT_ASSIGN_VALUE(iface
, ac
[WIFI_AC_BE
].retries
, wlc_cnt
->txretry
);
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
) {
2325 if ((macstat_cnt
= bcm_get_data_from_xtlv_buf(((wl_cnt_info_t
*)iovar_buf
)->data
,
2326 ((wl_cnt_info_t
*)iovar_buf
)->datalen
,
2327 WL_CNT_XTLV_GE40_UCODE_V1
, NULL
,
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
,
2332 BCM_XTLV_OPTION_ALIGN32
);
2336 if (macstat_cnt
== NULL
) {
2337 printf("wlmTxGetAckedPackets: macstat_cnt NULL!\n");
2342 err
= wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg
), &scbval
);
2343 if (unlikely(err
)) {
2344 WL_ERR(("get_rssi error (%d)\n", err
));
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
);
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
));
2358 #endif /* CONFIG_COMPAT */
2360 memcpy(output
, &iface
, sizeof(iface
));
2361 output
+= (sizeof(iface
) - sizeof(wifi_rate_stat
));
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
)));
2370 for (i
= 0; i
< NUM_RATE
; i
++) {
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
);
2390 total_len
= sizeof(wifi_radio_stat_h
) +
2391 NUM_CHAN
* sizeof(wifi_channel_stat
);
2393 #ifdef CONFIG_COMPAT
2394 if (compat_task_state
) {
2395 total_len
+= sizeof(compat_wifi_iface_stat
);
2397 #endif /* CONFIG_COMPAT */
2399 total_len
+= sizeof(wifi_iface_stat
);
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
));
2406 if (total_len
> WLC_IOCTL_MAXLEN
) {
2407 WL_ERR(("Error! total_len:%d is unexpected value\n", total_len
));
2411 err
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
2416 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
2424 #endif /* LINKSTAT_SUPPORT */
2427 static int wl_cfgvendor_dbg_start_logging(struct wiphy
*wiphy
,
2428 struct wireless_dev
*wdev
, const void *data
, int len
)
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
);
2439 case DEBUG_ATTRIBUTE_RING_NAME
:
2440 strncpy(ring_name
, nla_data(iter
),
2441 MIN(sizeof(ring_name
) -1, nla_len(iter
)));
2443 case DEBUG_ATTRIBUTE_LOG_LEVEL
:
2444 log_level
= nla_get_u32(iter
);
2446 case DEBUG_ATTRIBUTE_RING_FLAGS
:
2447 flags
= nla_get_u32(iter
);
2449 case DEBUG_ATTRIBUTE_LOG_TIME_INTVAL
:
2450 time_intval
= nla_get_u32(iter
);
2452 case DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE
:
2453 threshold
= nla_get_u32(iter
);
2456 WL_ERR(("Unknown type: %d\n", type
));
2462 ret
= dhd_os_start_logging(dhd_pub
, ring_name
, log_level
, flags
, time_intval
, threshold
);
2464 WL_ERR(("start_logging is failed ret: %d\n", ret
));
2470 static int wl_cfgvendor_dbg_reset_logging(struct wiphy
*wiphy
,
2471 struct wireless_dev
*wdev
, const void *data
, int len
)
2474 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2475 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2477 ret
= dhd_os_reset_logging(dhd_pub
);
2479 WL_ERR(("reset logging is failed ret: %d\n", ret
));
2486 wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy
*wiphy
,
2487 struct wireless_dev
*wdev
, const void *data
, int len
)
2491 struct sk_buff
*skb
;
2492 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2493 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
2495 dhdp
->memdump_type
= DUMP_TYPE_CFG_VENDOR_TRIGGERED
;
2497 ret
= dhd_os_socram_dump(bcmcfg_to_prmry_ndev(cfg
), &alloc_len
);
2499 WL_ERR(("failed to call dhd_os_socram_dump : %d\n", ret
));
2502 /* Alloc the SKB for vendor_event */
2503 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, 100);
2505 WL_ERR(("skb allocation is failed\n"));
2509 nla_put_u32(skb
, DEBUG_ATTRIBUTE_FW_DUMP_LEN
, alloc_len
);
2511 ret
= cfg80211_vendor_cmd_reply(skb
);
2514 WL_ERR(("Vendor Command reply failed ret:%d \n", ret
));
2522 wl_cfgvendor_dbg_get_mem_dump(struct wiphy
*wiphy
,
2523 struct wireless_dev
*wdev
, const void *data
, int len
)
2525 int ret
= BCME_OK
, rem
, type
;
2527 uintptr_t user_buf
= (uintptr_t)NULL
;
2528 const struct nlattr
*iter
;
2529 char *mem_buf
= NULL
;
2530 struct sk_buff
*skb
;
2531 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2533 nla_for_each_attr(iter
, data
, len
, rem
) {
2534 type
= nla_type(iter
);
2536 case DEBUG_ATTRIBUTE_FW_DUMP_LEN
:
2537 /* Check if the iter is valid and
2538 * buffer length is not already initialized.
2540 if ((nla_len(iter
) == sizeof(uint32
)) &&
2542 buf_len
= nla_get_u32(iter
);
2548 case DEBUG_ATTRIBUTE_FW_DUMP_DATA
:
2549 if (nla_len(iter
) != sizeof(uint64
)) {
2550 WL_ERR(("Invalid len\n"));
2554 user_buf
= (uintptr_t)nla_get_u64(iter
);
2557 WL_ERR(("Unknown type: %d\n", type
));
2562 if (buf_len
> 0 && user_buf
) {
2563 mem_buf
= vmalloc(buf_len
);
2565 WL_ERR(("failed to allocate mem_buf with size : %d\n", buf_len
));
2569 ret
= dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg
), &mem_buf
, &buf_len
);
2571 WL_ERR(("failed to get_socram_dump : %d\n", ret
));
2574 #ifdef CONFIG_COMPAT
2575 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2576 if (in_compat_syscall())
2578 if (is_compat_task())
2581 void * usr_ptr
= compat_ptr((uintptr_t) user_buf
);
2582 ret
= copy_to_user(usr_ptr
, mem_buf
, buf_len
);
2584 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret
));
2589 #endif /* CONFIG_COMPAT */
2591 ret
= copy_to_user((void*)user_buf
, mem_buf
, buf_len
);
2593 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret
));
2597 /* Alloc the SKB for vendor_event */
2598 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, 100);
2600 WL_ERR(("skb allocation is failed\n"));
2604 /* Indicate the memdump is succesfully copied */
2605 nla_put(skb
, DEBUG_ATTRIBUTE_FW_DUMP_DATA
, sizeof(ret
), &ret
);
2607 ret
= cfg80211_vendor_cmd_reply(skb
);
2610 WL_ERR(("Vendor Command reply failed ret:%d \n", ret
));
2620 static int wl_cfgvendor_dbg_get_version(struct wiphy
*wiphy
,
2621 struct wireless_dev
*wdev
, const void *data
, int len
)
2623 int ret
= BCME_OK
, rem
, type
;
2625 bool dhd_ver
= FALSE
;
2627 const struct nlattr
*iter
;
2629 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2630 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
2631 buf_ptr
= kzalloc(buf_len
, kflags
);
2633 WL_ERR(("failed to allocate the buffer for version n"));
2637 nla_for_each_attr(iter
, data
, len
, rem
) {
2638 type
= nla_type(iter
);
2640 case DEBUG_ATTRIBUTE_GET_DRIVER
:
2643 case DEBUG_ATTRIBUTE_GET_FW
:
2647 WL_ERR(("Unknown type: %d\n", type
));
2652 ret
= dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg
), dhd_ver
, &buf_ptr
, buf_len
);
2654 WL_ERR(("failed to get the version %d\n", ret
));
2657 ret
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
2658 buf_ptr
, strlen(buf_ptr
));
2664 static int wl_cfgvendor_dbg_get_ring_status(struct wiphy
*wiphy
,
2665 struct wireless_dev
*wdev
, const void *data
, int len
)
2670 struct sk_buff
*skb
;
2671 dhd_dbg_ring_status_t dbg_ring_status
[DEBUG_RING_ID_MAX
];
2672 dhd_dbg_ring_status_t ring_status
;
2673 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2674 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2675 memset(dbg_ring_status
, 0, DBG_RING_STATUS_SIZE
* DEBUG_RING_ID_MAX
);
2677 for (ring_id
= DEBUG_RING_ID_INVALID
+ 1; ring_id
< DEBUG_RING_ID_MAX
; ring_id
++) {
2678 ret
= dhd_os_get_ring_status(dhd_pub
, ring_id
, &ring_status
);
2679 if (ret
== BCME_NOTFOUND
) {
2680 WL_DBG(("The ring (%d) is not found \n", ring_id
));
2681 } else if (ret
== BCME_OK
) {
2682 dbg_ring_status
[ring_cnt
++] = ring_status
;
2685 /* Alloc the SKB for vendor_event */
2686 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
,
2687 (DBG_RING_STATUS_SIZE
* ring_cnt
) + 100);
2689 WL_ERR(("skb allocation is failed\n"));
2694 nla_put_u32(skb
, DEBUG_ATTRIBUTE_RING_NUM
, ring_cnt
);
2695 for (i
= 0; i
< ring_cnt
; i
++) {
2696 nla_put(skb
, DEBUG_ATTRIBUTE_RING_STATUS
, DBG_RING_STATUS_SIZE
,
2697 &dbg_ring_status
[i
]);
2699 ret
= cfg80211_vendor_cmd_reply(skb
);
2702 WL_ERR(("Vendor Command reply failed ret:%d \n", ret
));
2708 static int wl_cfgvendor_dbg_get_ring_data(struct wiphy
*wiphy
,
2709 struct wireless_dev
*wdev
, const void *data
, int len
)
2711 int ret
= BCME_OK
, rem
, type
;
2712 char ring_name
[DBGRING_NAME_MAX
] = {0};
2713 const struct nlattr
*iter
;
2714 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2715 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2717 nla_for_each_attr(iter
, data
, len
, rem
) {
2718 type
= nla_type(iter
);
2720 case DEBUG_ATTRIBUTE_RING_NAME
:
2721 strncpy(ring_name
, nla_data(iter
),
2722 MIN(sizeof(ring_name
) -1, nla_len(iter
)));
2725 WL_ERR(("Unknown type: %d\n", type
));
2730 ret
= dhd_os_trigger_get_ring_data(dhd_pub
, ring_name
);
2732 WL_ERR(("trigger_get_data failed ret:%d\n", ret
));
2738 static int wl_cfgvendor_dbg_get_feature(struct wiphy
*wiphy
,
2739 struct wireless_dev
*wdev
, const void *data
, int len
)
2742 u32 supported_features
= 0;
2743 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2744 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2746 ret
= dhd_os_dbg_get_feature(dhd_pub
, &supported_features
);
2748 WL_ERR(("dbg_get_feature failed ret:%d\n", ret
));
2751 ret
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
2752 &supported_features
, sizeof(supported_features
));
2754 WL_ERR(("wl_cfgvendor_send_cmd_reply failed ret:%d\n", ret
));
2761 static void wl_cfgvendor_dbg_ring_send_evt(void *ctx
,
2762 const int ring_id
, const void *data
, const uint32 len
,
2763 const dhd_dbg_ring_status_t ring_status
)
2765 struct net_device
*ndev
= ctx
;
2766 struct wiphy
*wiphy
;
2768 struct sk_buff
*skb
;
2770 WL_ERR(("ndev is NULL\n"));
2773 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
2774 wiphy
= ndev
->ieee80211_ptr
->wiphy
;
2775 /* Alloc the SKB for vendor_event */
2776 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2777 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2778 skb
= cfg80211_vendor_event_alloc(wiphy
, NULL
, len
+ 100,
2779 GOOGLE_DEBUG_RING_EVENT
, kflags
);
2781 skb
= cfg80211_vendor_event_alloc(wiphy
, len
+ 100,
2782 GOOGLE_DEBUG_RING_EVENT
, kflags
);
2783 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2784 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2786 WL_ERR(("skb alloc failed"));
2789 nla_put(skb
, DEBUG_ATTRIBUTE_RING_STATUS
, sizeof(ring_status
), &ring_status
);
2790 nla_put(skb
, DEBUG_ATTRIBUTE_RING_DATA
, len
, data
);
2791 cfg80211_vendor_event(skb
, kflags
);
2794 static void wl_cfgvendor_dbg_send_urgent_evt(void *ctx
, const void *data
,
2795 const uint32 len
, const uint32 fw_len
)
2797 struct net_device
*ndev
= ctx
;
2798 struct wiphy
*wiphy
;
2800 struct sk_buff
*skb
;
2802 WL_ERR(("ndev is NULL\n"));
2805 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
2806 wiphy
= ndev
->ieee80211_ptr
->wiphy
;
2807 /* Alloc the SKB for vendor_event */
2808 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2809 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2810 skb
= cfg80211_vendor_event_alloc(wiphy
, NULL
, len
+ 100,
2811 GOOGLE_FW_DUMP_EVENT
, kflags
);
2813 skb
= cfg80211_vendor_event_alloc(wiphy
, len
+ 100,
2814 GOOGLE_FW_DUMP_EVENT
, kflags
);
2815 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2816 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2818 WL_ERR(("skb alloc failed"));
2821 nla_put_u32(skb
, DEBUG_ATTRIBUTE_FW_DUMP_LEN
, fw_len
);
2822 nla_put(skb
, DEBUG_ATTRIBUTE_RING_DATA
, len
, data
);
2823 cfg80211_vendor_event(skb
, kflags
);
2825 #endif /* DEBUGABILITY */
2828 static int wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy
*wiphy
,
2829 struct wireless_dev
*wdev
, const void *data
, int len
)
2831 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2832 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2835 ret
= dhd_os_dbg_attach_pkt_monitor(dhd_pub
);
2836 if (unlikely(ret
)) {
2837 WL_ERR(("failed to start pkt fate monitoring, ret=%d", ret
));
2843 typedef int (*dbg_mon_get_pkts_t
) (dhd_pub_t
*dhdp
, void __user
*user_buf
,
2844 uint16 req_count
, uint16
*resp_count
);
2846 static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy
*wiphy
,
2847 const void *data
, int len
, dbg_mon_get_pkts_t dbg_mon_get_pkts
)
2849 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2850 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2851 struct sk_buff
*skb
= NULL
;
2852 const struct nlattr
*iter
;
2853 void __user
*user_buf
= NULL
;
2854 uint16 req_count
= 0, resp_count
= 0;
2855 int ret
, tmp
, type
, mem_needed
;
2857 nla_for_each_attr(iter
, data
, len
, tmp
) {
2858 type
= nla_type(iter
);
2860 case DEBUG_ATTRIBUTE_PKT_FATE_NUM
:
2861 req_count
= nla_get_u32(iter
);
2863 case DEBUG_ATTRIBUTE_PKT_FATE_DATA
:
2864 user_buf
= (void __user
*)(unsigned long) nla_get_u64(iter
);
2867 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__
, type
));
2873 if (!req_count
|| !user_buf
) {
2874 WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n",
2875 __FUNCTION__
, user_buf
, req_count
));
2880 ret
= dbg_mon_get_pkts(dhd_pub
, user_buf
, req_count
, &resp_count
);
2881 if (unlikely(ret
)) {
2882 WL_ERR(("failed to get packets, ret:%d \n", ret
));
2886 mem_needed
= VENDOR_REPLY_OVERHEAD
+ ATTRIBUTE_U32_LEN
;
2887 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, mem_needed
);
2888 if (unlikely(!skb
)) {
2889 WL_ERR(("skb alloc failed"));
2894 nla_put_u32(skb
, DEBUG_ATTRIBUTE_PKT_FATE_NUM
, resp_count
);
2896 ret
= cfg80211_vendor_cmd_reply(skb
);
2897 if (unlikely(ret
)) {
2898 WL_ERR(("vendor Command reply failed ret:%d \n", ret
));
2905 static int wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy
*wiphy
,
2906 struct wireless_dev
*wdev
, const void *data
, int len
)
2910 ret
= __wl_cfgvendor_dbg_get_pkt_fates(wiphy
, data
, len
,
2911 dhd_os_dbg_monitor_get_tx_pkts
);
2912 if (unlikely(ret
)) {
2913 WL_ERR(("failed to get tx packets, ret:%d \n", ret
));
2919 static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy
*wiphy
,
2920 struct wireless_dev
*wdev
, const void *data
, int len
)
2924 ret
= __wl_cfgvendor_dbg_get_pkt_fates(wiphy
, data
, len
,
2925 dhd_os_dbg_monitor_get_rx_pkts
);
2926 if (unlikely(ret
)) {
2927 WL_ERR(("failed to get rx packets, ret:%d \n", ret
));
2932 #endif /* DBG_PKT_MON */
2935 static int wl_cfgvendor_start_mkeep_alive(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
2936 const void *data
, int len
)
2938 /* max size of IP packet for keep alive */
2939 const int MKEEP_ALIVE_IP_PKT_MAX
= 256;
2941 int ret
= BCME_OK
, rem
, type
;
2942 uint8 mkeep_alive_id
= 0;
2943 uint8
*ip_pkt
= NULL
;
2944 uint16 ip_pkt_len
= 0;
2945 uint8 src_mac
[ETHER_ADDR_LEN
];
2946 uint8 dst_mac
[ETHER_ADDR_LEN
];
2947 uint32 period_msec
= 0;
2948 const struct nlattr
*iter
;
2949 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2950 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2951 gfp_t kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
2953 nla_for_each_attr(iter
, data
, len
, rem
) {
2954 type
= nla_type(iter
);
2956 case MKEEP_ALIVE_ATTRIBUTE_ID
:
2957 mkeep_alive_id
= nla_get_u8(iter
);
2959 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN
:
2960 ip_pkt_len
= nla_get_u16(iter
);
2961 if (ip_pkt_len
> MKEEP_ALIVE_IP_PKT_MAX
) {
2966 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT
:
2969 WL_ERR(("ip packet length is 0\n"));
2972 ip_pkt
= (u8
*)kzalloc(ip_pkt_len
, kflags
);
2973 if (ip_pkt
== NULL
) {
2975 WL_ERR(("Failed to allocate mem for ip packet\n"));
2978 memcpy(ip_pkt
, (u8
*)nla_data(iter
), ip_pkt_len
);
2980 case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR
:
2981 memcpy(src_mac
, nla_data(iter
), ETHER_ADDR_LEN
);
2983 case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR
:
2984 memcpy(dst_mac
, nla_data(iter
), ETHER_ADDR_LEN
);
2986 case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
:
2987 period_msec
= nla_get_u32(iter
);
2990 WL_ERR(("Unknown type: %d\n", type
));
2996 if (ip_pkt
== NULL
) {
2998 WL_ERR(("ip packet is NULL\n"));
3002 ret
= dhd_dev_start_mkeep_alive(dhd_pub
, mkeep_alive_id
, ip_pkt
, ip_pkt_len
, src_mac
,
3003 dst_mac
, period_msec
);
3005 WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret
));
3016 static int wl_cfgvendor_stop_mkeep_alive(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
3017 const void *data
, int len
)
3019 int ret
= BCME_OK
, rem
, type
;
3020 uint8 mkeep_alive_id
= 0;
3021 const struct nlattr
*iter
;
3022 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3023 dhd_pub_t
*dhd_pub
= cfg
->pub
;
3025 nla_for_each_attr(iter
, data
, len
, rem
) {
3026 type
= nla_type(iter
);
3028 case MKEEP_ALIVE_ATTRIBUTE_ID
:
3029 mkeep_alive_id
= nla_get_u8(iter
);
3032 WL_ERR(("Unknown type: %d\n", type
));
3038 ret
= dhd_dev_stop_mkeep_alive(dhd_pub
, mkeep_alive_id
);
3040 WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret
));
3045 #endif /* KEEP_ALIVE */
3047 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
3049 wl_cfgvendor_apf_get_capabilities(struct wiphy
*wiphy
,
3050 struct wireless_dev
*wdev
, const void *data
, int len
)
3052 struct net_device
*ndev
= wdev_to_ndev(wdev
);
3053 struct sk_buff
*skb
;
3054 int ret
, ver
, max_len
, mem_needed
;
3058 ret
= dhd_dev_apf_get_version(ndev
, &ver
);
3059 if (unlikely(ret
)) {
3060 WL_ERR(("APF get version failed, ret=%d\n", ret
));
3064 /* APF memory size limit */
3066 ret
= dhd_dev_apf_get_max_len(ndev
, &max_len
);
3067 if (unlikely(ret
)) {
3068 WL_ERR(("APF get maximum length failed, ret=%d\n", ret
));
3072 mem_needed
= VENDOR_REPLY_OVERHEAD
+ (ATTRIBUTE_U32_LEN
* 2);
3074 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, mem_needed
);
3075 if (unlikely(!skb
)) {
3076 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__
, mem_needed
));
3080 nla_put_u32(skb
, APF_ATTRIBUTE_VERSION
, ver
);
3081 nla_put_u32(skb
, APF_ATTRIBUTE_MAX_LEN
, max_len
);
3083 ret
= cfg80211_vendor_cmd_reply(skb
);
3084 if (unlikely(ret
)) {
3085 WL_ERR(("vendor command reply failed, ret=%d\n", ret
));
3092 wl_cfgvendor_apf_set_filter(struct wiphy
*wiphy
,
3093 struct wireless_dev
*wdev
, const void *data
, int len
)
3095 struct net_device
*ndev
= wdev_to_ndev(wdev
);
3096 const struct nlattr
*iter
;
3098 u32 program_len
= 0;
3103 WL_ERR(("Invalid len: %d\n", len
));
3107 nla_for_each_attr(iter
, data
, len
, tmp
) {
3108 type
= nla_type(iter
);
3110 case APF_ATTRIBUTE_PROGRAM_LEN
:
3111 /* check if the iter value is valid and program_len
3112 * is not already initialized.
3114 if (nla_len(iter
) == sizeof(uint32
) && !program_len
) {
3115 program_len
= nla_get_u32(iter
);
3121 if (program_len
> WL_APF_PROGRAM_MAX_SIZE
) {
3122 WL_ERR(("program len is more than expected len\n"));
3127 if (unlikely(!program_len
)) {
3128 WL_ERR(("zero program length\n"));
3133 case APF_ATTRIBUTE_PROGRAM
:
3134 if (unlikely(!program_len
)) {
3135 WL_ERR(("program len is not set\n"));
3139 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
3140 program
= kzalloc(program_len
, kflags
);
3141 if (unlikely(!program
)) {
3142 WL_ERR(("%s: can't allocate %d bytes\n",
3143 __FUNCTION__
, program_len
));
3147 memcpy(program
, (u8
*)nla_data(iter
), program_len
);
3150 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__
, type
));
3156 ret
= dhd_dev_apf_add_filter(ndev
, program
, program_len
);
3164 #endif /* PKT_FILTER_SUPPORT && APF */
3166 #ifdef NDO_CONFIG_SUPPORT
3167 static int wl_cfgvendor_configure_nd_offload(struct wiphy
*wiphy
,
3168 struct wireless_dev
*wdev
, const void *data
, int len
)
3170 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3171 const struct nlattr
*iter
;
3172 int ret
= BCME_OK
, rem
, type
;
3175 nla_for_each_attr(iter
, data
, len
, rem
) {
3176 type
= nla_type(iter
);
3178 case ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE
:
3179 enable
= nla_get_u8(iter
);
3182 WL_ERR(("Unknown type: %d\n", type
));
3188 ret
= dhd_dev_ndo_cfg(bcmcfg_to_prmry_ndev(cfg
), enable
);
3190 WL_ERR(("dhd_dev_ndo_cfg() failed: %d\n", ret
));
3196 #endif /* NDO_CONFIG_SUPPORT */
3198 static const struct wiphy_vendor_command wl_vendor_cmds
[] = {
3201 .vendor_id
= OUI_BRCM
,
3202 .subcmd
= BRCM_VENDOR_SCMD_PRIV_STR
3204 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3205 .doit
= wl_cfgvendor_priv_string_handler
3209 .vendor_id
= OUI_BRCM
,
3210 .subcmd
= BRCM_VENDOR_SCMD_BCM_STR
3212 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3213 .doit
= wl_cfgvendor_priv_bcm_handler
3215 #ifdef GSCAN_SUPPORT
3218 .vendor_id
= OUI_GOOGLE
,
3219 .subcmd
= GSCAN_SUBCMD_GET_CAPABILITIES
3221 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3222 .doit
= wl_cfgvendor_gscan_get_capabilities
3226 .vendor_id
= OUI_GOOGLE
,
3227 .subcmd
= GSCAN_SUBCMD_SET_CONFIG
3229 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3230 .doit
= wl_cfgvendor_set_scan_cfg
3234 .vendor_id
= OUI_GOOGLE
,
3235 .subcmd
= GSCAN_SUBCMD_SET_SCAN_CONFIG
3237 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3238 .doit
= wl_cfgvendor_set_batch_scan_cfg
3242 .vendor_id
= OUI_GOOGLE
,
3243 .subcmd
= GSCAN_SUBCMD_ENABLE_GSCAN
3245 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3246 .doit
= wl_cfgvendor_initiate_gscan
3250 .vendor_id
= OUI_GOOGLE
,
3251 .subcmd
= GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
3253 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3254 .doit
= wl_cfgvendor_enable_full_scan_result
3258 .vendor_id
= OUI_GOOGLE
,
3259 .subcmd
= GSCAN_SUBCMD_SET_HOTLIST
3261 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3262 .doit
= wl_cfgvendor_hotlist_cfg
3266 .vendor_id
= OUI_GOOGLE
,
3267 .subcmd
= GSCAN_SUBCMD_GET_SCAN_RESULTS
3269 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3270 .doit
= wl_cfgvendor_gscan_get_batch_results
3272 #endif /* GSCAN_SUPPORT */
3273 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
3276 .vendor_id
= OUI_GOOGLE
,
3277 .subcmd
= GSCAN_SUBCMD_GET_CHANNEL_LIST
3279 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3280 .doit
= wl_cfgvendor_gscan_get_channel_list
3282 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
3286 .vendor_id
= OUI_GOOGLE
,
3287 .subcmd
= RTT_SUBCMD_SET_CONFIG
3289 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3290 .doit
= wl_cfgvendor_rtt_set_config
3294 .vendor_id
= OUI_GOOGLE
,
3295 .subcmd
= RTT_SUBCMD_CANCEL_CONFIG
3297 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3298 .doit
= wl_cfgvendor_rtt_cancel_config
3302 .vendor_id
= OUI_GOOGLE
,
3303 .subcmd
= RTT_SUBCMD_GETCAPABILITY
3305 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3306 .doit
= wl_cfgvendor_rtt_get_capability
3310 .vendor_id
= OUI_GOOGLE
,
3311 .subcmd
= RTT_SUBCMD_GETAVAILCHANNEL
3313 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3314 .doit
= wl_cfgvendor_rtt_get_responder_info
3318 .vendor_id
= OUI_GOOGLE
,
3319 .subcmd
= RTT_SUBCMD_SET_RESPONDER
3321 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3322 .doit
= wl_cfgvendor_rtt_set_responder
3326 .vendor_id
= OUI_GOOGLE
,
3327 .subcmd
= RTT_SUBCMD_CANCEL_RESPONDER
3329 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3330 .doit
= wl_cfgvendor_rtt_cancel_responder
3332 #endif /* RTT_SUPPORT */
3335 .vendor_id
= OUI_GOOGLE
,
3336 .subcmd
= ANDR_WIFI_SUBCMD_GET_FEATURE_SET
3338 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3339 .doit
= wl_cfgvendor_get_feature_set
3343 .vendor_id
= OUI_GOOGLE
,
3344 .subcmd
= ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
3346 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3347 .doit
= wl_cfgvendor_get_feature_set_matrix
3351 .vendor_id
= OUI_GOOGLE
,
3352 .subcmd
= ANDR_WIFI_RANDOM_MAC_OUI
3354 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3355 .doit
= wl_cfgvendor_set_rand_mac_oui
3357 #ifdef CUSTOM_FORCE_NODFS_FLAG
3360 .vendor_id
= OUI_GOOGLE
,
3361 .subcmd
= ANDR_WIFI_NODFS_CHANNELS
3363 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3364 .doit
= wl_cfgvendor_set_nodfs_flag
3366 #endif /* CUSTOM_FORCE_NODFS_FLAG */
3369 .vendor_id
= OUI_GOOGLE
,
3370 .subcmd
= ANDR_WIFI_SET_COUNTRY
3372 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3373 .doit
= wl_cfgvendor_set_country
3375 #ifdef LINKSTAT_SUPPORT
3378 .vendor_id
= OUI_GOOGLE
,
3379 .subcmd
= LSTATS_SUBCMD_GET_INFO
3381 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3382 .doit
= wl_cfgvendor_lstats_get_info
3384 #endif /* LINKSTAT_SUPPORT */
3386 #ifdef GSCAN_SUPPORT
3389 .vendor_id
= OUI_GOOGLE
,
3390 .subcmd
= GSCAN_SUBCMD_SET_EPNO_SSID
3392 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3393 .doit
= wl_cfgvendor_epno_cfg
3398 .vendor_id
= OUI_GOOGLE
,
3399 .subcmd
= WIFI_SUBCMD_SET_SSID_WHITELIST
3401 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3402 .doit
= wl_cfgvendor_set_ssid_whitelist
3407 .vendor_id
= OUI_GOOGLE
,
3408 .subcmd
= WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
3410 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3411 .doit
= wl_cfgvendor_set_lazy_roam_cfg
3416 .vendor_id
= OUI_GOOGLE
,
3417 .subcmd
= WIFI_SUBCMD_ENABLE_LAZY_ROAM
3419 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3420 .doit
= wl_cfgvendor_enable_lazy_roam
3425 .vendor_id
= OUI_GOOGLE
,
3426 .subcmd
= WIFI_SUBCMD_SET_BSSID_PREF
3428 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3429 .doit
= wl_cfgvendor_set_bssid_pref
3434 .vendor_id
= OUI_GOOGLE
,
3435 .subcmd
= WIFI_SUBCMD_SET_BSSID_BLACKLIST
3437 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3438 .doit
= wl_cfgvendor_set_bssid_blacklist
3440 #endif /* GSCAN_SUPPORT */
3444 .vendor_id
= OUI_GOOGLE
,
3445 .subcmd
= DEBUG_START_LOGGING
3447 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3448 .doit
= wl_cfgvendor_dbg_start_logging
3452 .vendor_id
= OUI_GOOGLE
,
3453 .subcmd
= DEBUG_RESET_LOGGING
3455 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3456 .doit
= wl_cfgvendor_dbg_reset_logging
3460 .vendor_id
= OUI_GOOGLE
,
3461 .subcmd
= DEBUG_TRIGGER_MEM_DUMP
3463 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3464 .doit
= wl_cfgvendor_dbg_trigger_mem_dump
3468 .vendor_id
= OUI_GOOGLE
,
3469 .subcmd
= DEBUG_GET_MEM_DUMP
3471 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3472 .doit
= wl_cfgvendor_dbg_get_mem_dump
3476 .vendor_id
= OUI_GOOGLE
,
3477 .subcmd
= DEBUG_GET_VER
3479 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3480 .doit
= wl_cfgvendor_dbg_get_version
3484 .vendor_id
= OUI_GOOGLE
,
3485 .subcmd
= DEBUG_GET_RING_STATUS
3487 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3488 .doit
= wl_cfgvendor_dbg_get_ring_status
3492 .vendor_id
= OUI_GOOGLE
,
3493 .subcmd
= DEBUG_GET_RING_DATA
3495 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3496 .doit
= wl_cfgvendor_dbg_get_ring_data
3500 .vendor_id
= OUI_GOOGLE
,
3501 .subcmd
= DEBUG_GET_FEATURE
3503 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3504 .doit
= wl_cfgvendor_dbg_get_feature
3506 #endif /* DEBUGABILITY */
3510 .vendor_id
= OUI_GOOGLE
,
3511 .subcmd
= DEBUG_START_PKT_FATE_MONITORING
3513 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3514 .doit
= wl_cfgvendor_dbg_start_pkt_fate_monitoring
3518 .vendor_id
= OUI_GOOGLE
,
3519 .subcmd
= DEBUG_GET_TX_PKT_FATES
3521 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3522 .doit
= wl_cfgvendor_dbg_get_tx_pkt_fates
3526 .vendor_id
= OUI_GOOGLE
,
3527 .subcmd
= DEBUG_GET_RX_PKT_FATES
3529 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3530 .doit
= wl_cfgvendor_dbg_get_rx_pkt_fates
3532 #endif /* DBG_PKT_MON */
3536 .vendor_id
= OUI_GOOGLE
,
3537 .subcmd
= WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
3539 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3540 .doit
= wl_cfgvendor_start_mkeep_alive
3544 .vendor_id
= OUI_GOOGLE
,
3545 .subcmd
= WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
3547 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3548 .doit
= wl_cfgvendor_stop_mkeep_alive
3550 #endif /* KEEP_ALIVE */
3551 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
3554 .vendor_id
= OUI_GOOGLE
,
3555 .subcmd
= APF_SUBCMD_GET_CAPABILITIES
3557 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3558 .doit
= wl_cfgvendor_apf_get_capabilities
3563 .vendor_id
= OUI_GOOGLE
,
3564 .subcmd
= APF_SUBCMD_SET_FILTER
3566 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3567 .doit
= wl_cfgvendor_apf_set_filter
3569 #endif /* PKT_FILTER_SUPPORT && APF */
3570 #ifdef NDO_CONFIG_SUPPORT
3573 .vendor_id
= OUI_GOOGLE
,
3574 .subcmd
= WIFI_SUBCMD_CONFIG_ND_OFFLOAD
3576 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3577 .doit
= wl_cfgvendor_configure_nd_offload
3579 #endif /* NDO_CONFIG_SUPPORT */
3580 #ifdef RSSI_MONITOR_SUPPORT
3583 .vendor_id
= OUI_GOOGLE
,
3584 .subcmd
= WIFI_SUBCMD_SET_RSSI_MONITOR
3586 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3587 .doit
= wl_cfgvendor_set_rssi_monitor
3589 #endif /* RSSI_MONITOR_SUPPORT */
3590 #ifdef DHDTCPACK_SUPPRESS
3593 .vendor_id
= OUI_GOOGLE
,
3594 .subcmd
= WIFI_SUBCMD_CONFIG_TCPACK_SUP
3596 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3597 .doit
= wl_cfgvendor_set_tcpack_sup_mode
3599 #endif /* DHDTCPACK_SUPPRESS */
3600 #ifdef DHD_WAKE_STATUS
3603 .vendor_id
= OUI_GOOGLE
,
3604 .subcmd
= DEBUG_GET_WAKE_REASON_STATS
3606 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3607 .doit
= wl_cfgvendor_get_wake_reason_stats
3609 #endif /* DHD_WAKE_STATUS */
3612 static const struct nl80211_vendor_cmd_info wl_vendor_events
[] = {
3613 { OUI_BRCM
, BRCM_VENDOR_EVENT_UNSPEC
},
3614 { OUI_BRCM
, BRCM_VENDOR_EVENT_PRIV_STR
},
3615 #ifdef GSCAN_SUPPORT
3616 { OUI_GOOGLE
, GOOGLE_GSCAN_SIGNIFICANT_EVENT
},
3617 { OUI_GOOGLE
, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT
},
3618 { OUI_GOOGLE
, GOOGLE_GSCAN_BATCH_SCAN_EVENT
},
3619 { OUI_GOOGLE
, GOOGLE_SCAN_FULL_RESULTS_EVENT
},
3620 #endif /* GSCAN_SUPPORT */
3622 { OUI_GOOGLE
, GOOGLE_RTT_COMPLETE_EVENT
},
3623 #endif /* RTT_SUPPORT */
3624 #ifdef GSCAN_SUPPORT
3625 { OUI_GOOGLE
, GOOGLE_SCAN_COMPLETE_EVENT
},
3626 { OUI_GOOGLE
, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT
},
3627 { OUI_GOOGLE
, GOOGLE_SCAN_EPNO_EVENT
},
3628 #endif /* GSCAN_SUPPORT */
3629 { OUI_GOOGLE
, GOOGLE_DEBUG_RING_EVENT
},
3630 { OUI_GOOGLE
, GOOGLE_FW_DUMP_EVENT
},
3631 #ifdef GSCAN_SUPPORT
3632 { OUI_GOOGLE
, GOOGLE_PNO_HOTSPOT_FOUND_EVENT
},
3633 #endif /* GSCAN_SUPPORT */
3634 { OUI_GOOGLE
, GOOGLE_RSSI_MONITOR_EVENT
},
3635 { OUI_GOOGLE
, GOOGLE_MKEEP_ALIVE_EVENT
},
3636 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_ENABLED
},
3637 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_DISABLED
},
3638 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_PUBLISH_TERMINATED
},
3639 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH
},
3640 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH
},
3641 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED
},
3642 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_DE_EVENT
},
3643 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_FOLLOWUP
},
3644 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_TCA
},
3646 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_DATA_PATH_OPEN
},
3648 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_UNKNOWN
}
3651 int wl_cfgvendor_attach(struct wiphy
*wiphy
, dhd_pub_t
*dhd
)
3654 WL_INFORM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
3655 NL80211_CMD_VENDOR
));
3657 wiphy
->vendor_commands
= wl_vendor_cmds
;
3658 wiphy
->n_vendor_commands
= ARRAY_SIZE(wl_vendor_cmds
);
3659 wiphy
->vendor_events
= wl_vendor_events
;
3660 wiphy
->n_vendor_events
= ARRAY_SIZE(wl_vendor_events
);
3663 dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID
, wl_cfgvendor_dbg_ring_send_evt
);
3664 dhd_os_dbg_register_callback(FW_EVENT_RING_ID
, wl_cfgvendor_dbg_ring_send_evt
);
3665 dhd_os_dbg_register_callback(DHD_EVENT_RING_ID
, wl_cfgvendor_dbg_ring_send_evt
);
3666 dhd_os_dbg_register_callback(NAN_EVENT_RING_ID
, wl_cfgvendor_dbg_ring_send_evt
);
3667 dhd_os_dbg_register_urgent_notifier(dhd
, wl_cfgvendor_dbg_send_urgent_evt
);
3668 #endif /* DEBUGABILITY */
3673 int wl_cfgvendor_detach(struct wiphy
*wiphy
)
3675 WL_INFORM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
3677 wiphy
->vendor_commands
= NULL
;
3678 wiphy
->vendor_events
= NULL
;
3679 wiphy
->n_vendor_commands
= 0;
3680 wiphy
->n_vendor_events
= 0;
3684 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */