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 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
);
2331 if (macstat_cnt
== NULL
) {
2332 printf("wlmTxGetAckedPackets: macstat_cnt NULL!\n");
2337 err
= wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg
), &scbval
);
2338 if (unlikely(err
)) {
2339 WL_ERR(("get_rssi error (%d)\n", err
));
2343 COMPAT_ASSIGN_VALUE(iface
, beacon_rx
, macstat_cnt
->rxbeaconmbss
);
2344 COMPAT_ASSIGN_VALUE(iface
, rssi_mgmt
, scbval
.val
);
2345 COMPAT_ASSIGN_VALUE(iface
, num_peers
, NUM_PEER
);
2346 COMPAT_ASSIGN_VALUE(iface
, peer_info
->num_rate
, NUM_RATE
);
2348 #ifdef CONFIG_COMPAT
2349 if (compat_task_state
) {
2350 memcpy(output
, &compat_iface
, sizeof(compat_iface
));
2351 output
+= (sizeof(compat_iface
) - sizeof(wifi_rate_stat
));
2353 #endif /* CONFIG_COMPAT */
2355 memcpy(output
, &iface
, sizeof(iface
));
2356 output
+= (sizeof(iface
) - sizeof(wifi_rate_stat
));
2359 err
= wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg
), "ratestat", NULL
, 0,
2360 iovar_buf
, WLC_IOCTL_MAXLEN
, NULL
);
2361 if (err
!= BCME_OK
&& err
!= BCME_UNSUPPORTED
) {
2362 WL_ERR(("error (%d) - size = %zu\n", err
, NUM_RATE
*sizeof(wifi_rate_stat
)));
2365 for (i
= 0; i
< NUM_RATE
; i
++) {
2367 (wifi_rate_stat
*)(iovar_buf
+ i
*sizeof(wifi_rate_stat
));
2368 p_wifi_rate_stat_v1
= (wifi_rate_stat_v1
*)output
;
2369 p_wifi_rate_stat_v1
->rate
.preamble
= p_wifi_rate_stat
->rate
.preamble
;
2370 p_wifi_rate_stat_v1
->rate
.nss
= p_wifi_rate_stat
->rate
.nss
;
2371 p_wifi_rate_stat_v1
->rate
.bw
= p_wifi_rate_stat
->rate
.bw
;
2372 p_wifi_rate_stat_v1
->rate
.rateMcsIdx
= p_wifi_rate_stat
->rate
.rateMcsIdx
;
2373 p_wifi_rate_stat_v1
->rate
.reserved
= p_wifi_rate_stat
->rate
.reserved
;
2374 p_wifi_rate_stat_v1
->rate
.bitrate
= p_wifi_rate_stat
->rate
.bitrate
;
2375 p_wifi_rate_stat_v1
->tx_mpdu
= p_wifi_rate_stat
->tx_mpdu
;
2376 p_wifi_rate_stat_v1
->rx_mpdu
= p_wifi_rate_stat
->rx_mpdu
;
2377 p_wifi_rate_stat_v1
->mpdu_lost
= p_wifi_rate_stat
->mpdu_lost
;
2378 p_wifi_rate_stat_v1
->retries
= p_wifi_rate_stat
->retries
;
2379 p_wifi_rate_stat_v1
->retries_short
= p_wifi_rate_stat
->retries_short
;
2380 p_wifi_rate_stat_v1
->retries_long
= p_wifi_rate_stat
->retries_long
;
2381 output
= (char *) &(p_wifi_rate_stat_v1
->retries_long
);
2382 output
+= sizeof(p_wifi_rate_stat_v1
->retries_long
);
2385 total_len
= sizeof(wifi_radio_stat_h
) +
2386 NUM_CHAN
* sizeof(wifi_channel_stat
);
2388 #ifdef CONFIG_COMPAT
2389 if (compat_task_state
) {
2390 total_len
+= sizeof(compat_wifi_iface_stat
);
2392 #endif /* CONFIG_COMPAT */
2394 total_len
+= sizeof(wifi_iface_stat
);
2397 total_len
= total_len
- sizeof(wifi_peer_info
) +
2398 NUM_PEER
* (sizeof(wifi_peer_info
) - sizeof(wifi_rate_stat_v1
) +
2399 NUM_RATE
* sizeof(wifi_rate_stat_v1
));
2401 if (total_len
> WLC_IOCTL_MAXLEN
) {
2402 WL_ERR(("Error! total_len:%d is unexpected value\n", total_len
));
2406 err
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
2411 WL_ERR(("Vendor Command reply failed ret:%d \n", err
));
2419 #endif /* LINKSTAT_SUPPORT */
2422 static int wl_cfgvendor_dbg_start_logging(struct wiphy
*wiphy
,
2423 struct wireless_dev
*wdev
, const void *data
, int len
)
2425 int ret
= BCME_OK
, rem
, type
;
2426 char ring_name
[DBGRING_NAME_MAX
] = {0};
2427 int log_level
= 0, flags
= 0, time_intval
= 0, threshold
= 0;
2428 const struct nlattr
*iter
;
2429 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2430 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2431 nla_for_each_attr(iter
, data
, len
, rem
) {
2432 type
= nla_type(iter
);
2434 case DEBUG_ATTRIBUTE_RING_NAME
:
2435 strncpy(ring_name
, nla_data(iter
),
2436 MIN(sizeof(ring_name
) -1, nla_len(iter
)));
2438 case DEBUG_ATTRIBUTE_LOG_LEVEL
:
2439 log_level
= nla_get_u32(iter
);
2441 case DEBUG_ATTRIBUTE_RING_FLAGS
:
2442 flags
= nla_get_u32(iter
);
2444 case DEBUG_ATTRIBUTE_LOG_TIME_INTVAL
:
2445 time_intval
= nla_get_u32(iter
);
2447 case DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE
:
2448 threshold
= nla_get_u32(iter
);
2451 WL_ERR(("Unknown type: %d\n", type
));
2457 ret
= dhd_os_start_logging(dhd_pub
, ring_name
, log_level
, flags
, time_intval
, threshold
);
2459 WL_ERR(("start_logging is failed ret: %d\n", ret
));
2465 static int wl_cfgvendor_dbg_reset_logging(struct wiphy
*wiphy
,
2466 struct wireless_dev
*wdev
, const void *data
, int len
)
2469 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2470 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2472 ret
= dhd_os_reset_logging(dhd_pub
);
2474 WL_ERR(("reset logging is failed ret: %d\n", ret
));
2481 wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy
*wiphy
,
2482 struct wireless_dev
*wdev
, const void *data
, int len
)
2486 struct sk_buff
*skb
;
2487 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2488 dhd_pub_t
*dhdp
= (dhd_pub_t
*)(cfg
->pub
);
2490 dhdp
->memdump_type
= DUMP_TYPE_CFG_VENDOR_TRIGGERED
;
2492 ret
= dhd_os_socram_dump(bcmcfg_to_prmry_ndev(cfg
), &alloc_len
);
2494 WL_ERR(("failed to call dhd_os_socram_dump : %d\n", ret
));
2497 /* Alloc the SKB for vendor_event */
2498 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, 100);
2500 WL_ERR(("skb allocation is failed\n"));
2504 nla_put_u32(skb
, DEBUG_ATTRIBUTE_FW_DUMP_LEN
, alloc_len
);
2506 ret
= cfg80211_vendor_cmd_reply(skb
);
2509 WL_ERR(("Vendor Command reply failed ret:%d \n", ret
));
2517 wl_cfgvendor_dbg_get_mem_dump(struct wiphy
*wiphy
,
2518 struct wireless_dev
*wdev
, const void *data
, int len
)
2520 int ret
= BCME_OK
, rem
, type
;
2522 uintptr_t user_buf
= (uintptr_t)NULL
;
2523 const struct nlattr
*iter
;
2524 char *mem_buf
= NULL
;
2525 struct sk_buff
*skb
;
2526 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2528 nla_for_each_attr(iter
, data
, len
, rem
) {
2529 type
= nla_type(iter
);
2531 case DEBUG_ATTRIBUTE_FW_DUMP_LEN
:
2532 /* Check if the iter is valid and
2533 * buffer length is not already initialized.
2535 if ((nla_len(iter
) == sizeof(uint32
)) &&
2537 buf_len
= nla_get_u32(iter
);
2543 case DEBUG_ATTRIBUTE_FW_DUMP_DATA
:
2544 if (nla_len(iter
) != sizeof(uint64
)) {
2545 WL_ERR(("Invalid len\n"));
2549 user_buf
= (uintptr_t)nla_get_u64(iter
);
2552 WL_ERR(("Unknown type: %d\n", type
));
2557 if (buf_len
> 0 && user_buf
) {
2558 mem_buf
= vmalloc(buf_len
);
2560 WL_ERR(("failed to allocate mem_buf with size : %d\n", buf_len
));
2564 ret
= dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg
), &mem_buf
, &buf_len
);
2566 WL_ERR(("failed to get_socram_dump : %d\n", ret
));
2569 #ifdef CONFIG_COMPAT
2570 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2571 if (in_compat_syscall())
2573 if (is_compat_task())
2576 void * usr_ptr
= compat_ptr((uintptr_t) user_buf
);
2577 ret
= copy_to_user(usr_ptr
, mem_buf
, buf_len
);
2579 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret
));
2584 #endif /* CONFIG_COMPAT */
2586 ret
= copy_to_user((void*)user_buf
, mem_buf
, buf_len
);
2588 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret
));
2592 /* Alloc the SKB for vendor_event */
2593 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, 100);
2595 WL_ERR(("skb allocation is failed\n"));
2599 /* Indicate the memdump is succesfully copied */
2600 nla_put(skb
, DEBUG_ATTRIBUTE_FW_DUMP_DATA
, sizeof(ret
), &ret
);
2602 ret
= cfg80211_vendor_cmd_reply(skb
);
2605 WL_ERR(("Vendor Command reply failed ret:%d \n", ret
));
2615 static int wl_cfgvendor_dbg_get_version(struct wiphy
*wiphy
,
2616 struct wireless_dev
*wdev
, const void *data
, int len
)
2618 int ret
= BCME_OK
, rem
, type
;
2620 bool dhd_ver
= FALSE
;
2622 const struct nlattr
*iter
;
2624 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2625 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
2626 buf_ptr
= kzalloc(buf_len
, kflags
);
2628 WL_ERR(("failed to allocate the buffer for version n"));
2632 nla_for_each_attr(iter
, data
, len
, rem
) {
2633 type
= nla_type(iter
);
2635 case DEBUG_ATTRIBUTE_GET_DRIVER
:
2638 case DEBUG_ATTRIBUTE_GET_FW
:
2642 WL_ERR(("Unknown type: %d\n", type
));
2647 ret
= dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg
), dhd_ver
, &buf_ptr
, buf_len
);
2649 WL_ERR(("failed to get the version %d\n", ret
));
2652 ret
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
2653 buf_ptr
, strlen(buf_ptr
));
2659 static int wl_cfgvendor_dbg_get_ring_status(struct wiphy
*wiphy
,
2660 struct wireless_dev
*wdev
, const void *data
, int len
)
2665 struct sk_buff
*skb
;
2666 dhd_dbg_ring_status_t dbg_ring_status
[DEBUG_RING_ID_MAX
];
2667 dhd_dbg_ring_status_t ring_status
;
2668 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2669 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2670 memset(dbg_ring_status
, 0, DBG_RING_STATUS_SIZE
* DEBUG_RING_ID_MAX
);
2672 for (ring_id
= DEBUG_RING_ID_INVALID
+ 1; ring_id
< DEBUG_RING_ID_MAX
; ring_id
++) {
2673 ret
= dhd_os_get_ring_status(dhd_pub
, ring_id
, &ring_status
);
2674 if (ret
== BCME_NOTFOUND
) {
2675 WL_DBG(("The ring (%d) is not found \n", ring_id
));
2676 } else if (ret
== BCME_OK
) {
2677 dbg_ring_status
[ring_cnt
++] = ring_status
;
2680 /* Alloc the SKB for vendor_event */
2681 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
,
2682 (DBG_RING_STATUS_SIZE
* ring_cnt
) + 100);
2684 WL_ERR(("skb allocation is failed\n"));
2689 nla_put_u32(skb
, DEBUG_ATTRIBUTE_RING_NUM
, ring_cnt
);
2690 for (i
= 0; i
< ring_cnt
; i
++) {
2691 nla_put(skb
, DEBUG_ATTRIBUTE_RING_STATUS
, DBG_RING_STATUS_SIZE
,
2692 &dbg_ring_status
[i
]);
2694 ret
= cfg80211_vendor_cmd_reply(skb
);
2697 WL_ERR(("Vendor Command reply failed ret:%d \n", ret
));
2703 static int wl_cfgvendor_dbg_get_ring_data(struct wiphy
*wiphy
,
2704 struct wireless_dev
*wdev
, const void *data
, int len
)
2706 int ret
= BCME_OK
, rem
, type
;
2707 char ring_name
[DBGRING_NAME_MAX
] = {0};
2708 const struct nlattr
*iter
;
2709 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2710 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2712 nla_for_each_attr(iter
, data
, len
, rem
) {
2713 type
= nla_type(iter
);
2715 case DEBUG_ATTRIBUTE_RING_NAME
:
2716 strncpy(ring_name
, nla_data(iter
),
2717 MIN(sizeof(ring_name
) -1, nla_len(iter
)));
2720 WL_ERR(("Unknown type: %d\n", type
));
2725 ret
= dhd_os_trigger_get_ring_data(dhd_pub
, ring_name
);
2727 WL_ERR(("trigger_get_data failed ret:%d\n", ret
));
2733 static int wl_cfgvendor_dbg_get_feature(struct wiphy
*wiphy
,
2734 struct wireless_dev
*wdev
, const void *data
, int len
)
2737 u32 supported_features
= 0;
2738 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2739 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2741 ret
= dhd_os_dbg_get_feature(dhd_pub
, &supported_features
);
2743 WL_ERR(("dbg_get_feature failed ret:%d\n", ret
));
2746 ret
= wl_cfgvendor_send_cmd_reply(wiphy
, bcmcfg_to_prmry_ndev(cfg
),
2747 &supported_features
, sizeof(supported_features
));
2749 WL_ERR(("wl_cfgvendor_send_cmd_reply failed ret:%d\n", ret
));
2756 static void wl_cfgvendor_dbg_ring_send_evt(void *ctx
,
2757 const int ring_id
, const void *data
, const uint32 len
,
2758 const dhd_dbg_ring_status_t ring_status
)
2760 struct net_device
*ndev
= ctx
;
2761 struct wiphy
*wiphy
;
2763 struct sk_buff
*skb
;
2765 WL_ERR(("ndev is NULL\n"));
2768 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
2769 wiphy
= ndev
->ieee80211_ptr
->wiphy
;
2770 /* Alloc the SKB for vendor_event */
2771 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2772 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2773 skb
= cfg80211_vendor_event_alloc(wiphy
, NULL
, len
+ 100,
2774 GOOGLE_DEBUG_RING_EVENT
, kflags
);
2776 skb
= cfg80211_vendor_event_alloc(wiphy
, len
+ 100,
2777 GOOGLE_DEBUG_RING_EVENT
, kflags
);
2778 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2779 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2781 WL_ERR(("skb alloc failed"));
2784 nla_put(skb
, DEBUG_ATTRIBUTE_RING_STATUS
, sizeof(ring_status
), &ring_status
);
2785 nla_put(skb
, DEBUG_ATTRIBUTE_RING_DATA
, len
, data
);
2786 cfg80211_vendor_event(skb
, kflags
);
2789 static void wl_cfgvendor_dbg_send_urgent_evt(void *ctx
, const void *data
,
2790 const uint32 len
, const uint32 fw_len
)
2792 struct net_device
*ndev
= ctx
;
2793 struct wiphy
*wiphy
;
2795 struct sk_buff
*skb
;
2797 WL_ERR(("ndev is NULL\n"));
2800 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
2801 wiphy
= ndev
->ieee80211_ptr
->wiphy
;
2802 /* Alloc the SKB for vendor_event */
2803 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2804 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2805 skb
= cfg80211_vendor_event_alloc(wiphy
, NULL
, len
+ 100,
2806 GOOGLE_FW_DUMP_EVENT
, kflags
);
2808 skb
= cfg80211_vendor_event_alloc(wiphy
, len
+ 100,
2809 GOOGLE_FW_DUMP_EVENT
, kflags
);
2810 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2811 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2813 WL_ERR(("skb alloc failed"));
2816 nla_put_u32(skb
, DEBUG_ATTRIBUTE_FW_DUMP_LEN
, fw_len
);
2817 nla_put(skb
, DEBUG_ATTRIBUTE_RING_DATA
, len
, data
);
2818 cfg80211_vendor_event(skb
, kflags
);
2820 #endif /* DEBUGABILITY */
2823 static int wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy
*wiphy
,
2824 struct wireless_dev
*wdev
, const void *data
, int len
)
2826 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2827 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2830 ret
= dhd_os_dbg_attach_pkt_monitor(dhd_pub
);
2831 if (unlikely(ret
)) {
2832 WL_ERR(("failed to start pkt fate monitoring, ret=%d", ret
));
2838 typedef int (*dbg_mon_get_pkts_t
) (dhd_pub_t
*dhdp
, void __user
*user_buf
,
2839 uint16 req_count
, uint16
*resp_count
);
2841 static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy
*wiphy
,
2842 const void *data
, int len
, dbg_mon_get_pkts_t dbg_mon_get_pkts
)
2844 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2845 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2846 struct sk_buff
*skb
= NULL
;
2847 const struct nlattr
*iter
;
2848 void __user
*user_buf
= NULL
;
2849 uint16 req_count
= 0, resp_count
= 0;
2850 int ret
, tmp
, type
, mem_needed
;
2852 nla_for_each_attr(iter
, data
, len
, tmp
) {
2853 type
= nla_type(iter
);
2855 case DEBUG_ATTRIBUTE_PKT_FATE_NUM
:
2856 req_count
= nla_get_u32(iter
);
2858 case DEBUG_ATTRIBUTE_PKT_FATE_DATA
:
2859 user_buf
= (void __user
*)(unsigned long) nla_get_u64(iter
);
2862 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__
, type
));
2868 if (!req_count
|| !user_buf
) {
2869 WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n",
2870 __FUNCTION__
, user_buf
, req_count
));
2875 ret
= dbg_mon_get_pkts(dhd_pub
, user_buf
, req_count
, &resp_count
);
2876 if (unlikely(ret
)) {
2877 WL_ERR(("failed to get packets, ret:%d \n", ret
));
2881 mem_needed
= VENDOR_REPLY_OVERHEAD
+ ATTRIBUTE_U32_LEN
;
2882 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, mem_needed
);
2883 if (unlikely(!skb
)) {
2884 WL_ERR(("skb alloc failed"));
2889 nla_put_u32(skb
, DEBUG_ATTRIBUTE_PKT_FATE_NUM
, resp_count
);
2891 ret
= cfg80211_vendor_cmd_reply(skb
);
2892 if (unlikely(ret
)) {
2893 WL_ERR(("vendor Command reply failed ret:%d \n", ret
));
2900 static int wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy
*wiphy
,
2901 struct wireless_dev
*wdev
, const void *data
, int len
)
2905 ret
= __wl_cfgvendor_dbg_get_pkt_fates(wiphy
, data
, len
,
2906 dhd_os_dbg_monitor_get_tx_pkts
);
2907 if (unlikely(ret
)) {
2908 WL_ERR(("failed to get tx packets, ret:%d \n", ret
));
2914 static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy
*wiphy
,
2915 struct wireless_dev
*wdev
, const void *data
, int len
)
2919 ret
= __wl_cfgvendor_dbg_get_pkt_fates(wiphy
, data
, len
,
2920 dhd_os_dbg_monitor_get_rx_pkts
);
2921 if (unlikely(ret
)) {
2922 WL_ERR(("failed to get rx packets, ret:%d \n", ret
));
2927 #endif /* DBG_PKT_MON */
2930 static int wl_cfgvendor_start_mkeep_alive(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
2931 const void *data
, int len
)
2933 /* max size of IP packet for keep alive */
2934 const int MKEEP_ALIVE_IP_PKT_MAX
= 256;
2936 int ret
= BCME_OK
, rem
, type
;
2937 uint8 mkeep_alive_id
= 0;
2938 uint8
*ip_pkt
= NULL
;
2939 uint16 ip_pkt_len
= 0;
2940 uint8 src_mac
[ETHER_ADDR_LEN
];
2941 uint8 dst_mac
[ETHER_ADDR_LEN
];
2942 uint32 period_msec
= 0;
2943 const struct nlattr
*iter
;
2944 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2945 dhd_pub_t
*dhd_pub
= cfg
->pub
;
2946 gfp_t kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
2948 nla_for_each_attr(iter
, data
, len
, rem
) {
2949 type
= nla_type(iter
);
2951 case MKEEP_ALIVE_ATTRIBUTE_ID
:
2952 mkeep_alive_id
= nla_get_u8(iter
);
2954 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN
:
2955 ip_pkt_len
= nla_get_u16(iter
);
2956 if (ip_pkt_len
> MKEEP_ALIVE_IP_PKT_MAX
) {
2961 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT
:
2964 WL_ERR(("ip packet length is 0\n"));
2967 ip_pkt
= (u8
*)kzalloc(ip_pkt_len
, kflags
);
2968 if (ip_pkt
== NULL
) {
2970 WL_ERR(("Failed to allocate mem for ip packet\n"));
2973 memcpy(ip_pkt
, (u8
*)nla_data(iter
), ip_pkt_len
);
2975 case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR
:
2976 memcpy(src_mac
, nla_data(iter
), ETHER_ADDR_LEN
);
2978 case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR
:
2979 memcpy(dst_mac
, nla_data(iter
), ETHER_ADDR_LEN
);
2981 case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC
:
2982 period_msec
= nla_get_u32(iter
);
2985 WL_ERR(("Unknown type: %d\n", type
));
2991 if (ip_pkt
== NULL
) {
2993 WL_ERR(("ip packet is NULL\n"));
2997 ret
= dhd_dev_start_mkeep_alive(dhd_pub
, mkeep_alive_id
, ip_pkt
, ip_pkt_len
, src_mac
,
2998 dst_mac
, period_msec
);
3000 WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret
));
3011 static int wl_cfgvendor_stop_mkeep_alive(struct wiphy
*wiphy
, struct wireless_dev
*wdev
,
3012 const void *data
, int len
)
3014 int ret
= BCME_OK
, rem
, type
;
3015 uint8 mkeep_alive_id
= 0;
3016 const struct nlattr
*iter
;
3017 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3018 dhd_pub_t
*dhd_pub
= cfg
->pub
;
3020 nla_for_each_attr(iter
, data
, len
, rem
) {
3021 type
= nla_type(iter
);
3023 case MKEEP_ALIVE_ATTRIBUTE_ID
:
3024 mkeep_alive_id
= nla_get_u8(iter
);
3027 WL_ERR(("Unknown type: %d\n", type
));
3033 ret
= dhd_dev_stop_mkeep_alive(dhd_pub
, mkeep_alive_id
);
3035 WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret
));
3040 #endif /* KEEP_ALIVE */
3042 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
3044 wl_cfgvendor_apf_get_capabilities(struct wiphy
*wiphy
,
3045 struct wireless_dev
*wdev
, const void *data
, int len
)
3047 struct net_device
*ndev
= wdev_to_ndev(wdev
);
3048 struct sk_buff
*skb
;
3049 int ret
, ver
, max_len
, mem_needed
;
3053 ret
= dhd_dev_apf_get_version(ndev
, &ver
);
3054 if (unlikely(ret
)) {
3055 WL_ERR(("APF get version failed, ret=%d\n", ret
));
3059 /* APF memory size limit */
3061 ret
= dhd_dev_apf_get_max_len(ndev
, &max_len
);
3062 if (unlikely(ret
)) {
3063 WL_ERR(("APF get maximum length failed, ret=%d\n", ret
));
3067 mem_needed
= VENDOR_REPLY_OVERHEAD
+ (ATTRIBUTE_U32_LEN
* 2);
3069 skb
= cfg80211_vendor_cmd_alloc_reply_skb(wiphy
, mem_needed
);
3070 if (unlikely(!skb
)) {
3071 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__
, mem_needed
));
3075 nla_put_u32(skb
, APF_ATTRIBUTE_VERSION
, ver
);
3076 nla_put_u32(skb
, APF_ATTRIBUTE_MAX_LEN
, max_len
);
3078 ret
= cfg80211_vendor_cmd_reply(skb
);
3079 if (unlikely(ret
)) {
3080 WL_ERR(("vendor command reply failed, ret=%d\n", ret
));
3087 wl_cfgvendor_apf_set_filter(struct wiphy
*wiphy
,
3088 struct wireless_dev
*wdev
, const void *data
, int len
)
3090 struct net_device
*ndev
= wdev_to_ndev(wdev
);
3091 const struct nlattr
*iter
;
3093 u32 program_len
= 0;
3098 WL_ERR(("Invalid len: %d\n", len
));
3102 nla_for_each_attr(iter
, data
, len
, tmp
) {
3103 type
= nla_type(iter
);
3105 case APF_ATTRIBUTE_PROGRAM_LEN
:
3106 /* check if the iter value is valid and program_len
3107 * is not already initialized.
3109 if (nla_len(iter
) == sizeof(uint32
) && !program_len
) {
3110 program_len
= nla_get_u32(iter
);
3116 if (program_len
> WL_APF_PROGRAM_MAX_SIZE
) {
3117 WL_ERR(("program len is more than expected len\n"));
3122 if (unlikely(!program_len
)) {
3123 WL_ERR(("zero program length\n"));
3128 case APF_ATTRIBUTE_PROGRAM
:
3129 if (unlikely(!program_len
)) {
3130 WL_ERR(("program len is not set\n"));
3134 kflags
= in_atomic() ? GFP_ATOMIC
: GFP_KERNEL
;
3135 program
= kzalloc(program_len
, kflags
);
3136 if (unlikely(!program
)) {
3137 WL_ERR(("%s: can't allocate %d bytes\n",
3138 __FUNCTION__
, program_len
));
3142 memcpy(program
, (u8
*)nla_data(iter
), program_len
);
3145 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__
, type
));
3151 ret
= dhd_dev_apf_add_filter(ndev
, program
, program_len
);
3159 #endif /* PKT_FILTER_SUPPORT && APF */
3161 #ifdef NDO_CONFIG_SUPPORT
3162 static int wl_cfgvendor_configure_nd_offload(struct wiphy
*wiphy
,
3163 struct wireless_dev
*wdev
, const void *data
, int len
)
3165 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
3166 const struct nlattr
*iter
;
3167 int ret
= BCME_OK
, rem
, type
;
3170 nla_for_each_attr(iter
, data
, len
, rem
) {
3171 type
= nla_type(iter
);
3173 case ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE
:
3174 enable
= nla_get_u8(iter
);
3177 WL_ERR(("Unknown type: %d\n", type
));
3183 ret
= dhd_dev_ndo_cfg(bcmcfg_to_prmry_ndev(cfg
), enable
);
3185 WL_ERR(("dhd_dev_ndo_cfg() failed: %d\n", ret
));
3191 #endif /* NDO_CONFIG_SUPPORT */
3193 static const struct wiphy_vendor_command wl_vendor_cmds
[] = {
3196 .vendor_id
= OUI_BRCM
,
3197 .subcmd
= BRCM_VENDOR_SCMD_PRIV_STR
3199 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3200 .doit
= wl_cfgvendor_priv_string_handler
3204 .vendor_id
= OUI_BRCM
,
3205 .subcmd
= BRCM_VENDOR_SCMD_BCM_STR
3207 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3208 .doit
= wl_cfgvendor_priv_bcm_handler
3210 #ifdef GSCAN_SUPPORT
3213 .vendor_id
= OUI_GOOGLE
,
3214 .subcmd
= GSCAN_SUBCMD_GET_CAPABILITIES
3216 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3217 .doit
= wl_cfgvendor_gscan_get_capabilities
3221 .vendor_id
= OUI_GOOGLE
,
3222 .subcmd
= GSCAN_SUBCMD_SET_CONFIG
3224 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3225 .doit
= wl_cfgvendor_set_scan_cfg
3229 .vendor_id
= OUI_GOOGLE
,
3230 .subcmd
= GSCAN_SUBCMD_SET_SCAN_CONFIG
3232 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3233 .doit
= wl_cfgvendor_set_batch_scan_cfg
3237 .vendor_id
= OUI_GOOGLE
,
3238 .subcmd
= GSCAN_SUBCMD_ENABLE_GSCAN
3240 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3241 .doit
= wl_cfgvendor_initiate_gscan
3245 .vendor_id
= OUI_GOOGLE
,
3246 .subcmd
= GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
3248 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3249 .doit
= wl_cfgvendor_enable_full_scan_result
3253 .vendor_id
= OUI_GOOGLE
,
3254 .subcmd
= GSCAN_SUBCMD_SET_HOTLIST
3256 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3257 .doit
= wl_cfgvendor_hotlist_cfg
3261 .vendor_id
= OUI_GOOGLE
,
3262 .subcmd
= GSCAN_SUBCMD_GET_SCAN_RESULTS
3264 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3265 .doit
= wl_cfgvendor_gscan_get_batch_results
3267 #endif /* GSCAN_SUPPORT */
3268 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
3271 .vendor_id
= OUI_GOOGLE
,
3272 .subcmd
= GSCAN_SUBCMD_GET_CHANNEL_LIST
3274 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3275 .doit
= wl_cfgvendor_gscan_get_channel_list
3277 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
3281 .vendor_id
= OUI_GOOGLE
,
3282 .subcmd
= RTT_SUBCMD_SET_CONFIG
3284 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3285 .doit
= wl_cfgvendor_rtt_set_config
3289 .vendor_id
= OUI_GOOGLE
,
3290 .subcmd
= RTT_SUBCMD_CANCEL_CONFIG
3292 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3293 .doit
= wl_cfgvendor_rtt_cancel_config
3297 .vendor_id
= OUI_GOOGLE
,
3298 .subcmd
= RTT_SUBCMD_GETCAPABILITY
3300 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3301 .doit
= wl_cfgvendor_rtt_get_capability
3305 .vendor_id
= OUI_GOOGLE
,
3306 .subcmd
= RTT_SUBCMD_GETAVAILCHANNEL
3308 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3309 .doit
= wl_cfgvendor_rtt_get_responder_info
3313 .vendor_id
= OUI_GOOGLE
,
3314 .subcmd
= RTT_SUBCMD_SET_RESPONDER
3316 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3317 .doit
= wl_cfgvendor_rtt_set_responder
3321 .vendor_id
= OUI_GOOGLE
,
3322 .subcmd
= RTT_SUBCMD_CANCEL_RESPONDER
3324 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3325 .doit
= wl_cfgvendor_rtt_cancel_responder
3327 #endif /* RTT_SUPPORT */
3330 .vendor_id
= OUI_GOOGLE
,
3331 .subcmd
= ANDR_WIFI_SUBCMD_GET_FEATURE_SET
3333 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3334 .doit
= wl_cfgvendor_get_feature_set
3338 .vendor_id
= OUI_GOOGLE
,
3339 .subcmd
= ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
3341 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3342 .doit
= wl_cfgvendor_get_feature_set_matrix
3346 .vendor_id
= OUI_GOOGLE
,
3347 .subcmd
= ANDR_WIFI_RANDOM_MAC_OUI
3349 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3350 .doit
= wl_cfgvendor_set_rand_mac_oui
3352 #ifdef CUSTOM_FORCE_NODFS_FLAG
3355 .vendor_id
= OUI_GOOGLE
,
3356 .subcmd
= ANDR_WIFI_NODFS_CHANNELS
3358 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3359 .doit
= wl_cfgvendor_set_nodfs_flag
3361 #endif /* CUSTOM_FORCE_NODFS_FLAG */
3364 .vendor_id
= OUI_GOOGLE
,
3365 .subcmd
= ANDR_WIFI_SET_COUNTRY
3367 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3368 .doit
= wl_cfgvendor_set_country
3370 #ifdef LINKSTAT_SUPPORT
3373 .vendor_id
= OUI_GOOGLE
,
3374 .subcmd
= LSTATS_SUBCMD_GET_INFO
3376 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3377 .doit
= wl_cfgvendor_lstats_get_info
3379 #endif /* LINKSTAT_SUPPORT */
3381 #ifdef GSCAN_SUPPORT
3384 .vendor_id
= OUI_GOOGLE
,
3385 .subcmd
= GSCAN_SUBCMD_SET_EPNO_SSID
3387 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3388 .doit
= wl_cfgvendor_epno_cfg
3393 .vendor_id
= OUI_GOOGLE
,
3394 .subcmd
= WIFI_SUBCMD_SET_SSID_WHITELIST
3396 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3397 .doit
= wl_cfgvendor_set_ssid_whitelist
3402 .vendor_id
= OUI_GOOGLE
,
3403 .subcmd
= WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
3405 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3406 .doit
= wl_cfgvendor_set_lazy_roam_cfg
3411 .vendor_id
= OUI_GOOGLE
,
3412 .subcmd
= WIFI_SUBCMD_ENABLE_LAZY_ROAM
3414 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3415 .doit
= wl_cfgvendor_enable_lazy_roam
3420 .vendor_id
= OUI_GOOGLE
,
3421 .subcmd
= WIFI_SUBCMD_SET_BSSID_PREF
3423 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3424 .doit
= wl_cfgvendor_set_bssid_pref
3429 .vendor_id
= OUI_GOOGLE
,
3430 .subcmd
= WIFI_SUBCMD_SET_BSSID_BLACKLIST
3432 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3433 .doit
= wl_cfgvendor_set_bssid_blacklist
3435 #endif /* GSCAN_SUPPORT */
3439 .vendor_id
= OUI_GOOGLE
,
3440 .subcmd
= DEBUG_START_LOGGING
3442 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3443 .doit
= wl_cfgvendor_dbg_start_logging
3447 .vendor_id
= OUI_GOOGLE
,
3448 .subcmd
= DEBUG_RESET_LOGGING
3450 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3451 .doit
= wl_cfgvendor_dbg_reset_logging
3455 .vendor_id
= OUI_GOOGLE
,
3456 .subcmd
= DEBUG_TRIGGER_MEM_DUMP
3458 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3459 .doit
= wl_cfgvendor_dbg_trigger_mem_dump
3463 .vendor_id
= OUI_GOOGLE
,
3464 .subcmd
= DEBUG_GET_MEM_DUMP
3466 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3467 .doit
= wl_cfgvendor_dbg_get_mem_dump
3471 .vendor_id
= OUI_GOOGLE
,
3472 .subcmd
= DEBUG_GET_VER
3474 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3475 .doit
= wl_cfgvendor_dbg_get_version
3479 .vendor_id
= OUI_GOOGLE
,
3480 .subcmd
= DEBUG_GET_RING_STATUS
3482 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3483 .doit
= wl_cfgvendor_dbg_get_ring_status
3487 .vendor_id
= OUI_GOOGLE
,
3488 .subcmd
= DEBUG_GET_RING_DATA
3490 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3491 .doit
= wl_cfgvendor_dbg_get_ring_data
3495 .vendor_id
= OUI_GOOGLE
,
3496 .subcmd
= DEBUG_GET_FEATURE
3498 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3499 .doit
= wl_cfgvendor_dbg_get_feature
3501 #endif /* DEBUGABILITY */
3505 .vendor_id
= OUI_GOOGLE
,
3506 .subcmd
= DEBUG_START_PKT_FATE_MONITORING
3508 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3509 .doit
= wl_cfgvendor_dbg_start_pkt_fate_monitoring
3513 .vendor_id
= OUI_GOOGLE
,
3514 .subcmd
= DEBUG_GET_TX_PKT_FATES
3516 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3517 .doit
= wl_cfgvendor_dbg_get_tx_pkt_fates
3521 .vendor_id
= OUI_GOOGLE
,
3522 .subcmd
= DEBUG_GET_RX_PKT_FATES
3524 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3525 .doit
= wl_cfgvendor_dbg_get_rx_pkt_fates
3527 #endif /* DBG_PKT_MON */
3531 .vendor_id
= OUI_GOOGLE
,
3532 .subcmd
= WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
3534 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3535 .doit
= wl_cfgvendor_start_mkeep_alive
3539 .vendor_id
= OUI_GOOGLE
,
3540 .subcmd
= WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
3542 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3543 .doit
= wl_cfgvendor_stop_mkeep_alive
3545 #endif /* KEEP_ALIVE */
3546 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
3549 .vendor_id
= OUI_GOOGLE
,
3550 .subcmd
= APF_SUBCMD_GET_CAPABILITIES
3552 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3553 .doit
= wl_cfgvendor_apf_get_capabilities
3558 .vendor_id
= OUI_GOOGLE
,
3559 .subcmd
= APF_SUBCMD_SET_FILTER
3561 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3562 .doit
= wl_cfgvendor_apf_set_filter
3564 #endif /* PKT_FILTER_SUPPORT && APF */
3565 #ifdef NDO_CONFIG_SUPPORT
3568 .vendor_id
= OUI_GOOGLE
,
3569 .subcmd
= WIFI_SUBCMD_CONFIG_ND_OFFLOAD
3571 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3572 .doit
= wl_cfgvendor_configure_nd_offload
3574 #endif /* NDO_CONFIG_SUPPORT */
3575 #ifdef RSSI_MONITOR_SUPPORT
3578 .vendor_id
= OUI_GOOGLE
,
3579 .subcmd
= WIFI_SUBCMD_SET_RSSI_MONITOR
3581 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3582 .doit
= wl_cfgvendor_set_rssi_monitor
3584 #endif /* RSSI_MONITOR_SUPPORT */
3585 #ifdef DHDTCPACK_SUPPRESS
3588 .vendor_id
= OUI_GOOGLE
,
3589 .subcmd
= WIFI_SUBCMD_CONFIG_TCPACK_SUP
3591 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3592 .doit
= wl_cfgvendor_set_tcpack_sup_mode
3594 #endif /* DHDTCPACK_SUPPRESS */
3595 #ifdef DHD_WAKE_STATUS
3598 .vendor_id
= OUI_GOOGLE
,
3599 .subcmd
= DEBUG_GET_WAKE_REASON_STATS
3601 .flags
= WIPHY_VENDOR_CMD_NEED_WDEV
| WIPHY_VENDOR_CMD_NEED_NETDEV
,
3602 .doit
= wl_cfgvendor_get_wake_reason_stats
3604 #endif /* DHD_WAKE_STATUS */
3607 static const struct nl80211_vendor_cmd_info wl_vendor_events
[] = {
3608 { OUI_BRCM
, BRCM_VENDOR_EVENT_UNSPEC
},
3609 { OUI_BRCM
, BRCM_VENDOR_EVENT_PRIV_STR
},
3610 #ifdef GSCAN_SUPPORT
3611 { OUI_GOOGLE
, GOOGLE_GSCAN_SIGNIFICANT_EVENT
},
3612 { OUI_GOOGLE
, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT
},
3613 { OUI_GOOGLE
, GOOGLE_GSCAN_BATCH_SCAN_EVENT
},
3614 { OUI_GOOGLE
, GOOGLE_SCAN_FULL_RESULTS_EVENT
},
3615 #endif /* GSCAN_SUPPORT */
3617 { OUI_GOOGLE
, GOOGLE_RTT_COMPLETE_EVENT
},
3618 #endif /* RTT_SUPPORT */
3619 #ifdef GSCAN_SUPPORT
3620 { OUI_GOOGLE
, GOOGLE_SCAN_COMPLETE_EVENT
},
3621 { OUI_GOOGLE
, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT
},
3622 { OUI_GOOGLE
, GOOGLE_SCAN_EPNO_EVENT
},
3623 #endif /* GSCAN_SUPPORT */
3624 { OUI_GOOGLE
, GOOGLE_DEBUG_RING_EVENT
},
3625 { OUI_GOOGLE
, GOOGLE_FW_DUMP_EVENT
},
3626 #ifdef GSCAN_SUPPORT
3627 { OUI_GOOGLE
, GOOGLE_PNO_HOTSPOT_FOUND_EVENT
},
3628 #endif /* GSCAN_SUPPORT */
3629 { OUI_GOOGLE
, GOOGLE_RSSI_MONITOR_EVENT
},
3630 { OUI_GOOGLE
, GOOGLE_MKEEP_ALIVE_EVENT
},
3631 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_ENABLED
},
3632 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_DISABLED
},
3633 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_PUBLISH_TERMINATED
},
3634 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH
},
3635 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH
},
3636 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED
},
3637 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_DE_EVENT
},
3638 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_FOLLOWUP
},
3639 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_TCA
},
3641 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_DATA_PATH_OPEN
},
3643 { OUI_GOOGLE
, GOOGLE_NAN_EVENT_UNKNOWN
}
3646 int wl_cfgvendor_attach(struct wiphy
*wiphy
, dhd_pub_t
*dhd
)
3649 WL_INFORM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
3650 NL80211_CMD_VENDOR
));
3652 wiphy
->vendor_commands
= wl_vendor_cmds
;
3653 wiphy
->n_vendor_commands
= ARRAY_SIZE(wl_vendor_cmds
);
3654 wiphy
->vendor_events
= wl_vendor_events
;
3655 wiphy
->n_vendor_events
= ARRAY_SIZE(wl_vendor_events
);
3658 dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID
, wl_cfgvendor_dbg_ring_send_evt
);
3659 dhd_os_dbg_register_callback(FW_EVENT_RING_ID
, wl_cfgvendor_dbg_ring_send_evt
);
3660 dhd_os_dbg_register_callback(DHD_EVENT_RING_ID
, wl_cfgvendor_dbg_ring_send_evt
);
3661 dhd_os_dbg_register_callback(NAN_EVENT_RING_ID
, wl_cfgvendor_dbg_ring_send_evt
);
3662 dhd_os_dbg_register_urgent_notifier(dhd
, wl_cfgvendor_dbg_send_urgent_evt
);
3663 #endif /* DEBUGABILITY */
3668 int wl_cfgvendor_detach(struct wiphy
*wiphy
)
3670 WL_INFORM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
3672 wiphy
->vendor_commands
= NULL
;
3673 wiphy
->vendor_events
= NULL
;
3674 wiphy
->n_vendor_commands
= 0;
3675 wiphy
->n_vendor_events
= 0;
3679 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */