xref: /OK3568_Linux_fs/external/rkwifibt/drivers/infineon/wl_cfgvendor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Linux cfg80211 Vendor Extension Code
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Portions of this code are copyright (c) 2021 Cypress Semiconductor Corporation
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 1999-2017, Broadcom Corporation
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *      Unless you and Broadcom execute a separate written software license
9*4882a593Smuzhiyun  * agreement governing use of this software, this software is licensed to you
10*4882a593Smuzhiyun  * under the terms of the GNU General Public License version 2 (the "GPL"),
11*4882a593Smuzhiyun  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12*4882a593Smuzhiyun  * following added to such license:
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *      As a special exception, the copyright holders of this software give you
15*4882a593Smuzhiyun  * permission to link this software with independent modules, and to copy and
16*4882a593Smuzhiyun  * distribute the resulting executable under terms of your choice, provided that
17*4882a593Smuzhiyun  * you also meet, for each linked independent module, the terms and conditions of
18*4882a593Smuzhiyun  * the license of that module.  An independent module is a module which is not
19*4882a593Smuzhiyun  * derived from this software.  The special exception does not apply to any
20*4882a593Smuzhiyun  * modifications of the software.
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  *      Notwithstanding the above, under no circumstances may you combine this
23*4882a593Smuzhiyun  * software in any way with any other Broadcom software provided under a license
24*4882a593Smuzhiyun  * other than the GPL, without Broadcom's express prior written consent.
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * <<Broadcom-WL-IPTag/Open:>>
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * $Id: wl_cfgvendor.c 815871 2019-04-22 06:21:38Z $
30*4882a593Smuzhiyun  */
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * New vendor interface additon to nl80211/cfg80211 to allow vendors
34*4882a593Smuzhiyun  * to implement proprietary features over the cfg80211 stack.
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #include <typedefs.h>
38*4882a593Smuzhiyun #include <linuxver.h>
39*4882a593Smuzhiyun #include <osl.h>
40*4882a593Smuzhiyun #include <linux/kernel.h>
41*4882a593Smuzhiyun #include <linux/vmalloc.h>
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #include <bcmutils.h>
44*4882a593Smuzhiyun #include <bcmwifi_channels.h>
45*4882a593Smuzhiyun #include <bcmendian.h>
46*4882a593Smuzhiyun #include <ethernet.h>
47*4882a593Smuzhiyun #include <802.11.h>
48*4882a593Smuzhiyun #include <linux/if_arp.h>
49*4882a593Smuzhiyun #include <asm/uaccess.h>
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #include <dngl_stats.h>
52*4882a593Smuzhiyun #include <dhd.h>
53*4882a593Smuzhiyun #include <dhd_debug.h>
54*4882a593Smuzhiyun #include <dhdioctl.h>
55*4882a593Smuzhiyun #include <wlioctl.h>
56*4882a593Smuzhiyun #include <wlioctl_utils.h>
57*4882a593Smuzhiyun #include <dhd_cfg80211.h>
58*4882a593Smuzhiyun #ifdef DHD_PKT_LOGGING
59*4882a593Smuzhiyun #include <dhd_pktlog.h>
60*4882a593Smuzhiyun #endif /* DHD_PKT_LOGGING */
61*4882a593Smuzhiyun #ifdef PNO_SUPPORT
62*4882a593Smuzhiyun #include <dhd_pno.h>
63*4882a593Smuzhiyun #endif /* PNO_SUPPORT */
64*4882a593Smuzhiyun #ifdef RTT_SUPPORT
65*4882a593Smuzhiyun #include <dhd_rtt.h>
66*4882a593Smuzhiyun #endif /* RTT_SUPPORT */
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #include <ethernet.h>
69*4882a593Smuzhiyun #include <linux/kernel.h>
70*4882a593Smuzhiyun #include <linux/kthread.h>
71*4882a593Smuzhiyun #include <linux/netdevice.h>
72*4882a593Smuzhiyun #include <linux/sched.h>
73*4882a593Smuzhiyun #include <linux/etherdevice.h>
74*4882a593Smuzhiyun #include <linux/wireless.h>
75*4882a593Smuzhiyun #include <linux/ieee80211.h>
76*4882a593Smuzhiyun #include <linux/wait.h>
77*4882a593Smuzhiyun #include <net/cfg80211.h>
78*4882a593Smuzhiyun #include <net/rtnetlink.h>
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun #include <wlioctl.h>
81*4882a593Smuzhiyun #include <wldev_common.h>
82*4882a593Smuzhiyun #include <wl_cfg80211.h>
83*4882a593Smuzhiyun #include <wl_cfgp2p.h>
84*4882a593Smuzhiyun #ifdef WL_NAN
85*4882a593Smuzhiyun #include <wl_cfgnan.h>
86*4882a593Smuzhiyun #endif /* WL_NAN */
87*4882a593Smuzhiyun #ifdef OEM_ANDROID
88*4882a593Smuzhiyun #include <wl_android.h>
89*4882a593Smuzhiyun #endif /* OEM_ANDROID */
90*4882a593Smuzhiyun #include <wl_cfgvendor.h>
91*4882a593Smuzhiyun #ifdef PROP_TXSTATUS
92*4882a593Smuzhiyun #include <dhd_wlfc.h>
93*4882a593Smuzhiyun #endif // endif
94*4882a593Smuzhiyun #include <brcm_nl80211.h>
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun char*
wl_get_kernel_timestamp(void)97*4882a593Smuzhiyun wl_get_kernel_timestamp(void)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	static char buf[32];
100*4882a593Smuzhiyun 	u64 ts_nsec;
101*4882a593Smuzhiyun 	unsigned long rem_nsec;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	ts_nsec = local_clock();
104*4882a593Smuzhiyun 	rem_nsec = DIV_AND_MOD_U64_BY_U32(ts_nsec, NSEC_PER_SEC);
105*4882a593Smuzhiyun 	snprintf(buf, sizeof(buf), "%5lu.%06lu",
106*4882a593Smuzhiyun 		(unsigned long)ts_nsec, rem_nsec / NSEC_PER_USEC);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return buf;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
112*4882a593Smuzhiyun #if defined(WL_SUPP_EVENT)
113*4882a593Smuzhiyun int
wl_cfgvendor_send_supp_eventstring(const char * func_name,const char * fmt,...)114*4882a593Smuzhiyun wl_cfgvendor_send_supp_eventstring(const char *func_name, const char *fmt, ...)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	char buf[SUPP_LOG_LEN] = {0};
117*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg;
118*4882a593Smuzhiyun 	struct wiphy *wiphy;
119*4882a593Smuzhiyun 	va_list args;
120*4882a593Smuzhiyun 	int len;
121*4882a593Smuzhiyun 	int prefix_len;
122*4882a593Smuzhiyun 	int rem_len;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	cfg = wl_cfg80211_get_bcmcfg();
125*4882a593Smuzhiyun 	if (!cfg || !cfg->wdev) {
126*4882a593Smuzhiyun 		WL_DBG(("supp evt invalid arg\n"));
127*4882a593Smuzhiyun 		return BCME_OK;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	wiphy = cfg->wdev->wiphy;
131*4882a593Smuzhiyun 	prefix_len = snprintf(buf, SUPP_LOG_LEN, "[DHD]<%s> %s: ",
132*4882a593Smuzhiyun 		wl_get_kernel_timestamp(), __func__);
133*4882a593Smuzhiyun 	/* Remaining buffer len */
134*4882a593Smuzhiyun 	rem_len = SUPP_LOG_LEN - (prefix_len + 1);
135*4882a593Smuzhiyun 	/* Print the arg list on to the remaining part of the buffer */
136*4882a593Smuzhiyun 	va_start(args, fmt);
137*4882a593Smuzhiyun 	len = vsnprintf((buf + prefix_len), rem_len, fmt, args);
138*4882a593Smuzhiyun 	va_end(args);
139*4882a593Smuzhiyun 	if (len < 0) {
140*4882a593Smuzhiyun 		return -EINVAL;
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (len > rem_len) {
144*4882a593Smuzhiyun 		/* If return length is greater than buffer len,
145*4882a593Smuzhiyun 		 * then its truncated buffer case.
146*4882a593Smuzhiyun 		 */
147*4882a593Smuzhiyun 		len = rem_len;
148*4882a593Smuzhiyun 	}
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	/* Ensure the buffer is null terminated */
151*4882a593Smuzhiyun 	len += prefix_len;
152*4882a593Smuzhiyun 	buf[len] = '\0';
153*4882a593Smuzhiyun 	len++;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return wl_cfgvendor_send_async_event(wiphy,
156*4882a593Smuzhiyun 		bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_PRIV_STR, buf, len);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun int
wl_cfgvendor_notify_supp_event_str(const char * evt_name,const char * fmt,...)160*4882a593Smuzhiyun wl_cfgvendor_notify_supp_event_str(const char *evt_name, const char *fmt, ...)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun 	char buf[SUPP_LOG_LEN] = {0};
163*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg;
164*4882a593Smuzhiyun 	struct wiphy *wiphy;
165*4882a593Smuzhiyun 	va_list args;
166*4882a593Smuzhiyun 	int len;
167*4882a593Smuzhiyun 	int prefix_len;
168*4882a593Smuzhiyun 	int rem_len;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	cfg = wl_cfg80211_get_bcmcfg();
171*4882a593Smuzhiyun 	if (!cfg || !cfg->wdev) {
172*4882a593Smuzhiyun 		WL_DBG(("supp evt invalid arg\n"));
173*4882a593Smuzhiyun 		return BCME_OK;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 	wiphy = cfg->wdev->wiphy;
176*4882a593Smuzhiyun 	prefix_len = snprintf(buf, SUPP_LOG_LEN, "%s ", evt_name);
177*4882a593Smuzhiyun 	/* Remaining buffer len */
178*4882a593Smuzhiyun 	rem_len = SUPP_LOG_LEN - (prefix_len + 1);
179*4882a593Smuzhiyun 	/* Print the arg list on to the remaining part of the buffer */
180*4882a593Smuzhiyun 	va_start(args, fmt);
181*4882a593Smuzhiyun 	len = vsnprintf((buf + prefix_len), rem_len, fmt, args);
182*4882a593Smuzhiyun 	va_end(args);
183*4882a593Smuzhiyun 	if (len < 0) {
184*4882a593Smuzhiyun 		return -EINVAL;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if (len > rem_len) {
188*4882a593Smuzhiyun 		/* If return length is greater than buffer len,
189*4882a593Smuzhiyun 		 * then its truncated buffer case.
190*4882a593Smuzhiyun 		 */
191*4882a593Smuzhiyun 		len = rem_len;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* Ensure the buffer is null terminated */
195*4882a593Smuzhiyun 	len += prefix_len;
196*4882a593Smuzhiyun 	buf[len] = '\0';
197*4882a593Smuzhiyun 	len++;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	return wl_cfgvendor_send_async_event(wiphy,
200*4882a593Smuzhiyun 		bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_PRIV_STR, buf, len);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun #endif /* WL_SUPP_EVENT */
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun /*
205*4882a593Smuzhiyun  * This API is to be used for asynchronous vendor events. This
206*4882a593Smuzhiyun  * shouldn't be used in response to a vendor command from its
207*4882a593Smuzhiyun  * do_it handler context (instead wl_cfgvendor_send_cmd_reply should
208*4882a593Smuzhiyun  * be used).
209*4882a593Smuzhiyun  */
wl_cfgvendor_send_async_event(struct wiphy * wiphy,struct net_device * dev,int event_id,const void * data,int len)210*4882a593Smuzhiyun int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
211*4882a593Smuzhiyun 	struct net_device *dev, int event_id, const void  *data, int len)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	gfp_t kflags;
214*4882a593Smuzhiyun 	struct sk_buff *skb;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
219*4882a593Smuzhiyun #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
220*4882a593Smuzhiyun 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
221*4882a593Smuzhiyun 	skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev), len, event_id, kflags);
222*4882a593Smuzhiyun #else
223*4882a593Smuzhiyun 	skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
224*4882a593Smuzhiyun #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
225*4882a593Smuzhiyun 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
226*4882a593Smuzhiyun 	if (!skb) {
227*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
228*4882a593Smuzhiyun 		return -ENOMEM;
229*4882a593Smuzhiyun 	}
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	/* Push the data to the skb */
232*4882a593Smuzhiyun 	nla_put_nohdr(skb, len, data);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	cfg80211_vendor_event(skb, kflags);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	return 0;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun static int
wl_cfgvendor_send_cmd_reply(struct wiphy * wiphy,const void * data,int len)240*4882a593Smuzhiyun wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
241*4882a593Smuzhiyun 	const void  *data, int len)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	struct sk_buff *skb;
244*4882a593Smuzhiyun 	int err;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
247*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
248*4882a593Smuzhiyun 	if (unlikely(!skb)) {
249*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
250*4882a593Smuzhiyun 		err = -ENOMEM;
251*4882a593Smuzhiyun 		goto exit;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* Push the data to the skb */
255*4882a593Smuzhiyun 	nla_put_nohdr(skb, len, data);
256*4882a593Smuzhiyun 	err = cfg80211_vendor_cmd_reply(skb);
257*4882a593Smuzhiyun exit:
258*4882a593Smuzhiyun 	WL_DBG(("wl_cfgvendor_send_cmd_reply status %d", err));
259*4882a593Smuzhiyun 	return err;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun static int
wl_cfgvendor_get_feature_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)263*4882a593Smuzhiyun wl_cfgvendor_get_feature_set(struct wiphy *wiphy,
264*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	int err = 0;
267*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
268*4882a593Smuzhiyun 	int reply;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg));
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &reply, sizeof(int));
273*4882a593Smuzhiyun 	if (unlikely(err))
274*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return err;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun static int
wl_cfgvendor_get_feature_set_matrix(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)280*4882a593Smuzhiyun wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
281*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	int err = 0;
284*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
285*4882a593Smuzhiyun 	struct sk_buff *skb;
286*4882a593Smuzhiyun 	int reply;
287*4882a593Smuzhiyun 	int mem_needed, i;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	mem_needed = VENDOR_REPLY_OVERHEAD +
290*4882a593Smuzhiyun 		(ATTRIBUTE_U32_LEN * MAX_FEATURE_SET_CONCURRRENT_GROUPS) + ATTRIBUTE_U32_LEN;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
293*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
294*4882a593Smuzhiyun 	if (unlikely(!skb)) {
295*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
296*4882a593Smuzhiyun 		err = -ENOMEM;
297*4882a593Smuzhiyun 		goto exit;
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	err = nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
301*4882a593Smuzhiyun 		MAX_FEATURE_SET_CONCURRRENT_GROUPS);
302*4882a593Smuzhiyun 	if (unlikely(err)) {
303*4882a593Smuzhiyun 		kfree_skb(skb);
304*4882a593Smuzhiyun 		goto exit;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 	for (i = 0; i < MAX_FEATURE_SET_CONCURRRENT_GROUPS; i++) {
307*4882a593Smuzhiyun 		reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), i);
308*4882a593Smuzhiyun 		if (reply != WIFI_FEATURE_INVALID) {
309*4882a593Smuzhiyun 			err = nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
310*4882a593Smuzhiyun 				reply);
311*4882a593Smuzhiyun 			if (unlikely(err)) {
312*4882a593Smuzhiyun 				kfree_skb(skb);
313*4882a593Smuzhiyun 				goto exit;
314*4882a593Smuzhiyun 			}
315*4882a593Smuzhiyun 		}
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	err =  cfg80211_vendor_cmd_reply(skb);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (unlikely(err)) {
321*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun exit:
324*4882a593Smuzhiyun 	return err;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun static int
wl_cfgvendor_set_pno_rand_mac_oui(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)328*4882a593Smuzhiyun wl_cfgvendor_set_pno_rand_mac_oui(struct wiphy *wiphy,
329*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	int err = -EINVAL;
332*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
333*4882a593Smuzhiyun 	int type;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	if (!data) {
336*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
337*4882a593Smuzhiyun 		goto exit;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	if (len <= 0) {
341*4882a593Smuzhiyun 		WL_ERR(("invalid len %d\n", len));
342*4882a593Smuzhiyun 		goto exit;
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	type = nla_type(data);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	if (type == ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI) {
348*4882a593Smuzhiyun 		if (nla_len(data) != DOT11_OUI_LEN) {
349*4882a593Smuzhiyun 			WL_ERR(("nla_len not matched.\n"));
350*4882a593Smuzhiyun 			goto exit;
351*4882a593Smuzhiyun 		}
352*4882a593Smuzhiyun 		err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), nla_data(data));
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 		if (unlikely(err))
355*4882a593Smuzhiyun 			WL_ERR(("Bad OUI, could not set:%d \n", err));
356*4882a593Smuzhiyun 	}
357*4882a593Smuzhiyun exit:
358*4882a593Smuzhiyun 	return err;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun #ifdef CUSTOM_FORCE_NODFS_FLAG
361*4882a593Smuzhiyun static int
wl_cfgvendor_set_nodfs_flag(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)362*4882a593Smuzhiyun wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy,
363*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	int err = -EINVAL;
366*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
367*4882a593Smuzhiyun 	int type;
368*4882a593Smuzhiyun 	u32 nodfs;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (!data) {
371*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
372*4882a593Smuzhiyun 		return -EINVAL;
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (len <= 0) {
376*4882a593Smuzhiyun 		WL_ERR(("invalid len %d\n", len));
377*4882a593Smuzhiyun 		return -EINVAL;
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	type = nla_type(data);
381*4882a593Smuzhiyun 	if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) {
382*4882a593Smuzhiyun 		nodfs = nla_get_u32(data);
383*4882a593Smuzhiyun 		err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs);
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	return err;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun #endif /* CUSTOM_FORCE_NODFS_FLAG */
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun static int
wl_cfgvendor_set_country(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)391*4882a593Smuzhiyun wl_cfgvendor_set_country(struct wiphy *wiphy,
392*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	int err = BCME_ERROR, rem, type;
395*4882a593Smuzhiyun 	char country_code[WLC_CNTRY_BUF_SZ] = {0};
396*4882a593Smuzhiyun 	const struct nlattr *iter;
397*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
398*4882a593Smuzhiyun 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
401*4882a593Smuzhiyun 		type = nla_type(iter);
402*4882a593Smuzhiyun 		switch (type) {
403*4882a593Smuzhiyun 			case ANDR_WIFI_ATTRIBUTE_COUNTRY:
404*4882a593Smuzhiyun 				err = memcpy_s(country_code, WLC_CNTRY_BUF_SZ,
405*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
406*4882a593Smuzhiyun 				if (err) {
407*4882a593Smuzhiyun 					WL_ERR(("Failed to copy country code: %d\n", err));
408*4882a593Smuzhiyun 					return err;
409*4882a593Smuzhiyun 				}
410*4882a593Smuzhiyun 				break;
411*4882a593Smuzhiyun 			default:
412*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
413*4882a593Smuzhiyun 				return err;
414*4882a593Smuzhiyun 		}
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 	/* country code is unique for dongle..hence using primary interface. */
417*4882a593Smuzhiyun 	err = wl_cfg80211_set_country_code(primary_ndev, country_code, true, true, -1);
418*4882a593Smuzhiyun 	if (err < 0) {
419*4882a593Smuzhiyun 		WL_ERR(("Set country failed ret:%d\n", err));
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	return err;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun #ifdef GSCAN_SUPPORT
426*4882a593Smuzhiyun int
wl_cfgvendor_send_hotlist_event(struct wiphy * wiphy,struct net_device * dev,void * data,int len,wl_vendor_event_t event)427*4882a593Smuzhiyun wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
428*4882a593Smuzhiyun 	struct net_device *dev, void  *data, int len, wl_vendor_event_t event)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun 	gfp_t kflags;
431*4882a593Smuzhiyun 	const void *ptr;
432*4882a593Smuzhiyun 	struct sk_buff *skb;
433*4882a593Smuzhiyun 	int malloc_len, total, iter_cnt_to_send, cnt;
434*4882a593Smuzhiyun 	gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	total = len/sizeof(wifi_gscan_result_t);
437*4882a593Smuzhiyun 	while (total > 0) {
438*4882a593Smuzhiyun 		malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD;
439*4882a593Smuzhiyun 		if (malloc_len > NLMSG_DEFAULT_SIZE) {
440*4882a593Smuzhiyun 			malloc_len = NLMSG_DEFAULT_SIZE;
441*4882a593Smuzhiyun 		}
442*4882a593Smuzhiyun 		iter_cnt_to_send =
443*4882a593Smuzhiyun 		   (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t);
444*4882a593Smuzhiyun 		total = total - iter_cnt_to_send;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 		kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 		/* Alloc the SKB for vendor_event */
449*4882a593Smuzhiyun #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
450*4882a593Smuzhiyun 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
451*4882a593Smuzhiyun 		skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev),
452*4882a593Smuzhiyun 		malloc_len, event, kflags);
453*4882a593Smuzhiyun #else
454*4882a593Smuzhiyun 		skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags);
455*4882a593Smuzhiyun #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
456*4882a593Smuzhiyun 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
457*4882a593Smuzhiyun 		if (!skb) {
458*4882a593Smuzhiyun 			WL_ERR(("skb alloc failed"));
459*4882a593Smuzhiyun 			return -ENOMEM;
460*4882a593Smuzhiyun 		}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 		while (cache && iter_cnt_to_send) {
463*4882a593Smuzhiyun 			ptr = (const void *) &cache->results[cache->tot_consumed];
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 			if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) {
466*4882a593Smuzhiyun 				cnt = iter_cnt_to_send;
467*4882a593Smuzhiyun 			} else {
468*4882a593Smuzhiyun 				cnt = (cache->tot_count - cache->tot_consumed);
469*4882a593Smuzhiyun 			}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 			iter_cnt_to_send -= cnt;
472*4882a593Smuzhiyun 			cache->tot_consumed += cnt;
473*4882a593Smuzhiyun 			/* Push the data to the skb */
474*4882a593Smuzhiyun 			nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
475*4882a593Smuzhiyun 			if (cache->tot_consumed == cache->tot_count) {
476*4882a593Smuzhiyun 				cache = cache->next;
477*4882a593Smuzhiyun 			}
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 		}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 		cfg80211_vendor_event(skb, kflags);
482*4882a593Smuzhiyun 	}
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	return 0;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun static int
wl_cfgvendor_gscan_get_capabilities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)488*4882a593Smuzhiyun wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
489*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	int err = 0;
492*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
493*4882a593Smuzhiyun 	dhd_pno_gscan_capabilities_t *reply = NULL;
494*4882a593Smuzhiyun 	uint32 reply_len = 0;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
497*4882a593Smuzhiyun 	   DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
498*4882a593Smuzhiyun 	if (!reply) {
499*4882a593Smuzhiyun 		WL_ERR(("Could not get capabilities\n"));
500*4882a593Smuzhiyun 		err = -EINVAL;
501*4882a593Smuzhiyun 		return err;
502*4882a593Smuzhiyun 	}
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	err =  wl_cfgvendor_send_cmd_reply(wiphy, reply, reply_len);
505*4882a593Smuzhiyun 	if (unlikely(err)) {
506*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
507*4882a593Smuzhiyun 	}
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	MFREE(cfg->osh, reply, reply_len);
510*4882a593Smuzhiyun 	return err;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun static int
wl_cfgvendor_gscan_get_batch_results(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)514*4882a593Smuzhiyun wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
515*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	int err = 0;
518*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
519*4882a593Smuzhiyun 	gscan_results_cache_t *results, *iter;
520*4882a593Smuzhiyun 	uint32 reply_len, is_done = 1;
521*4882a593Smuzhiyun 	int32 mem_needed, num_results_iter;
522*4882a593Smuzhiyun 	wifi_gscan_result_t *ptr;
523*4882a593Smuzhiyun 	uint16 num_scan_ids, num_results;
524*4882a593Smuzhiyun 	struct sk_buff *skb;
525*4882a593Smuzhiyun 	struct nlattr *scan_hdr, *complete_flag;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
528*4882a593Smuzhiyun 	if (err != BCME_OK)
529*4882a593Smuzhiyun 		return -EBUSY;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
532*4882a593Smuzhiyun 	if (err != BCME_OK) {
533*4882a593Smuzhiyun 		WL_ERR(("Can't obtain lock to access batch results %d\n", err));
534*4882a593Smuzhiyun 		return -EBUSY;
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 	results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
537*4882a593Smuzhiyun 	             DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	if (!results) {
540*4882a593Smuzhiyun 		WL_ERR(("No results to send %d\n", err));
541*4882a593Smuzhiyun 		err =  wl_cfgvendor_send_cmd_reply(wiphy, results, 0);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 		if (unlikely(err))
544*4882a593Smuzhiyun 			WL_ERR(("Vendor Command reply failed ret:%d \n", err));
545*4882a593Smuzhiyun 		dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
546*4882a593Smuzhiyun 		return err;
547*4882a593Smuzhiyun 	}
548*4882a593Smuzhiyun 	num_scan_ids = reply_len & 0xFFFF;
549*4882a593Smuzhiyun 	num_results = (reply_len & 0xFFFF0000) >> 16;
550*4882a593Smuzhiyun 	mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
551*4882a593Smuzhiyun 	             (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
552*4882a593Smuzhiyun 	             VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
555*4882a593Smuzhiyun 		mem_needed = (int32)NLMSG_DEFAULT_SIZE;
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	WL_TRACE(("is_done %d mem_needed %d max_mem %d\n", is_done, mem_needed,
559*4882a593Smuzhiyun 		(int)NLMSG_DEFAULT_SIZE));
560*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
561*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
562*4882a593Smuzhiyun 	if (unlikely(!skb)) {
563*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
564*4882a593Smuzhiyun 		dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
565*4882a593Smuzhiyun 		return -ENOMEM;
566*4882a593Smuzhiyun 	}
567*4882a593Smuzhiyun 	iter = results;
568*4882a593Smuzhiyun 	complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,
569*4882a593Smuzhiyun 	                    sizeof(is_done));
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	if (unlikely(!complete_flag)) {
572*4882a593Smuzhiyun 		WL_ERR(("complete_flag could not be reserved"));
573*4882a593Smuzhiyun 		kfree_skb(skb);
574*4882a593Smuzhiyun 		dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
575*4882a593Smuzhiyun 		return -ENOMEM;
576*4882a593Smuzhiyun 	}
577*4882a593Smuzhiyun 	mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	while (iter) {
580*4882a593Smuzhiyun 		num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN);
581*4882a593Smuzhiyun 		num_results_iter /= (int32)sizeof(wifi_gscan_result_t);
582*4882a593Smuzhiyun 		if (num_results_iter <= 0 ||
583*4882a593Smuzhiyun 		    ((iter->tot_count - iter->tot_consumed) > num_results_iter)) {
584*4882a593Smuzhiyun 			break;
585*4882a593Smuzhiyun 		}
586*4882a593Smuzhiyun 		scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
587*4882a593Smuzhiyun 		/* no more room? we are done then (for now) */
588*4882a593Smuzhiyun 		if (scan_hdr == NULL) {
589*4882a593Smuzhiyun 			is_done = 0;
590*4882a593Smuzhiyun 			break;
591*4882a593Smuzhiyun 		}
592*4882a593Smuzhiyun 		err = nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
593*4882a593Smuzhiyun 		if (unlikely(err)) {
594*4882a593Smuzhiyun 			goto fail;
595*4882a593Smuzhiyun 		}
596*4882a593Smuzhiyun 		err = nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
597*4882a593Smuzhiyun 		if (unlikely(err)) {
598*4882a593Smuzhiyun 			goto fail;
599*4882a593Smuzhiyun 		}
600*4882a593Smuzhiyun 		err = nla_put_u32(skb, GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK, iter->scan_ch_bucket);
601*4882a593Smuzhiyun 		if (unlikely(err)) {
602*4882a593Smuzhiyun 			goto fail;
603*4882a593Smuzhiyun 		}
604*4882a593Smuzhiyun 		num_results_iter = iter->tot_count - iter->tot_consumed;
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 		err = nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
607*4882a593Smuzhiyun 		if (unlikely(err)) {
608*4882a593Smuzhiyun 			goto fail;
609*4882a593Smuzhiyun 		}
610*4882a593Smuzhiyun 		if (num_results_iter) {
611*4882a593Smuzhiyun 			ptr = &iter->results[iter->tot_consumed];
612*4882a593Smuzhiyun 			err = nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
613*4882a593Smuzhiyun 			 num_results_iter * sizeof(wifi_gscan_result_t), ptr);
614*4882a593Smuzhiyun 			if (unlikely(err)) {
615*4882a593Smuzhiyun 				goto fail;
616*4882a593Smuzhiyun 			}
617*4882a593Smuzhiyun 			iter->tot_consumed += num_results_iter;
618*4882a593Smuzhiyun 		}
619*4882a593Smuzhiyun 		nla_nest_end(skb, scan_hdr);
620*4882a593Smuzhiyun 		mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
621*4882a593Smuzhiyun 		    (num_results_iter * sizeof(wifi_gscan_result_t));
622*4882a593Smuzhiyun 		iter = iter->next;
623*4882a593Smuzhiyun 	}
624*4882a593Smuzhiyun 	/* Cleans up consumed results and returns TRUE if all results are consumed */
625*4882a593Smuzhiyun 	is_done = dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
626*4882a593Smuzhiyun 	memcpy(nla_data(complete_flag), &is_done, sizeof(is_done));
627*4882a593Smuzhiyun 	dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
628*4882a593Smuzhiyun 	return cfg80211_vendor_cmd_reply(skb);
629*4882a593Smuzhiyun fail:
630*4882a593Smuzhiyun 	/* Free up consumed results which will now not be sent */
631*4882a593Smuzhiyun 	(void)dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
632*4882a593Smuzhiyun 	kfree_skb(skb);
633*4882a593Smuzhiyun 	dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
634*4882a593Smuzhiyun 	return err;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun static int
wl_cfgvendor_initiate_gscan(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)638*4882a593Smuzhiyun wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
639*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun 	int err = 0;
642*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
643*4882a593Smuzhiyun 	int type, tmp = len;
644*4882a593Smuzhiyun 	int run = 0xFF;
645*4882a593Smuzhiyun 	int flush = 0;
646*4882a593Smuzhiyun 	const struct nlattr *iter;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
649*4882a593Smuzhiyun 		type = nla_type(iter);
650*4882a593Smuzhiyun 		if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
651*4882a593Smuzhiyun 			run = nla_get_u32(iter);
652*4882a593Smuzhiyun 		else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
653*4882a593Smuzhiyun 			flush = nla_get_u32(iter);
654*4882a593Smuzhiyun 	}
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	if (run != 0xFF) {
657*4882a593Smuzhiyun 		err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 		if (unlikely(err)) {
660*4882a593Smuzhiyun 			WL_ERR(("Could not run gscan:%d \n", err));
661*4882a593Smuzhiyun 		}
662*4882a593Smuzhiyun 		return err;
663*4882a593Smuzhiyun 	} else {
664*4882a593Smuzhiyun 		return -EINVAL;
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun static int
wl_cfgvendor_enable_full_scan_result(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)670*4882a593Smuzhiyun wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
671*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
672*4882a593Smuzhiyun {
673*4882a593Smuzhiyun 	int err = 0;
674*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
675*4882a593Smuzhiyun 	int type;
676*4882a593Smuzhiyun 	bool real_time = FALSE;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	if (!data) {
679*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
680*4882a593Smuzhiyun 		return -EINVAL;
681*4882a593Smuzhiyun 	}
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	if (len <= 0) {
684*4882a593Smuzhiyun 		WL_ERR(("invalid len %d\n", len));
685*4882a593Smuzhiyun 		return -EINVAL;
686*4882a593Smuzhiyun 	}
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	type = nla_type(data);
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
691*4882a593Smuzhiyun 		real_time = nla_get_u32(data);
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 		err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 		if (unlikely(err)) {
696*4882a593Smuzhiyun 			WL_ERR(("Could not run gscan:%d \n", err));
697*4882a593Smuzhiyun 		}
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	} else {
700*4882a593Smuzhiyun 		err = -EINVAL;
701*4882a593Smuzhiyun 	}
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	return err;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun static int
wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr * prev,gscan_scan_params_t * scan_param,int num)707*4882a593Smuzhiyun wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev,
708*4882a593Smuzhiyun 	gscan_scan_params_t *scan_param, int num)
709*4882a593Smuzhiyun {
710*4882a593Smuzhiyun 	struct dhd_pno_gscan_channel_bucket  *ch_bucket;
711*4882a593Smuzhiyun 	int k = 0;
712*4882a593Smuzhiyun 	int type, err = 0, rem;
713*4882a593Smuzhiyun 	const struct nlattr *cur, *next;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	nla_for_each_nested(cur, prev, rem) {
716*4882a593Smuzhiyun 		type = nla_type(cur);
717*4882a593Smuzhiyun 		ch_bucket = scan_param->channel_bucket;
718*4882a593Smuzhiyun 		switch (type) {
719*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_BUCKET_ID:
720*4882a593Smuzhiyun 			break;
721*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
722*4882a593Smuzhiyun 			if (nla_len(cur) != sizeof(uint32)) {
723*4882a593Smuzhiyun 				err = -EINVAL;
724*4882a593Smuzhiyun 				goto exit;
725*4882a593Smuzhiyun 			}
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 			ch_bucket[num].bucket_freq_multiple =
728*4882a593Smuzhiyun 				nla_get_u32(cur) / MSEC_PER_SEC;
729*4882a593Smuzhiyun 			break;
730*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
731*4882a593Smuzhiyun 			if (nla_len(cur) != sizeof(uint32)) {
732*4882a593Smuzhiyun 				err = -EINVAL;
733*4882a593Smuzhiyun 				goto exit;
734*4882a593Smuzhiyun 			}
735*4882a593Smuzhiyun 			ch_bucket[num].num_channels = nla_get_u32(cur);
736*4882a593Smuzhiyun 			if (ch_bucket[num].num_channels >
737*4882a593Smuzhiyun 				GSCAN_MAX_CHANNELS_IN_BUCKET) {
738*4882a593Smuzhiyun 				WL_ERR(("channel range:%d,bucket:%d\n",
739*4882a593Smuzhiyun 					ch_bucket[num].num_channels,
740*4882a593Smuzhiyun 					num));
741*4882a593Smuzhiyun 				err = -EINVAL;
742*4882a593Smuzhiyun 				goto exit;
743*4882a593Smuzhiyun 			}
744*4882a593Smuzhiyun 			break;
745*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
746*4882a593Smuzhiyun 			nla_for_each_nested(next, cur, rem) {
747*4882a593Smuzhiyun 				if (k >= GSCAN_MAX_CHANNELS_IN_BUCKET)
748*4882a593Smuzhiyun 					break;
749*4882a593Smuzhiyun 				if (nla_len(next) != sizeof(uint32)) {
750*4882a593Smuzhiyun 					err = -EINVAL;
751*4882a593Smuzhiyun 					goto exit;
752*4882a593Smuzhiyun 				}
753*4882a593Smuzhiyun 				ch_bucket[num].chan_list[k] = nla_get_u32(next);
754*4882a593Smuzhiyun 				k++;
755*4882a593Smuzhiyun 			}
756*4882a593Smuzhiyun 			break;
757*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_BUCKETS_BAND:
758*4882a593Smuzhiyun 			if (nla_len(cur) != sizeof(uint32)) {
759*4882a593Smuzhiyun 				err = -EINVAL;
760*4882a593Smuzhiyun 				goto exit;
761*4882a593Smuzhiyun 			}
762*4882a593Smuzhiyun 			ch_bucket[num].band = (uint16)nla_get_u32(cur);
763*4882a593Smuzhiyun 			break;
764*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_REPORT_EVENTS:
765*4882a593Smuzhiyun 			if (nla_len(cur) != sizeof(uint32)) {
766*4882a593Smuzhiyun 				err = -EINVAL;
767*4882a593Smuzhiyun 				goto exit;
768*4882a593Smuzhiyun 			}
769*4882a593Smuzhiyun 			ch_bucket[num].report_flag = (uint8)nla_get_u32(cur);
770*4882a593Smuzhiyun 			break;
771*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT:
772*4882a593Smuzhiyun 			if (nla_len(cur) != sizeof(uint32)) {
773*4882a593Smuzhiyun 				err = -EINVAL;
774*4882a593Smuzhiyun 				goto exit;
775*4882a593Smuzhiyun 			}
776*4882a593Smuzhiyun 			ch_bucket[num].repeat = (uint16)nla_get_u32(cur);
777*4882a593Smuzhiyun 			break;
778*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD:
779*4882a593Smuzhiyun 			if (nla_len(cur) != sizeof(uint32)) {
780*4882a593Smuzhiyun 				err = -EINVAL;
781*4882a593Smuzhiyun 				goto exit;
782*4882a593Smuzhiyun 			}
783*4882a593Smuzhiyun 			ch_bucket[num].bucket_max_multiple =
784*4882a593Smuzhiyun 				nla_get_u32(cur) / MSEC_PER_SEC;
785*4882a593Smuzhiyun 			break;
786*4882a593Smuzhiyun 		default:
787*4882a593Smuzhiyun 			WL_ERR(("unknown attr type:%d\n", type));
788*4882a593Smuzhiyun 			err = -EINVAL;
789*4882a593Smuzhiyun 			goto exit;
790*4882a593Smuzhiyun 		}
791*4882a593Smuzhiyun 	}
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun exit:
794*4882a593Smuzhiyun 	return err;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun static int
wl_cfgvendor_set_scan_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)798*4882a593Smuzhiyun wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, struct wireless_dev *wdev,
799*4882a593Smuzhiyun 	const void  *data, int len)
800*4882a593Smuzhiyun {
801*4882a593Smuzhiyun 	int err = 0;
802*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
803*4882a593Smuzhiyun 	gscan_scan_params_t *scan_param;
804*4882a593Smuzhiyun 	int j = 0;
805*4882a593Smuzhiyun 	int type, tmp;
806*4882a593Smuzhiyun 	const struct nlattr *iter;
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	scan_param = (gscan_scan_params_t *)MALLOCZ(cfg->osh,
809*4882a593Smuzhiyun 		sizeof(gscan_scan_params_t));
810*4882a593Smuzhiyun 	if (!scan_param) {
811*4882a593Smuzhiyun 		WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
812*4882a593Smuzhiyun 		err = -EINVAL;
813*4882a593Smuzhiyun 		return err;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	}
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
818*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
819*4882a593Smuzhiyun 		type = nla_type(iter);
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 		if (j >= GSCAN_MAX_CH_BUCKETS) {
822*4882a593Smuzhiyun 			break;
823*4882a593Smuzhiyun 		}
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 		switch (type) {
826*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_BASE_PERIOD:
827*4882a593Smuzhiyun 				if (nla_len(iter) != sizeof(uint32)) {
828*4882a593Smuzhiyun 					err = -EINVAL;
829*4882a593Smuzhiyun 					goto exit;
830*4882a593Smuzhiyun 				}
831*4882a593Smuzhiyun 				scan_param->scan_fr = nla_get_u32(iter) / MSEC_PER_SEC;
832*4882a593Smuzhiyun 				break;
833*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_NUM_BUCKETS:
834*4882a593Smuzhiyun 				if (nla_len(iter) != sizeof(uint32)) {
835*4882a593Smuzhiyun 					err = -EINVAL;
836*4882a593Smuzhiyun 					goto exit;
837*4882a593Smuzhiyun 				}
838*4882a593Smuzhiyun 				scan_param->nchannel_buckets = nla_get_u32(iter);
839*4882a593Smuzhiyun 				if (scan_param->nchannel_buckets >=
840*4882a593Smuzhiyun 				    GSCAN_MAX_CH_BUCKETS) {
841*4882a593Smuzhiyun 					WL_ERR(("ncha_buck out of range %d\n",
842*4882a593Smuzhiyun 					scan_param->nchannel_buckets));
843*4882a593Smuzhiyun 					err = -EINVAL;
844*4882a593Smuzhiyun 					goto exit;
845*4882a593Smuzhiyun 				}
846*4882a593Smuzhiyun 				break;
847*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_CH_BUCKET_1:
848*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_CH_BUCKET_2:
849*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_CH_BUCKET_3:
850*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_CH_BUCKET_4:
851*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_CH_BUCKET_5:
852*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_CH_BUCKET_6:
853*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_CH_BUCKET_7:
854*4882a593Smuzhiyun 				err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j);
855*4882a593Smuzhiyun 				if (err < 0) {
856*4882a593Smuzhiyun 					WL_ERR(("set_scan_cfg_buck error:%d\n", err));
857*4882a593Smuzhiyun 					goto exit;
858*4882a593Smuzhiyun 				}
859*4882a593Smuzhiyun 				j++;
860*4882a593Smuzhiyun 				break;
861*4882a593Smuzhiyun 			default:
862*4882a593Smuzhiyun 				WL_ERR(("Unknown type %d\n", type));
863*4882a593Smuzhiyun 				err = -EINVAL;
864*4882a593Smuzhiyun 				goto exit;
865*4882a593Smuzhiyun 		}
866*4882a593Smuzhiyun 	}
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
869*4882a593Smuzhiyun 	     DHD_PNO_SCAN_CFG_ID, scan_param, FALSE);
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	if (err < 0) {
872*4882a593Smuzhiyun 		WL_ERR(("Could not set GSCAN scan cfg\n"));
873*4882a593Smuzhiyun 		err = -EINVAL;
874*4882a593Smuzhiyun 	}
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun exit:
877*4882a593Smuzhiyun 	MFREE(cfg->osh, scan_param, sizeof(gscan_scan_params_t));
878*4882a593Smuzhiyun 	return err;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun static int
wl_cfgvendor_hotlist_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)883*4882a593Smuzhiyun wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
884*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun 	int err = 0;
887*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
888*4882a593Smuzhiyun 	gscan_hotlist_scan_params_t *hotlist_params;
889*4882a593Smuzhiyun 	int tmp, tmp1, tmp2, type, j = 0, dummy;
890*4882a593Smuzhiyun 	const struct nlattr *outer, *inner = NULL, *iter;
891*4882a593Smuzhiyun 	bool flush = FALSE;
892*4882a593Smuzhiyun 	struct bssid_t *pbssid;
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	BCM_REFERENCE(dummy);
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) {
897*4882a593Smuzhiyun 		WL_ERR(("buffer length :%d wrong - bail out.\n", len));
898*4882a593Smuzhiyun 		return -EINVAL;
899*4882a593Smuzhiyun 	}
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	hotlist_params = (gscan_hotlist_scan_params_t *)MALLOCZ(cfg->osh,
902*4882a593Smuzhiyun 		sizeof(*hotlist_params)
903*4882a593Smuzhiyun 		+ (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)));
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	if (!hotlist_params) {
906*4882a593Smuzhiyun 		WL_ERR(("Cannot Malloc memory.\n"));
907*4882a593Smuzhiyun 		return -ENOMEM;
908*4882a593Smuzhiyun 	}
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp2) {
913*4882a593Smuzhiyun 		type = nla_type(iter);
914*4882a593Smuzhiyun 		switch (type) {
915*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT:
916*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
917*4882a593Smuzhiyun 				WL_DBG(("type:%d length:%d not matching.\n",
918*4882a593Smuzhiyun 					type, nla_len(iter)));
919*4882a593Smuzhiyun 				err = -EINVAL;
920*4882a593Smuzhiyun 				goto exit;
921*4882a593Smuzhiyun 			}
922*4882a593Smuzhiyun 			hotlist_params->nbssid = (uint16)nla_get_u32(iter);
923*4882a593Smuzhiyun 			if ((hotlist_params->nbssid == 0) ||
924*4882a593Smuzhiyun 			    (hotlist_params->nbssid > PFN_SWC_MAX_NUM_APS)) {
925*4882a593Smuzhiyun 				WL_ERR(("nbssid:%d exceed limit.\n",
926*4882a593Smuzhiyun 					hotlist_params->nbssid));
927*4882a593Smuzhiyun 				err = -EINVAL;
928*4882a593Smuzhiyun 				goto exit;
929*4882a593Smuzhiyun 			}
930*4882a593Smuzhiyun 			break;
931*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
932*4882a593Smuzhiyun 			if (hotlist_params->nbssid == 0) {
933*4882a593Smuzhiyun 				WL_ERR(("nbssid not retrieved.\n"));
934*4882a593Smuzhiyun 				err = -EINVAL;
935*4882a593Smuzhiyun 				goto exit;
936*4882a593Smuzhiyun 			}
937*4882a593Smuzhiyun 			pbssid = hotlist_params->bssid;
938*4882a593Smuzhiyun 			nla_for_each_nested(outer, iter, tmp) {
939*4882a593Smuzhiyun 				if (j >= hotlist_params->nbssid)
940*4882a593Smuzhiyun 					break;
941*4882a593Smuzhiyun 				nla_for_each_nested(inner, outer, tmp1) {
942*4882a593Smuzhiyun 					type = nla_type(inner);
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 					switch (type) {
945*4882a593Smuzhiyun 					case GSCAN_ATTRIBUTE_BSSID:
946*4882a593Smuzhiyun 						if (nla_len(inner) != sizeof(pbssid[j].macaddr)) {
947*4882a593Smuzhiyun 							WL_ERR(("type:%d length:%d not matching.\n",
948*4882a593Smuzhiyun 								type, nla_len(inner)));
949*4882a593Smuzhiyun 							err = -EINVAL;
950*4882a593Smuzhiyun 							goto exit;
951*4882a593Smuzhiyun 						}
952*4882a593Smuzhiyun 						memcpy(
953*4882a593Smuzhiyun 							&(pbssid[j].macaddr),
954*4882a593Smuzhiyun 							nla_data(inner),
955*4882a593Smuzhiyun 							sizeof(pbssid[j].macaddr));
956*4882a593Smuzhiyun 						break;
957*4882a593Smuzhiyun 					case GSCAN_ATTRIBUTE_RSSI_LOW:
958*4882a593Smuzhiyun 						if (nla_len(inner) != sizeof(uint8)) {
959*4882a593Smuzhiyun 							WL_ERR(("type:%d length:%d not matching.\n",
960*4882a593Smuzhiyun 								type, nla_len(inner)));
961*4882a593Smuzhiyun 							err = -EINVAL;
962*4882a593Smuzhiyun 							goto exit;
963*4882a593Smuzhiyun 						}
964*4882a593Smuzhiyun 						pbssid[j].rssi_reporting_threshold =
965*4882a593Smuzhiyun 							(int8)nla_get_u8(inner);
966*4882a593Smuzhiyun 						break;
967*4882a593Smuzhiyun 					case GSCAN_ATTRIBUTE_RSSI_HIGH:
968*4882a593Smuzhiyun 						if (nla_len(inner) != sizeof(uint8)) {
969*4882a593Smuzhiyun 							WL_ERR(("type:%d length:%d not matching.\n",
970*4882a593Smuzhiyun 								type, nla_len(inner)));
971*4882a593Smuzhiyun 							err = -EINVAL;
972*4882a593Smuzhiyun 							goto exit;
973*4882a593Smuzhiyun 						}
974*4882a593Smuzhiyun 						dummy = (int8)nla_get_u8(inner);
975*4882a593Smuzhiyun 						WL_DBG(("dummy %d\n", dummy));
976*4882a593Smuzhiyun 						break;
977*4882a593Smuzhiyun 					default:
978*4882a593Smuzhiyun 						WL_ERR(("ATTR unknown %d\n", type));
979*4882a593Smuzhiyun 						err = -EINVAL;
980*4882a593Smuzhiyun 						goto exit;
981*4882a593Smuzhiyun 					}
982*4882a593Smuzhiyun 				}
983*4882a593Smuzhiyun 				j++;
984*4882a593Smuzhiyun 			}
985*4882a593Smuzhiyun 			if (j != hotlist_params->nbssid) {
986*4882a593Smuzhiyun 				WL_ERR(("bssid_cnt:%d != nbssid:%d.\n", j,
987*4882a593Smuzhiyun 					hotlist_params->nbssid));
988*4882a593Smuzhiyun 				err = -EINVAL;
989*4882a593Smuzhiyun 				goto exit;
990*4882a593Smuzhiyun 			}
991*4882a593Smuzhiyun 			break;
992*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
993*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
994*4882a593Smuzhiyun 				WL_ERR(("type:%d length:%d not matching.\n",
995*4882a593Smuzhiyun 					type, nla_len(iter)));
996*4882a593Smuzhiyun 				err = -EINVAL;
997*4882a593Smuzhiyun 				goto exit;
998*4882a593Smuzhiyun 			}
999*4882a593Smuzhiyun 			flush = nla_get_u8(iter);
1000*4882a593Smuzhiyun 			break;
1001*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
1002*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
1003*4882a593Smuzhiyun 				WL_ERR(("type:%d length:%d not matching.\n",
1004*4882a593Smuzhiyun 					type, nla_len(iter)));
1005*4882a593Smuzhiyun 				err = -EINVAL;
1006*4882a593Smuzhiyun 				goto exit;
1007*4882a593Smuzhiyun 			}
1008*4882a593Smuzhiyun 			hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter);
1009*4882a593Smuzhiyun 			break;
1010*4882a593Smuzhiyun 		default:
1011*4882a593Smuzhiyun 			WL_ERR(("Unknown type %d\n", type));
1012*4882a593Smuzhiyun 			err = -EINVAL;
1013*4882a593Smuzhiyun 			goto exit;
1014*4882a593Smuzhiyun 		}
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	}
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1019*4882a593Smuzhiyun 	      DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
1020*4882a593Smuzhiyun 		WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err));
1021*4882a593Smuzhiyun 		err = -EINVAL;
1022*4882a593Smuzhiyun 		goto exit;
1023*4882a593Smuzhiyun 	}
1024*4882a593Smuzhiyun exit:
1025*4882a593Smuzhiyun 	MFREE(cfg->osh, hotlist_params, sizeof(*hotlist_params)
1026*4882a593Smuzhiyun 		+ (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)));
1027*4882a593Smuzhiyun 	return err;
1028*4882a593Smuzhiyun }
1029*4882a593Smuzhiyun 
wl_cfgvendor_epno_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1030*4882a593Smuzhiyun static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy,
1031*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
1032*4882a593Smuzhiyun {
1033*4882a593Smuzhiyun 	int err = 0;
1034*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1035*4882a593Smuzhiyun 	dhd_pno_ssid_t *ssid_elem = NULL;
1036*4882a593Smuzhiyun 	int tmp, tmp1, tmp2, type = 0, num = 0;
1037*4882a593Smuzhiyun 	const struct nlattr *outer, *inner, *iter;
1038*4882a593Smuzhiyun 	uint8 flush = FALSE, i = 0;
1039*4882a593Smuzhiyun 	wl_ssid_ext_params_t params;
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp2) {
1042*4882a593Smuzhiyun 		type = nla_type(iter);
1043*4882a593Smuzhiyun 		switch (type) {
1044*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_SSID_LIST:
1045*4882a593Smuzhiyun 				nla_for_each_nested(outer, iter, tmp) {
1046*4882a593Smuzhiyun 					ssid_elem = (dhd_pno_ssid_t *)
1047*4882a593Smuzhiyun 						dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
1048*4882a593Smuzhiyun 						DHD_PNO_GET_NEW_EPNO_SSID_ELEM,
1049*4882a593Smuzhiyun 						NULL, &num);
1050*4882a593Smuzhiyun 					if (!ssid_elem) {
1051*4882a593Smuzhiyun 						WL_ERR(("Failed to get SSID LIST buffer\n"));
1052*4882a593Smuzhiyun 						err = -ENOMEM;
1053*4882a593Smuzhiyun 						goto exit;
1054*4882a593Smuzhiyun 					}
1055*4882a593Smuzhiyun 					i++;
1056*4882a593Smuzhiyun 					nla_for_each_nested(inner, outer, tmp1) {
1057*4882a593Smuzhiyun 						type = nla_type(inner);
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun 						switch (type) {
1060*4882a593Smuzhiyun 							case GSCAN_ATTRIBUTE_EPNO_SSID:
1061*4882a593Smuzhiyun 								memcpy(ssid_elem->SSID,
1062*4882a593Smuzhiyun 								  nla_data(inner),
1063*4882a593Smuzhiyun 								  DOT11_MAX_SSID_LEN);
1064*4882a593Smuzhiyun 								break;
1065*4882a593Smuzhiyun 							case GSCAN_ATTRIBUTE_EPNO_SSID_LEN:
1066*4882a593Smuzhiyun 								ssid_elem->SSID_len =
1067*4882a593Smuzhiyun 									nla_get_u32(inner);
1068*4882a593Smuzhiyun 								if (ssid_elem->SSID_len >
1069*4882a593Smuzhiyun 									DOT11_MAX_SSID_LEN) {
1070*4882a593Smuzhiyun 									WL_ERR(("SSID too"
1071*4882a593Smuzhiyun 									"long %d\n",
1072*4882a593Smuzhiyun 									ssid_elem->SSID_len));
1073*4882a593Smuzhiyun 									err = -EINVAL;
1074*4882a593Smuzhiyun 									MFREE(cfg->osh, ssid_elem,
1075*4882a593Smuzhiyun 										num);
1076*4882a593Smuzhiyun 									goto exit;
1077*4882a593Smuzhiyun 								}
1078*4882a593Smuzhiyun 								break;
1079*4882a593Smuzhiyun 							case GSCAN_ATTRIBUTE_EPNO_FLAGS:
1080*4882a593Smuzhiyun 								ssid_elem->flags =
1081*4882a593Smuzhiyun 									nla_get_u32(inner);
1082*4882a593Smuzhiyun 								ssid_elem->hidden =
1083*4882a593Smuzhiyun 									((ssid_elem->flags &
1084*4882a593Smuzhiyun 									DHD_EPNO_HIDDEN_SSID) != 0);
1085*4882a593Smuzhiyun 								break;
1086*4882a593Smuzhiyun 							case GSCAN_ATTRIBUTE_EPNO_AUTH:
1087*4882a593Smuzhiyun 								ssid_elem->wpa_auth =
1088*4882a593Smuzhiyun 								        nla_get_u32(inner);
1089*4882a593Smuzhiyun 								break;
1090*4882a593Smuzhiyun 						}
1091*4882a593Smuzhiyun 					}
1092*4882a593Smuzhiyun 					if (!ssid_elem->SSID_len) {
1093*4882a593Smuzhiyun 						WL_ERR(("Broadcast SSID is illegal for ePNO\n"));
1094*4882a593Smuzhiyun 						err = -EINVAL;
1095*4882a593Smuzhiyun 						MFREE(cfg->osh, ssid_elem, num);
1096*4882a593Smuzhiyun 						goto exit;
1097*4882a593Smuzhiyun 					}
1098*4882a593Smuzhiyun 					dhd_pno_translate_epno_fw_flags(&ssid_elem->flags);
1099*4882a593Smuzhiyun 					dhd_pno_set_epno_auth_flag(&ssid_elem->wpa_auth);
1100*4882a593Smuzhiyun 					MFREE(cfg->osh, ssid_elem, num);
1101*4882a593Smuzhiyun 				}
1102*4882a593Smuzhiyun 				break;
1103*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_SSID_NUM:
1104*4882a593Smuzhiyun 				num = nla_get_u8(iter);
1105*4882a593Smuzhiyun 				break;
1106*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_FLUSH:
1107*4882a593Smuzhiyun 				flush = (bool)nla_get_u32(iter);
1108*4882a593Smuzhiyun 				/* Flush attribute is expected before any ssid attribute */
1109*4882a593Smuzhiyun 				if (i && flush) {
1110*4882a593Smuzhiyun 					WL_ERR(("Bad attributes\n"));
1111*4882a593Smuzhiyun 					err = -EINVAL;
1112*4882a593Smuzhiyun 					goto exit;
1113*4882a593Smuzhiyun 				}
1114*4882a593Smuzhiyun 				/* Need to flush driver and FW cfg */
1115*4882a593Smuzhiyun 				dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1116*4882a593Smuzhiyun 				DHD_PNO_EPNO_CFG_ID, NULL, flush);
1117*4882a593Smuzhiyun 				dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
1118*4882a593Smuzhiyun 				break;
1119*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR:
1120*4882a593Smuzhiyun 				params.min5G_rssi = nla_get_s8(iter);
1121*4882a593Smuzhiyun 				break;
1122*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR:
1123*4882a593Smuzhiyun 				params.min2G_rssi = nla_get_s8(iter);
1124*4882a593Smuzhiyun 				break;
1125*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX:
1126*4882a593Smuzhiyun 				params.init_score_max = nla_get_s16(iter);
1127*4882a593Smuzhiyun 				break;
1128*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS:
1129*4882a593Smuzhiyun 				params.cur_bssid_bonus = nla_get_s16(iter);
1130*4882a593Smuzhiyun 				break;
1131*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS:
1132*4882a593Smuzhiyun 				params.same_ssid_bonus = nla_get_s16(iter);
1133*4882a593Smuzhiyun 				break;
1134*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS:
1135*4882a593Smuzhiyun 				params.secure_bonus = nla_get_s16(iter);
1136*4882a593Smuzhiyun 				break;
1137*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_EPNO_5G_BONUS:
1138*4882a593Smuzhiyun 				params.band_5g_bonus = nla_get_s16(iter);
1139*4882a593Smuzhiyun 				break;
1140*4882a593Smuzhiyun 			default:
1141*4882a593Smuzhiyun 				WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1142*4882a593Smuzhiyun 				err = -EINVAL;
1143*4882a593Smuzhiyun 				goto exit;
1144*4882a593Smuzhiyun 			}
1145*4882a593Smuzhiyun 	}
1146*4882a593Smuzhiyun 	if (i != num) {
1147*4882a593Smuzhiyun 		WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__,
1148*4882a593Smuzhiyun 		     num, i));
1149*4882a593Smuzhiyun 		err = -EINVAL;
1150*4882a593Smuzhiyun 	}
1151*4882a593Smuzhiyun exit:
1152*4882a593Smuzhiyun 	/* Flush all configs if error condition */
1153*4882a593Smuzhiyun 	if (err < 0) {
1154*4882a593Smuzhiyun 		dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1155*4882a593Smuzhiyun 		   DHD_PNO_EPNO_CFG_ID, NULL, TRUE);
1156*4882a593Smuzhiyun 		dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
1157*4882a593Smuzhiyun 	} else if (type != GSCAN_ATTRIBUTE_EPNO_FLUSH) {
1158*4882a593Smuzhiyun 		/* If the last attribute was FLUSH, nothing else to do */
1159*4882a593Smuzhiyun 		dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1160*4882a593Smuzhiyun 		DHD_PNO_EPNO_PARAMS_ID, &params, FALSE);
1161*4882a593Smuzhiyun 		err = dhd_dev_set_epno(bcmcfg_to_prmry_ndev(cfg));
1162*4882a593Smuzhiyun 	}
1163*4882a593Smuzhiyun 	return err;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun static int
wl_cfgvendor_set_batch_scan_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1167*4882a593Smuzhiyun wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
1168*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
1169*4882a593Smuzhiyun {
1170*4882a593Smuzhiyun 	int err = 0, tmp, type;
1171*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1172*4882a593Smuzhiyun 	gscan_batch_params_t batch_param;
1173*4882a593Smuzhiyun 	const struct nlattr *iter;
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	batch_param.mscan = batch_param.bestn = 0;
1176*4882a593Smuzhiyun 	batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
1179*4882a593Smuzhiyun 		type = nla_type(iter);
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 		switch (type) {
1182*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
1183*4882a593Smuzhiyun 				batch_param.bestn = nla_get_u32(iter);
1184*4882a593Smuzhiyun 				break;
1185*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
1186*4882a593Smuzhiyun 				batch_param.mscan = nla_get_u32(iter);
1187*4882a593Smuzhiyun 				break;
1188*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
1189*4882a593Smuzhiyun 				batch_param.buffer_threshold = nla_get_u32(iter);
1190*4882a593Smuzhiyun 				break;
1191*4882a593Smuzhiyun 			default:
1192*4882a593Smuzhiyun 				WL_ERR(("Unknown type %d\n", type));
1193*4882a593Smuzhiyun 				break;
1194*4882a593Smuzhiyun 		}
1195*4882a593Smuzhiyun 	}
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1198*4882a593Smuzhiyun 	       DHD_PNO_BATCH_SCAN_CFG_ID, &batch_param, FALSE) < 0) {
1199*4882a593Smuzhiyun 		WL_ERR(("Could not set batch cfg\n"));
1200*4882a593Smuzhiyun 		err = -EINVAL;
1201*4882a593Smuzhiyun 		return err;
1202*4882a593Smuzhiyun 	}
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	return err;
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun #endif /* GSCAN_SUPPORT */
1208*4882a593Smuzhiyun #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
1209*4882a593Smuzhiyun static int
wl_cfgvendor_gscan_get_channel_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1210*4882a593Smuzhiyun wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
1211*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
1212*4882a593Smuzhiyun {
1213*4882a593Smuzhiyun 	int err = 0, type, band;
1214*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1215*4882a593Smuzhiyun 	uint16 *reply = NULL;
1216*4882a593Smuzhiyun 	uint32 reply_len = 0, num_channels, mem_needed;
1217*4882a593Smuzhiyun 	struct sk_buff *skb;
1218*4882a593Smuzhiyun 	dhd_pub_t *dhdp;
1219*4882a593Smuzhiyun 	struct net_device *ndev = wdev->netdev;
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 	if (!ndev) {
1222*4882a593Smuzhiyun 		WL_ERR(("ndev null\n"));
1223*4882a593Smuzhiyun 		return -EINVAL;
1224*4882a593Smuzhiyun 	}
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	dhdp = wl_cfg80211_get_dhdp(ndev);
1227*4882a593Smuzhiyun 	if (!dhdp) {
1228*4882a593Smuzhiyun 		WL_ERR(("dhdp null\n"));
1229*4882a593Smuzhiyun 		return -EINVAL;
1230*4882a593Smuzhiyun 	}
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	if (!data) {
1233*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
1234*4882a593Smuzhiyun 		return -EINVAL;
1235*4882a593Smuzhiyun 	}
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun 	if (len <= 0) {
1238*4882a593Smuzhiyun 		WL_ERR(("invalid len %d\n", len));
1239*4882a593Smuzhiyun 		return -EINVAL;
1240*4882a593Smuzhiyun 	}
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 	type = nla_type(data);
1243*4882a593Smuzhiyun 	if (type == GSCAN_ATTRIBUTE_BAND) {
1244*4882a593Smuzhiyun 		band = nla_get_u32(data);
1245*4882a593Smuzhiyun 	} else {
1246*4882a593Smuzhiyun 		return -EINVAL;
1247*4882a593Smuzhiyun 	}
1248*4882a593Smuzhiyun 
1249*4882a593Smuzhiyun 	reply = dhd_pno_get_gscan(dhdp,
1250*4882a593Smuzhiyun 	   DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
1251*4882a593Smuzhiyun 	if (!reply) {
1252*4882a593Smuzhiyun 		WL_ERR(("Could not get channel list\n"));
1253*4882a593Smuzhiyun 		err = -EINVAL;
1254*4882a593Smuzhiyun 		return err;
1255*4882a593Smuzhiyun 	}
1256*4882a593Smuzhiyun 	num_channels =  reply_len/ sizeof(uint32);
1257*4882a593Smuzhiyun 	mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
1260*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1261*4882a593Smuzhiyun 	if (unlikely(!skb)) {
1262*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
1263*4882a593Smuzhiyun 		err = -ENOMEM;
1264*4882a593Smuzhiyun 		goto exit;
1265*4882a593Smuzhiyun 	}
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
1268*4882a593Smuzhiyun 	nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun 	err =  cfg80211_vendor_cmd_reply(skb);
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 	if (unlikely(err)) {
1273*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1274*4882a593Smuzhiyun 	}
1275*4882a593Smuzhiyun exit:
1276*4882a593Smuzhiyun 	MFREE(cfg->osh, reply, reply_len);
1277*4882a593Smuzhiyun 	return err;
1278*4882a593Smuzhiyun }
1279*4882a593Smuzhiyun #endif	/* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun #ifdef RSSI_MONITOR_SUPPORT
wl_cfgvendor_set_rssi_monitor(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1282*4882a593Smuzhiyun static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy,
1283*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
1284*4882a593Smuzhiyun {
1285*4882a593Smuzhiyun 	int err = 0, tmp, type, start = 0;
1286*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1287*4882a593Smuzhiyun 	int8 max_rssi = 0, min_rssi = 0;
1288*4882a593Smuzhiyun 	const struct nlattr *iter;
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
1291*4882a593Smuzhiyun 		type = nla_type(iter);
1292*4882a593Smuzhiyun 		switch (type) {
1293*4882a593Smuzhiyun 			case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI:
1294*4882a593Smuzhiyun 				max_rssi = (int8) nla_get_u32(iter);
1295*4882a593Smuzhiyun 				break;
1296*4882a593Smuzhiyun 			case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI:
1297*4882a593Smuzhiyun 				min_rssi = (int8) nla_get_u32(iter);
1298*4882a593Smuzhiyun 				break;
1299*4882a593Smuzhiyun 			case RSSI_MONITOR_ATTRIBUTE_START:
1300*4882a593Smuzhiyun 				start = nla_get_u32(iter);
1301*4882a593Smuzhiyun 		}
1302*4882a593Smuzhiyun 	}
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
1305*4882a593Smuzhiyun 	       start, max_rssi, min_rssi) < 0) {
1306*4882a593Smuzhiyun 		WL_ERR(("Could not set rssi monitor cfg\n"));
1307*4882a593Smuzhiyun 		err = -EINVAL;
1308*4882a593Smuzhiyun 	}
1309*4882a593Smuzhiyun 	return err;
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun #endif /* RSSI_MONITOR_SUPPORT */
1312*4882a593Smuzhiyun 
1313*4882a593Smuzhiyun #ifdef DHD_WAKE_STATUS
1314*4882a593Smuzhiyun static int
wl_cfgvendor_get_wake_reason_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1315*4882a593Smuzhiyun wl_cfgvendor_get_wake_reason_stats(struct wiphy *wiphy,
1316*4882a593Smuzhiyun         struct wireless_dev *wdev, const void *data, int len)
1317*4882a593Smuzhiyun {
1318*4882a593Smuzhiyun 	struct net_device *ndev = wdev_to_ndev(wdev);
1319*4882a593Smuzhiyun 	wake_counts_t *pwake_count_info;
1320*4882a593Smuzhiyun 	int ret, mem_needed;
1321*4882a593Smuzhiyun #if defined(DHD_DEBUG) && defined(DHD_WAKE_EVENT_STATUS)
1322*4882a593Smuzhiyun 	int flowid;
1323*4882a593Smuzhiyun #endif /* DHD_DEBUG && DHD_WAKE_EVENT_STATUS */
1324*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
1325*4882a593Smuzhiyun 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 	WL_DBG(("Recv get wake status info cmd.\n"));
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun 	pwake_count_info = dhd_get_wakecount(dhdp);
1330*4882a593Smuzhiyun 	mem_needed =  VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 20) +
1331*4882a593Smuzhiyun 		(WLC_E_LAST * sizeof(uint));
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1334*4882a593Smuzhiyun 	if (unlikely(!skb)) {
1335*4882a593Smuzhiyun 		WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
1336*4882a593Smuzhiyun 		ret = -ENOMEM;
1337*4882a593Smuzhiyun 		goto exit;
1338*4882a593Smuzhiyun 	}
1339*4882a593Smuzhiyun #ifdef DHD_WAKE_EVENT_STATUS
1340*4882a593Smuzhiyun 	WL_ERR(("pwake_count_info->rcwake %d\n", pwake_count_info->rcwake));
1341*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, pwake_count_info->rcwake);
1342*4882a593Smuzhiyun 	if (unlikely(ret)) {
1343*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total count of CMD event, ret=%d\n", ret));
1344*4882a593Smuzhiyun 		goto exit;
1345*4882a593Smuzhiyun 	}
1346*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED, WLC_E_LAST);
1347*4882a593Smuzhiyun 	if (unlikely(ret)) {
1348*4882a593Smuzhiyun 		WL_ERR(("Failed to put Max count of event used, ret=%d\n", ret));
1349*4882a593Smuzhiyun 		goto exit;
1350*4882a593Smuzhiyun 	}
1351*4882a593Smuzhiyun 	ret = nla_put(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE, (WLC_E_LAST * sizeof(uint)),
1352*4882a593Smuzhiyun 		pwake_count_info->rc_event);
1353*4882a593Smuzhiyun 	if (unlikely(ret)) {
1354*4882a593Smuzhiyun 		WL_ERR(("Failed to put Event wake data, ret=%d\n", ret));
1355*4882a593Smuzhiyun 		goto exit;
1356*4882a593Smuzhiyun 	}
1357*4882a593Smuzhiyun #ifdef DHD_DEBUG
1358*4882a593Smuzhiyun 	for (flowid = 0; flowid < WLC_E_LAST; flowid++) {
1359*4882a593Smuzhiyun 		if (pwake_count_info->rc_event[flowid] != 0) {
1360*4882a593Smuzhiyun 			WL_ERR((" %s = %u\n", bcmevent_get_name(flowid),
1361*4882a593Smuzhiyun 				pwake_count_info->rc_event[flowid]));
1362*4882a593Smuzhiyun 		}
1363*4882a593Smuzhiyun 	}
1364*4882a593Smuzhiyun #endif /* DHD_DEBUG */
1365*4882a593Smuzhiyun #endif /* DHD_WAKE_EVENT_STATUS */
1366*4882a593Smuzhiyun #ifdef DHD_WAKE_RX_STATUS
1367*4882a593Smuzhiyun 	WL_ERR(("pwake_count_info->rxwake %d\n", pwake_count_info->rxwake));
1368*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE, pwake_count_info->rxwake);
1369*4882a593Smuzhiyun 	if (unlikely(ret)) {
1370*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total Wake due RX data, ret=%d\n", ret));
1371*4882a593Smuzhiyun 		goto exit;
1372*4882a593Smuzhiyun 	}
1373*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT, pwake_count_info->rx_ucast);
1374*4882a593Smuzhiyun 	if (unlikely(ret)) {
1375*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to RX unicast, ret=%d\n", ret));
1376*4882a593Smuzhiyun 		goto exit;
1377*4882a593Smuzhiyun 	}
1378*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT, pwake_count_info->rx_mcast);
1379*4882a593Smuzhiyun 	if (unlikely(ret)) {
1380*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due RX multicast, ret=%d\n", ret));
1381*4882a593Smuzhiyun 		goto exit;
1382*4882a593Smuzhiyun 	}
1383*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT, pwake_count_info->rx_bcast);
1384*4882a593Smuzhiyun 	if (unlikely(ret)) {
1385*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to RX broadcast, ret=%d\n", ret));
1386*4882a593Smuzhiyun 		goto exit;
1387*4882a593Smuzhiyun 	}
1388*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT, pwake_count_info->rx_arp);
1389*4882a593Smuzhiyun 	if (unlikely(ret)) {
1390*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to ICMP pkt, ret=%d\n", ret));
1391*4882a593Smuzhiyun 		goto exit;
1392*4882a593Smuzhiyun 	}
1393*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT, pwake_count_info->rx_icmpv6);
1394*4882a593Smuzhiyun 	if (unlikely(ret)) {
1395*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due ICMPV6 pkt, ret=%d\n", ret));
1396*4882a593Smuzhiyun 		goto exit;
1397*4882a593Smuzhiyun 	}
1398*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA, pwake_count_info->rx_icmpv6_ra);
1399*4882a593Smuzhiyun 	if (unlikely(ret)) {
1400*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to ICMPV6_RA, ret=%d\n", ret));
1401*4882a593Smuzhiyun 		goto exit;
1402*4882a593Smuzhiyun 	}
1403*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA, pwake_count_info->rx_icmpv6_na);
1404*4882a593Smuzhiyun 	if (unlikely(ret)) {
1405*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to ICMPV6_NA, ret=%d\n", ret));
1406*4882a593Smuzhiyun 		goto exit;
1407*4882a593Smuzhiyun 	}
1408*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS, pwake_count_info->rx_icmpv6_ns);
1409*4882a593Smuzhiyun 	if (unlikely(ret)) {
1410*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to ICMPV6_NS, ret=%d\n", ret));
1411*4882a593Smuzhiyun 		goto exit;
1412*4882a593Smuzhiyun 	}
1413*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
1414*4882a593Smuzhiyun 		pwake_count_info->rx_multi_ipv4);
1415*4882a593Smuzhiyun 	if (unlikely(ret)) {
1416*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to RX IPV4 MULTICAST, ret=%d\n", ret));
1417*4882a593Smuzhiyun 		goto exit;
1418*4882a593Smuzhiyun 	}
1419*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
1420*4882a593Smuzhiyun 		pwake_count_info->rx_multi_ipv6);
1421*4882a593Smuzhiyun 	if (unlikely(ret)) {
1422*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to RX IPV6 MULTICAST, ret=%d\n", ret));
1423*4882a593Smuzhiyun 		goto exit;
1424*4882a593Smuzhiyun 	}
1425*4882a593Smuzhiyun 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT,
1426*4882a593Smuzhiyun 		pwake_count_info->rx_multi_other);
1427*4882a593Smuzhiyun 	if (unlikely(ret)) {
1428*4882a593Smuzhiyun 		WL_ERR(("Failed to put Total wake due to Other RX Multicast, ret=%d\n", ret));
1429*4882a593Smuzhiyun 		goto exit;
1430*4882a593Smuzhiyun 	}
1431*4882a593Smuzhiyun #endif /* #ifdef DHD_WAKE_RX_STATUS */
1432*4882a593Smuzhiyun 	ret = cfg80211_vendor_cmd_reply(skb);
1433*4882a593Smuzhiyun 	if (unlikely(ret)) {
1434*4882a593Smuzhiyun 		WL_ERR(("Vendor cmd reply for -get wake status failed:%d \n", ret));
1435*4882a593Smuzhiyun 	}
1436*4882a593Smuzhiyun 	/* On cfg80211_vendor_cmd_reply() skb is consumed and freed in case of success or failure */
1437*4882a593Smuzhiyun 	return ret;
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun exit:
1440*4882a593Smuzhiyun 	/* Free skb memory */
1441*4882a593Smuzhiyun 	if (skb) {
1442*4882a593Smuzhiyun 		kfree_skb(skb);
1443*4882a593Smuzhiyun 	}
1444*4882a593Smuzhiyun 	return ret;
1445*4882a593Smuzhiyun }
1446*4882a593Smuzhiyun #endif /* DHD_WAKE_STATUS */
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun #ifdef DHDTCPACK_SUPPRESS
1449*4882a593Smuzhiyun static int
wl_cfgvendor_set_tcpack_sup_mode(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1450*4882a593Smuzhiyun wl_cfgvendor_set_tcpack_sup_mode(struct wiphy *wiphy,
1451*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
1452*4882a593Smuzhiyun {
1453*4882a593Smuzhiyun 	int err = BCME_OK, type;
1454*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1455*4882a593Smuzhiyun 	struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1456*4882a593Smuzhiyun 	uint8 enable = 0;
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	if (!data) {
1459*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
1460*4882a593Smuzhiyun 		err = BCME_BADARG;
1461*4882a593Smuzhiyun 		goto exit;
1462*4882a593Smuzhiyun 	}
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 	if (len <= 0) {
1465*4882a593Smuzhiyun 		WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
1466*4882a593Smuzhiyun 		err = BCME_BADARG;
1467*4882a593Smuzhiyun 		goto exit;
1468*4882a593Smuzhiyun 	}
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 	type = nla_type(data);
1471*4882a593Smuzhiyun 	if (type == ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE) {
1472*4882a593Smuzhiyun 		enable = (uint8) nla_get_u32(data);
1473*4882a593Smuzhiyun 		err = dhd_dev_set_tcpack_sup_mode_cfg(ndev, enable);
1474*4882a593Smuzhiyun 		if (unlikely(err)) {
1475*4882a593Smuzhiyun 			WL_ERR(("Could not set TCP Ack Suppress mode cfg: %d\n", err));
1476*4882a593Smuzhiyun 		}
1477*4882a593Smuzhiyun 	} else {
1478*4882a593Smuzhiyun 		err = BCME_BADARG;
1479*4882a593Smuzhiyun 	}
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun exit:
1482*4882a593Smuzhiyun 	return err;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun #endif /* DHDTCPACK_SUPPRESS */
1485*4882a593Smuzhiyun 
1486*4882a593Smuzhiyun static int
wl_cfgvendor_set_latency_mode(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1487*4882a593Smuzhiyun wl_cfgvendor_set_latency_mode(struct wiphy *wiphy,
1488*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
1489*4882a593Smuzhiyun {
1490*4882a593Smuzhiyun 	int err = BCME_OK;
1491*4882a593Smuzhiyun 	int type;
1492*4882a593Smuzhiyun 	bool lmode;
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun 	struct net_device *ndev = wdev_to_ndev(wdev);
1495*4882a593Smuzhiyun 	WL_DBG(("wl_cfgvendor_set_latency_mode Enter \n"));
1496*4882a593Smuzhiyun 	if (!data) {
1497*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
1498*4882a593Smuzhiyun 		return -EINVAL;
1499*4882a593Smuzhiyun 	}
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	if (len <= 0) {
1502*4882a593Smuzhiyun 		WL_ERR(("invalid len %d\n", len));
1503*4882a593Smuzhiyun 		return -EINVAL;
1504*4882a593Smuzhiyun 	}
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	type = nla_type(data);
1507*4882a593Smuzhiyun 	if (type == ANDR_WIFI_ATTRIBUTE_LATENCY_MODE) {
1508*4882a593Smuzhiyun 		lmode = (bool)nla_get_u32(data);
1509*4882a593Smuzhiyun 		err = wl_cfg80211_set_power_mgmt(wiphy, ndev, !lmode, 0);
1510*4882a593Smuzhiyun 	}
1511*4882a593Smuzhiyun 	return err;
1512*4882a593Smuzhiyun }
1513*4882a593Smuzhiyun 
1514*4882a593Smuzhiyun #if (0)//ndef CONFIG_SOC_S5E5515
1515*4882a593Smuzhiyun static int
wl_cfgvendor_set_random_mac(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1516*4882a593Smuzhiyun wl_cfgvendor_set_random_mac(struct wiphy *wiphy,
1517*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
1518*4882a593Smuzhiyun {
1519*4882a593Smuzhiyun 	int err = BCME_OK;
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	WL_ERR(("ANDR_WIFI_ATTRIBUTE_RANDOM_MAC is not available\n"));
1522*4882a593Smuzhiyun 	err = BCME_UNSUPPORTED;
1523*4882a593Smuzhiyun 
1524*4882a593Smuzhiyun 	return err;
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun #endif /* CONFIG_SOC_S5E5515 */
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun static int
wl_cfgvendor_set_tx_power_scenario(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1529*4882a593Smuzhiyun wl_cfgvendor_set_tx_power_scenario(struct wiphy *wiphy,
1530*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
1531*4882a593Smuzhiyun {
1532*4882a593Smuzhiyun     int err = BCME_OK;
1533*4882a593Smuzhiyun     int type;
1534*4882a593Smuzhiyun     if (!data) {
1535*4882a593Smuzhiyun         WL_ERR(("data is not available\n"));
1536*4882a593Smuzhiyun 		return -EINVAL;
1537*4882a593Smuzhiyun     }
1538*4882a593Smuzhiyun     if (len <= 0) {
1539*4882a593Smuzhiyun 	    WL_ERR(("invalid len %d\n", len));
1540*4882a593Smuzhiyun         return -EINVAL;
1541*4882a593Smuzhiyun     }
1542*4882a593Smuzhiyun     type = nla_type(data);
1543*4882a593Smuzhiyun     if (type == ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO) {
1544*4882a593Smuzhiyun         //Handling to be implemented
1545*4882a593Smuzhiyun         //err = wl_cfg80211_set_tx_power(wiphy,wdev,type,0);
1546*4882a593Smuzhiyun         err = BCME_OK;
1547*4882a593Smuzhiyun     }
1548*4882a593Smuzhiyun 	return err;
1549*4882a593Smuzhiyun }
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT)
1552*4882a593Smuzhiyun static int
wl_cfgvendor_notify_dump_completion(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1553*4882a593Smuzhiyun wl_cfgvendor_notify_dump_completion(struct wiphy *wiphy,
1554*4882a593Smuzhiyun         struct wireless_dev *wdev, const void *data, int len)
1555*4882a593Smuzhiyun {
1556*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1557*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
1558*4882a593Smuzhiyun 	unsigned long flags = 0;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 	WL_INFORM(("%s, [DUMP] received file dump notification from HAL\n", __FUNCTION__));
1561*4882a593Smuzhiyun 
1562*4882a593Smuzhiyun 	DHD_GENERAL_LOCK(dhd_pub, flags);
1563*4882a593Smuzhiyun 	/* call wmb() to synchronize with the previous memory operations */
1564*4882a593Smuzhiyun 	OSL_SMP_WMB();
1565*4882a593Smuzhiyun 	DHD_BUS_BUSY_CLEAR_IN_HALDUMP(dhd_pub);
1566*4882a593Smuzhiyun 	/* Call another wmb() to make sure wait_for_dump_completion value
1567*4882a593Smuzhiyun 	 * gets updated before waking up waiting context.
1568*4882a593Smuzhiyun 	 */
1569*4882a593Smuzhiyun 	OSL_SMP_WMB();
1570*4882a593Smuzhiyun 	dhd_os_busbusy_wake(dhd_pub);
1571*4882a593Smuzhiyun 	DHD_GENERAL_UNLOCK(dhd_pub, flags);
1572*4882a593Smuzhiyun 
1573*4882a593Smuzhiyun 	return BCME_OK;
1574*4882a593Smuzhiyun }
1575*4882a593Smuzhiyun #endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */
1576*4882a593Smuzhiyun 
1577*4882a593Smuzhiyun #if defined(WL_CFG80211)
1578*4882a593Smuzhiyun static int
wl_cfgvendor_set_hal_started(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1579*4882a593Smuzhiyun wl_cfgvendor_set_hal_started(struct wiphy *wiphy,
1580*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void  *data, int len)
1581*4882a593Smuzhiyun {
1582*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1583*4882a593Smuzhiyun 	WL_INFORM(("%s,[DUMP] HAL STARTED\n", __FUNCTION__));
1584*4882a593Smuzhiyun 
1585*4882a593Smuzhiyun 	cfg->hal_started = true;
1586*4882a593Smuzhiyun 	return BCME_OK;
1587*4882a593Smuzhiyun }
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun static int
wl_cfgvendor_stop_hal(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1590*4882a593Smuzhiyun wl_cfgvendor_stop_hal(struct wiphy *wiphy,
1591*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void  *data, int len)
1592*4882a593Smuzhiyun {
1593*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1594*4882a593Smuzhiyun 	WL_INFORM(("%s,[DUMP] HAL STOPPED\n", __FUNCTION__));
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun 	cfg->hal_started = false;
1597*4882a593Smuzhiyun 	return BCME_OK;
1598*4882a593Smuzhiyun }
1599*4882a593Smuzhiyun #endif /* WL_CFG80211 */
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun #ifdef RTT_SUPPORT
1602*4882a593Smuzhiyun void
wl_cfgvendor_rtt_evt(void * ctx,void * rtt_data)1603*4882a593Smuzhiyun wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
1604*4882a593Smuzhiyun {
1605*4882a593Smuzhiyun 	struct wireless_dev *wdev = (struct wireless_dev *)ctx;
1606*4882a593Smuzhiyun 	struct wiphy *wiphy;
1607*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
1608*4882a593Smuzhiyun 	uint32 evt_complete = 0;
1609*4882a593Smuzhiyun 	gfp_t kflags;
1610*4882a593Smuzhiyun 	rtt_result_t *rtt_result;
1611*4882a593Smuzhiyun 	rtt_results_header_t *rtt_header;
1612*4882a593Smuzhiyun 	struct list_head *rtt_cache_list;
1613*4882a593Smuzhiyun 	struct nlattr *rtt_nl_hdr;
1614*4882a593Smuzhiyun 	int ret = BCME_OK;
1615*4882a593Smuzhiyun 	wiphy = wdev->wiphy;
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	WL_DBG(("In\n"));
1618*4882a593Smuzhiyun 	/* Push the data to the skb */
1619*4882a593Smuzhiyun 	if (!rtt_data) {
1620*4882a593Smuzhiyun 		WL_ERR(("rtt_data is NULL\n"));
1621*4882a593Smuzhiyun 		return;
1622*4882a593Smuzhiyun 	}
1623*4882a593Smuzhiyun 	rtt_cache_list = (struct list_head *)rtt_data;
1624*4882a593Smuzhiyun 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1625*4882a593Smuzhiyun 	if (list_empty(rtt_cache_list)) {
1626*4882a593Smuzhiyun #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1627*4882a593Smuzhiyun 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1628*4882a593Smuzhiyun 		skb = cfg80211_vendor_event_alloc(wiphy, NULL, 100,
1629*4882a593Smuzhiyun 			GOOGLE_RTT_COMPLETE_EVENT, kflags);
1630*4882a593Smuzhiyun #else
1631*4882a593Smuzhiyun 		skb = cfg80211_vendor_event_alloc(wiphy, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags);
1632*4882a593Smuzhiyun #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1633*4882a593Smuzhiyun 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1634*4882a593Smuzhiyun 		if (!skb) {
1635*4882a593Smuzhiyun 			WL_ERR(("skb alloc failed"));
1636*4882a593Smuzhiyun 			return;
1637*4882a593Smuzhiyun 		}
1638*4882a593Smuzhiyun 		evt_complete = 1;
1639*4882a593Smuzhiyun 		ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1640*4882a593Smuzhiyun 		if (ret < 0) {
1641*4882a593Smuzhiyun 			WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
1642*4882a593Smuzhiyun 			goto free_mem;
1643*4882a593Smuzhiyun 		}
1644*4882a593Smuzhiyun 		cfg80211_vendor_event(skb, kflags);
1645*4882a593Smuzhiyun 		return;
1646*4882a593Smuzhiyun 	}
1647*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1648*4882a593Smuzhiyun 	list_for_each_entry(rtt_header, rtt_cache_list, list) {
1649*4882a593Smuzhiyun 		/* Alloc the SKB for vendor_event */
1650*4882a593Smuzhiyun #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1651*4882a593Smuzhiyun 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1652*4882a593Smuzhiyun 		skb = cfg80211_vendor_event_alloc(wiphy, NULL, rtt_header->result_tot_len + 100,
1653*4882a593Smuzhiyun 			GOOGLE_RTT_COMPLETE_EVENT, kflags);
1654*4882a593Smuzhiyun #else
1655*4882a593Smuzhiyun 		skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100,
1656*4882a593Smuzhiyun 			GOOGLE_RTT_COMPLETE_EVENT, kflags);
1657*4882a593Smuzhiyun #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1658*4882a593Smuzhiyun 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1659*4882a593Smuzhiyun 		if (!skb) {
1660*4882a593Smuzhiyun 			WL_ERR(("skb alloc failed"));
1661*4882a593Smuzhiyun 			return;
1662*4882a593Smuzhiyun 		}
1663*4882a593Smuzhiyun 		if (list_is_last(&rtt_header->list, rtt_cache_list)) {
1664*4882a593Smuzhiyun 			evt_complete = 1;
1665*4882a593Smuzhiyun 		}
1666*4882a593Smuzhiyun 		ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1667*4882a593Smuzhiyun 		if (ret < 0) {
1668*4882a593Smuzhiyun 			WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
1669*4882a593Smuzhiyun 			goto free_mem;
1670*4882a593Smuzhiyun 		}
1671*4882a593Smuzhiyun 		rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET);
1672*4882a593Smuzhiyun 		if (!rtt_nl_hdr) {
1673*4882a593Smuzhiyun 			WL_ERR(("rtt_nl_hdr is NULL\n"));
1674*4882a593Smuzhiyun 		        dev_kfree_skb_any(skb);
1675*4882a593Smuzhiyun 			break;
1676*4882a593Smuzhiyun 		}
1677*4882a593Smuzhiyun 		ret = nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN,
1678*4882a593Smuzhiyun 				&rtt_header->peer_mac);
1679*4882a593Smuzhiyun 		if (ret < 0) {
1680*4882a593Smuzhiyun 			WL_ERR(("Failed to put RTT_ATTRIBUTE_TARGET_MAC, ret:%d\n", ret));
1681*4882a593Smuzhiyun 			goto free_mem;
1682*4882a593Smuzhiyun 		}
1683*4882a593Smuzhiyun 		ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt);
1684*4882a593Smuzhiyun 		if (ret < 0) {
1685*4882a593Smuzhiyun 			WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_CNT, ret:%d\n", ret));
1686*4882a593Smuzhiyun 			goto free_mem;
1687*4882a593Smuzhiyun 		}
1688*4882a593Smuzhiyun 		list_for_each_entry(rtt_result, &rtt_header->result_list, list) {
1689*4882a593Smuzhiyun 			ret = nla_put(skb, RTT_ATTRIBUTE_RESULT,
1690*4882a593Smuzhiyun 				rtt_result->report_len, &rtt_result->report);
1691*4882a593Smuzhiyun 			if (ret < 0) {
1692*4882a593Smuzhiyun 				WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT, ret:%d\n", ret));
1693*4882a593Smuzhiyun 				goto free_mem;
1694*4882a593Smuzhiyun 			}
1695*4882a593Smuzhiyun 			ret = nla_put(skb, RTT_ATTRIBUTE_RESULT_DETAIL,
1696*4882a593Smuzhiyun 				rtt_result->detail_len, &rtt_result->rtt_detail);
1697*4882a593Smuzhiyun 			if (ret < 0) {
1698*4882a593Smuzhiyun 				WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_DETAIL, ret:%d\n",
1699*4882a593Smuzhiyun 					ret));
1700*4882a593Smuzhiyun 				goto free_mem;
1701*4882a593Smuzhiyun 			}
1702*4882a593Smuzhiyun 		}
1703*4882a593Smuzhiyun 		nla_nest_end(skb, rtt_nl_hdr);
1704*4882a593Smuzhiyun 		cfg80211_vendor_event(skb, kflags);
1705*4882a593Smuzhiyun 	}
1706*4882a593Smuzhiyun 	GCC_DIAGNOSTIC_POP();
1707*4882a593Smuzhiyun 
1708*4882a593Smuzhiyun 	return;
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun free_mem:
1711*4882a593Smuzhiyun 	/* Free skb memory */
1712*4882a593Smuzhiyun 	if (skb) {
1713*4882a593Smuzhiyun 		kfree_skb(skb);
1714*4882a593Smuzhiyun 	}
1715*4882a593Smuzhiyun }
1716*4882a593Smuzhiyun 
1717*4882a593Smuzhiyun static int
wl_cfgvendor_rtt_set_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1718*4882a593Smuzhiyun wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1719*4882a593Smuzhiyun 	const void *data, int len) {
1720*4882a593Smuzhiyun 	int err = 0, rem, rem1, rem2, type;
1721*4882a593Smuzhiyun 	int target_cnt = 0;
1722*4882a593Smuzhiyun 	rtt_config_params_t rtt_param;
1723*4882a593Smuzhiyun 	rtt_target_info_t* rtt_target = NULL;
1724*4882a593Smuzhiyun 	const struct nlattr *iter, *iter1, *iter2;
1725*4882a593Smuzhiyun 	int8 eabuf[ETHER_ADDR_STR_LEN];
1726*4882a593Smuzhiyun 	int8 chanbuf[CHANSPEC_STR_LEN];
1727*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1728*4882a593Smuzhiyun 	rtt_capabilities_t capability;
1729*4882a593Smuzhiyun 
1730*4882a593Smuzhiyun 	bzero(&rtt_param, sizeof(rtt_param));
1731*4882a593Smuzhiyun 
1732*4882a593Smuzhiyun 	WL_DBG(("In\n"));
1733*4882a593Smuzhiyun 	err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
1734*4882a593Smuzhiyun 	if (err < 0) {
1735*4882a593Smuzhiyun 		WL_ERR(("failed to register rtt_noti_callback\n"));
1736*4882a593Smuzhiyun 		goto exit;
1737*4882a593Smuzhiyun 	}
1738*4882a593Smuzhiyun 	err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1739*4882a593Smuzhiyun 	if (err < 0) {
1740*4882a593Smuzhiyun 		WL_ERR(("failed to get the capability\n"));
1741*4882a593Smuzhiyun 		goto exit;
1742*4882a593Smuzhiyun 	}
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun 	if (len <= 0) {
1745*4882a593Smuzhiyun 		WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
1746*4882a593Smuzhiyun 		err = BCME_ERROR;
1747*4882a593Smuzhiyun 		goto exit;
1748*4882a593Smuzhiyun 	}
1749*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
1750*4882a593Smuzhiyun 		type = nla_type(iter);
1751*4882a593Smuzhiyun 		switch (type) {
1752*4882a593Smuzhiyun 		case RTT_ATTRIBUTE_TARGET_CNT:
1753*4882a593Smuzhiyun 			if (target_cnt != 0) {
1754*4882a593Smuzhiyun 				WL_ERR(("attempt to overwrite target_cnt"));
1755*4882a593Smuzhiyun 				err = -EINVAL;
1756*4882a593Smuzhiyun 				goto exit;
1757*4882a593Smuzhiyun 			}
1758*4882a593Smuzhiyun 			target_cnt = nla_get_u8(iter);
1759*4882a593Smuzhiyun 			if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) {
1760*4882a593Smuzhiyun 				WL_ERR(("target_cnt is not valid : %d\n",
1761*4882a593Smuzhiyun 					target_cnt));
1762*4882a593Smuzhiyun 				err = BCME_RANGE;
1763*4882a593Smuzhiyun 				goto exit;
1764*4882a593Smuzhiyun 			}
1765*4882a593Smuzhiyun 			rtt_param.rtt_target_cnt = target_cnt;
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun 			rtt_param.target_info = (rtt_target_info_t *)MALLOCZ(cfg->osh,
1768*4882a593Smuzhiyun 				TARGET_INFO_SIZE(target_cnt));
1769*4882a593Smuzhiyun 			if (rtt_param.target_info == NULL) {
1770*4882a593Smuzhiyun 				WL_ERR(("failed to allocate target info for (%d)\n", target_cnt));
1771*4882a593Smuzhiyun 				err = BCME_NOMEM;
1772*4882a593Smuzhiyun 				goto exit;
1773*4882a593Smuzhiyun 			}
1774*4882a593Smuzhiyun 			break;
1775*4882a593Smuzhiyun 		case RTT_ATTRIBUTE_TARGET_INFO:
1776*4882a593Smuzhiyun 			/* Added this variable for safe check to avoid crash
1777*4882a593Smuzhiyun 			 * incase the caller did not respect the order
1778*4882a593Smuzhiyun 			 */
1779*4882a593Smuzhiyun 			if (rtt_param.target_info == NULL) {
1780*4882a593Smuzhiyun 				WL_ERR(("rtt_target_info is NULL\n"));
1781*4882a593Smuzhiyun 				err = BCME_NOMEM;
1782*4882a593Smuzhiyun 				goto exit;
1783*4882a593Smuzhiyun 			}
1784*4882a593Smuzhiyun 			rtt_target = rtt_param.target_info;
1785*4882a593Smuzhiyun 			nla_for_each_nested(iter1, iter, rem1) {
1786*4882a593Smuzhiyun 				if ((uint8 *)rtt_target >= ((uint8 *)rtt_param.target_info +
1787*4882a593Smuzhiyun 					TARGET_INFO_SIZE(target_cnt))) {
1788*4882a593Smuzhiyun 					WL_ERR(("rtt_target increased over its max size"));
1789*4882a593Smuzhiyun 					err = -EINVAL;
1790*4882a593Smuzhiyun 					goto exit;
1791*4882a593Smuzhiyun 				}
1792*4882a593Smuzhiyun 				nla_for_each_nested(iter2, iter1, rem2) {
1793*4882a593Smuzhiyun 					type = nla_type(iter2);
1794*4882a593Smuzhiyun 					switch (type) {
1795*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_MAC:
1796*4882a593Smuzhiyun 						if (nla_len(iter2) != ETHER_ADDR_LEN) {
1797*4882a593Smuzhiyun 							WL_ERR(("mac_addr length not match\n"));
1798*4882a593Smuzhiyun 							err = -EINVAL;
1799*4882a593Smuzhiyun 							goto exit;
1800*4882a593Smuzhiyun 						}
1801*4882a593Smuzhiyun 						memcpy(&rtt_target->addr, nla_data(iter2),
1802*4882a593Smuzhiyun 							ETHER_ADDR_LEN);
1803*4882a593Smuzhiyun 						break;
1804*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_TYPE:
1805*4882a593Smuzhiyun 						rtt_target->type = nla_get_u8(iter2);
1806*4882a593Smuzhiyun 						if (rtt_target->type == RTT_INVALID ||
1807*4882a593Smuzhiyun 							(rtt_target->type == RTT_ONE_WAY &&
1808*4882a593Smuzhiyun 							!capability.rtt_one_sided_supported)) {
1809*4882a593Smuzhiyun 							WL_ERR(("doesn't support RTT type"
1810*4882a593Smuzhiyun 								" : %d\n",
1811*4882a593Smuzhiyun 								rtt_target->type));
1812*4882a593Smuzhiyun 							err = -EINVAL;
1813*4882a593Smuzhiyun 							goto exit;
1814*4882a593Smuzhiyun 						}
1815*4882a593Smuzhiyun 						break;
1816*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_PEER:
1817*4882a593Smuzhiyun 						rtt_target->peer = nla_get_u8(iter2);
1818*4882a593Smuzhiyun 						break;
1819*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_CHAN:
1820*4882a593Smuzhiyun 						memcpy(&rtt_target->channel, nla_data(iter2),
1821*4882a593Smuzhiyun 							sizeof(rtt_target->channel));
1822*4882a593Smuzhiyun 						break;
1823*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_PERIOD:
1824*4882a593Smuzhiyun 						rtt_target->burst_period = nla_get_u32(iter2);
1825*4882a593Smuzhiyun 						if (rtt_target->burst_period < 32) {
1826*4882a593Smuzhiyun 							/* 100ms unit */
1827*4882a593Smuzhiyun 							rtt_target->burst_period *= 100;
1828*4882a593Smuzhiyun 						} else {
1829*4882a593Smuzhiyun 							WL_ERR(("%d value must in (0-31)\n",
1830*4882a593Smuzhiyun 								rtt_target->burst_period));
1831*4882a593Smuzhiyun 							err = EINVAL;
1832*4882a593Smuzhiyun 							goto exit;
1833*4882a593Smuzhiyun 						}
1834*4882a593Smuzhiyun 						break;
1835*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_NUM_BURST:
1836*4882a593Smuzhiyun 						rtt_target->num_burst = nla_get_u32(iter2);
1837*4882a593Smuzhiyun 						if (rtt_target->num_burst > 16) {
1838*4882a593Smuzhiyun 							WL_ERR(("%d value must in (0-15)\n",
1839*4882a593Smuzhiyun 								rtt_target->num_burst));
1840*4882a593Smuzhiyun 							err = -EINVAL;
1841*4882a593Smuzhiyun 							goto exit;
1842*4882a593Smuzhiyun 						}
1843*4882a593Smuzhiyun 						rtt_target->num_burst = BIT(rtt_target->num_burst);
1844*4882a593Smuzhiyun 						break;
1845*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST:
1846*4882a593Smuzhiyun 						rtt_target->num_frames_per_burst =
1847*4882a593Smuzhiyun 						nla_get_u32(iter2);
1848*4882a593Smuzhiyun 						break;
1849*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM:
1850*4882a593Smuzhiyun 						rtt_target->num_retries_per_ftm =
1851*4882a593Smuzhiyun 						nla_get_u32(iter2);
1852*4882a593Smuzhiyun 						break;
1853*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR:
1854*4882a593Smuzhiyun 						rtt_target->num_retries_per_ftmr =
1855*4882a593Smuzhiyun 						nla_get_u32(iter2);
1856*4882a593Smuzhiyun 						if (rtt_target->num_retries_per_ftmr > 3) {
1857*4882a593Smuzhiyun 							WL_ERR(("%d value must in (0-3)\n",
1858*4882a593Smuzhiyun 								rtt_target->num_retries_per_ftmr));
1859*4882a593Smuzhiyun 							err = -EINVAL;
1860*4882a593Smuzhiyun 							goto exit;
1861*4882a593Smuzhiyun 						}
1862*4882a593Smuzhiyun 						break;
1863*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_LCI:
1864*4882a593Smuzhiyun 						rtt_target->LCI_request = nla_get_u8(iter2);
1865*4882a593Smuzhiyun 						break;
1866*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_LCR:
1867*4882a593Smuzhiyun 						rtt_target->LCI_request = nla_get_u8(iter2);
1868*4882a593Smuzhiyun 						break;
1869*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_BURST_DURATION:
1870*4882a593Smuzhiyun 						if ((nla_get_u32(iter2) > 1 &&
1871*4882a593Smuzhiyun 							nla_get_u32(iter2) < 12)) {
1872*4882a593Smuzhiyun 							rtt_target->burst_duration =
1873*4882a593Smuzhiyun 							dhd_rtt_idx_to_burst_duration(
1874*4882a593Smuzhiyun 								nla_get_u32(iter2));
1875*4882a593Smuzhiyun 						} else if (nla_get_u32(iter2) == 15) {
1876*4882a593Smuzhiyun 							/* use default value */
1877*4882a593Smuzhiyun 							rtt_target->burst_duration = 0;
1878*4882a593Smuzhiyun 						} else {
1879*4882a593Smuzhiyun 							WL_ERR(("%d value must in (2-11) or 15\n",
1880*4882a593Smuzhiyun 								nla_get_u32(iter2)));
1881*4882a593Smuzhiyun 							err = -EINVAL;
1882*4882a593Smuzhiyun 							goto exit;
1883*4882a593Smuzhiyun 						}
1884*4882a593Smuzhiyun 						break;
1885*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_BW:
1886*4882a593Smuzhiyun 						rtt_target->bw = nla_get_u8(iter2);
1887*4882a593Smuzhiyun 						break;
1888*4882a593Smuzhiyun 					case RTT_ATTRIBUTE_TARGET_PREAMBLE:
1889*4882a593Smuzhiyun 						rtt_target->preamble = nla_get_u8(iter2);
1890*4882a593Smuzhiyun 						break;
1891*4882a593Smuzhiyun 					}
1892*4882a593Smuzhiyun 				}
1893*4882a593Smuzhiyun 				/* convert to chanspec value */
1894*4882a593Smuzhiyun 				rtt_target->chanspec =
1895*4882a593Smuzhiyun 					dhd_rtt_convert_to_chspec(rtt_target->channel);
1896*4882a593Smuzhiyun 				if (rtt_target->chanspec == 0) {
1897*4882a593Smuzhiyun 					WL_ERR(("Channel is not valid \n"));
1898*4882a593Smuzhiyun 					err = -EINVAL;
1899*4882a593Smuzhiyun 					goto exit;
1900*4882a593Smuzhiyun 				}
1901*4882a593Smuzhiyun 				WL_INFORM_MEM(("Target addr %s, Channel : %s for RTT \n",
1902*4882a593Smuzhiyun 					bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr,
1903*4882a593Smuzhiyun 					eabuf),
1904*4882a593Smuzhiyun 					wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
1905*4882a593Smuzhiyun 				rtt_target++;
1906*4882a593Smuzhiyun 			}
1907*4882a593Smuzhiyun 			break;
1908*4882a593Smuzhiyun 		}
1909*4882a593Smuzhiyun 	}
1910*4882a593Smuzhiyun 	WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
1911*4882a593Smuzhiyun 	if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
1912*4882a593Smuzhiyun 		WL_ERR(("Could not set RTT configuration\n"));
1913*4882a593Smuzhiyun 		err = -EINVAL;
1914*4882a593Smuzhiyun 	}
1915*4882a593Smuzhiyun exit:
1916*4882a593Smuzhiyun 	/* free the target info list */
1917*4882a593Smuzhiyun 	if (rtt_param.target_info) {
1918*4882a593Smuzhiyun 		MFREE(cfg->osh, rtt_param.target_info,
1919*4882a593Smuzhiyun 			TARGET_INFO_SIZE(target_cnt));
1920*4882a593Smuzhiyun 	}
1921*4882a593Smuzhiyun 	return err;
1922*4882a593Smuzhiyun }
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun static int
wl_cfgvendor_rtt_cancel_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1925*4882a593Smuzhiyun wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1926*4882a593Smuzhiyun 	const void *data, int len)
1927*4882a593Smuzhiyun {
1928*4882a593Smuzhiyun 	int err = 0, rem, type, target_cnt = 0;
1929*4882a593Smuzhiyun 	int target_idx = 0;
1930*4882a593Smuzhiyun 	const struct nlattr *iter;
1931*4882a593Smuzhiyun 	struct ether_addr *mac_list = NULL;
1932*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun 	if (len <= 0) {
1935*4882a593Smuzhiyun 		WL_ERR(("Length of nlattr is not valid len : %d\n", len));
1936*4882a593Smuzhiyun 		err = -EINVAL;
1937*4882a593Smuzhiyun 		goto exit;
1938*4882a593Smuzhiyun 	}
1939*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
1940*4882a593Smuzhiyun 		type = nla_type(iter);
1941*4882a593Smuzhiyun 		switch (type) {
1942*4882a593Smuzhiyun 		case RTT_ATTRIBUTE_TARGET_CNT:
1943*4882a593Smuzhiyun 			if (mac_list != NULL) {
1944*4882a593Smuzhiyun 				WL_ERR(("mac_list is not NULL\n"));
1945*4882a593Smuzhiyun 				err = -EINVAL;
1946*4882a593Smuzhiyun 				goto exit;
1947*4882a593Smuzhiyun 			}
1948*4882a593Smuzhiyun 			target_cnt = nla_get_u8(iter);
1949*4882a593Smuzhiyun 			if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) {
1950*4882a593Smuzhiyun 				mac_list = (struct ether_addr *)MALLOCZ(cfg->osh,
1951*4882a593Smuzhiyun 					target_cnt * ETHER_ADDR_LEN);
1952*4882a593Smuzhiyun 				if (mac_list == NULL) {
1953*4882a593Smuzhiyun 					WL_ERR(("failed to allocate mem for mac list\n"));
1954*4882a593Smuzhiyun 					err = -EINVAL;
1955*4882a593Smuzhiyun 					goto exit;
1956*4882a593Smuzhiyun 				}
1957*4882a593Smuzhiyun 			} else {
1958*4882a593Smuzhiyun 				/* cancel the current whole RTT process */
1959*4882a593Smuzhiyun 				goto cancel;
1960*4882a593Smuzhiyun 			}
1961*4882a593Smuzhiyun 			break;
1962*4882a593Smuzhiyun 		case RTT_ATTRIBUTE_TARGET_MAC:
1963*4882a593Smuzhiyun 			if (mac_list == NULL) {
1964*4882a593Smuzhiyun 				WL_ERR(("ATTRIBUTE_TARGET_CNT not found before "
1965*4882a593Smuzhiyun 						" ATTRIBUTE_TARGET_MAC\n"));
1966*4882a593Smuzhiyun 				err = -EINVAL;
1967*4882a593Smuzhiyun 				goto exit;
1968*4882a593Smuzhiyun 			}
1969*4882a593Smuzhiyun 
1970*4882a593Smuzhiyun 			if (target_idx >= target_cnt) {
1971*4882a593Smuzhiyun 				WL_ERR(("More TARGET_MAC entries found, "
1972*4882a593Smuzhiyun 						"expected TARGET_CNT:%d\n", target_cnt));
1973*4882a593Smuzhiyun 				err = -EINVAL;
1974*4882a593Smuzhiyun 				goto exit;
1975*4882a593Smuzhiyun 			}
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun 			if (nla_len(iter) != ETHER_ADDR_LEN) {
1978*4882a593Smuzhiyun 				WL_ERR(("Invalid TARGET_MAC ATTR len :%d\n", nla_len(iter)));
1979*4882a593Smuzhiyun 				err = -EINVAL;
1980*4882a593Smuzhiyun 				goto exit;
1981*4882a593Smuzhiyun 			}
1982*4882a593Smuzhiyun 
1983*4882a593Smuzhiyun 			memcpy(&mac_list[target_idx], nla_data(iter), ETHER_ADDR_LEN);
1984*4882a593Smuzhiyun 			target_idx++;
1985*4882a593Smuzhiyun 
1986*4882a593Smuzhiyun 			break;
1987*4882a593Smuzhiyun 		default:
1988*4882a593Smuzhiyun 			WL_ERR(("Uknown type : %d\n", type));
1989*4882a593Smuzhiyun 			err = -EINVAL;
1990*4882a593Smuzhiyun 			goto exit;
1991*4882a593Smuzhiyun 		}
1992*4882a593Smuzhiyun 	}
1993*4882a593Smuzhiyun cancel:
1994*4882a593Smuzhiyun 	if (mac_list && dhd_dev_rtt_cancel_cfg(
1995*4882a593Smuzhiyun 		bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
1996*4882a593Smuzhiyun 		WL_ERR(("Could not cancel RTT configuration\n"));
1997*4882a593Smuzhiyun 		err = -EINVAL;
1998*4882a593Smuzhiyun 	}
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun exit:
2001*4882a593Smuzhiyun 	if (mac_list) {
2002*4882a593Smuzhiyun 		MFREE(cfg->osh, mac_list, target_cnt * ETHER_ADDR_LEN);
2003*4882a593Smuzhiyun 	}
2004*4882a593Smuzhiyun 	return err;
2005*4882a593Smuzhiyun }
2006*4882a593Smuzhiyun 
2007*4882a593Smuzhiyun static int
wl_cfgvendor_rtt_get_capability(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2008*4882a593Smuzhiyun wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
2009*4882a593Smuzhiyun 	const void *data, int len)
2010*4882a593Smuzhiyun {
2011*4882a593Smuzhiyun 	int err = 0;
2012*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2013*4882a593Smuzhiyun 	rtt_capabilities_t capability;
2014*4882a593Smuzhiyun 
2015*4882a593Smuzhiyun 	err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
2016*4882a593Smuzhiyun 	if (unlikely(err)) {
2017*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2018*4882a593Smuzhiyun 		goto exit;
2019*4882a593Smuzhiyun 	}
2020*4882a593Smuzhiyun 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &capability, sizeof(capability));
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun 	if (unlikely(err)) {
2023*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2024*4882a593Smuzhiyun 	}
2025*4882a593Smuzhiyun exit:
2026*4882a593Smuzhiyun 	return err;
2027*4882a593Smuzhiyun }
2028*4882a593Smuzhiyun static int
get_responder_info(struct bcm_cfg80211 * cfg,struct wifi_rtt_responder * responder_info)2029*4882a593Smuzhiyun get_responder_info(struct bcm_cfg80211 *cfg,
2030*4882a593Smuzhiyun 	struct wifi_rtt_responder *responder_info)
2031*4882a593Smuzhiyun {
2032*4882a593Smuzhiyun 	int err = 0;
2033*4882a593Smuzhiyun 	rtt_capabilities_t capability;
2034*4882a593Smuzhiyun 	err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
2035*4882a593Smuzhiyun 	if (unlikely(err)) {
2036*4882a593Smuzhiyun 		WL_ERR(("Could not get responder capability:%d \n", err));
2037*4882a593Smuzhiyun 		return err;
2038*4882a593Smuzhiyun 	}
2039*4882a593Smuzhiyun 	if (capability.preamble_support & RTT_PREAMBLE_VHT) {
2040*4882a593Smuzhiyun 		responder_info->preamble |= RTT_PREAMBLE_VHT;
2041*4882a593Smuzhiyun 	}
2042*4882a593Smuzhiyun 	if (capability.preamble_support & RTT_PREAMBLE_HT) {
2043*4882a593Smuzhiyun 		responder_info->preamble |= RTT_PREAMBLE_HT;
2044*4882a593Smuzhiyun 	}
2045*4882a593Smuzhiyun 	err = dhd_dev_rtt_avail_channel(bcmcfg_to_prmry_ndev(cfg), &(responder_info->channel));
2046*4882a593Smuzhiyun 	if (unlikely(err)) {
2047*4882a593Smuzhiyun 		WL_ERR(("Could not get available channel:%d \n", err));
2048*4882a593Smuzhiyun 		return err;
2049*4882a593Smuzhiyun 	}
2050*4882a593Smuzhiyun 	return err;
2051*4882a593Smuzhiyun }
2052*4882a593Smuzhiyun static int
wl_cfgvendor_rtt_get_responder_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2053*4882a593Smuzhiyun wl_cfgvendor_rtt_get_responder_info(struct wiphy *wiphy, struct wireless_dev *wdev,
2054*4882a593Smuzhiyun 	const void *data, int len)
2055*4882a593Smuzhiyun {
2056*4882a593Smuzhiyun 	int err = 0;
2057*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2058*4882a593Smuzhiyun 	wifi_rtt_responder_t responder_info;
2059*4882a593Smuzhiyun 
2060*4882a593Smuzhiyun 	WL_DBG(("Recv -get_avail_ch command \n"));
2061*4882a593Smuzhiyun 
2062*4882a593Smuzhiyun 	bzero(&responder_info, sizeof(responder_info));
2063*4882a593Smuzhiyun 	err = get_responder_info(cfg, &responder_info);
2064*4882a593Smuzhiyun 	if (unlikely(err)) {
2065*4882a593Smuzhiyun 		WL_ERR(("Failed to get responder info:%d \n", err));
2066*4882a593Smuzhiyun 		return err;
2067*4882a593Smuzhiyun 	}
2068*4882a593Smuzhiyun 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &responder_info, sizeof(responder_info));
2069*4882a593Smuzhiyun 	if (unlikely(err)) {
2070*4882a593Smuzhiyun 		WL_ERR(("Vendor cmd reply for -get_avail_ch failed ret:%d \n", err));
2071*4882a593Smuzhiyun 	}
2072*4882a593Smuzhiyun 	return err;
2073*4882a593Smuzhiyun }
2074*4882a593Smuzhiyun 
2075*4882a593Smuzhiyun static int
wl_cfgvendor_rtt_set_responder(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2076*4882a593Smuzhiyun wl_cfgvendor_rtt_set_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
2077*4882a593Smuzhiyun 	const void *data, int len)
2078*4882a593Smuzhiyun {
2079*4882a593Smuzhiyun 	int err = 0;
2080*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2081*4882a593Smuzhiyun 	struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
2082*4882a593Smuzhiyun 	wifi_rtt_responder_t responder_info;
2083*4882a593Smuzhiyun 
2084*4882a593Smuzhiyun 	WL_DBG(("Recv rtt -enable_resp cmd.\n"));
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	bzero(&responder_info, sizeof(responder_info));
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun 	/*
2089*4882a593Smuzhiyun 	*Passing channel as NULL until implementation
2090*4882a593Smuzhiyun 	*to get chan info from upper layers is donex
2091*4882a593Smuzhiyun 	*/
2092*4882a593Smuzhiyun 	err = dhd_dev_rtt_enable_responder(ndev, NULL);
2093*4882a593Smuzhiyun 	if (unlikely(err)) {
2094*4882a593Smuzhiyun 		WL_ERR(("Could not enable responder ret:%d \n", err));
2095*4882a593Smuzhiyun 		goto done;
2096*4882a593Smuzhiyun 	}
2097*4882a593Smuzhiyun 	err = get_responder_info(cfg, &responder_info);
2098*4882a593Smuzhiyun 	if (unlikely(err)) {
2099*4882a593Smuzhiyun 		WL_ERR(("Failed to get responder info:%d \n", err));
2100*4882a593Smuzhiyun 		dhd_dev_rtt_cancel_responder(ndev);
2101*4882a593Smuzhiyun 		goto done;
2102*4882a593Smuzhiyun 	}
2103*4882a593Smuzhiyun done:
2104*4882a593Smuzhiyun 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &responder_info, sizeof(responder_info));
2105*4882a593Smuzhiyun 	if (unlikely(err)) {
2106*4882a593Smuzhiyun 		WL_ERR(("Vendor cmd reply for -enable_resp failed ret:%d \n", err));
2107*4882a593Smuzhiyun 	}
2108*4882a593Smuzhiyun 	return err;
2109*4882a593Smuzhiyun }
2110*4882a593Smuzhiyun 
2111*4882a593Smuzhiyun static int
wl_cfgvendor_rtt_cancel_responder(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2112*4882a593Smuzhiyun wl_cfgvendor_rtt_cancel_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
2113*4882a593Smuzhiyun 	const void *data, int len)
2114*4882a593Smuzhiyun {
2115*4882a593Smuzhiyun 	int err = 0;
2116*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	WL_DBG(("Recv rtt -cancel_resp cmd \n"));
2119*4882a593Smuzhiyun 
2120*4882a593Smuzhiyun 	err = dhd_dev_rtt_cancel_responder(bcmcfg_to_prmry_ndev(cfg));
2121*4882a593Smuzhiyun 	if (unlikely(err)) {
2122*4882a593Smuzhiyun 		WL_ERR(("Vendor cmd -cancel_resp failed ret:%d \n", err));
2123*4882a593Smuzhiyun 	}
2124*4882a593Smuzhiyun 	return err;
2125*4882a593Smuzhiyun }
2126*4882a593Smuzhiyun #endif /* RTT_SUPPORT */
2127*4882a593Smuzhiyun 
2128*4882a593Smuzhiyun #ifdef GSCAN_SUPPORT
wl_cfgvendor_enable_lazy_roam(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2129*4882a593Smuzhiyun static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy,
2130*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2131*4882a593Smuzhiyun {
2132*4882a593Smuzhiyun 	int err = -EINVAL;
2133*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2134*4882a593Smuzhiyun 	int type;
2135*4882a593Smuzhiyun 	uint32 lazy_roam_enable_flag;
2136*4882a593Smuzhiyun 
2137*4882a593Smuzhiyun 	if (!data) {
2138*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
2139*4882a593Smuzhiyun 		return -EINVAL;
2140*4882a593Smuzhiyun 	}
2141*4882a593Smuzhiyun 
2142*4882a593Smuzhiyun 	if (len <= 0) {
2143*4882a593Smuzhiyun 		WL_ERR(("invaild len %d\n", len));
2144*4882a593Smuzhiyun 		return -EINVAL;
2145*4882a593Smuzhiyun 	}
2146*4882a593Smuzhiyun 
2147*4882a593Smuzhiyun 	type = nla_type(data);
2148*4882a593Smuzhiyun 
2149*4882a593Smuzhiyun 	if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) {
2150*4882a593Smuzhiyun 		lazy_roam_enable_flag = nla_get_u32(data);
2151*4882a593Smuzhiyun 
2152*4882a593Smuzhiyun 		err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg),
2153*4882a593Smuzhiyun 		           lazy_roam_enable_flag);
2154*4882a593Smuzhiyun 		if (unlikely(err))
2155*4882a593Smuzhiyun 			WL_ERR(("Could not enable lazy roam:%d \n", err));
2156*4882a593Smuzhiyun 	}
2157*4882a593Smuzhiyun 
2158*4882a593Smuzhiyun 	return err;
2159*4882a593Smuzhiyun }
2160*4882a593Smuzhiyun 
wl_cfgvendor_set_lazy_roam_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2161*4882a593Smuzhiyun static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy,
2162*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2163*4882a593Smuzhiyun {
2164*4882a593Smuzhiyun 	int err = 0, tmp, type;
2165*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2166*4882a593Smuzhiyun 	wlc_roam_exp_params_t roam_param;
2167*4882a593Smuzhiyun 	const struct nlattr *iter;
2168*4882a593Smuzhiyun 
2169*4882a593Smuzhiyun 	bzero(&roam_param, sizeof(roam_param));
2170*4882a593Smuzhiyun 
2171*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
2172*4882a593Smuzhiyun 		type = nla_type(iter);
2173*4882a593Smuzhiyun 		switch (type) {
2174*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD:
2175*4882a593Smuzhiyun 				roam_param.a_band_boost_threshold = nla_get_u32(iter);
2176*4882a593Smuzhiyun 				break;
2177*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD:
2178*4882a593Smuzhiyun 				roam_param.a_band_penalty_threshold = nla_get_u32(iter);
2179*4882a593Smuzhiyun 				break;
2180*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR:
2181*4882a593Smuzhiyun 				roam_param.a_band_boost_factor = nla_get_u32(iter);
2182*4882a593Smuzhiyun 				break;
2183*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR:
2184*4882a593Smuzhiyun 				roam_param.a_band_penalty_factor = nla_get_u32(iter);
2185*4882a593Smuzhiyun 				break;
2186*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST:
2187*4882a593Smuzhiyun 				roam_param.a_band_max_boost = nla_get_u32(iter);
2188*4882a593Smuzhiyun 				break;
2189*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS:
2190*4882a593Smuzhiyun 				roam_param.cur_bssid_boost = nla_get_u32(iter);
2191*4882a593Smuzhiyun 				break;
2192*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER:
2193*4882a593Smuzhiyun 				roam_param.alert_roam_trigger_threshold = nla_get_u32(iter);
2194*4882a593Smuzhiyun 				break;
2195*4882a593Smuzhiyun 		}
2196*4882a593Smuzhiyun 	}
2197*4882a593Smuzhiyun 
2198*4882a593Smuzhiyun 	if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) {
2199*4882a593Smuzhiyun 		WL_ERR(("Could not set batch cfg\n"));
2200*4882a593Smuzhiyun 		err = -EINVAL;
2201*4882a593Smuzhiyun 	}
2202*4882a593Smuzhiyun 	return err;
2203*4882a593Smuzhiyun }
2204*4882a593Smuzhiyun 
2205*4882a593Smuzhiyun /* small helper function */
2206*4882a593Smuzhiyun static wl_bssid_pref_cfg_t *
create_bssid_pref_cfg(struct bcm_cfg80211 * cfg,uint32 num,uint32 * buf_len)2207*4882a593Smuzhiyun create_bssid_pref_cfg(struct bcm_cfg80211 *cfg, uint32 num, uint32 *buf_len)
2208*4882a593Smuzhiyun {
2209*4882a593Smuzhiyun 	wl_bssid_pref_cfg_t *bssid_pref;
2210*4882a593Smuzhiyun 
2211*4882a593Smuzhiyun 	*buf_len = sizeof(wl_bssid_pref_cfg_t);
2212*4882a593Smuzhiyun 	if (num) {
2213*4882a593Smuzhiyun 		*buf_len += (num - 1) * sizeof(wl_bssid_pref_list_t);
2214*4882a593Smuzhiyun 	}
2215*4882a593Smuzhiyun 	bssid_pref = (wl_bssid_pref_cfg_t *)MALLOC(cfg->osh, *buf_len);
2216*4882a593Smuzhiyun 
2217*4882a593Smuzhiyun 	return bssid_pref;
2218*4882a593Smuzhiyun }
2219*4882a593Smuzhiyun 
2220*4882a593Smuzhiyun static int
wl_cfgvendor_set_bssid_pref(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2221*4882a593Smuzhiyun wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy,
2222*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2223*4882a593Smuzhiyun {
2224*4882a593Smuzhiyun 	int err = 0;
2225*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2226*4882a593Smuzhiyun 	wl_bssid_pref_cfg_t *bssid_pref = NULL;
2227*4882a593Smuzhiyun 	wl_bssid_pref_list_t *bssids;
2228*4882a593Smuzhiyun 	int tmp, tmp1, tmp2, type;
2229*4882a593Smuzhiyun 	const struct nlattr *outer, *inner, *iter;
2230*4882a593Smuzhiyun 	uint32 flush = 0, num = 0, buf_len = 0;
2231*4882a593Smuzhiyun 	uint8 bssid_found = 0, rssi_found = 0;
2232*4882a593Smuzhiyun 
2233*4882a593Smuzhiyun 	/* Assumption: NUM attribute must come first */
2234*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp2) {
2235*4882a593Smuzhiyun 		type = nla_type(iter);
2236*4882a593Smuzhiyun 		switch (type) {
2237*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_NUM_BSSID:
2238*4882a593Smuzhiyun 				if (num) {
2239*4882a593Smuzhiyun 					WL_ERR(("attempt overide bssid num.\n"));
2240*4882a593Smuzhiyun 					err = -EINVAL;
2241*4882a593Smuzhiyun 					goto exit;
2242*4882a593Smuzhiyun 				}
2243*4882a593Smuzhiyun 				if (nla_len(iter) != sizeof(uint32)) {
2244*4882a593Smuzhiyun 					WL_ERR(("nla_len not match\n"));
2245*4882a593Smuzhiyun 					err = -EINVAL;
2246*4882a593Smuzhiyun 					goto exit;
2247*4882a593Smuzhiyun 				}
2248*4882a593Smuzhiyun 				num = nla_get_u32(iter);
2249*4882a593Smuzhiyun 				if (num == 0 || num > MAX_BSSID_PREF_LIST_NUM) {
2250*4882a593Smuzhiyun 					WL_ERR(("wrong BSSID num:%d\n", num));
2251*4882a593Smuzhiyun 					err = -EINVAL;
2252*4882a593Smuzhiyun 					goto exit;
2253*4882a593Smuzhiyun 				}
2254*4882a593Smuzhiyun 				if ((bssid_pref = create_bssid_pref_cfg(cfg, num, &buf_len))
2255*4882a593Smuzhiyun 							== NULL) {
2256*4882a593Smuzhiyun 					WL_ERR(("Can't malloc memory\n"));
2257*4882a593Smuzhiyun 					err = -ENOMEM;
2258*4882a593Smuzhiyun 					goto exit;
2259*4882a593Smuzhiyun 				}
2260*4882a593Smuzhiyun 				break;
2261*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH:
2262*4882a593Smuzhiyun 				if (nla_len(iter) != sizeof(uint32)) {
2263*4882a593Smuzhiyun 					WL_ERR(("nla_len not match\n"));
2264*4882a593Smuzhiyun 					err = -EINVAL;
2265*4882a593Smuzhiyun 					goto exit;
2266*4882a593Smuzhiyun 				}
2267*4882a593Smuzhiyun 				flush = nla_get_u32(iter);
2268*4882a593Smuzhiyun 				if (flush != 1) {
2269*4882a593Smuzhiyun 					WL_ERR(("wrong flush value\n"));
2270*4882a593Smuzhiyun 					err = -EINVAL;
2271*4882a593Smuzhiyun 					goto exit;
2272*4882a593Smuzhiyun 				}
2273*4882a593Smuzhiyun 				break;
2274*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_BSSID_PREF_LIST:
2275*4882a593Smuzhiyun 				if (!num || !bssid_pref) {
2276*4882a593Smuzhiyun 					WL_ERR(("bssid list count not set\n"));
2277*4882a593Smuzhiyun 					err = -EINVAL;
2278*4882a593Smuzhiyun 					goto exit;
2279*4882a593Smuzhiyun 				}
2280*4882a593Smuzhiyun 				bssid_pref->count = 0;
2281*4882a593Smuzhiyun 				bssids = bssid_pref->bssids;
2282*4882a593Smuzhiyun 				nla_for_each_nested(outer, iter, tmp) {
2283*4882a593Smuzhiyun 					if (bssid_pref->count >= num) {
2284*4882a593Smuzhiyun 						WL_ERR(("too many bssid list\n"));
2285*4882a593Smuzhiyun 						err = -EINVAL;
2286*4882a593Smuzhiyun 						goto exit;
2287*4882a593Smuzhiyun 					}
2288*4882a593Smuzhiyun 					bssid_found = 0;
2289*4882a593Smuzhiyun 					rssi_found = 0;
2290*4882a593Smuzhiyun 					nla_for_each_nested(inner, outer, tmp1) {
2291*4882a593Smuzhiyun 						type = nla_type(inner);
2292*4882a593Smuzhiyun 						switch (type) {
2293*4882a593Smuzhiyun 						case GSCAN_ATTRIBUTE_BSSID_PREF:
2294*4882a593Smuzhiyun 							if (nla_len(inner) != ETHER_ADDR_LEN) {
2295*4882a593Smuzhiyun 								WL_ERR(("nla_len not match.\n"));
2296*4882a593Smuzhiyun 								err = -EINVAL;
2297*4882a593Smuzhiyun 								goto exit;
2298*4882a593Smuzhiyun 							}
2299*4882a593Smuzhiyun 							memcpy(&(bssids[bssid_pref->count].bssid),
2300*4882a593Smuzhiyun 							  nla_data(inner), ETHER_ADDR_LEN);
2301*4882a593Smuzhiyun 							/* not used for now */
2302*4882a593Smuzhiyun 							bssids[bssid_pref->count].flags = 0;
2303*4882a593Smuzhiyun 							bssid_found = 1;
2304*4882a593Smuzhiyun 							break;
2305*4882a593Smuzhiyun 						case GSCAN_ATTRIBUTE_RSSI_MODIFIER:
2306*4882a593Smuzhiyun 							if (nla_len(inner) != sizeof(uint32)) {
2307*4882a593Smuzhiyun 								WL_ERR(("nla_len not match.\n"));
2308*4882a593Smuzhiyun 								err = -EINVAL;
2309*4882a593Smuzhiyun 								goto exit;
2310*4882a593Smuzhiyun 							}
2311*4882a593Smuzhiyun 							bssids[bssid_pref->count].rssi_factor =
2312*4882a593Smuzhiyun 							       (int8) nla_get_u32(inner);
2313*4882a593Smuzhiyun 							rssi_found = 1;
2314*4882a593Smuzhiyun 							break;
2315*4882a593Smuzhiyun 						default:
2316*4882a593Smuzhiyun 							WL_ERR(("wrong type:%d\n", type));
2317*4882a593Smuzhiyun 							err = -EINVAL;
2318*4882a593Smuzhiyun 							goto exit;
2319*4882a593Smuzhiyun 						}
2320*4882a593Smuzhiyun 						if (bssid_found && rssi_found) {
2321*4882a593Smuzhiyun 							break;
2322*4882a593Smuzhiyun 						}
2323*4882a593Smuzhiyun 					}
2324*4882a593Smuzhiyun 					bssid_pref->count++;
2325*4882a593Smuzhiyun 				}
2326*4882a593Smuzhiyun 				break;
2327*4882a593Smuzhiyun 			default:
2328*4882a593Smuzhiyun 				WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
2329*4882a593Smuzhiyun 				break;
2330*4882a593Smuzhiyun 			}
2331*4882a593Smuzhiyun 	}
2332*4882a593Smuzhiyun 
2333*4882a593Smuzhiyun 	if (!bssid_pref) {
2334*4882a593Smuzhiyun 		/* What if only flush is desired? */
2335*4882a593Smuzhiyun 		if (flush) {
2336*4882a593Smuzhiyun 			if ((bssid_pref = create_bssid_pref_cfg(cfg, 0, &buf_len)) == NULL) {
2337*4882a593Smuzhiyun 				WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__));
2338*4882a593Smuzhiyun 				err = -ENOMEM;
2339*4882a593Smuzhiyun 				goto exit;
2340*4882a593Smuzhiyun 			}
2341*4882a593Smuzhiyun 			bssid_pref->count = 0;
2342*4882a593Smuzhiyun 		} else {
2343*4882a593Smuzhiyun 			err = -EINVAL;
2344*4882a593Smuzhiyun 			goto exit;
2345*4882a593Smuzhiyun 		}
2346*4882a593Smuzhiyun 	}
2347*4882a593Smuzhiyun 	err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg),
2348*4882a593Smuzhiyun 	          bssid_pref, flush);
2349*4882a593Smuzhiyun exit:
2350*4882a593Smuzhiyun 	if (bssid_pref) {
2351*4882a593Smuzhiyun 		MFREE(cfg->osh, bssid_pref, buf_len);
2352*4882a593Smuzhiyun 	}
2353*4882a593Smuzhiyun 	return err;
2354*4882a593Smuzhiyun }
2355*4882a593Smuzhiyun #endif /* GSCAN_SUPPORT */
2356*4882a593Smuzhiyun #if defined(GSCAN_SUPPORT) || defined(ROAMEXP_SUPPORT)
2357*4882a593Smuzhiyun static int
wl_cfgvendor_set_bssid_blacklist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2358*4882a593Smuzhiyun wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy,
2359*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2360*4882a593Smuzhiyun {
2361*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2362*4882a593Smuzhiyun 	maclist_t *blacklist = NULL;
2363*4882a593Smuzhiyun 	int err = 0;
2364*4882a593Smuzhiyun 	int type, tmp;
2365*4882a593Smuzhiyun 	const struct nlattr *iter;
2366*4882a593Smuzhiyun 	uint32 mem_needed = 0, flush = 0, num = 0;
2367*4882a593Smuzhiyun 
2368*4882a593Smuzhiyun 	/* Assumption: NUM attribute must come first */
2369*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
2370*4882a593Smuzhiyun 		type = nla_type(iter);
2371*4882a593Smuzhiyun 		switch (type) {
2372*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_NUM_BSSID:
2373*4882a593Smuzhiyun 				if (num != 0) {
2374*4882a593Smuzhiyun 					WL_ERR(("attempt to change BSSID num\n"));
2375*4882a593Smuzhiyun 					err = -EINVAL;
2376*4882a593Smuzhiyun 					goto exit;
2377*4882a593Smuzhiyun 				}
2378*4882a593Smuzhiyun 				if (nla_len(iter) != sizeof(uint32)) {
2379*4882a593Smuzhiyun 					WL_ERR(("not matching nla_len.\n"));
2380*4882a593Smuzhiyun 					err = -EINVAL;
2381*4882a593Smuzhiyun 					goto exit;
2382*4882a593Smuzhiyun 				}
2383*4882a593Smuzhiyun 				num = nla_get_u32(iter);
2384*4882a593Smuzhiyun 				if (num == 0 || num > MAX_BSSID_BLACKLIST_NUM) {
2385*4882a593Smuzhiyun 					WL_ERR(("wrong BSSID count:%d\n", num));
2386*4882a593Smuzhiyun 					err = -EINVAL;
2387*4882a593Smuzhiyun 					goto exit;
2388*4882a593Smuzhiyun 				}
2389*4882a593Smuzhiyun 				if (!blacklist) {
2390*4882a593Smuzhiyun 					mem_needed = OFFSETOF(maclist_t, ea) +
2391*4882a593Smuzhiyun 						sizeof(struct ether_addr) * (num);
2392*4882a593Smuzhiyun 					blacklist = (maclist_t *)
2393*4882a593Smuzhiyun 						MALLOCZ(cfg->osh, mem_needed);
2394*4882a593Smuzhiyun 					if (!blacklist) {
2395*4882a593Smuzhiyun 						WL_ERR(("MALLOCZ failed.\n"));
2396*4882a593Smuzhiyun 						err = -ENOMEM;
2397*4882a593Smuzhiyun 						goto exit;
2398*4882a593Smuzhiyun 					}
2399*4882a593Smuzhiyun 				}
2400*4882a593Smuzhiyun 				break;
2401*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH:
2402*4882a593Smuzhiyun 				if (nla_len(iter) != sizeof(uint32)) {
2403*4882a593Smuzhiyun 					WL_ERR(("not matching nla_len.\n"));
2404*4882a593Smuzhiyun 					err = -EINVAL;
2405*4882a593Smuzhiyun 					goto exit;
2406*4882a593Smuzhiyun 				}
2407*4882a593Smuzhiyun 				flush = nla_get_u32(iter);
2408*4882a593Smuzhiyun 				if (flush != 1) {
2409*4882a593Smuzhiyun 					WL_ERR(("flush arg is worng:%d\n", flush));
2410*4882a593Smuzhiyun 					err = -EINVAL;
2411*4882a593Smuzhiyun 					goto exit;
2412*4882a593Smuzhiyun 				}
2413*4882a593Smuzhiyun 				break;
2414*4882a593Smuzhiyun 			case GSCAN_ATTRIBUTE_BLACKLIST_BSSID:
2415*4882a593Smuzhiyun 				if (num == 0 || !blacklist) {
2416*4882a593Smuzhiyun 					WL_ERR(("number of BSSIDs not received.\n"));
2417*4882a593Smuzhiyun 					err = -EINVAL;
2418*4882a593Smuzhiyun 					goto exit;
2419*4882a593Smuzhiyun 				}
2420*4882a593Smuzhiyun 				if (nla_len(iter) != ETHER_ADDR_LEN) {
2421*4882a593Smuzhiyun 					WL_ERR(("not matching nla_len.\n"));
2422*4882a593Smuzhiyun 					err = -EINVAL;
2423*4882a593Smuzhiyun 					goto exit;
2424*4882a593Smuzhiyun 				}
2425*4882a593Smuzhiyun 				if (blacklist->count >= num) {
2426*4882a593Smuzhiyun 					WL_ERR(("too many BSSIDs than expected:%d\n",
2427*4882a593Smuzhiyun 						blacklist->count));
2428*4882a593Smuzhiyun 					err = -EINVAL;
2429*4882a593Smuzhiyun 					goto exit;
2430*4882a593Smuzhiyun 				}
2431*4882a593Smuzhiyun 				memcpy(&(blacklist->ea[blacklist->count]), nla_data(iter),
2432*4882a593Smuzhiyun 						ETHER_ADDR_LEN);
2433*4882a593Smuzhiyun 				blacklist->count++;
2434*4882a593Smuzhiyun 				break;
2435*4882a593Smuzhiyun 		default:
2436*4882a593Smuzhiyun 			WL_ERR(("No such attribute:%d\n", type));
2437*4882a593Smuzhiyun 			break;
2438*4882a593Smuzhiyun 		}
2439*4882a593Smuzhiyun 	}
2440*4882a593Smuzhiyun 
2441*4882a593Smuzhiyun 	if (blacklist && (blacklist->count != num)) {
2442*4882a593Smuzhiyun 		WL_ERR(("not matching bssid count:%d to expected:%d\n",
2443*4882a593Smuzhiyun 				blacklist->count, num));
2444*4882a593Smuzhiyun 		err = -EINVAL;
2445*4882a593Smuzhiyun 		goto exit;
2446*4882a593Smuzhiyun 	}
2447*4882a593Smuzhiyun 
2448*4882a593Smuzhiyun 	err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg),
2449*4882a593Smuzhiyun 	          blacklist, mem_needed, flush);
2450*4882a593Smuzhiyun exit:
2451*4882a593Smuzhiyun 	MFREE(cfg->osh, blacklist, mem_needed);
2452*4882a593Smuzhiyun 	return err;
2453*4882a593Smuzhiyun }
2454*4882a593Smuzhiyun 
2455*4882a593Smuzhiyun static int
wl_cfgvendor_set_ssid_whitelist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2456*4882a593Smuzhiyun wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy,
2457*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2458*4882a593Smuzhiyun {
2459*4882a593Smuzhiyun 	int err = 0;
2460*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2461*4882a593Smuzhiyun 	wl_ssid_whitelist_t *ssid_whitelist = NULL;
2462*4882a593Smuzhiyun 	wlc_ssid_t *ssid_elem;
2463*4882a593Smuzhiyun 	int tmp, tmp1, mem_needed = 0, type;
2464*4882a593Smuzhiyun 	const struct nlattr *iter, *iter1;
2465*4882a593Smuzhiyun 	uint32 flush = 0, num = 0;
2466*4882a593Smuzhiyun 	int ssid_found = 0;
2467*4882a593Smuzhiyun 
2468*4882a593Smuzhiyun 	/* Assumption: NUM attribute must come first */
2469*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
2470*4882a593Smuzhiyun 		type = nla_type(iter);
2471*4882a593Smuzhiyun 		switch (type) {
2472*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_NUM_WL_SSID:
2473*4882a593Smuzhiyun 			if (num != 0) {
2474*4882a593Smuzhiyun 				WL_ERR(("try to change SSID num\n"));
2475*4882a593Smuzhiyun 				err = -EINVAL;
2476*4882a593Smuzhiyun 				goto exit;
2477*4882a593Smuzhiyun 			}
2478*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
2479*4882a593Smuzhiyun 				WL_ERR(("not matching nla_len.\n"));
2480*4882a593Smuzhiyun 				err = -EINVAL;
2481*4882a593Smuzhiyun 				goto exit;
2482*4882a593Smuzhiyun 			}
2483*4882a593Smuzhiyun 			num = nla_get_u32(iter);
2484*4882a593Smuzhiyun 			if (num == 0 || num > MAX_SSID_WHITELIST_NUM) {
2485*4882a593Smuzhiyun 				WL_ERR(("wrong SSID count:%d\n", num));
2486*4882a593Smuzhiyun 				err = -EINVAL;
2487*4882a593Smuzhiyun 				goto exit;
2488*4882a593Smuzhiyun 			}
2489*4882a593Smuzhiyun 			mem_needed = sizeof(wl_ssid_whitelist_t) +
2490*4882a593Smuzhiyun 				sizeof(wlc_ssid_t) * num;
2491*4882a593Smuzhiyun 			ssid_whitelist = (wl_ssid_whitelist_t *)
2492*4882a593Smuzhiyun 				MALLOCZ(cfg->osh, mem_needed);
2493*4882a593Smuzhiyun 			if (ssid_whitelist == NULL) {
2494*4882a593Smuzhiyun 				WL_ERR(("failed to alloc mem\n"));
2495*4882a593Smuzhiyun 				err = -ENOMEM;
2496*4882a593Smuzhiyun 				goto exit;
2497*4882a593Smuzhiyun 			}
2498*4882a593Smuzhiyun 			break;
2499*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_WL_SSID_FLUSH:
2500*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
2501*4882a593Smuzhiyun 				WL_ERR(("not matching nla_len.\n"));
2502*4882a593Smuzhiyun 				err = -EINVAL;
2503*4882a593Smuzhiyun 				goto exit;
2504*4882a593Smuzhiyun 			}
2505*4882a593Smuzhiyun 			flush = nla_get_u32(iter);
2506*4882a593Smuzhiyun 			if (flush != 1) {
2507*4882a593Smuzhiyun 				WL_ERR(("flush arg worng:%d\n", flush));
2508*4882a593Smuzhiyun 				err = -EINVAL;
2509*4882a593Smuzhiyun 				goto exit;
2510*4882a593Smuzhiyun 			}
2511*4882a593Smuzhiyun 			break;
2512*4882a593Smuzhiyun 		case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM:
2513*4882a593Smuzhiyun 			if (!num || !ssid_whitelist) {
2514*4882a593Smuzhiyun 				WL_ERR(("num ssid is not set!\n"));
2515*4882a593Smuzhiyun 				err = -EINVAL;
2516*4882a593Smuzhiyun 				goto exit;
2517*4882a593Smuzhiyun 			}
2518*4882a593Smuzhiyun 			if (ssid_whitelist->ssid_count >= num) {
2519*4882a593Smuzhiyun 				WL_ERR(("too many SSIDs:%d\n",
2520*4882a593Smuzhiyun 					ssid_whitelist->ssid_count));
2521*4882a593Smuzhiyun 				err = -EINVAL;
2522*4882a593Smuzhiyun 				goto exit;
2523*4882a593Smuzhiyun 			}
2524*4882a593Smuzhiyun 
2525*4882a593Smuzhiyun 			ssid_elem = &ssid_whitelist->ssids[
2526*4882a593Smuzhiyun 					ssid_whitelist->ssid_count];
2527*4882a593Smuzhiyun 			ssid_found = 0;
2528*4882a593Smuzhiyun 			nla_for_each_nested(iter1, iter, tmp1) {
2529*4882a593Smuzhiyun 				type = nla_type(iter1);
2530*4882a593Smuzhiyun 				switch (type) {
2531*4882a593Smuzhiyun 				case GSCAN_ATTRIBUTE_WL_SSID_LEN:
2532*4882a593Smuzhiyun 					if (nla_len(iter1) != sizeof(uint32)) {
2533*4882a593Smuzhiyun 						WL_ERR(("not match nla_len\n"));
2534*4882a593Smuzhiyun 						err = -EINVAL;
2535*4882a593Smuzhiyun 						goto exit;
2536*4882a593Smuzhiyun 					}
2537*4882a593Smuzhiyun 					ssid_elem->SSID_len = nla_get_u32(iter1);
2538*4882a593Smuzhiyun 					if (ssid_elem->SSID_len >
2539*4882a593Smuzhiyun 							DOT11_MAX_SSID_LEN) {
2540*4882a593Smuzhiyun 						WL_ERR(("wrong SSID len:%d\n",
2541*4882a593Smuzhiyun 							ssid_elem->SSID_len));
2542*4882a593Smuzhiyun 						err = -EINVAL;
2543*4882a593Smuzhiyun 						goto exit;
2544*4882a593Smuzhiyun 					}
2545*4882a593Smuzhiyun 					break;
2546*4882a593Smuzhiyun 				case GSCAN_ATTRIBUTE_WHITELIST_SSID:
2547*4882a593Smuzhiyun 					if (ssid_elem->SSID_len == 0) {
2548*4882a593Smuzhiyun 						WL_ERR(("SSID_len not received\n"));
2549*4882a593Smuzhiyun 						err = -EINVAL;
2550*4882a593Smuzhiyun 						goto exit;
2551*4882a593Smuzhiyun 					}
2552*4882a593Smuzhiyun 					if (nla_len(iter1) != ssid_elem->SSID_len) {
2553*4882a593Smuzhiyun 						WL_ERR(("not match nla_len\n"));
2554*4882a593Smuzhiyun 						err = -EINVAL;
2555*4882a593Smuzhiyun 						goto exit;
2556*4882a593Smuzhiyun 					}
2557*4882a593Smuzhiyun 					memcpy(ssid_elem->SSID, nla_data(iter1),
2558*4882a593Smuzhiyun 							ssid_elem->SSID_len);
2559*4882a593Smuzhiyun 					ssid_found = 1;
2560*4882a593Smuzhiyun 					break;
2561*4882a593Smuzhiyun 				}
2562*4882a593Smuzhiyun 				if (ssid_found) {
2563*4882a593Smuzhiyun 					ssid_whitelist->ssid_count++;
2564*4882a593Smuzhiyun 					break;
2565*4882a593Smuzhiyun 				}
2566*4882a593Smuzhiyun 			}
2567*4882a593Smuzhiyun 			break;
2568*4882a593Smuzhiyun 		default:
2569*4882a593Smuzhiyun 			WL_ERR(("No such attribute: %d\n", type));
2570*4882a593Smuzhiyun 			break;
2571*4882a593Smuzhiyun 		}
2572*4882a593Smuzhiyun 	}
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun 	if (ssid_whitelist && (ssid_whitelist->ssid_count != num)) {
2575*4882a593Smuzhiyun 		WL_ERR(("not matching ssid count:%d to expected:%d\n",
2576*4882a593Smuzhiyun 				ssid_whitelist->ssid_count, num));
2577*4882a593Smuzhiyun 		err = -EINVAL;
2578*4882a593Smuzhiyun 		goto exit;
2579*4882a593Smuzhiyun 	}
2580*4882a593Smuzhiyun 	err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg),
2581*4882a593Smuzhiyun 	          ssid_whitelist, mem_needed, flush);
2582*4882a593Smuzhiyun exit:
2583*4882a593Smuzhiyun 	MFREE(cfg->osh, ssid_whitelist, mem_needed);
2584*4882a593Smuzhiyun 	return err;
2585*4882a593Smuzhiyun }
2586*4882a593Smuzhiyun #endif /* GSCAN_SUPPORT || ROAMEXP_SUPPORT */
2587*4882a593Smuzhiyun 
2588*4882a593Smuzhiyun #ifdef ROAMEXP_SUPPORT
2589*4882a593Smuzhiyun typedef enum {
2590*4882a593Smuzhiyun 	FW_ROAMING_ENABLE = 1,
2591*4882a593Smuzhiyun 	FW_ROAMING_DISABLE,
2592*4882a593Smuzhiyun 	FW_ROAMING_PAUSE,
2593*4882a593Smuzhiyun 	FW_ROAMING_RESUME
2594*4882a593Smuzhiyun } fw_roaming_state_t;
2595*4882a593Smuzhiyun 
2596*4882a593Smuzhiyun static int
wl_cfgvendor_set_fw_roaming_state(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2597*4882a593Smuzhiyun wl_cfgvendor_set_fw_roaming_state(struct wiphy *wiphy,
2598*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2599*4882a593Smuzhiyun {
2600*4882a593Smuzhiyun 	fw_roaming_state_t requested_roaming_state;
2601*4882a593Smuzhiyun 	int type;
2602*4882a593Smuzhiyun 	int err = 0;
2603*4882a593Smuzhiyun 
2604*4882a593Smuzhiyun 	if (!data) {
2605*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
2606*4882a593Smuzhiyun 		return -EINVAL;
2607*4882a593Smuzhiyun 	}
2608*4882a593Smuzhiyun 
2609*4882a593Smuzhiyun 	if (len <= 0) {
2610*4882a593Smuzhiyun 		WL_ERR(("invalid len %d\n", len));
2611*4882a593Smuzhiyun 		return -EINVAL;
2612*4882a593Smuzhiyun 	}
2613*4882a593Smuzhiyun 
2614*4882a593Smuzhiyun 	/* Get the requested fw roaming state */
2615*4882a593Smuzhiyun 	type = nla_type(data);
2616*4882a593Smuzhiyun 	if (type != GSCAN_ATTRIBUTE_ROAM_STATE_SET) {
2617*4882a593Smuzhiyun 		WL_ERR(("%s: Invalid attribute %d\n", __FUNCTION__, type));
2618*4882a593Smuzhiyun 		return -EINVAL;
2619*4882a593Smuzhiyun 	}
2620*4882a593Smuzhiyun 
2621*4882a593Smuzhiyun 	requested_roaming_state = nla_get_u32(data);
2622*4882a593Smuzhiyun 	WL_INFORM(("setting FW roaming state to %d\n", requested_roaming_state));
2623*4882a593Smuzhiyun 
2624*4882a593Smuzhiyun 	if ((requested_roaming_state == FW_ROAMING_ENABLE) ||
2625*4882a593Smuzhiyun 		(requested_roaming_state == FW_ROAMING_RESUME)) {
2626*4882a593Smuzhiyun 		err = wldev_iovar_setint(wdev_to_ndev(wdev), "roam_off", FALSE);
2627*4882a593Smuzhiyun 	} else if ((requested_roaming_state == FW_ROAMING_DISABLE) ||
2628*4882a593Smuzhiyun 		(requested_roaming_state == FW_ROAMING_PAUSE)) {
2629*4882a593Smuzhiyun 		err = wldev_iovar_setint(wdev_to_ndev(wdev), "roam_off", TRUE);
2630*4882a593Smuzhiyun 	} else {
2631*4882a593Smuzhiyun 		err = -EINVAL;
2632*4882a593Smuzhiyun 	}
2633*4882a593Smuzhiyun 
2634*4882a593Smuzhiyun 	return err;
2635*4882a593Smuzhiyun }
2636*4882a593Smuzhiyun 
2637*4882a593Smuzhiyun static int
wl_cfgvendor_fw_roam_get_capability(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2638*4882a593Smuzhiyun wl_cfgvendor_fw_roam_get_capability(struct wiphy *wiphy,
2639*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2640*4882a593Smuzhiyun {
2641*4882a593Smuzhiyun 	int err = 0;
2642*4882a593Smuzhiyun 	wifi_roaming_capabilities_t roaming_capability;
2643*4882a593Smuzhiyun 
2644*4882a593Smuzhiyun 	/* Update max number of blacklist bssids supported */
2645*4882a593Smuzhiyun 	roaming_capability.max_blacklist_size = MAX_BSSID_BLACKLIST_NUM;
2646*4882a593Smuzhiyun 	roaming_capability.max_whitelist_size = MAX_SSID_WHITELIST_NUM;
2647*4882a593Smuzhiyun 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &roaming_capability,
2648*4882a593Smuzhiyun 		sizeof(roaming_capability));
2649*4882a593Smuzhiyun 	if (unlikely(err)) {
2650*4882a593Smuzhiyun 		WL_ERR(("Vendor cmd reply for fw roam capability failed ret:%d \n", err));
2651*4882a593Smuzhiyun 	}
2652*4882a593Smuzhiyun 
2653*4882a593Smuzhiyun 	return err;
2654*4882a593Smuzhiyun }
2655*4882a593Smuzhiyun #endif /* ROAMEXP_SUPPORT */
2656*4882a593Smuzhiyun 
2657*4882a593Smuzhiyun static int
wl_cfgvendor_priv_string_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2658*4882a593Smuzhiyun wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
2659*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2660*4882a593Smuzhiyun {
2661*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2662*4882a593Smuzhiyun 	int ret = 0;
2663*4882a593Smuzhiyun 	int ret_len = 0, payload = 0, msglen;
2664*4882a593Smuzhiyun 	const struct bcm_nlmsg_hdr *nlioc = data;
2665*4882a593Smuzhiyun 	void *buf = NULL, *cur;
2666*4882a593Smuzhiyun 	int maxmsglen = PAGE_SIZE - 0x100;
2667*4882a593Smuzhiyun 	struct sk_buff *reply;
2668*4882a593Smuzhiyun #if defined(OEM_ANDROID)
2669*4882a593Smuzhiyun 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
2670*4882a593Smuzhiyun 
2671*4882a593Smuzhiyun 	/* send to dongle only if we are not waiting for reload already */
2672*4882a593Smuzhiyun 	if (dhdp && dhdp->hang_was_sent) {
2673*4882a593Smuzhiyun 		WL_INFORM(("Bus down. HANG was sent up earlier\n"));
2674*4882a593Smuzhiyun 		DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, DHD_EVENT_TIMEOUT_MS);
2675*4882a593Smuzhiyun 		DHD_OS_WAKE_UNLOCK(dhdp);
2676*4882a593Smuzhiyun 		return OSL_ERROR(BCME_DONGLE_DOWN);
2677*4882a593Smuzhiyun 	}
2678*4882a593Smuzhiyun #endif /* (OEM_ANDROID) */
2679*4882a593Smuzhiyun 
2680*4882a593Smuzhiyun 	if (!data) {
2681*4882a593Smuzhiyun 		WL_ERR(("data is not available\n"));
2682*4882a593Smuzhiyun 		return BCME_BADARG;
2683*4882a593Smuzhiyun 	}
2684*4882a593Smuzhiyun 
2685*4882a593Smuzhiyun 	if (len <= 0) {
2686*4882a593Smuzhiyun 		WL_ERR(("invalid len %d\n", len));
2687*4882a593Smuzhiyun 		return BCME_BADARG;
2688*4882a593Smuzhiyun 	}
2689*4882a593Smuzhiyun 
2690*4882a593Smuzhiyun 	WL_DBG(("entry: cmd = %d\n", nlioc->cmd));
2691*4882a593Smuzhiyun 
2692*4882a593Smuzhiyun 	if (nlioc->offset != sizeof(struct bcm_nlmsg_hdr) ||
2693*4882a593Smuzhiyun 		len <= sizeof(struct bcm_nlmsg_hdr)) {
2694*4882a593Smuzhiyun 		WL_ERR(("invalid offset %d\n", nlioc->offset));
2695*4882a593Smuzhiyun 		return BCME_BADARG;
2696*4882a593Smuzhiyun 	}
2697*4882a593Smuzhiyun 	len -= sizeof(struct bcm_nlmsg_hdr);
2698*4882a593Smuzhiyun 	ret_len = nlioc->len;
2699*4882a593Smuzhiyun 	if (ret_len > 0 || len > 0) {
2700*4882a593Smuzhiyun 		if (len >= DHD_IOCTL_MAXLEN) {
2701*4882a593Smuzhiyun 			WL_ERR(("oversize input buffer %d\n", len));
2702*4882a593Smuzhiyun 			len = DHD_IOCTL_MAXLEN - 1;
2703*4882a593Smuzhiyun 		}
2704*4882a593Smuzhiyun 		if (ret_len >= DHD_IOCTL_MAXLEN) {
2705*4882a593Smuzhiyun 			WL_ERR(("oversize return buffer %d\n", ret_len));
2706*4882a593Smuzhiyun 			ret_len = DHD_IOCTL_MAXLEN - 1;
2707*4882a593Smuzhiyun 		}
2708*4882a593Smuzhiyun 
2709*4882a593Smuzhiyun 		payload = max(ret_len, len) + 1;
2710*4882a593Smuzhiyun 		buf = vzalloc(payload);
2711*4882a593Smuzhiyun 		if (!buf) {
2712*4882a593Smuzhiyun 			return -ENOMEM;
2713*4882a593Smuzhiyun 		}
2714*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2715*4882a593Smuzhiyun 		memcpy(buf, (void *)((char *)nlioc + nlioc->offset), len);
2716*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_POP();
2717*4882a593Smuzhiyun 		*((char *)buf + len) = '\0';
2718*4882a593Smuzhiyun 	}
2719*4882a593Smuzhiyun 
2720*4882a593Smuzhiyun 	ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf);
2721*4882a593Smuzhiyun 	if (ret) {
2722*4882a593Smuzhiyun 		WL_ERR(("dhd_cfgvendor returned error %d", ret));
2723*4882a593Smuzhiyun 		vfree(buf);
2724*4882a593Smuzhiyun 		return ret;
2725*4882a593Smuzhiyun 	}
2726*4882a593Smuzhiyun 	cur = buf;
2727*4882a593Smuzhiyun 	while (ret_len > 0) {
2728*4882a593Smuzhiyun 		msglen = ret_len > maxmsglen ? maxmsglen : ret_len;
2729*4882a593Smuzhiyun 		ret_len -= msglen;
2730*4882a593Smuzhiyun 		payload = msglen + sizeof(msglen);
2731*4882a593Smuzhiyun 		reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
2732*4882a593Smuzhiyun 		if (!reply) {
2733*4882a593Smuzhiyun 			WL_ERR(("Failed to allocate reply msg\n"));
2734*4882a593Smuzhiyun 			ret = -ENOMEM;
2735*4882a593Smuzhiyun 			break;
2736*4882a593Smuzhiyun 		}
2737*4882a593Smuzhiyun 
2738*4882a593Smuzhiyun 		if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
2739*4882a593Smuzhiyun 			nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
2740*4882a593Smuzhiyun 			kfree_skb(reply);
2741*4882a593Smuzhiyun 			ret = -ENOBUFS;
2742*4882a593Smuzhiyun 			break;
2743*4882a593Smuzhiyun 		}
2744*4882a593Smuzhiyun 
2745*4882a593Smuzhiyun 		ret = cfg80211_vendor_cmd_reply(reply);
2746*4882a593Smuzhiyun 		if (ret) {
2747*4882a593Smuzhiyun 			WL_ERR(("testmode reply failed:%d\n", ret));
2748*4882a593Smuzhiyun 			break;
2749*4882a593Smuzhiyun 		}
2750*4882a593Smuzhiyun 		cur = (void *)((char *)cur + msglen);
2751*4882a593Smuzhiyun 	}
2752*4882a593Smuzhiyun 
2753*4882a593Smuzhiyun 	return ret;
2754*4882a593Smuzhiyun }
2755*4882a593Smuzhiyun 
2756*4882a593Smuzhiyun struct net_device *
wl_cfgvendor_get_ndev(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const char * data,unsigned long int * out_addr)2757*4882a593Smuzhiyun wl_cfgvendor_get_ndev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
2758*4882a593Smuzhiyun 	const char *data, unsigned long int *out_addr)
2759*4882a593Smuzhiyun {
2760*4882a593Smuzhiyun 	char *pos, *pos1;
2761*4882a593Smuzhiyun 	char ifname[IFNAMSIZ + 1] = {0};
2762*4882a593Smuzhiyun 	struct net_info *iter, *next;
2763*4882a593Smuzhiyun 	struct net_device *ndev = NULL;
2764*4882a593Smuzhiyun 	ulong ifname_len;
2765*4882a593Smuzhiyun 	*out_addr = (unsigned long int) data; /* point to command str by default */
2766*4882a593Smuzhiyun 
2767*4882a593Smuzhiyun 	/* check whether ifname=<ifname> is provided in the command */
2768*4882a593Smuzhiyun 	pos = strstr(data, "ifname=");
2769*4882a593Smuzhiyun 	if (pos) {
2770*4882a593Smuzhiyun 		pos += strlen("ifname=");
2771*4882a593Smuzhiyun 		pos1 = strstr(pos, " ");
2772*4882a593Smuzhiyun 		if (!pos1) {
2773*4882a593Smuzhiyun 			WL_ERR(("command format error \n"));
2774*4882a593Smuzhiyun 			return NULL;
2775*4882a593Smuzhiyun 		}
2776*4882a593Smuzhiyun 
2777*4882a593Smuzhiyun 		ifname_len = pos1 - pos;
2778*4882a593Smuzhiyun 		if (memcpy_s(ifname, (sizeof(ifname) - 1), pos, ifname_len) != BCME_OK) {
2779*4882a593Smuzhiyun 			WL_ERR(("Failed to copy data. len: %ld\n", ifname_len));
2780*4882a593Smuzhiyun 			return NULL;
2781*4882a593Smuzhiyun 		}
2782*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2783*4882a593Smuzhiyun 		for_each_ndev(cfg, iter, next) {
2784*4882a593Smuzhiyun 			if (iter->ndev) {
2785*4882a593Smuzhiyun 				if (strncmp(iter->ndev->name, ifname,
2786*4882a593Smuzhiyun 					strlen(iter->ndev->name)) == 0) {
2787*4882a593Smuzhiyun 					/* matching ifname found */
2788*4882a593Smuzhiyun 					WL_DBG(("matching interface (%s) found ndev:%p \n",
2789*4882a593Smuzhiyun 						iter->ndev->name, iter->ndev));
2790*4882a593Smuzhiyun 					*out_addr = (unsigned long int)(pos1 + 1);
2791*4882a593Smuzhiyun 					/* Returns the command portion after ifname=<name> */
2792*4882a593Smuzhiyun 					return iter->ndev;
2793*4882a593Smuzhiyun 				}
2794*4882a593Smuzhiyun 			}
2795*4882a593Smuzhiyun 		}
2796*4882a593Smuzhiyun 		GCC_DIAGNOSTIC_POP();
2797*4882a593Smuzhiyun 		WL_ERR(("Couldn't find ifname:%s in the netinfo list \n",
2798*4882a593Smuzhiyun 			ifname));
2799*4882a593Smuzhiyun 		return NULL;
2800*4882a593Smuzhiyun 	}
2801*4882a593Smuzhiyun 
2802*4882a593Smuzhiyun 	/* If ifname=<name> arg is not provided, use default ndev */
2803*4882a593Smuzhiyun 	ndev = wdev->netdev ? wdev->netdev : bcmcfg_to_prmry_ndev(cfg);
2804*4882a593Smuzhiyun 	WL_DBG(("Using default ndev (%s) \n", ndev->name));
2805*4882a593Smuzhiyun 	return ndev;
2806*4882a593Smuzhiyun }
2807*4882a593Smuzhiyun 
2808*4882a593Smuzhiyun #ifdef WL_SAE
2809*4882a593Smuzhiyun static int
wl_cfgvendor_set_sae_password(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2810*4882a593Smuzhiyun wl_cfgvendor_set_sae_password(struct wiphy *wiphy,
2811*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2812*4882a593Smuzhiyun {
2813*4882a593Smuzhiyun 	int err = BCME_OK;
2814*4882a593Smuzhiyun 	struct net_device *net = wdev->netdev;
2815*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
2816*4882a593Smuzhiyun 	wsec_pmk_t pmk;
2817*4882a593Smuzhiyun 	s32 bssidx;
2818*4882a593Smuzhiyun 
2819*4882a593Smuzhiyun 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, net->ieee80211_ptr)) < 0) {
2820*4882a593Smuzhiyun 		WL_ERR(("Find p2p index from wdev(%p) failed\n", net->ieee80211_ptr));
2821*4882a593Smuzhiyun 		return BCME_ERROR;
2822*4882a593Smuzhiyun 	}
2823*4882a593Smuzhiyun 
2824*4882a593Smuzhiyun 	if (len < WSEC_MIN_PSK_LEN || len >= WSEC_MAX_PSK_LEN) {
2825*4882a593Smuzhiyun 		WL_ERR(("Invalid passphrase length %d..should be >=8 and <=63\n",
2826*4882a593Smuzhiyun 			len));
2827*4882a593Smuzhiyun 		err = BCME_BADLEN;
2828*4882a593Smuzhiyun 		goto done;
2829*4882a593Smuzhiyun 	}
2830*4882a593Smuzhiyun 	/* Set AUTH to SAE */
2831*4882a593Smuzhiyun 	err = wldev_iovar_setint_bsscfg(net, "wpa_auth", WPA3_AUTH_SAE_PSK, bssidx);
2832*4882a593Smuzhiyun 	if (unlikely(err)) {
2833*4882a593Smuzhiyun 		WL_ERR(("could not set wpa_auth (0x%x)\n", err));
2834*4882a593Smuzhiyun 		goto done;
2835*4882a593Smuzhiyun 	}
2836*4882a593Smuzhiyun 	pmk.key_len = htod16(len);
2837*4882a593Smuzhiyun 	bcopy((const u8*)data, pmk.key, len);
2838*4882a593Smuzhiyun 	pmk.flags = htod16(WSEC_PASSPHRASE);
2839*4882a593Smuzhiyun 
2840*4882a593Smuzhiyun 	err = wldev_ioctl_set(net, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
2841*4882a593Smuzhiyun 	if (err) {
2842*4882a593Smuzhiyun 		WL_ERR(("\n failed to set pmk %d\n", err));
2843*4882a593Smuzhiyun 		goto done;
2844*4882a593Smuzhiyun 	} else {
2845*4882a593Smuzhiyun 		WL_MEM(("sae passphrase set successfully\n"));
2846*4882a593Smuzhiyun 	}
2847*4882a593Smuzhiyun done:
2848*4882a593Smuzhiyun 	return err;
2849*4882a593Smuzhiyun }
2850*4882a593Smuzhiyun #endif /* WL_SAE */
2851*4882a593Smuzhiyun 
2852*4882a593Smuzhiyun #ifdef BCM_PRIV_CMD_SUPPORT
2853*4882a593Smuzhiyun /* strlen("ifname=") + IFNAMESIZE + strlen(" ") + '\0' */
2854*4882a593Smuzhiyun #define ANDROID_PRIV_CMD_IF_PREFIX_LEN	(7 + IFNAMSIZ + 2)
2855*4882a593Smuzhiyun /* Max length for the reply buffer. For BRCM_ATTR_DRIVER_CMD, the reply
2856*4882a593Smuzhiyun  * would be a formatted string and reply buf would be the size of the
2857*4882a593Smuzhiyun  * string.
2858*4882a593Smuzhiyun  */
2859*4882a593Smuzhiyun #define WL_DRIVER_PRIV_CMD_LEN 512
2860*4882a593Smuzhiyun static int
wl_cfgvendor_priv_bcm_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2861*4882a593Smuzhiyun wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy,
2862*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
2863*4882a593Smuzhiyun {
2864*4882a593Smuzhiyun 	const struct nlattr *iter;
2865*4882a593Smuzhiyun 	int err = 0;
2866*4882a593Smuzhiyun 	int data_len = 0, cmd_len = 0, tmp = 0, type = 0;
2867*4882a593Smuzhiyun 	struct net_device *ndev = wdev->netdev;
2868*4882a593Smuzhiyun 	char *cmd = NULL;
2869*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2870*4882a593Smuzhiyun 	int bytes_written;
2871*4882a593Smuzhiyun 	struct net_device *net = NULL;
2872*4882a593Smuzhiyun 	unsigned long int cmd_out = 0;
2873*4882a593Smuzhiyun #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
2874*4882a593Smuzhiyun 	u32 cmd_buf_len = WL_DRIVER_PRIV_CMD_LEN;
2875*4882a593Smuzhiyun 	char cmd_prefix[ANDROID_PRIV_CMD_IF_PREFIX_LEN + 1] = {0};
2876*4882a593Smuzhiyun 	char *cmd_buf = NULL;
2877*4882a593Smuzhiyun 	char *current_pos;
2878*4882a593Smuzhiyun 	u32 cmd_offset;
2879*4882a593Smuzhiyun #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
2880*4882a593Smuzhiyun 
2881*4882a593Smuzhiyun 	WL_DBG(("%s: Enter \n", __func__));
2882*4882a593Smuzhiyun 
2883*4882a593Smuzhiyun 	/* hold wake lock */
2884*4882a593Smuzhiyun 	net_os_wake_lock(ndev);
2885*4882a593Smuzhiyun 
2886*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
2887*4882a593Smuzhiyun 		type = nla_type(iter);
2888*4882a593Smuzhiyun 		cmd = nla_data(iter);
2889*4882a593Smuzhiyun 		cmd_len = nla_len(iter);
2890*4882a593Smuzhiyun 
2891*4882a593Smuzhiyun 		WL_DBG(("%s: type: %d cmd_len:%d cmd_ptr:%p \n", __func__, type, cmd_len, cmd));
2892*4882a593Smuzhiyun 		if (!cmd || !cmd_len) {
2893*4882a593Smuzhiyun 			WL_ERR(("Invalid cmd data \n"));
2894*4882a593Smuzhiyun 			err = -EINVAL;
2895*4882a593Smuzhiyun 			goto exit;
2896*4882a593Smuzhiyun 		}
2897*4882a593Smuzhiyun 
2898*4882a593Smuzhiyun #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
2899*4882a593Smuzhiyun 		if (type == BRCM_ATTR_DRIVER_CMD) {
2900*4882a593Smuzhiyun 			if ((cmd_len >= WL_DRIVER_PRIV_CMD_LEN) ||
2901*4882a593Smuzhiyun 				(cmd_len < ANDROID_PRIV_CMD_IF_PREFIX_LEN)) {
2902*4882a593Smuzhiyun 				WL_ERR(("Unexpected command length (%u)."
2903*4882a593Smuzhiyun 					"Ignore the command\n", cmd_len));
2904*4882a593Smuzhiyun 				err = -EINVAL;
2905*4882a593Smuzhiyun 				goto exit;
2906*4882a593Smuzhiyun 			}
2907*4882a593Smuzhiyun 
2908*4882a593Smuzhiyun 			/* check whether there is any ifname prefix provided */
2909*4882a593Smuzhiyun 			if (memcpy_s(cmd_prefix, (sizeof(cmd_prefix) - 1),
2910*4882a593Smuzhiyun 					cmd, ANDROID_PRIV_CMD_IF_PREFIX_LEN) != BCME_OK) {
2911*4882a593Smuzhiyun 				WL_ERR(("memcpy failed for cmd buffer. len:%d\n", cmd_len));
2912*4882a593Smuzhiyun 				err = -ENOMEM;
2913*4882a593Smuzhiyun 				goto exit;
2914*4882a593Smuzhiyun 			}
2915*4882a593Smuzhiyun 
2916*4882a593Smuzhiyun 			net = wl_cfgvendor_get_ndev(cfg, wdev, cmd_prefix, &cmd_out);
2917*4882a593Smuzhiyun 			if (!cmd_out || !net) {
2918*4882a593Smuzhiyun 				WL_ERR(("ndev not found\n"));
2919*4882a593Smuzhiyun 				err = -ENODEV;
2920*4882a593Smuzhiyun 				goto exit;
2921*4882a593Smuzhiyun 			}
2922*4882a593Smuzhiyun 
2923*4882a593Smuzhiyun 			/* find offset of the command */
2924*4882a593Smuzhiyun 			current_pos = (char *)cmd_out;
2925*4882a593Smuzhiyun 			cmd_offset = current_pos - cmd_prefix;
2926*4882a593Smuzhiyun 
2927*4882a593Smuzhiyun 			if (!current_pos || (cmd_offset) > ANDROID_PRIV_CMD_IF_PREFIX_LEN) {
2928*4882a593Smuzhiyun 				WL_ERR(("Invalid len cmd_offset: %u \n", cmd_offset));
2929*4882a593Smuzhiyun 				err = -EINVAL;
2930*4882a593Smuzhiyun 				goto exit;
2931*4882a593Smuzhiyun 			}
2932*4882a593Smuzhiyun 
2933*4882a593Smuzhiyun 			/* Private command data in expected to be in str format. To ensure that
2934*4882a593Smuzhiyun 			 * the data is null terminated, copy to a local buffer before use
2935*4882a593Smuzhiyun 			 */
2936*4882a593Smuzhiyun 			cmd_buf = (char *)MALLOCZ(cfg->osh, cmd_buf_len);
2937*4882a593Smuzhiyun 			if (!cmd_buf) {
2938*4882a593Smuzhiyun 				WL_ERR(("memory alloc failed for %u \n", cmd_buf_len));
2939*4882a593Smuzhiyun 				err = -ENOMEM;
2940*4882a593Smuzhiyun 				goto exit;
2941*4882a593Smuzhiyun 			}
2942*4882a593Smuzhiyun 
2943*4882a593Smuzhiyun 			/* Point to the start of command */
2944*4882a593Smuzhiyun 			if (memcpy_s(cmd_buf, (WL_DRIVER_PRIV_CMD_LEN - 1),
2945*4882a593Smuzhiyun 				(const void *)(cmd + cmd_offset),
2946*4882a593Smuzhiyun 				(cmd_len - cmd_offset - 1)) != BCME_OK) {
2947*4882a593Smuzhiyun 				WL_ERR(("memcpy failed for cmd buffer. len:%d\n", cmd_len));
2948*4882a593Smuzhiyun 				err = -ENOMEM;
2949*4882a593Smuzhiyun 				goto exit;
2950*4882a593Smuzhiyun 			}
2951*4882a593Smuzhiyun 			cmd_buf[WL_DRIVER_PRIV_CMD_LEN - 1] = '\0';
2952*4882a593Smuzhiyun 
2953*4882a593Smuzhiyun 			WL_DBG(("vendor_command: %s len: %u \n", cmd_buf, cmd_buf_len));
2954*4882a593Smuzhiyun 			bytes_written = wl_handle_private_cmd(net, cmd_buf, cmd_buf_len);
2955*4882a593Smuzhiyun 			WL_DBG(("bytes_written: %d \n", bytes_written));
2956*4882a593Smuzhiyun 			if (bytes_written == 0) {
2957*4882a593Smuzhiyun 				snprintf(cmd_buf, cmd_buf_len, "%s", "OK");
2958*4882a593Smuzhiyun 				data_len = sizeof("OK");
2959*4882a593Smuzhiyun 			} else if (bytes_written > 0) {
2960*4882a593Smuzhiyun 				if (bytes_written >= (cmd_buf_len - 1)) {
2961*4882a593Smuzhiyun 					/* Not expected */
2962*4882a593Smuzhiyun 					ASSERT(0);
2963*4882a593Smuzhiyun 					err = -EINVAL;
2964*4882a593Smuzhiyun 					goto exit;
2965*4882a593Smuzhiyun 				}
2966*4882a593Smuzhiyun 				data_len = bytes_written;
2967*4882a593Smuzhiyun 			} else {
2968*4882a593Smuzhiyun 				/* -ve return value. Propagate the error back */
2969*4882a593Smuzhiyun 				err = bytes_written;
2970*4882a593Smuzhiyun 				goto exit;
2971*4882a593Smuzhiyun 			}
2972*4882a593Smuzhiyun 			if ((data_len > 0) && (data_len < (cmd_buf_len - 1)) && cmd_buf) {
2973*4882a593Smuzhiyun 				err =  wl_cfgvendor_send_cmd_reply(wiphy, cmd_buf, data_len);
2974*4882a593Smuzhiyun 				if (unlikely(err)) {
2975*4882a593Smuzhiyun 					WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2976*4882a593Smuzhiyun 				} else {
2977*4882a593Smuzhiyun 					WL_DBG(("Vendor Command reply sent successfully!\n"));
2978*4882a593Smuzhiyun 				}
2979*4882a593Smuzhiyun 			} else {
2980*4882a593Smuzhiyun 				/* No data to be sent back as reply */
2981*4882a593Smuzhiyun 				WL_ERR(("Vendor_cmd: No reply expected. data_len:%u cmd_buf %p \n",
2982*4882a593Smuzhiyun 					data_len, cmd_buf));
2983*4882a593Smuzhiyun 			}
2984*4882a593Smuzhiyun 			break;
2985*4882a593Smuzhiyun 		}
2986*4882a593Smuzhiyun #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
2987*4882a593Smuzhiyun 	}
2988*4882a593Smuzhiyun 
2989*4882a593Smuzhiyun exit:
2990*4882a593Smuzhiyun #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
2991*4882a593Smuzhiyun 	if (cmd_buf) {
2992*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_buf, cmd_buf_len);
2993*4882a593Smuzhiyun 	}
2994*4882a593Smuzhiyun #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
2995*4882a593Smuzhiyun 	net_os_wake_unlock(ndev);
2996*4882a593Smuzhiyun 	return err;
2997*4882a593Smuzhiyun }
2998*4882a593Smuzhiyun #endif /* BCM_PRIV_CMD_SUPPORT */
2999*4882a593Smuzhiyun 
3000*4882a593Smuzhiyun #ifdef WL_NAN
nan_attr_to_str(u16 cmd)3001*4882a593Smuzhiyun static const char *nan_attr_to_str(u16 cmd)
3002*4882a593Smuzhiyun {
3003*4882a593Smuzhiyun 	switch (cmd) {
3004*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_HEADER)
3005*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_HANDLE)
3006*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_TRANSAC_ID)
3007*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_2G_SUPPORT)
3008*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SDF_2G_SUPPORT)
3009*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SDF_5G_SUPPORT)
3010*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_5G_SUPPORT)
3011*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON)
3012*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON)
3013*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CLUSTER_LOW)
3014*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CLUSTER_HIGH)
3015*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SID_BEACON)
3016*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSSI_CLOSE)
3017*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSSI_MIDDLE)
3018*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSSI_PROXIMITY)
3019*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSSI_CLOSE_5G)
3020*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSSI_MIDDLE_5G)
3021*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSSI_PROXIMITY_5G)
3022*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_HOP_COUNT_LIMIT)
3023*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RANDOM_TIME)
3024*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_MASTER_PREF)
3025*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL)
3026*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PUBLISH_ID)
3027*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_TTL)
3028*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PERIOD)
3029*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_REPLIED_EVENT_FLAG)
3030*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PUBLISH_TYPE)
3031*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_TX_TYPE)
3032*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PUBLISH_COUNT)
3033*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SERVICE_NAME_LEN)
3034*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SERVICE_NAME)
3035*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN)
3036*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO)
3037*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN)
3038*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RX_MATCH_FILTER)
3039*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN)
3040*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_TX_MATCH_FILTER)
3041*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SUBSCRIBE_ID)
3042*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SUBSCRIBE_TYPE)
3043*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SERVICERESPONSEFILTER)
3044*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE)
3045*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_USESERVICERESPONSEFILTER)
3046*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION)
3047*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SUBSCRIBE_MATCH)
3048*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SUBSCRIBE_COUNT)
3049*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_MAC_ADDR)
3050*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_MAC_ADDR_LIST)
3051*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES)
3052*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PUBLISH_MATCH)
3053*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_ENABLE_STATUS)
3054*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_JOIN_STATUS)
3055*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_ROLE)
3056*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_MASTER_RANK)
3057*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_ANCHOR_MASTER_RANK)
3058*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CNT_PEND_TXFRM)
3059*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CNT_BCN_TX)
3060*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CNT_BCN_RX)
3061*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CNT_SVC_DISC_TX)
3062*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CNT_SVC_DISC_RX)
3063*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_AMBTT)
3064*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CLUSTER_ID)
3065*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_INST_ID)
3066*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_OUI)
3067*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_STATUS)
3068*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_DE_EVENT_TYPE)
3069*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_MERGE)
3070*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_IFACE)
3071*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CHANNEL)
3072*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_24G_CHANNEL)
3073*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_5G_CHANNEL)
3074*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PEER_ID)
3075*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_NDP_ID)
3076*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SECURITY)
3077*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_QOS)
3078*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSP_CODE)
3079*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_INST_COUNT)
3080*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR)
3081*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR)
3082*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_IF_ADDR)
3083*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_WARMUP_TIME)
3084*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RECV_IND_CFG)
3085*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CONNMAP)
3086*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_DWELL_TIME)
3087*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SCAN_PERIOD)
3088*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSSI_WINDOW_SIZE)
3089*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CONF_CLUSTER_VAL)
3090*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE)
3091*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_KEY_TYPE)
3092*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_KEY_LEN)
3093*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SCID)
3094*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SCID_LEN)
3095*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP)
3096*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SDE_CONTROL_SECURITY)
3097*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE)
3098*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT)
3099*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_NO_CONFIG_AVAIL)
3100*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_2G_AWAKE_DW)
3101*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_5G_AWAKE_DW)
3102*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG)
3103*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_KEY_DATA)
3104*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN)
3105*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO)
3106*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_REASON)
3107*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_DISC_IND_CFG)
3108*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_DWELL_TIME_5G)
3109*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SCAN_PERIOD_5G)
3110*4882a593Smuzhiyun 	C2S(NAN_ATTRIBUTE_SUB_SID_BEACON)
3111*4882a593Smuzhiyun 	default:
3112*4882a593Smuzhiyun 		return "NAN_ATTRIBUTE_UNKNOWN";
3113*4882a593Smuzhiyun 	}
3114*4882a593Smuzhiyun }
3115*4882a593Smuzhiyun 
3116*4882a593Smuzhiyun nan_hal_status_t nan_status_reasonstr_map[] = {
3117*4882a593Smuzhiyun 	{NAN_STATUS_SUCCESS, "NAN status success"},
3118*4882a593Smuzhiyun 	{NAN_STATUS_INTERNAL_FAILURE, "NAN Discovery engine failure"},
3119*4882a593Smuzhiyun 	{NAN_STATUS_PROTOCOL_FAILURE, "protocol failure"},
3120*4882a593Smuzhiyun 	{NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID, "invalid pub_sub ID"},
3121*4882a593Smuzhiyun 	{NAN_STATUS_NO_RESOURCE_AVAILABLE, "No space available"},
3122*4882a593Smuzhiyun 	{NAN_STATUS_INVALID_PARAM, "invalid param"},
3123*4882a593Smuzhiyun 	{NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID, "invalid req inst id"},
3124*4882a593Smuzhiyun 	{NAN_STATUS_INVALID_NDP_ID, "invalid ndp id"},
3125*4882a593Smuzhiyun 	{NAN_STATUS_NAN_NOT_ALLOWED, "Nan not allowed"},
3126*4882a593Smuzhiyun 	{NAN_STATUS_NO_OTA_ACK, "No OTA ack"},
3127*4882a593Smuzhiyun 	{NAN_STATUS_ALREADY_ENABLED, "NAN is Already enabled"},
3128*4882a593Smuzhiyun 	{NAN_STATUS_FOLLOWUP_QUEUE_FULL, "Follow-up queue full"},
3129*4882a593Smuzhiyun 	{NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED, "unsupported concurrency"},
3130*4882a593Smuzhiyun };
3131*4882a593Smuzhiyun 
3132*4882a593Smuzhiyun void
wl_cfgvendor_add_nan_reason_str(nan_status_type_t status,nan_hal_resp_t * nan_req_resp)3133*4882a593Smuzhiyun wl_cfgvendor_add_nan_reason_str(nan_status_type_t status, nan_hal_resp_t *nan_req_resp)
3134*4882a593Smuzhiyun {
3135*4882a593Smuzhiyun 	int i = 0;
3136*4882a593Smuzhiyun 	int num = (int)(sizeof(nan_status_reasonstr_map)/sizeof(nan_status_reasonstr_map[0]));
3137*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
3138*4882a593Smuzhiyun 		if (nan_status_reasonstr_map[i].status == status) {
3139*4882a593Smuzhiyun 			strlcpy(nan_req_resp->nan_reason, nan_status_reasonstr_map[i].nan_reason,
3140*4882a593Smuzhiyun 				sizeof(nan_status_reasonstr_map[i].nan_reason));
3141*4882a593Smuzhiyun 			break;
3142*4882a593Smuzhiyun 		}
3143*4882a593Smuzhiyun 	}
3144*4882a593Smuzhiyun }
3145*4882a593Smuzhiyun 
3146*4882a593Smuzhiyun nan_status_type_t
wl_cfgvendor_brcm_to_nanhal_status(int32 vendor_status)3147*4882a593Smuzhiyun wl_cfgvendor_brcm_to_nanhal_status(int32 vendor_status)
3148*4882a593Smuzhiyun {
3149*4882a593Smuzhiyun 	nan_status_type_t hal_status;
3150*4882a593Smuzhiyun 	switch (vendor_status) {
3151*4882a593Smuzhiyun 		case BCME_OK:
3152*4882a593Smuzhiyun 			hal_status = NAN_STATUS_SUCCESS;
3153*4882a593Smuzhiyun 			break;
3154*4882a593Smuzhiyun 		case BCME_BUSY:
3155*4882a593Smuzhiyun 		case BCME_NOTREADY:
3156*4882a593Smuzhiyun 			hal_status = NAN_STATUS_NAN_NOT_ALLOWED;
3157*4882a593Smuzhiyun 			break;
3158*4882a593Smuzhiyun 		case BCME_BADLEN:
3159*4882a593Smuzhiyun 		case BCME_BADBAND:
3160*4882a593Smuzhiyun 		case BCME_UNSUPPORTED:
3161*4882a593Smuzhiyun 		case BCME_USAGE_ERROR:
3162*4882a593Smuzhiyun 		case BCME_BADARG:
3163*4882a593Smuzhiyun 			hal_status = NAN_STATUS_INVALID_PARAM;
3164*4882a593Smuzhiyun 			break;
3165*4882a593Smuzhiyun 		case BCME_NOMEM:
3166*4882a593Smuzhiyun 		case BCME_NORESOURCE:
3167*4882a593Smuzhiyun 		case WL_NAN_E_SVC_SUB_LIST_FULL:
3168*4882a593Smuzhiyun 			hal_status = NAN_STATUS_NO_RESOURCE_AVAILABLE;
3169*4882a593Smuzhiyun 			break;
3170*4882a593Smuzhiyun 		case WL_NAN_E_SD_TX_LIST_FULL:
3171*4882a593Smuzhiyun 			hal_status = NAN_STATUS_FOLLOWUP_QUEUE_FULL;
3172*4882a593Smuzhiyun 			break;
3173*4882a593Smuzhiyun 		case WL_NAN_E_BAD_INSTANCE:
3174*4882a593Smuzhiyun 			hal_status = NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
3175*4882a593Smuzhiyun 			break;
3176*4882a593Smuzhiyun 		default:
3177*4882a593Smuzhiyun 			WL_ERR(("%s Unknown vendor status, status = %d\n",
3178*4882a593Smuzhiyun 					__func__, vendor_status));
3179*4882a593Smuzhiyun 			/* Generic error */
3180*4882a593Smuzhiyun 			hal_status = NAN_STATUS_INTERNAL_FAILURE;
3181*4882a593Smuzhiyun 	}
3182*4882a593Smuzhiyun 	return hal_status;
3183*4882a593Smuzhiyun }
3184*4882a593Smuzhiyun 
3185*4882a593Smuzhiyun static int
wl_cfgvendor_nan_cmd_reply(struct wiphy * wiphy,int nan_cmd,nan_hal_resp_t * nan_req_resp,int ret,int nan_cmd_status)3186*4882a593Smuzhiyun wl_cfgvendor_nan_cmd_reply(struct wiphy *wiphy, int nan_cmd,
3187*4882a593Smuzhiyun 	nan_hal_resp_t *nan_req_resp, int ret, int nan_cmd_status)
3188*4882a593Smuzhiyun {
3189*4882a593Smuzhiyun 	int err;
3190*4882a593Smuzhiyun 	int nan_reply;
3191*4882a593Smuzhiyun 	nan_req_resp->subcmd = nan_cmd;
3192*4882a593Smuzhiyun 	if (ret == BCME_OK) {
3193*4882a593Smuzhiyun 		nan_reply = nan_cmd_status;
3194*4882a593Smuzhiyun 	} else {
3195*4882a593Smuzhiyun 		nan_reply = ret;
3196*4882a593Smuzhiyun 	}
3197*4882a593Smuzhiyun 	nan_req_resp->status = wl_cfgvendor_brcm_to_nanhal_status(nan_reply);
3198*4882a593Smuzhiyun 	nan_req_resp->value = ret;
3199*4882a593Smuzhiyun 	err = wl_cfgvendor_send_cmd_reply(wiphy, nan_req_resp,
3200*4882a593Smuzhiyun 		sizeof(*nan_req_resp));
3201*4882a593Smuzhiyun 	/* giving more prio to ret than err */
3202*4882a593Smuzhiyun 	return (ret == 0) ? err : ret;
3203*4882a593Smuzhiyun }
3204*4882a593Smuzhiyun 
3205*4882a593Smuzhiyun static void
wl_cfgvendor_free_disc_cmd_data(struct bcm_cfg80211 * cfg,nan_discover_cmd_data_t * cmd_data)3206*4882a593Smuzhiyun wl_cfgvendor_free_disc_cmd_data(struct bcm_cfg80211 *cfg,
3207*4882a593Smuzhiyun 	nan_discover_cmd_data_t *cmd_data)
3208*4882a593Smuzhiyun {
3209*4882a593Smuzhiyun 	if (!cmd_data) {
3210*4882a593Smuzhiyun 		WL_ERR(("Cmd_data is null\n"));
3211*4882a593Smuzhiyun 		return;
3212*4882a593Smuzhiyun 	}
3213*4882a593Smuzhiyun 	if (cmd_data->svc_info.data) {
3214*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->svc_info.data, cmd_data->svc_info.dlen);
3215*4882a593Smuzhiyun 	}
3216*4882a593Smuzhiyun 	if (cmd_data->svc_hash.data) {
3217*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->svc_hash.data, cmd_data->svc_hash.dlen);
3218*4882a593Smuzhiyun 	}
3219*4882a593Smuzhiyun 	if (cmd_data->rx_match.data) {
3220*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->rx_match.data, cmd_data->rx_match.dlen);
3221*4882a593Smuzhiyun 	}
3222*4882a593Smuzhiyun 	if (cmd_data->tx_match.data) {
3223*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->tx_match.data, cmd_data->tx_match.dlen);
3224*4882a593Smuzhiyun 	}
3225*4882a593Smuzhiyun 	if (cmd_data->mac_list.list) {
3226*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->mac_list.list,
3227*4882a593Smuzhiyun 			cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN);
3228*4882a593Smuzhiyun 	}
3229*4882a593Smuzhiyun 	if (cmd_data->key.data) {
3230*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->key.data, NAN_MAX_PMK_LEN);
3231*4882a593Smuzhiyun 	}
3232*4882a593Smuzhiyun 	if (cmd_data->sde_svc_info.data) {
3233*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->sde_svc_info.data, cmd_data->sde_svc_info.dlen);
3234*4882a593Smuzhiyun 	}
3235*4882a593Smuzhiyun 	MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
3236*4882a593Smuzhiyun }
3237*4882a593Smuzhiyun 
3238*4882a593Smuzhiyun static void
wl_cfgvendor_free_dp_cmd_data(struct bcm_cfg80211 * cfg,nan_datapath_cmd_data_t * cmd_data)3239*4882a593Smuzhiyun wl_cfgvendor_free_dp_cmd_data(struct bcm_cfg80211 *cfg,
3240*4882a593Smuzhiyun 	nan_datapath_cmd_data_t *cmd_data)
3241*4882a593Smuzhiyun {
3242*4882a593Smuzhiyun 	if (!cmd_data) {
3243*4882a593Smuzhiyun 		WL_ERR(("Cmd_data is null\n"));
3244*4882a593Smuzhiyun 		return;
3245*4882a593Smuzhiyun 	}
3246*4882a593Smuzhiyun 	if (cmd_data->svc_hash.data) {
3247*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->svc_hash.data, cmd_data->svc_hash.dlen);
3248*4882a593Smuzhiyun 	}
3249*4882a593Smuzhiyun 	if (cmd_data->svc_info.data) {
3250*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->svc_info.data, cmd_data->svc_info.dlen);
3251*4882a593Smuzhiyun 	}
3252*4882a593Smuzhiyun 	if (cmd_data->key.data) {
3253*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data->key.data, NAN_MAX_PMK_LEN);
3254*4882a593Smuzhiyun 	}
3255*4882a593Smuzhiyun 	MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
3256*4882a593Smuzhiyun }
3257*4882a593Smuzhiyun 
3258*4882a593Smuzhiyun #define WL_NAN_EVENT_MAX_BUF 256
3259*4882a593Smuzhiyun #ifdef WL_NAN_DISC_CACHE
3260*4882a593Smuzhiyun static int
wl_cfgvendor_nan_parse_dp_sec_info_args(struct wiphy * wiphy,const void * buf,int len,nan_datapath_sec_info_cmd_data_t * cmd_data)3261*4882a593Smuzhiyun wl_cfgvendor_nan_parse_dp_sec_info_args(struct wiphy *wiphy,
3262*4882a593Smuzhiyun 	const void *buf, int len, nan_datapath_sec_info_cmd_data_t *cmd_data)
3263*4882a593Smuzhiyun {
3264*4882a593Smuzhiyun 	int ret = BCME_OK;
3265*4882a593Smuzhiyun 	int attr_type;
3266*4882a593Smuzhiyun 	int rem = len;
3267*4882a593Smuzhiyun 	const struct nlattr *iter;
3268*4882a593Smuzhiyun 
3269*4882a593Smuzhiyun 	NAN_DBG_ENTER();
3270*4882a593Smuzhiyun 
3271*4882a593Smuzhiyun 	nla_for_each_attr(iter, buf, len, rem) {
3272*4882a593Smuzhiyun 		attr_type = nla_type(iter);
3273*4882a593Smuzhiyun 		WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
3274*4882a593Smuzhiyun 
3275*4882a593Smuzhiyun 		switch (attr_type) {
3276*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_MAC_ADDR:
3277*4882a593Smuzhiyun 			ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
3278*4882a593Smuzhiyun 				(char*)nla_data(iter), nla_len(iter));
3279*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3280*4882a593Smuzhiyun 				WL_ERR(("Failed to copy mac addr\n"));
3281*4882a593Smuzhiyun 				return ret;
3282*4882a593Smuzhiyun 			}
3283*4882a593Smuzhiyun 			break;
3284*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PUBLISH_ID:
3285*4882a593Smuzhiyun 			cmd_data->pub_id = nla_get_u16(iter);
3286*4882a593Smuzhiyun 			break;
3287*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_NDP_ID:
3288*4882a593Smuzhiyun 			cmd_data->ndp_instance_id = nla_get_u32(iter);
3289*4882a593Smuzhiyun 			break;
3290*4882a593Smuzhiyun 		default:
3291*4882a593Smuzhiyun 			WL_ERR(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
3292*4882a593Smuzhiyun 			ret = BCME_BADARG;
3293*4882a593Smuzhiyun 			break;
3294*4882a593Smuzhiyun 		}
3295*4882a593Smuzhiyun 	}
3296*4882a593Smuzhiyun 	/* We need to call set_config_handler b/f calling start enable TBD */
3297*4882a593Smuzhiyun 	NAN_DBG_EXIT();
3298*4882a593Smuzhiyun 	return ret;
3299*4882a593Smuzhiyun }
3300*4882a593Smuzhiyun #endif /* WL_NAN_DISC_CACHE */
3301*4882a593Smuzhiyun 
3302*4882a593Smuzhiyun int8 chanbuf[CHANSPEC_STR_LEN];
3303*4882a593Smuzhiyun static int
wl_cfgvendor_nan_parse_datapath_args(struct wiphy * wiphy,const void * buf,int len,nan_datapath_cmd_data_t * cmd_data)3304*4882a593Smuzhiyun wl_cfgvendor_nan_parse_datapath_args(struct wiphy *wiphy,
3305*4882a593Smuzhiyun 	const void *buf, int len, nan_datapath_cmd_data_t *cmd_data)
3306*4882a593Smuzhiyun {
3307*4882a593Smuzhiyun 	int ret = BCME_OK;
3308*4882a593Smuzhiyun 	int attr_type;
3309*4882a593Smuzhiyun 	int rem = len;
3310*4882a593Smuzhiyun 	const struct nlattr *iter;
3311*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3312*4882a593Smuzhiyun 	int chan;
3313*4882a593Smuzhiyun 
3314*4882a593Smuzhiyun 	NAN_DBG_ENTER();
3315*4882a593Smuzhiyun 
3316*4882a593Smuzhiyun 	nla_for_each_attr(iter, buf, len, rem) {
3317*4882a593Smuzhiyun 		attr_type = nla_type(iter);
3318*4882a593Smuzhiyun 		WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
3319*4882a593Smuzhiyun 
3320*4882a593Smuzhiyun 		switch (attr_type) {
3321*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_NDP_ID:
3322*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
3323*4882a593Smuzhiyun 				ret = -EINVAL;
3324*4882a593Smuzhiyun 				goto exit;
3325*4882a593Smuzhiyun 			}
3326*4882a593Smuzhiyun 			cmd_data->ndp_instance_id = nla_get_u32(iter);
3327*4882a593Smuzhiyun 			break;
3328*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_IFACE:
3329*4882a593Smuzhiyun 			if (nla_len(iter) >= sizeof(cmd_data->ndp_iface)) {
3330*4882a593Smuzhiyun 				WL_ERR(("iface_name len wrong:%d\n", nla_len(iter)));
3331*4882a593Smuzhiyun 				ret = -EINVAL;
3332*4882a593Smuzhiyun 				goto exit;
3333*4882a593Smuzhiyun 			}
3334*4882a593Smuzhiyun 			strlcpy((char *)cmd_data->ndp_iface, (char *)nla_data(iter),
3335*4882a593Smuzhiyun 				nla_len(iter));
3336*4882a593Smuzhiyun 			break;
3337*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SECURITY:
3338*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3339*4882a593Smuzhiyun 				ret = -EINVAL;
3340*4882a593Smuzhiyun 				goto exit;
3341*4882a593Smuzhiyun 			}
3342*4882a593Smuzhiyun 			cmd_data->ndp_cfg.security_cfg = nla_get_u8(iter);
3343*4882a593Smuzhiyun 			break;
3344*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_QOS:
3345*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3346*4882a593Smuzhiyun 				ret = -EINVAL;
3347*4882a593Smuzhiyun 				goto exit;
3348*4882a593Smuzhiyun 			}
3349*4882a593Smuzhiyun 			cmd_data->ndp_cfg.qos_cfg = nla_get_u8(iter);
3350*4882a593Smuzhiyun 			break;
3351*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSP_CODE:
3352*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3353*4882a593Smuzhiyun 				ret = -EINVAL;
3354*4882a593Smuzhiyun 				goto exit;
3355*4882a593Smuzhiyun 			}
3356*4882a593Smuzhiyun 			cmd_data->rsp_code = nla_get_u8(iter);
3357*4882a593Smuzhiyun 			break;
3358*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_INST_COUNT:
3359*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3360*4882a593Smuzhiyun 				ret = -EINVAL;
3361*4882a593Smuzhiyun 				goto exit;
3362*4882a593Smuzhiyun 			}
3363*4882a593Smuzhiyun 			cmd_data->num_ndp_instances = nla_get_u8(iter);
3364*4882a593Smuzhiyun 			break;
3365*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR:
3366*4882a593Smuzhiyun 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3367*4882a593Smuzhiyun 				ret = -EINVAL;
3368*4882a593Smuzhiyun 				goto exit;
3369*4882a593Smuzhiyun 			}
3370*4882a593Smuzhiyun 			ret = memcpy_s((char*)&cmd_data->peer_disc_mac_addr,
3371*4882a593Smuzhiyun 				ETHER_ADDR_LEN,	(char*)nla_data(iter), nla_len(iter));
3372*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3373*4882a593Smuzhiyun 				WL_ERR(("Failed to copy peer_disc_mac_addr\n"));
3374*4882a593Smuzhiyun 				goto exit;
3375*4882a593Smuzhiyun 			}
3376*4882a593Smuzhiyun 			break;
3377*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR:
3378*4882a593Smuzhiyun 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3379*4882a593Smuzhiyun 				ret = -EINVAL;
3380*4882a593Smuzhiyun 				goto exit;
3381*4882a593Smuzhiyun 			}
3382*4882a593Smuzhiyun 			ret = memcpy_s((char*)&cmd_data->peer_ndi_mac_addr,
3383*4882a593Smuzhiyun 				ETHER_ADDR_LEN,	(char*)nla_data(iter), nla_len(iter));
3384*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3385*4882a593Smuzhiyun 				WL_ERR(("Failed to copy peer_ndi_mac_addr\n"));
3386*4882a593Smuzhiyun 				goto exit;
3387*4882a593Smuzhiyun 			}
3388*4882a593Smuzhiyun 			break;
3389*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_MAC_ADDR:
3390*4882a593Smuzhiyun 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3391*4882a593Smuzhiyun 				ret = -EINVAL;
3392*4882a593Smuzhiyun 				goto exit;
3393*4882a593Smuzhiyun 			}
3394*4882a593Smuzhiyun 			ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
3395*4882a593Smuzhiyun 					(char*)nla_data(iter), nla_len(iter));
3396*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3397*4882a593Smuzhiyun 				WL_ERR(("Failed to copy mac_addr\n"));
3398*4882a593Smuzhiyun 				goto exit;
3399*4882a593Smuzhiyun 			}
3400*4882a593Smuzhiyun 			break;
3401*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_IF_ADDR:
3402*4882a593Smuzhiyun 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3403*4882a593Smuzhiyun 				ret = -EINVAL;
3404*4882a593Smuzhiyun 				goto exit;
3405*4882a593Smuzhiyun 			}
3406*4882a593Smuzhiyun 			ret = memcpy_s((char*)&cmd_data->if_addr, ETHER_ADDR_LEN,
3407*4882a593Smuzhiyun 					(char*)nla_data(iter), nla_len(iter));
3408*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3409*4882a593Smuzhiyun 				WL_ERR(("Failed to copy if_addr\n"));
3410*4882a593Smuzhiyun 				goto exit;
3411*4882a593Smuzhiyun 			}
3412*4882a593Smuzhiyun 			break;
3413*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_ENTRY_CONTROL:
3414*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3415*4882a593Smuzhiyun 				ret = -EINVAL;
3416*4882a593Smuzhiyun 				goto exit;
3417*4882a593Smuzhiyun 			}
3418*4882a593Smuzhiyun 			cmd_data->avail_params.duration = nla_get_u8(iter);
3419*4882a593Smuzhiyun 			break;
3420*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_AVAIL_BIT_MAP:
3421*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
3422*4882a593Smuzhiyun 				ret = -EINVAL;
3423*4882a593Smuzhiyun 				goto exit;
3424*4882a593Smuzhiyun 			}
3425*4882a593Smuzhiyun 			cmd_data->avail_params.bmap = nla_get_u32(iter);
3426*4882a593Smuzhiyun 			break;
3427*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_CHANNEL: {
3428*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
3429*4882a593Smuzhiyun 				ret = -EINVAL;
3430*4882a593Smuzhiyun 				goto exit;
3431*4882a593Smuzhiyun 			}
3432*4882a593Smuzhiyun 			/* take the default channel start_factor frequency */
3433*4882a593Smuzhiyun 			chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
3434*4882a593Smuzhiyun 			if (chan <= CH_MAX_2G_CHANNEL) {
3435*4882a593Smuzhiyun 				cmd_data->avail_params.chanspec[0] =
3436*4882a593Smuzhiyun 					wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
3437*4882a593Smuzhiyun 			} else {
3438*4882a593Smuzhiyun 				cmd_data->avail_params.chanspec[0] =
3439*4882a593Smuzhiyun 					wf_channel2chspec(chan, WL_CHANSPEC_BW_80);
3440*4882a593Smuzhiyun 			}
3441*4882a593Smuzhiyun 			if (cmd_data->avail_params.chanspec[0] == 0) {
3442*4882a593Smuzhiyun 				WL_ERR(("Channel is not valid \n"));
3443*4882a593Smuzhiyun 				ret = -EINVAL;
3444*4882a593Smuzhiyun 				goto exit;
3445*4882a593Smuzhiyun 			}
3446*4882a593Smuzhiyun 			WL_TRACE(("valid chanspec, chanspec = 0x%04x \n",
3447*4882a593Smuzhiyun 				cmd_data->avail_params.chanspec[0]));
3448*4882a593Smuzhiyun 			break;
3449*4882a593Smuzhiyun 		}
3450*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_NO_CONFIG_AVAIL:
3451*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3452*4882a593Smuzhiyun 				ret = -EINVAL;
3453*4882a593Smuzhiyun 				goto exit;
3454*4882a593Smuzhiyun 			}
3455*4882a593Smuzhiyun 			cmd_data->avail_params.no_config_avail = (bool)nla_get_u8(iter);
3456*4882a593Smuzhiyun 			break;
3457*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICE_NAME_LEN: {
3458*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3459*4882a593Smuzhiyun 				ret = -EINVAL;
3460*4882a593Smuzhiyun 				goto exit;
3461*4882a593Smuzhiyun 			}
3462*4882a593Smuzhiyun 			if (cmd_data->svc_hash.dlen) {
3463*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3464*4882a593Smuzhiyun 				ret = -EINVAL;
3465*4882a593Smuzhiyun 				goto exit;
3466*4882a593Smuzhiyun 			}
3467*4882a593Smuzhiyun 			cmd_data->svc_hash.dlen = nla_get_u16(iter);
3468*4882a593Smuzhiyun 			if (cmd_data->svc_hash.dlen != WL_NAN_SVC_HASH_LEN) {
3469*4882a593Smuzhiyun 				WL_ERR(("invalid svc_hash length = %u\n", cmd_data->svc_hash.dlen));
3470*4882a593Smuzhiyun 				ret = -EINVAL;
3471*4882a593Smuzhiyun 				goto exit;
3472*4882a593Smuzhiyun 			}
3473*4882a593Smuzhiyun 			break;
3474*4882a593Smuzhiyun 		}
3475*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICE_NAME:
3476*4882a593Smuzhiyun 			if ((!cmd_data->svc_hash.dlen) ||
3477*4882a593Smuzhiyun 				(nla_len(iter) != cmd_data->svc_hash.dlen)) {
3478*4882a593Smuzhiyun 				WL_ERR(("invalid svc_hash length = %d,%d\n",
3479*4882a593Smuzhiyun 					cmd_data->svc_hash.dlen, nla_len(iter)));
3480*4882a593Smuzhiyun 				ret = -EINVAL;
3481*4882a593Smuzhiyun 				goto exit;
3482*4882a593Smuzhiyun 			}
3483*4882a593Smuzhiyun 			if (cmd_data->svc_hash.data) {
3484*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3485*4882a593Smuzhiyun 				ret = -EINVAL;
3486*4882a593Smuzhiyun 				goto exit;
3487*4882a593Smuzhiyun 			}
3488*4882a593Smuzhiyun 			cmd_data->svc_hash.data =
3489*4882a593Smuzhiyun 				MALLOCZ(cfg->osh, cmd_data->svc_hash.dlen);
3490*4882a593Smuzhiyun 			if (!cmd_data->svc_hash.data) {
3491*4882a593Smuzhiyun 				WL_ERR(("failed to allocate svc_hash data, len=%d\n",
3492*4882a593Smuzhiyun 					cmd_data->svc_hash.dlen));
3493*4882a593Smuzhiyun 				ret = -ENOMEM;
3494*4882a593Smuzhiyun 				goto exit;
3495*4882a593Smuzhiyun 			}
3496*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->svc_hash.data, cmd_data->svc_hash.dlen,
3497*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
3498*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3499*4882a593Smuzhiyun 				WL_ERR(("Failed to copy svc hash data\n"));
3500*4882a593Smuzhiyun 				goto exit;
3501*4882a593Smuzhiyun 			}
3502*4882a593Smuzhiyun 			break;
3503*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN:
3504*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3505*4882a593Smuzhiyun 				ret = -EINVAL;
3506*4882a593Smuzhiyun 				goto exit;
3507*4882a593Smuzhiyun 			}
3508*4882a593Smuzhiyun 			if (cmd_data->svc_info.dlen) {
3509*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3510*4882a593Smuzhiyun 				ret = -EINVAL;
3511*4882a593Smuzhiyun 				goto exit;
3512*4882a593Smuzhiyun 			}
3513*4882a593Smuzhiyun 			cmd_data->svc_info.dlen = nla_get_u16(iter);
3514*4882a593Smuzhiyun 			if (cmd_data->svc_info.dlen > MAX_APP_INFO_LEN) {
3515*4882a593Smuzhiyun 				WL_ERR_RLMT(("Not allowed beyond :%d\n", MAX_APP_INFO_LEN));
3516*4882a593Smuzhiyun 				ret = -EINVAL;
3517*4882a593Smuzhiyun 				goto exit;
3518*4882a593Smuzhiyun 			}
3519*4882a593Smuzhiyun 			break;
3520*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO:
3521*4882a593Smuzhiyun 			if ((!cmd_data->svc_info.dlen) ||
3522*4882a593Smuzhiyun 				(nla_len(iter) != cmd_data->svc_info.dlen)) {
3523*4882a593Smuzhiyun 				WL_ERR(("failed to allocate svc info by invalid len=%d,%d\n",
3524*4882a593Smuzhiyun 					cmd_data->svc_info.dlen, nla_len(iter)));
3525*4882a593Smuzhiyun 				ret = -EINVAL;
3526*4882a593Smuzhiyun 				goto exit;
3527*4882a593Smuzhiyun 			}
3528*4882a593Smuzhiyun 			if (cmd_data->svc_info.data) {
3529*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3530*4882a593Smuzhiyun 				ret = -EINVAL;
3531*4882a593Smuzhiyun 				goto exit;
3532*4882a593Smuzhiyun 			}
3533*4882a593Smuzhiyun 			cmd_data->svc_info.data = MALLOCZ(cfg->osh, cmd_data->svc_info.dlen);
3534*4882a593Smuzhiyun 			if (cmd_data->svc_info.data == NULL) {
3535*4882a593Smuzhiyun 				WL_ERR(("failed to allocate svc info data, len=%d\n",
3536*4882a593Smuzhiyun 					cmd_data->svc_info.dlen));
3537*4882a593Smuzhiyun 				ret = -ENOMEM;
3538*4882a593Smuzhiyun 				goto exit;
3539*4882a593Smuzhiyun 			}
3540*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->svc_info.data, cmd_data->svc_info.dlen,
3541*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
3542*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3543*4882a593Smuzhiyun 				WL_ERR(("Failed to copy svc info\n"));
3544*4882a593Smuzhiyun 				goto exit;
3545*4882a593Smuzhiyun 			}
3546*4882a593Smuzhiyun 			break;
3547*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PUBLISH_ID:
3548*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
3549*4882a593Smuzhiyun 				ret = -EINVAL;
3550*4882a593Smuzhiyun 				goto exit;
3551*4882a593Smuzhiyun 			}
3552*4882a593Smuzhiyun 			cmd_data->pub_id = nla_get_u32(iter);
3553*4882a593Smuzhiyun 			break;
3554*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
3555*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3556*4882a593Smuzhiyun 				ret = -EINVAL;
3557*4882a593Smuzhiyun 				goto exit;
3558*4882a593Smuzhiyun 			}
3559*4882a593Smuzhiyun 			cmd_data->csid = nla_get_u8(iter);
3560*4882a593Smuzhiyun 			WL_TRACE(("CSID = %u\n", cmd_data->csid));
3561*4882a593Smuzhiyun 			break;
3562*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_KEY_TYPE:
3563*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3564*4882a593Smuzhiyun 				ret = -EINVAL;
3565*4882a593Smuzhiyun 				goto exit;
3566*4882a593Smuzhiyun 			}
3567*4882a593Smuzhiyun 			cmd_data->key_type = nla_get_u8(iter);
3568*4882a593Smuzhiyun 			WL_TRACE(("Key Type = %u\n", cmd_data->key_type));
3569*4882a593Smuzhiyun 			break;
3570*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_KEY_LEN:
3571*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
3572*4882a593Smuzhiyun 				ret = -EINVAL;
3573*4882a593Smuzhiyun 				goto exit;
3574*4882a593Smuzhiyun 			}
3575*4882a593Smuzhiyun 			if (cmd_data->key.dlen) {
3576*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3577*4882a593Smuzhiyun 				ret = -EINVAL;
3578*4882a593Smuzhiyun 				goto exit;
3579*4882a593Smuzhiyun 			}
3580*4882a593Smuzhiyun 			cmd_data->key.dlen = nla_get_u32(iter);
3581*4882a593Smuzhiyun 			if ((!cmd_data->key.dlen) || (cmd_data->key.dlen > WL_NAN_NCS_SK_PMK_LEN)) {
3582*4882a593Smuzhiyun 				WL_ERR(("invalid key length = %u\n", cmd_data->key.dlen));
3583*4882a593Smuzhiyun 				ret = -EINVAL;
3584*4882a593Smuzhiyun 				goto exit;
3585*4882a593Smuzhiyun 			}
3586*4882a593Smuzhiyun 			WL_TRACE(("valid key length = %u\n", cmd_data->key.dlen));
3587*4882a593Smuzhiyun 			break;
3588*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_KEY_DATA:
3589*4882a593Smuzhiyun 			if ((!cmd_data->key.dlen) ||
3590*4882a593Smuzhiyun 				(nla_len(iter) != cmd_data->key.dlen)) {
3591*4882a593Smuzhiyun 				WL_ERR(("failed to allocate key data by invalid len=%d,%d\n",
3592*4882a593Smuzhiyun 					cmd_data->key.dlen, nla_len(iter)));
3593*4882a593Smuzhiyun 				ret = -EINVAL;
3594*4882a593Smuzhiyun 				goto exit;
3595*4882a593Smuzhiyun 			}
3596*4882a593Smuzhiyun 			if (cmd_data->key.data) {
3597*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite key data.\n"));
3598*4882a593Smuzhiyun 				ret = -EINVAL;
3599*4882a593Smuzhiyun 				goto exit;
3600*4882a593Smuzhiyun 			}
3601*4882a593Smuzhiyun 
3602*4882a593Smuzhiyun 			cmd_data->key.data = MALLOCZ(cfg->osh, NAN_MAX_PMK_LEN);
3603*4882a593Smuzhiyun 			if (cmd_data->key.data == NULL) {
3604*4882a593Smuzhiyun 				WL_ERR(("failed to allocate key data, len=%d\n",
3605*4882a593Smuzhiyun 					cmd_data->key.dlen));
3606*4882a593Smuzhiyun 				ret = -ENOMEM;
3607*4882a593Smuzhiyun 				goto exit;
3608*4882a593Smuzhiyun 			}
3609*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->key.data, NAN_MAX_PMK_LEN,
3610*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
3611*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3612*4882a593Smuzhiyun 				WL_ERR(("Failed to key data\n"));
3613*4882a593Smuzhiyun 				goto exit;
3614*4882a593Smuzhiyun 			}
3615*4882a593Smuzhiyun 			break;
3616*4882a593Smuzhiyun 
3617*4882a593Smuzhiyun 		default:
3618*4882a593Smuzhiyun 			WL_ERR(("Unknown type, %d\n", attr_type));
3619*4882a593Smuzhiyun 			ret = -EINVAL;
3620*4882a593Smuzhiyun 			goto exit;
3621*4882a593Smuzhiyun 		}
3622*4882a593Smuzhiyun 	}
3623*4882a593Smuzhiyun exit:
3624*4882a593Smuzhiyun 	/* We need to call set_config_handler b/f calling start enable TBD */
3625*4882a593Smuzhiyun 	NAN_DBG_EXIT();
3626*4882a593Smuzhiyun 	return ret;
3627*4882a593Smuzhiyun }
3628*4882a593Smuzhiyun 
3629*4882a593Smuzhiyun static int
wl_cfgvendor_nan_parse_discover_args(struct wiphy * wiphy,const void * buf,int len,nan_discover_cmd_data_t * cmd_data)3630*4882a593Smuzhiyun wl_cfgvendor_nan_parse_discover_args(struct wiphy *wiphy,
3631*4882a593Smuzhiyun 	const void *buf, int len, nan_discover_cmd_data_t *cmd_data)
3632*4882a593Smuzhiyun {
3633*4882a593Smuzhiyun 	int ret = BCME_OK;
3634*4882a593Smuzhiyun 	int attr_type;
3635*4882a593Smuzhiyun 	int rem = len;
3636*4882a593Smuzhiyun 	const struct nlattr *iter;
3637*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3638*4882a593Smuzhiyun 	u8 val_u8;
3639*4882a593Smuzhiyun 	u32 bit_flag;
3640*4882a593Smuzhiyun 	u8 flag_match;
3641*4882a593Smuzhiyun 
3642*4882a593Smuzhiyun 	NAN_DBG_ENTER();
3643*4882a593Smuzhiyun 
3644*4882a593Smuzhiyun 	nla_for_each_attr(iter, buf, len, rem) {
3645*4882a593Smuzhiyun 		attr_type = nla_type(iter);
3646*4882a593Smuzhiyun 		WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
3647*4882a593Smuzhiyun 
3648*4882a593Smuzhiyun 		switch (attr_type) {
3649*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_TRANSAC_ID:
3650*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3651*4882a593Smuzhiyun 				ret = -EINVAL;
3652*4882a593Smuzhiyun 				goto exit;
3653*4882a593Smuzhiyun 			}
3654*4882a593Smuzhiyun 			cmd_data->token = nla_get_u16(iter);
3655*4882a593Smuzhiyun 			break;
3656*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL:
3657*4882a593Smuzhiyun 			break;
3658*4882a593Smuzhiyun 
3659*4882a593Smuzhiyun 		/* Nan Publish/Subscribe request Attributes */
3660*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PUBLISH_ID:
3661*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3662*4882a593Smuzhiyun 				ret = -EINVAL;
3663*4882a593Smuzhiyun 				goto exit;
3664*4882a593Smuzhiyun 			}
3665*4882a593Smuzhiyun 			cmd_data->pub_id = nla_get_u16(iter);
3666*4882a593Smuzhiyun 			cmd_data->local_id = cmd_data->pub_id;
3667*4882a593Smuzhiyun 			break;
3668*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_MAC_ADDR:
3669*4882a593Smuzhiyun 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3670*4882a593Smuzhiyun 				ret = -EINVAL;
3671*4882a593Smuzhiyun 				goto exit;
3672*4882a593Smuzhiyun 			}
3673*4882a593Smuzhiyun 			ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
3674*4882a593Smuzhiyun 					(char*)nla_data(iter), nla_len(iter));
3675*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3676*4882a593Smuzhiyun 				WL_ERR(("Failed to copy mac addr\n"));
3677*4882a593Smuzhiyun 				return ret;
3678*4882a593Smuzhiyun 			}
3679*4882a593Smuzhiyun 			break;
3680*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN:
3681*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3682*4882a593Smuzhiyun 				ret = -EINVAL;
3683*4882a593Smuzhiyun 				goto exit;
3684*4882a593Smuzhiyun 			}
3685*4882a593Smuzhiyun 			if (cmd_data->svc_info.dlen) {
3686*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3687*4882a593Smuzhiyun 				ret = -EINVAL;
3688*4882a593Smuzhiyun 				goto exit;
3689*4882a593Smuzhiyun 			}
3690*4882a593Smuzhiyun 			cmd_data->svc_info.dlen = nla_get_u16(iter);
3691*4882a593Smuzhiyun 			if (cmd_data->svc_info.dlen > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
3692*4882a593Smuzhiyun 				WL_ERR_RLMT(("Not allowed beyond :%d\n",
3693*4882a593Smuzhiyun 					NAN_MAX_SERVICE_SPECIFIC_INFO_LEN));
3694*4882a593Smuzhiyun 				ret = -EINVAL;
3695*4882a593Smuzhiyun 				goto exit;
3696*4882a593Smuzhiyun 			}
3697*4882a593Smuzhiyun 			break;
3698*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO:
3699*4882a593Smuzhiyun 			if ((!cmd_data->svc_info.dlen) ||
3700*4882a593Smuzhiyun 				(nla_len(iter) != cmd_data->svc_info.dlen)) {
3701*4882a593Smuzhiyun 				WL_ERR(("failed to allocate svc info by invalid len=%d,%d\n",
3702*4882a593Smuzhiyun 					cmd_data->svc_info.dlen, nla_len(iter)));
3703*4882a593Smuzhiyun 				ret = -EINVAL;
3704*4882a593Smuzhiyun 				goto exit;
3705*4882a593Smuzhiyun 			}
3706*4882a593Smuzhiyun 			if (cmd_data->svc_info.data) {
3707*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3708*4882a593Smuzhiyun 				ret = -EINVAL;
3709*4882a593Smuzhiyun 				goto exit;
3710*4882a593Smuzhiyun 			}
3711*4882a593Smuzhiyun 
3712*4882a593Smuzhiyun 			cmd_data->svc_info.data = MALLOCZ(cfg->osh, cmd_data->svc_info.dlen);
3713*4882a593Smuzhiyun 			if (cmd_data->svc_info.data == NULL) {
3714*4882a593Smuzhiyun 				WL_ERR(("failed to allocate svc info data, len=%d\n",
3715*4882a593Smuzhiyun 					cmd_data->svc_info.dlen));
3716*4882a593Smuzhiyun 				ret = -ENOMEM;
3717*4882a593Smuzhiyun 				goto exit;
3718*4882a593Smuzhiyun 			}
3719*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->svc_info.data, cmd_data->svc_info.dlen,
3720*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
3721*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3722*4882a593Smuzhiyun 				WL_ERR(("Failed to copy svc info\n"));
3723*4882a593Smuzhiyun 				return ret;
3724*4882a593Smuzhiyun 			}
3725*4882a593Smuzhiyun 			break;
3726*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SUBSCRIBE_ID:
3727*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3728*4882a593Smuzhiyun 				ret = -EINVAL;
3729*4882a593Smuzhiyun 				goto exit;
3730*4882a593Smuzhiyun 			}
3731*4882a593Smuzhiyun 			cmd_data->sub_id = nla_get_u16(iter);
3732*4882a593Smuzhiyun 			cmd_data->local_id = cmd_data->sub_id;
3733*4882a593Smuzhiyun 			break;
3734*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SUBSCRIBE_TYPE:
3735*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3736*4882a593Smuzhiyun 				ret = -EINVAL;
3737*4882a593Smuzhiyun 				goto exit;
3738*4882a593Smuzhiyun 			}
3739*4882a593Smuzhiyun 			cmd_data->flags |= nla_get_u8(iter) ? WL_NAN_SUB_ACTIVE : 0;
3740*4882a593Smuzhiyun 			break;
3741*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PUBLISH_COUNT:
3742*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3743*4882a593Smuzhiyun 				ret = -EINVAL;
3744*4882a593Smuzhiyun 				goto exit;
3745*4882a593Smuzhiyun 			}
3746*4882a593Smuzhiyun 			cmd_data->life_count = nla_get_u8(iter);
3747*4882a593Smuzhiyun 			break;
3748*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PUBLISH_TYPE: {
3749*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3750*4882a593Smuzhiyun 				ret = -EINVAL;
3751*4882a593Smuzhiyun 				goto exit;
3752*4882a593Smuzhiyun 			}
3753*4882a593Smuzhiyun 			val_u8 = nla_get_u8(iter);
3754*4882a593Smuzhiyun 			if (val_u8 == 0) {
3755*4882a593Smuzhiyun 				cmd_data->flags |= WL_NAN_PUB_UNSOLICIT;
3756*4882a593Smuzhiyun 			} else if (val_u8 == 1) {
3757*4882a593Smuzhiyun 				cmd_data->flags |= WL_NAN_PUB_SOLICIT;
3758*4882a593Smuzhiyun 			} else {
3759*4882a593Smuzhiyun 				cmd_data->flags |= WL_NAN_PUB_BOTH;
3760*4882a593Smuzhiyun 			}
3761*4882a593Smuzhiyun 			break;
3762*4882a593Smuzhiyun 		}
3763*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PERIOD: {
3764*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3765*4882a593Smuzhiyun 				ret = -EINVAL;
3766*4882a593Smuzhiyun 				goto exit;
3767*4882a593Smuzhiyun 			}
3768*4882a593Smuzhiyun 			if (nla_get_u16(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
3769*4882a593Smuzhiyun 				WL_ERR(("Invalid/Out of bound value = %u\n", nla_get_u16(iter)));
3770*4882a593Smuzhiyun 				ret = BCME_BADARG;
3771*4882a593Smuzhiyun 				break;
3772*4882a593Smuzhiyun 			}
3773*4882a593Smuzhiyun 			if (nla_get_u16(iter)) {
3774*4882a593Smuzhiyun 				cmd_data->period = 1 << (nla_get_u16(iter)-1);
3775*4882a593Smuzhiyun 			}
3776*4882a593Smuzhiyun 			break;
3777*4882a593Smuzhiyun 		}
3778*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_REPLIED_EVENT_FLAG:
3779*4882a593Smuzhiyun 			break;
3780*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_TTL:
3781*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3782*4882a593Smuzhiyun 				ret = -EINVAL;
3783*4882a593Smuzhiyun 				goto exit;
3784*4882a593Smuzhiyun 			}
3785*4882a593Smuzhiyun 			cmd_data->ttl = nla_get_u16(iter);
3786*4882a593Smuzhiyun 			break;
3787*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICE_NAME_LEN: {
3788*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3789*4882a593Smuzhiyun 				ret = -EINVAL;
3790*4882a593Smuzhiyun 				goto exit;
3791*4882a593Smuzhiyun 			}
3792*4882a593Smuzhiyun 			if (cmd_data->svc_hash.dlen) {
3793*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3794*4882a593Smuzhiyun 				ret = -EINVAL;
3795*4882a593Smuzhiyun 				goto exit;
3796*4882a593Smuzhiyun 			}
3797*4882a593Smuzhiyun 
3798*4882a593Smuzhiyun 			cmd_data->svc_hash.dlen = nla_get_u16(iter);
3799*4882a593Smuzhiyun 			if (cmd_data->svc_hash.dlen != WL_NAN_SVC_HASH_LEN) {
3800*4882a593Smuzhiyun 				WL_ERR(("invalid svc_hash length = %u\n", cmd_data->svc_hash.dlen));
3801*4882a593Smuzhiyun 				ret = -EINVAL;
3802*4882a593Smuzhiyun 				goto exit;
3803*4882a593Smuzhiyun 			}
3804*4882a593Smuzhiyun 			break;
3805*4882a593Smuzhiyun 		}
3806*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICE_NAME:
3807*4882a593Smuzhiyun 			if ((!cmd_data->svc_hash.dlen) ||
3808*4882a593Smuzhiyun 				(nla_len(iter) != cmd_data->svc_hash.dlen)) {
3809*4882a593Smuzhiyun 				WL_ERR(("invalid svc_hash length = %d,%d\n",
3810*4882a593Smuzhiyun 					cmd_data->svc_hash.dlen, nla_len(iter)));
3811*4882a593Smuzhiyun 				ret = -EINVAL;
3812*4882a593Smuzhiyun 				goto exit;
3813*4882a593Smuzhiyun 			}
3814*4882a593Smuzhiyun 			if (cmd_data->svc_hash.data) {
3815*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3816*4882a593Smuzhiyun 				ret = -EINVAL;
3817*4882a593Smuzhiyun 				goto exit;
3818*4882a593Smuzhiyun 			}
3819*4882a593Smuzhiyun 
3820*4882a593Smuzhiyun 			cmd_data->svc_hash.data =
3821*4882a593Smuzhiyun 				MALLOCZ(cfg->osh, cmd_data->svc_hash.dlen);
3822*4882a593Smuzhiyun 			if (!cmd_data->svc_hash.data) {
3823*4882a593Smuzhiyun 				WL_ERR(("failed to allocate svc_hash data, len=%d\n",
3824*4882a593Smuzhiyun 					cmd_data->svc_hash.dlen));
3825*4882a593Smuzhiyun 				ret = -ENOMEM;
3826*4882a593Smuzhiyun 				goto exit;
3827*4882a593Smuzhiyun 			}
3828*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->svc_hash.data, cmd_data->svc_hash.dlen,
3829*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
3830*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3831*4882a593Smuzhiyun 				WL_ERR(("Failed to copy svc hash data\n"));
3832*4882a593Smuzhiyun 				return ret;
3833*4882a593Smuzhiyun 			}
3834*4882a593Smuzhiyun 			break;
3835*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PEER_ID:
3836*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
3837*4882a593Smuzhiyun 				ret = -EINVAL;
3838*4882a593Smuzhiyun 				goto exit;
3839*4882a593Smuzhiyun 			}
3840*4882a593Smuzhiyun 			cmd_data->remote_id = nla_get_u32(iter);
3841*4882a593Smuzhiyun 			break;
3842*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_INST_ID:
3843*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3844*4882a593Smuzhiyun 				ret = -EINVAL;
3845*4882a593Smuzhiyun 				goto exit;
3846*4882a593Smuzhiyun 			}
3847*4882a593Smuzhiyun 			cmd_data->local_id = nla_get_u16(iter);
3848*4882a593Smuzhiyun 			break;
3849*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SUBSCRIBE_COUNT:
3850*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3851*4882a593Smuzhiyun 				ret = -EINVAL;
3852*4882a593Smuzhiyun 				goto exit;
3853*4882a593Smuzhiyun 			}
3854*4882a593Smuzhiyun 			cmd_data->life_count = nla_get_u8(iter);
3855*4882a593Smuzhiyun 			break;
3856*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION: {
3857*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3858*4882a593Smuzhiyun 				ret = -EINVAL;
3859*4882a593Smuzhiyun 				goto exit;
3860*4882a593Smuzhiyun 			}
3861*4882a593Smuzhiyun 			bit_flag = (u32)nla_get_u8(iter);
3862*4882a593Smuzhiyun 			cmd_data->flags |=
3863*4882a593Smuzhiyun 				bit_flag ? WL_NAN_SUB_MATCH_IF_SVC_INFO : 0;
3864*4882a593Smuzhiyun 			break;
3865*4882a593Smuzhiyun 		}
3866*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SUBSCRIBE_MATCH:
3867*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_PUBLISH_MATCH: {
3868*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3869*4882a593Smuzhiyun 				ret = -EINVAL;
3870*4882a593Smuzhiyun 				goto exit;
3871*4882a593Smuzhiyun 			}
3872*4882a593Smuzhiyun 			flag_match = nla_get_u8(iter);
3873*4882a593Smuzhiyun 
3874*4882a593Smuzhiyun 			switch (flag_match) {
3875*4882a593Smuzhiyun 			case NAN_MATCH_ALG_MATCH_CONTINUOUS:
3876*4882a593Smuzhiyun 				/* Default fw behaviour, no need to set explicitly */
3877*4882a593Smuzhiyun 				break;
3878*4882a593Smuzhiyun 			case NAN_MATCH_ALG_MATCH_ONCE:
3879*4882a593Smuzhiyun 				cmd_data->flags |= WL_NAN_MATCH_ONCE;
3880*4882a593Smuzhiyun 				break;
3881*4882a593Smuzhiyun 			case NAN_MATCH_ALG_MATCH_NEVER:
3882*4882a593Smuzhiyun 				cmd_data->flags |= WL_NAN_MATCH_NEVER;
3883*4882a593Smuzhiyun 				break;
3884*4882a593Smuzhiyun 			default:
3885*4882a593Smuzhiyun 				WL_ERR(("invalid nan match alg = %u\n", flag_match));
3886*4882a593Smuzhiyun 				ret = -EINVAL;
3887*4882a593Smuzhiyun 				goto exit;
3888*4882a593Smuzhiyun 			}
3889*4882a593Smuzhiyun 			break;
3890*4882a593Smuzhiyun 		}
3891*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICERESPONSEFILTER:
3892*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3893*4882a593Smuzhiyun 				ret = -EINVAL;
3894*4882a593Smuzhiyun 				goto exit;
3895*4882a593Smuzhiyun 			}
3896*4882a593Smuzhiyun 			cmd_data->srf_type = nla_get_u8(iter);
3897*4882a593Smuzhiyun 			break;
3898*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE:
3899*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3900*4882a593Smuzhiyun 				ret = -EINVAL;
3901*4882a593Smuzhiyun 				goto exit;
3902*4882a593Smuzhiyun 			}
3903*4882a593Smuzhiyun 			cmd_data->srf_include = nla_get_u8(iter);
3904*4882a593Smuzhiyun 			break;
3905*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_USESERVICERESPONSEFILTER:
3906*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
3907*4882a593Smuzhiyun 				ret = -EINVAL;
3908*4882a593Smuzhiyun 				goto exit;
3909*4882a593Smuzhiyun 			}
3910*4882a593Smuzhiyun 			cmd_data->use_srf = nla_get_u8(iter);
3911*4882a593Smuzhiyun 			break;
3912*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN:
3913*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3914*4882a593Smuzhiyun 				ret = -EINVAL;
3915*4882a593Smuzhiyun 				goto exit;
3916*4882a593Smuzhiyun 			}
3917*4882a593Smuzhiyun 			if (cmd_data->rx_match.dlen) {
3918*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3919*4882a593Smuzhiyun 				ret = -EINVAL;
3920*4882a593Smuzhiyun 				goto exit;
3921*4882a593Smuzhiyun 			}
3922*4882a593Smuzhiyun 			cmd_data->rx_match.dlen = nla_get_u16(iter);
3923*4882a593Smuzhiyun 			if (cmd_data->rx_match.dlen > MAX_MATCH_FILTER_LEN) {
3924*4882a593Smuzhiyun 				ret = -EINVAL;
3925*4882a593Smuzhiyun 				WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_MATCH_FILTER_LEN));
3926*4882a593Smuzhiyun 				goto exit;
3927*4882a593Smuzhiyun 			}
3928*4882a593Smuzhiyun 			break;
3929*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RX_MATCH_FILTER:
3930*4882a593Smuzhiyun 			if ((!cmd_data->rx_match.dlen) ||
3931*4882a593Smuzhiyun 			    (nla_len(iter) != cmd_data->rx_match.dlen)) {
3932*4882a593Smuzhiyun 				WL_ERR(("RX match filter len wrong:%d,%d\n",
3933*4882a593Smuzhiyun 					cmd_data->rx_match.dlen, nla_len(iter)));
3934*4882a593Smuzhiyun 				ret = -EINVAL;
3935*4882a593Smuzhiyun 				goto exit;
3936*4882a593Smuzhiyun 			}
3937*4882a593Smuzhiyun 			if (cmd_data->rx_match.data) {
3938*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3939*4882a593Smuzhiyun 				ret = -EINVAL;
3940*4882a593Smuzhiyun 				goto exit;
3941*4882a593Smuzhiyun 			}
3942*4882a593Smuzhiyun 			cmd_data->rx_match.data =
3943*4882a593Smuzhiyun 				MALLOCZ(cfg->osh, cmd_data->rx_match.dlen);
3944*4882a593Smuzhiyun 			if (cmd_data->rx_match.data == NULL) {
3945*4882a593Smuzhiyun 				WL_ERR(("failed to allocate LEN=[%u]\n",
3946*4882a593Smuzhiyun 					cmd_data->rx_match.dlen));
3947*4882a593Smuzhiyun 				ret = -ENOMEM;
3948*4882a593Smuzhiyun 				goto exit;
3949*4882a593Smuzhiyun 			}
3950*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->rx_match.data, cmd_data->rx_match.dlen,
3951*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
3952*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3953*4882a593Smuzhiyun 				WL_ERR(("Failed to copy rx match data\n"));
3954*4882a593Smuzhiyun 				return ret;
3955*4882a593Smuzhiyun 			}
3956*4882a593Smuzhiyun 			break;
3957*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN:
3958*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
3959*4882a593Smuzhiyun 				ret = -EINVAL;
3960*4882a593Smuzhiyun 				goto exit;
3961*4882a593Smuzhiyun 			}
3962*4882a593Smuzhiyun 			if (cmd_data->tx_match.dlen) {
3963*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3964*4882a593Smuzhiyun 				ret = -EINVAL;
3965*4882a593Smuzhiyun 				goto exit;
3966*4882a593Smuzhiyun 			}
3967*4882a593Smuzhiyun 			cmd_data->tx_match.dlen = nla_get_u16(iter);
3968*4882a593Smuzhiyun 			if (cmd_data->tx_match.dlen > MAX_MATCH_FILTER_LEN) {
3969*4882a593Smuzhiyun 				ret = -EINVAL;
3970*4882a593Smuzhiyun 				WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_MATCH_FILTER_LEN));
3971*4882a593Smuzhiyun 				goto exit;
3972*4882a593Smuzhiyun 			}
3973*4882a593Smuzhiyun 			break;
3974*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_TX_MATCH_FILTER:
3975*4882a593Smuzhiyun 			if ((!cmd_data->tx_match.dlen) ||
3976*4882a593Smuzhiyun 			    (nla_len(iter) != cmd_data->tx_match.dlen)) {
3977*4882a593Smuzhiyun 				WL_ERR(("TX match filter len wrong:%d,%d\n",
3978*4882a593Smuzhiyun 					cmd_data->tx_match.dlen, nla_len(iter)));
3979*4882a593Smuzhiyun 				ret = -EINVAL;
3980*4882a593Smuzhiyun 				goto exit;
3981*4882a593Smuzhiyun 			}
3982*4882a593Smuzhiyun 			if (cmd_data->tx_match.data) {
3983*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3984*4882a593Smuzhiyun 				ret = -EINVAL;
3985*4882a593Smuzhiyun 				goto exit;
3986*4882a593Smuzhiyun 			}
3987*4882a593Smuzhiyun 			cmd_data->tx_match.data =
3988*4882a593Smuzhiyun 				MALLOCZ(cfg->osh, cmd_data->tx_match.dlen);
3989*4882a593Smuzhiyun 			if (cmd_data->tx_match.data == NULL) {
3990*4882a593Smuzhiyun 				WL_ERR(("failed to allocate LEN=[%u]\n",
3991*4882a593Smuzhiyun 					cmd_data->tx_match.dlen));
3992*4882a593Smuzhiyun 				ret = -EINVAL;
3993*4882a593Smuzhiyun 				goto exit;
3994*4882a593Smuzhiyun 			}
3995*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->tx_match.data, cmd_data->tx_match.dlen,
3996*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
3997*4882a593Smuzhiyun 			if (ret != BCME_OK) {
3998*4882a593Smuzhiyun 				WL_ERR(("Failed to copy tx match data\n"));
3999*4882a593Smuzhiyun 				return ret;
4000*4882a593Smuzhiyun 			}
4001*4882a593Smuzhiyun 			break;
4002*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES:
4003*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
4004*4882a593Smuzhiyun 				ret = -EINVAL;
4005*4882a593Smuzhiyun 				goto exit;
4006*4882a593Smuzhiyun 			}
4007*4882a593Smuzhiyun 			if (cmd_data->mac_list.num_mac_addr) {
4008*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4009*4882a593Smuzhiyun 				ret = -EINVAL;
4010*4882a593Smuzhiyun 				goto exit;
4011*4882a593Smuzhiyun 			}
4012*4882a593Smuzhiyun 			cmd_data->mac_list.num_mac_addr = nla_get_u16(iter);
4013*4882a593Smuzhiyun 			break;
4014*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_MAC_ADDR_LIST:
4015*4882a593Smuzhiyun 			if ((!cmd_data->mac_list.num_mac_addr) ||
4016*4882a593Smuzhiyun 			    (nla_len(iter) != (cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN))) {
4017*4882a593Smuzhiyun 				WL_ERR(("wrong mac list len:%d,%d\n",
4018*4882a593Smuzhiyun 					cmd_data->mac_list.num_mac_addr, nla_len(iter)));
4019*4882a593Smuzhiyun 				ret = -EINVAL;
4020*4882a593Smuzhiyun 				goto exit;
4021*4882a593Smuzhiyun 			}
4022*4882a593Smuzhiyun 			if (cmd_data->mac_list.list) {
4023*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4024*4882a593Smuzhiyun 				ret = -EINVAL;
4025*4882a593Smuzhiyun 				goto exit;
4026*4882a593Smuzhiyun 			}
4027*4882a593Smuzhiyun 			cmd_data->mac_list.list =
4028*4882a593Smuzhiyun 				MALLOCZ(cfg->osh, (cmd_data->mac_list.num_mac_addr
4029*4882a593Smuzhiyun 						* ETHER_ADDR_LEN));
4030*4882a593Smuzhiyun 			if (cmd_data->mac_list.list == NULL) {
4031*4882a593Smuzhiyun 				WL_ERR(("failed to allocate LEN=[%u]\n",
4032*4882a593Smuzhiyun 				(cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN)));
4033*4882a593Smuzhiyun 				ret = -ENOMEM;
4034*4882a593Smuzhiyun 				goto exit;
4035*4882a593Smuzhiyun 			}
4036*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->mac_list.list,
4037*4882a593Smuzhiyun 				(cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN),
4038*4882a593Smuzhiyun 				nla_data(iter), nla_len(iter));
4039*4882a593Smuzhiyun 			if (ret != BCME_OK) {
4040*4882a593Smuzhiyun 				WL_ERR(("Failed to copy list of mac addresses\n"));
4041*4882a593Smuzhiyun 				return ret;
4042*4882a593Smuzhiyun 			}
4043*4882a593Smuzhiyun 			break;
4044*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_TX_TYPE:
4045*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4046*4882a593Smuzhiyun 				ret = -EINVAL;
4047*4882a593Smuzhiyun 				goto exit;
4048*4882a593Smuzhiyun 			}
4049*4882a593Smuzhiyun 			val_u8 =  nla_get_u8(iter);
4050*4882a593Smuzhiyun 			if (val_u8 == 0) {
4051*4882a593Smuzhiyun 				cmd_data->flags |= WL_NAN_PUB_BCAST;
4052*4882a593Smuzhiyun 				WL_TRACE(("NAN_ATTRIBUTE_TX_TYPE: flags=NAN_PUB_BCAST\n"));
4053*4882a593Smuzhiyun 			}
4054*4882a593Smuzhiyun 			break;
4055*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP:
4056*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4057*4882a593Smuzhiyun 				ret = -EINVAL;
4058*4882a593Smuzhiyun 				goto exit;
4059*4882a593Smuzhiyun 			}
4060*4882a593Smuzhiyun 			if (nla_get_u8(iter) == 1) {
4061*4882a593Smuzhiyun 				cmd_data->sde_control_flag
4062*4882a593Smuzhiyun 					|= NAN_SDE_CF_DP_REQUIRED;
4063*4882a593Smuzhiyun 				break;
4064*4882a593Smuzhiyun 			}
4065*4882a593Smuzhiyun 			break;
4066*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT:
4067*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4068*4882a593Smuzhiyun 				ret = -EINVAL;
4069*4882a593Smuzhiyun 				goto exit;
4070*4882a593Smuzhiyun 			}
4071*4882a593Smuzhiyun 			cmd_data->sde_control_config = TRUE;
4072*4882a593Smuzhiyun 			if (nla_get_u8(iter) == 1) {
4073*4882a593Smuzhiyun 				cmd_data->sde_control_flag
4074*4882a593Smuzhiyun 					|= NAN_SDE_CF_RANGING_REQUIRED;
4075*4882a593Smuzhiyun 				break;
4076*4882a593Smuzhiyun 			}
4077*4882a593Smuzhiyun 			break;
4078*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE:
4079*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4080*4882a593Smuzhiyun 				ret = -EINVAL;
4081*4882a593Smuzhiyun 				goto exit;
4082*4882a593Smuzhiyun 			}
4083*4882a593Smuzhiyun 			if (nla_get_u8(iter) == 1) {
4084*4882a593Smuzhiyun 				cmd_data->sde_control_flag
4085*4882a593Smuzhiyun 					|= NAN_SDE_CF_MULTICAST_TYPE;
4086*4882a593Smuzhiyun 				break;
4087*4882a593Smuzhiyun 			}
4088*4882a593Smuzhiyun 			break;
4089*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SDE_CONTROL_SECURITY:
4090*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4091*4882a593Smuzhiyun 				ret = -EINVAL;
4092*4882a593Smuzhiyun 				goto exit;
4093*4882a593Smuzhiyun 			}
4094*4882a593Smuzhiyun 			if (nla_get_u8(iter) == 1) {
4095*4882a593Smuzhiyun 				cmd_data->sde_control_flag
4096*4882a593Smuzhiyun 					|= NAN_SDE_CF_SECURITY_REQUIRED;
4097*4882a593Smuzhiyun 				break;
4098*4882a593Smuzhiyun 			}
4099*4882a593Smuzhiyun 			break;
4100*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RECV_IND_CFG:
4101*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4102*4882a593Smuzhiyun 				ret = -EINVAL;
4103*4882a593Smuzhiyun 				goto exit;
4104*4882a593Smuzhiyun 			}
4105*4882a593Smuzhiyun 			cmd_data->recv_ind_flag = nla_get_u8(iter);
4106*4882a593Smuzhiyun 			break;
4107*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
4108*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4109*4882a593Smuzhiyun 				ret = -EINVAL;
4110*4882a593Smuzhiyun 				goto exit;
4111*4882a593Smuzhiyun 			}
4112*4882a593Smuzhiyun 			cmd_data->csid = nla_get_u8(iter);
4113*4882a593Smuzhiyun 			WL_TRACE(("CSID = %u\n", cmd_data->csid));
4114*4882a593Smuzhiyun 			break;
4115*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_KEY_TYPE:
4116*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4117*4882a593Smuzhiyun 				ret = -EINVAL;
4118*4882a593Smuzhiyun 				goto exit;
4119*4882a593Smuzhiyun 			}
4120*4882a593Smuzhiyun 			cmd_data->key_type = nla_get_u8(iter);
4121*4882a593Smuzhiyun 			WL_TRACE(("Key Type = %u\n", cmd_data->key_type));
4122*4882a593Smuzhiyun 			break;
4123*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_KEY_LEN:
4124*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4125*4882a593Smuzhiyun 				ret = -EINVAL;
4126*4882a593Smuzhiyun 				goto exit;
4127*4882a593Smuzhiyun 			}
4128*4882a593Smuzhiyun 			if (cmd_data->key.dlen) {
4129*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4130*4882a593Smuzhiyun 				ret = -EINVAL;
4131*4882a593Smuzhiyun 				goto exit;
4132*4882a593Smuzhiyun 			}
4133*4882a593Smuzhiyun 			cmd_data->key.dlen = nla_get_u32(iter);
4134*4882a593Smuzhiyun 			if ((!cmd_data->key.dlen) || (cmd_data->key.dlen > WL_NAN_NCS_SK_PMK_LEN)) {
4135*4882a593Smuzhiyun 				WL_ERR(("invalid key length = %u\n",
4136*4882a593Smuzhiyun 					cmd_data->key.dlen));
4137*4882a593Smuzhiyun 				break;
4138*4882a593Smuzhiyun 			}
4139*4882a593Smuzhiyun 			WL_TRACE(("valid key length = %u\n", cmd_data->key.dlen));
4140*4882a593Smuzhiyun 			break;
4141*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_KEY_DATA:
4142*4882a593Smuzhiyun 			if (!cmd_data->key.dlen ||
4143*4882a593Smuzhiyun 			    (nla_len(iter) != cmd_data->key.dlen)) {
4144*4882a593Smuzhiyun 				WL_ERR(("failed to allocate key data by invalid len=%d,%d\n",
4145*4882a593Smuzhiyun 					cmd_data->key.dlen, nla_len(iter)));
4146*4882a593Smuzhiyun 				ret = -EINVAL;
4147*4882a593Smuzhiyun 				goto exit;
4148*4882a593Smuzhiyun 			}
4149*4882a593Smuzhiyun 			if (cmd_data->key.data) {
4150*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4151*4882a593Smuzhiyun 				ret = -EINVAL;
4152*4882a593Smuzhiyun 				goto exit;
4153*4882a593Smuzhiyun 			}
4154*4882a593Smuzhiyun 
4155*4882a593Smuzhiyun 			cmd_data->key.data = MALLOCZ(cfg->osh, NAN_MAX_PMK_LEN);
4156*4882a593Smuzhiyun 			if (cmd_data->key.data == NULL) {
4157*4882a593Smuzhiyun 				WL_ERR(("failed to allocate key data, len=%d\n",
4158*4882a593Smuzhiyun 					cmd_data->key.dlen));
4159*4882a593Smuzhiyun 				ret = -ENOMEM;
4160*4882a593Smuzhiyun 				goto exit;
4161*4882a593Smuzhiyun 			}
4162*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->key.data, NAN_MAX_PMK_LEN,
4163*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
4164*4882a593Smuzhiyun 			if (ret != BCME_OK) {
4165*4882a593Smuzhiyun 				WL_ERR(("Failed to key data\n"));
4166*4882a593Smuzhiyun 				return ret;
4167*4882a593Smuzhiyun 			}
4168*4882a593Smuzhiyun 			break;
4169*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG:
4170*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4171*4882a593Smuzhiyun 				ret = -EINVAL;
4172*4882a593Smuzhiyun 				goto exit;
4173*4882a593Smuzhiyun 			}
4174*4882a593Smuzhiyun 			if (nla_get_u8(iter) == 1) {
4175*4882a593Smuzhiyun 				cmd_data->flags |=
4176*4882a593Smuzhiyun 					WL_NAN_RANGE_LIMITED;
4177*4882a593Smuzhiyun 				break;
4178*4882a593Smuzhiyun 			}
4179*4882a593Smuzhiyun 			break;
4180*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_DISC_IND_CFG:
4181*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4182*4882a593Smuzhiyun 				ret = -EINVAL;
4183*4882a593Smuzhiyun 				goto exit;
4184*4882a593Smuzhiyun 			}
4185*4882a593Smuzhiyun 			cmd_data->disc_ind_cfg = nla_get_u8(iter);
4186*4882a593Smuzhiyun 			break;
4187*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN:
4188*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
4189*4882a593Smuzhiyun 				ret = -EINVAL;
4190*4882a593Smuzhiyun 				goto exit;
4191*4882a593Smuzhiyun 			}
4192*4882a593Smuzhiyun 			if (cmd_data->sde_svc_info.dlen) {
4193*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4194*4882a593Smuzhiyun 				ret = -EINVAL;
4195*4882a593Smuzhiyun 				goto exit;
4196*4882a593Smuzhiyun 			}
4197*4882a593Smuzhiyun 			cmd_data->sde_svc_info.dlen = nla_get_u16(iter);
4198*4882a593Smuzhiyun 			if (cmd_data->sde_svc_info.dlen > MAX_SDEA_SVC_INFO_LEN) {
4199*4882a593Smuzhiyun 				ret = -EINVAL;
4200*4882a593Smuzhiyun 				WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_SDEA_SVC_INFO_LEN));
4201*4882a593Smuzhiyun 				goto exit;
4202*4882a593Smuzhiyun 			}
4203*4882a593Smuzhiyun 			break;
4204*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO:
4205*4882a593Smuzhiyun 			if ((!cmd_data->sde_svc_info.dlen) ||
4206*4882a593Smuzhiyun 			    (nla_len(iter) != cmd_data->sde_svc_info.dlen)) {
4207*4882a593Smuzhiyun 				WL_ERR(("wrong sdea info len:%d,%d\n",
4208*4882a593Smuzhiyun 					cmd_data->sde_svc_info.dlen, nla_len(iter)));
4209*4882a593Smuzhiyun 				ret = -EINVAL;
4210*4882a593Smuzhiyun 				goto exit;
4211*4882a593Smuzhiyun 			}
4212*4882a593Smuzhiyun 			if (cmd_data->sde_svc_info.data) {
4213*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4214*4882a593Smuzhiyun 				ret = -EINVAL;
4215*4882a593Smuzhiyun 				goto exit;
4216*4882a593Smuzhiyun 			}
4217*4882a593Smuzhiyun 			cmd_data->sde_svc_info.data = MALLOCZ(cfg->osh,
4218*4882a593Smuzhiyun 				cmd_data->sde_svc_info.dlen);
4219*4882a593Smuzhiyun 			if (cmd_data->sde_svc_info.data == NULL) {
4220*4882a593Smuzhiyun 				WL_ERR(("failed to allocate svc info data, len=%d\n",
4221*4882a593Smuzhiyun 					cmd_data->sde_svc_info.dlen));
4222*4882a593Smuzhiyun 				ret = -ENOMEM;
4223*4882a593Smuzhiyun 				goto exit;
4224*4882a593Smuzhiyun 			}
4225*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->sde_svc_info.data,
4226*4882a593Smuzhiyun 					cmd_data->sde_svc_info.dlen,
4227*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
4228*4882a593Smuzhiyun 			if (ret != BCME_OK) {
4229*4882a593Smuzhiyun 				WL_ERR(("Failed to sdea info data\n"));
4230*4882a593Smuzhiyun 				return ret;
4231*4882a593Smuzhiyun 			}
4232*4882a593Smuzhiyun 			break;
4233*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SECURITY:
4234*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4235*4882a593Smuzhiyun 				ret = -EINVAL;
4236*4882a593Smuzhiyun 				goto exit;
4237*4882a593Smuzhiyun 			}
4238*4882a593Smuzhiyun 			cmd_data->ndp_cfg.security_cfg = nla_get_u8(iter);
4239*4882a593Smuzhiyun 			break;
4240*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RANGING_INTERVAL:
4241*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4242*4882a593Smuzhiyun 				ret = -EINVAL;
4243*4882a593Smuzhiyun 				goto exit;
4244*4882a593Smuzhiyun 			}
4245*4882a593Smuzhiyun 			cmd_data->ranging_intvl_msec = nla_get_u32(iter);
4246*4882a593Smuzhiyun 			break;
4247*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT:
4248*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4249*4882a593Smuzhiyun 				ret = -EINVAL;
4250*4882a593Smuzhiyun 				goto exit;
4251*4882a593Smuzhiyun 			}
4252*4882a593Smuzhiyun 			cmd_data->ingress_limit = nla_get_u32(iter);
4253*4882a593Smuzhiyun 			break;
4254*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT:
4255*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4256*4882a593Smuzhiyun 				ret = -EINVAL;
4257*4882a593Smuzhiyun 				goto exit;
4258*4882a593Smuzhiyun 			}
4259*4882a593Smuzhiyun 			cmd_data->egress_limit = nla_get_u32(iter);
4260*4882a593Smuzhiyun 			break;
4261*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RANGING_INDICATION:
4262*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4263*4882a593Smuzhiyun 				ret = -EINVAL;
4264*4882a593Smuzhiyun 				goto exit;
4265*4882a593Smuzhiyun 			}
4266*4882a593Smuzhiyun 			cmd_data->ranging_indication = nla_get_u32(iter);
4267*4882a593Smuzhiyun 			break;
4268*4882a593Smuzhiyun 		/* Nan accept policy: Per service basis policy
4269*4882a593Smuzhiyun 		 * Based on this policy(ALL/NONE), responder side
4270*4882a593Smuzhiyun 		 * will send ACCEPT/REJECT
4271*4882a593Smuzhiyun 		 */
4272*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SVC_RESPONDER_POLICY:
4273*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4274*4882a593Smuzhiyun 				ret = -EINVAL;
4275*4882a593Smuzhiyun 				goto exit;
4276*4882a593Smuzhiyun 			}
4277*4882a593Smuzhiyun 			cmd_data->service_responder_policy = nla_get_u8(iter);
4278*4882a593Smuzhiyun 			break;
4279*4882a593Smuzhiyun 		default:
4280*4882a593Smuzhiyun 			WL_ERR(("Unknown type, %d\n", attr_type));
4281*4882a593Smuzhiyun 			ret = -EINVAL;
4282*4882a593Smuzhiyun 			goto exit;
4283*4882a593Smuzhiyun 		}
4284*4882a593Smuzhiyun 	}
4285*4882a593Smuzhiyun exit:
4286*4882a593Smuzhiyun 	/* We need to call set_config_handler b/f calling start enable TBD */
4287*4882a593Smuzhiyun 	NAN_DBG_EXIT();
4288*4882a593Smuzhiyun 	return ret;
4289*4882a593Smuzhiyun }
4290*4882a593Smuzhiyun 
4291*4882a593Smuzhiyun static int
wl_cfgvendor_nan_parse_args(struct wiphy * wiphy,const void * buf,int len,nan_config_cmd_data_t * cmd_data,uint32 * nan_attr_mask)4292*4882a593Smuzhiyun wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf,
4293*4882a593Smuzhiyun 	int len, nan_config_cmd_data_t *cmd_data, uint32 *nan_attr_mask)
4294*4882a593Smuzhiyun {
4295*4882a593Smuzhiyun 	int ret = BCME_OK;
4296*4882a593Smuzhiyun 	int attr_type = 0;
4297*4882a593Smuzhiyun 	int rem = len;
4298*4882a593Smuzhiyun 	const struct nlattr *iter;
4299*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4300*4882a593Smuzhiyun 	int chan;
4301*4882a593Smuzhiyun 	u8 sid_beacon = 0, sub_sid_beacon = 0;
4302*4882a593Smuzhiyun 
4303*4882a593Smuzhiyun 	NAN_DBG_ENTER();
4304*4882a593Smuzhiyun 
4305*4882a593Smuzhiyun 	nla_for_each_attr(iter, buf, len, rem) {
4306*4882a593Smuzhiyun 		attr_type = nla_type(iter);
4307*4882a593Smuzhiyun 		WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
4308*4882a593Smuzhiyun 
4309*4882a593Smuzhiyun 		switch (attr_type) {
4310*4882a593Smuzhiyun 		/* NAN Enable request attributes */
4311*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_2G_SUPPORT:{
4312*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4313*4882a593Smuzhiyun 				ret = -EINVAL;
4314*4882a593Smuzhiyun 				goto exit;
4315*4882a593Smuzhiyun 			}
4316*4882a593Smuzhiyun 			cmd_data->support_2g = nla_get_u8(iter);
4317*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_SUPPORT_2G_CONFIG;
4318*4882a593Smuzhiyun 			break;
4319*4882a593Smuzhiyun 		}
4320*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_5G_SUPPORT:{
4321*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4322*4882a593Smuzhiyun 				ret = -EINVAL;
4323*4882a593Smuzhiyun 				goto exit;
4324*4882a593Smuzhiyun 			}
4325*4882a593Smuzhiyun 			cmd_data->support_5g = nla_get_u8(iter);
4326*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_SUPPORT_5G_CONFIG;
4327*4882a593Smuzhiyun 			break;
4328*4882a593Smuzhiyun 		}
4329*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_CLUSTER_LOW: {
4330*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
4331*4882a593Smuzhiyun 				ret = -EINVAL;
4332*4882a593Smuzhiyun 				goto exit;
4333*4882a593Smuzhiyun 			}
4334*4882a593Smuzhiyun 			cmd_data->clus_id.octet[5] = nla_get_u16(iter);
4335*4882a593Smuzhiyun 			break;
4336*4882a593Smuzhiyun 		}
4337*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_CLUSTER_HIGH: {
4338*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
4339*4882a593Smuzhiyun 				ret = -EINVAL;
4340*4882a593Smuzhiyun 				goto exit;
4341*4882a593Smuzhiyun 			}
4342*4882a593Smuzhiyun 			cmd_data->clus_id.octet[4] = nla_get_u16(iter);
4343*4882a593Smuzhiyun 			break;
4344*4882a593Smuzhiyun 		}
4345*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SID_BEACON: {
4346*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4347*4882a593Smuzhiyun 				ret = -EINVAL;
4348*4882a593Smuzhiyun 				goto exit;
4349*4882a593Smuzhiyun 			}
4350*4882a593Smuzhiyun 			sid_beacon = nla_get_u8(iter);
4351*4882a593Smuzhiyun 			cmd_data->sid_beacon.sid_enable = (sid_beacon & 0x01);
4352*4882a593Smuzhiyun 			if (cmd_data->sid_beacon.sid_enable) {
4353*4882a593Smuzhiyun 				cmd_data->sid_beacon.sid_count = (sid_beacon >> 1);
4354*4882a593Smuzhiyun 				*nan_attr_mask |= NAN_ATTR_SID_BEACON_CONFIG;
4355*4882a593Smuzhiyun 			}
4356*4882a593Smuzhiyun 			break;
4357*4882a593Smuzhiyun 		}
4358*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SUB_SID_BEACON: {
4359*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4360*4882a593Smuzhiyun 				ret = -EINVAL;
4361*4882a593Smuzhiyun 				goto exit;
4362*4882a593Smuzhiyun 			}
4363*4882a593Smuzhiyun 			sub_sid_beacon = nla_get_u8(iter);
4364*4882a593Smuzhiyun 			cmd_data->sid_beacon.sub_sid_enable = (sub_sid_beacon & 0x01);
4365*4882a593Smuzhiyun 			if (cmd_data->sid_beacon.sub_sid_enable) {
4366*4882a593Smuzhiyun 				cmd_data->sid_beacon.sub_sid_count = (sub_sid_beacon >> 1);
4367*4882a593Smuzhiyun 				*nan_attr_mask |= NAN_ATTR_SUB_SID_BEACON_CONFIG;
4368*4882a593Smuzhiyun 			}
4369*4882a593Smuzhiyun 			break;
4370*4882a593Smuzhiyun 		}
4371*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON:
4372*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4373*4882a593Smuzhiyun 				ret = -EINVAL;
4374*4882a593Smuzhiyun 				goto exit;
4375*4882a593Smuzhiyun 			}
4376*4882a593Smuzhiyun 			cmd_data->beacon_2g_val = nla_get_u8(iter);
4377*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_SYNC_DISC_2G_BEACON_CONFIG;
4378*4882a593Smuzhiyun 			break;
4379*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON:
4380*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4381*4882a593Smuzhiyun 				ret = -EINVAL;
4382*4882a593Smuzhiyun 				goto exit;
4383*4882a593Smuzhiyun 			}
4384*4882a593Smuzhiyun 			cmd_data->beacon_5g_val = nla_get_u8(iter);
4385*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_SYNC_DISC_5G_BEACON_CONFIG;
4386*4882a593Smuzhiyun 			break;
4387*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SDF_2G_SUPPORT:
4388*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4389*4882a593Smuzhiyun 				ret = -EINVAL;
4390*4882a593Smuzhiyun 				goto exit;
4391*4882a593Smuzhiyun 			}
4392*4882a593Smuzhiyun 			cmd_data->sdf_2g_val = nla_get_u8(iter);
4393*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_SDF_2G_SUPPORT_CONFIG;
4394*4882a593Smuzhiyun 			break;
4395*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SDF_5G_SUPPORT:
4396*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4397*4882a593Smuzhiyun 				ret = -EINVAL;
4398*4882a593Smuzhiyun 				goto exit;
4399*4882a593Smuzhiyun 			}
4400*4882a593Smuzhiyun 			cmd_data->sdf_5g_val = nla_get_u8(iter);
4401*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_SDF_5G_SUPPORT_CONFIG;
4402*4882a593Smuzhiyun 			break;
4403*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_HOP_COUNT_LIMIT:
4404*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4405*4882a593Smuzhiyun 				ret = -EINVAL;
4406*4882a593Smuzhiyun 				goto exit;
4407*4882a593Smuzhiyun 			}
4408*4882a593Smuzhiyun 			cmd_data->hop_count_limit = nla_get_u8(iter);
4409*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_HOP_COUNT_LIMIT_CONFIG;
4410*4882a593Smuzhiyun 			break;
4411*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RANDOM_TIME:
4412*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4413*4882a593Smuzhiyun 				ret = -EINVAL;
4414*4882a593Smuzhiyun 				goto exit;
4415*4882a593Smuzhiyun 			}
4416*4882a593Smuzhiyun 			cmd_data->metrics.random_factor = nla_get_u8(iter);
4417*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_RAND_FACTOR_CONFIG;
4418*4882a593Smuzhiyun 			break;
4419*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_MASTER_PREF:
4420*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4421*4882a593Smuzhiyun 				ret = -EINVAL;
4422*4882a593Smuzhiyun 				goto exit;
4423*4882a593Smuzhiyun 			}
4424*4882a593Smuzhiyun 			cmd_data->metrics.master_pref = nla_get_u8(iter);
4425*4882a593Smuzhiyun 			break;
4426*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_OUI:
4427*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4428*4882a593Smuzhiyun 				ret = -EINVAL;
4429*4882a593Smuzhiyun 				goto exit;
4430*4882a593Smuzhiyun 			}
4431*4882a593Smuzhiyun 			cmd_data->nan_oui = nla_get_u32(iter);
4432*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_OUI_CONFIG;
4433*4882a593Smuzhiyun 			WL_TRACE(("nan_oui=%d\n", cmd_data->nan_oui));
4434*4882a593Smuzhiyun 			break;
4435*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_WARMUP_TIME:
4436*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
4437*4882a593Smuzhiyun 				ret = -EINVAL;
4438*4882a593Smuzhiyun 				goto exit;
4439*4882a593Smuzhiyun 			}
4440*4882a593Smuzhiyun 			cmd_data->warmup_time = nla_get_u16(iter);
4441*4882a593Smuzhiyun 			break;
4442*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_AMBTT:
4443*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_MASTER_RANK:
4444*4882a593Smuzhiyun 			WL_DBG(("Unhandled attribute, %d\n", attr_type));
4445*4882a593Smuzhiyun 			break;
4446*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_CHANNEL: {
4447*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4448*4882a593Smuzhiyun 				ret = -EINVAL;
4449*4882a593Smuzhiyun 				goto exit;
4450*4882a593Smuzhiyun 			}
4451*4882a593Smuzhiyun 			/* take the default channel start_factor frequency */
4452*4882a593Smuzhiyun 			chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4453*4882a593Smuzhiyun 			if (chan <= CH_MAX_2G_CHANNEL) {
4454*4882a593Smuzhiyun 				cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4455*4882a593Smuzhiyun 			} else {
4456*4882a593Smuzhiyun 				cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_80);
4457*4882a593Smuzhiyun 			}
4458*4882a593Smuzhiyun 			if (cmd_data->chanspec[0] == 0) {
4459*4882a593Smuzhiyun 				WL_ERR(("Channel is not valid \n"));
4460*4882a593Smuzhiyun 				ret = -EINVAL;
4461*4882a593Smuzhiyun 				goto exit;
4462*4882a593Smuzhiyun 			}
4463*4882a593Smuzhiyun 			WL_TRACE(("valid chanspec, chanspec = 0x%04x \n",
4464*4882a593Smuzhiyun 				cmd_data->chanspec[0]));
4465*4882a593Smuzhiyun 			break;
4466*4882a593Smuzhiyun 		}
4467*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_24G_CHANNEL: {
4468*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4469*4882a593Smuzhiyun 				ret = -EINVAL;
4470*4882a593Smuzhiyun 				goto exit;
4471*4882a593Smuzhiyun 			}
4472*4882a593Smuzhiyun 			/* take the default channel start_factor frequency */
4473*4882a593Smuzhiyun 			chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4474*4882a593Smuzhiyun 			/* 20MHz as BW */
4475*4882a593Smuzhiyun 			cmd_data->chanspec[1] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4476*4882a593Smuzhiyun 			if (cmd_data->chanspec[1] == 0) {
4477*4882a593Smuzhiyun 				WL_ERR((" 2.4GHz Channel is not valid \n"));
4478*4882a593Smuzhiyun 				ret = -EINVAL;
4479*4882a593Smuzhiyun 				break;
4480*4882a593Smuzhiyun 			}
4481*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_2G_CHAN_CONFIG;
4482*4882a593Smuzhiyun 			WL_TRACE(("valid 2.4GHz chanspec, chanspec = 0x%04x \n",
4483*4882a593Smuzhiyun 				cmd_data->chanspec[1]));
4484*4882a593Smuzhiyun 			break;
4485*4882a593Smuzhiyun 		}
4486*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_5G_CHANNEL: {
4487*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4488*4882a593Smuzhiyun 				ret = -EINVAL;
4489*4882a593Smuzhiyun 				goto exit;
4490*4882a593Smuzhiyun 			}
4491*4882a593Smuzhiyun 			/* take the default channel start_factor frequency */
4492*4882a593Smuzhiyun 			chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4493*4882a593Smuzhiyun 			/* 20MHz as BW */
4494*4882a593Smuzhiyun 			cmd_data->chanspec[2] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4495*4882a593Smuzhiyun 			if (cmd_data->chanspec[2] == 0) {
4496*4882a593Smuzhiyun 				WL_ERR((" 5GHz Channel is not valid \n"));
4497*4882a593Smuzhiyun 				ret = -EINVAL;
4498*4882a593Smuzhiyun 				break;
4499*4882a593Smuzhiyun 			}
4500*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_5G_CHAN_CONFIG;
4501*4882a593Smuzhiyun 			WL_TRACE(("valid 5GHz chanspec, chanspec = 0x%04x \n",
4502*4882a593Smuzhiyun 				cmd_data->chanspec[2]));
4503*4882a593Smuzhiyun 			break;
4504*4882a593Smuzhiyun 		}
4505*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_CONF_CLUSTER_VAL:
4506*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4507*4882a593Smuzhiyun 				ret = -EINVAL;
4508*4882a593Smuzhiyun 				goto exit;
4509*4882a593Smuzhiyun 			}
4510*4882a593Smuzhiyun 			cmd_data->config_cluster_val = nla_get_u8(iter);
4511*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_CLUSTER_VAL_CONFIG;
4512*4882a593Smuzhiyun 			break;
4513*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_DWELL_TIME:
4514*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4515*4882a593Smuzhiyun 				ret = -EINVAL;
4516*4882a593Smuzhiyun 				goto exit;
4517*4882a593Smuzhiyun 			}
4518*4882a593Smuzhiyun 			cmd_data->dwell_time[0] = nla_get_u8(iter);
4519*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_2G_DWELL_TIME_CONFIG;
4520*4882a593Smuzhiyun 			break;
4521*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SCAN_PERIOD:
4522*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
4523*4882a593Smuzhiyun 				ret = -EINVAL;
4524*4882a593Smuzhiyun 				goto exit;
4525*4882a593Smuzhiyun 			}
4526*4882a593Smuzhiyun 			cmd_data->scan_period[0] = nla_get_u16(iter);
4527*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_2G_SCAN_PERIOD_CONFIG;
4528*4882a593Smuzhiyun 			break;
4529*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_DWELL_TIME_5G:
4530*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4531*4882a593Smuzhiyun 				ret = -EINVAL;
4532*4882a593Smuzhiyun 				goto exit;
4533*4882a593Smuzhiyun 			}
4534*4882a593Smuzhiyun 			cmd_data->dwell_time[1] = nla_get_u8(iter);
4535*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_5G_DWELL_TIME_CONFIG;
4536*4882a593Smuzhiyun 			break;
4537*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SCAN_PERIOD_5G:
4538*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint16)) {
4539*4882a593Smuzhiyun 				ret = -EINVAL;
4540*4882a593Smuzhiyun 				goto exit;
4541*4882a593Smuzhiyun 			}
4542*4882a593Smuzhiyun 			cmd_data->scan_period[1] = nla_get_u16(iter);
4543*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_5G_SCAN_PERIOD_CONFIG;
4544*4882a593Smuzhiyun 			break;
4545*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_AVAIL_BIT_MAP:
4546*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4547*4882a593Smuzhiyun 				ret = -EINVAL;
4548*4882a593Smuzhiyun 				goto exit;
4549*4882a593Smuzhiyun 			}
4550*4882a593Smuzhiyun 			cmd_data->bmap = nla_get_u32(iter);
4551*4882a593Smuzhiyun 			break;
4552*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_ENTRY_CONTROL:
4553*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4554*4882a593Smuzhiyun 				ret = -EINVAL;
4555*4882a593Smuzhiyun 				goto exit;
4556*4882a593Smuzhiyun 			}
4557*4882a593Smuzhiyun 			cmd_data->avail_params.duration = nla_get_u8(iter);
4558*4882a593Smuzhiyun 			break;
4559*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSSI_CLOSE:
4560*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4561*4882a593Smuzhiyun 				ret = -EINVAL;
4562*4882a593Smuzhiyun 				goto exit;
4563*4882a593Smuzhiyun 			}
4564*4882a593Smuzhiyun 			cmd_data->rssi_attr.rssi_close_2dot4g_val = nla_get_s8(iter);
4565*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_RSSI_CLOSE_CONFIG;
4566*4882a593Smuzhiyun 			break;
4567*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSSI_MIDDLE:
4568*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4569*4882a593Smuzhiyun 				ret = -EINVAL;
4570*4882a593Smuzhiyun 				goto exit;
4571*4882a593Smuzhiyun 			}
4572*4882a593Smuzhiyun 			cmd_data->rssi_attr.rssi_middle_2dot4g_val = nla_get_s8(iter);
4573*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_RSSI_MIDDLE_2G_CONFIG;
4574*4882a593Smuzhiyun 			break;
4575*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSSI_PROXIMITY:
4576*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4577*4882a593Smuzhiyun 				ret = -EINVAL;
4578*4882a593Smuzhiyun 				goto exit;
4579*4882a593Smuzhiyun 			}
4580*4882a593Smuzhiyun 			cmd_data->rssi_attr.rssi_proximity_2dot4g_val = nla_get_s8(iter);
4581*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_RSSI_PROXIMITY_2G_CONFIG;
4582*4882a593Smuzhiyun 			break;
4583*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSSI_CLOSE_5G:
4584*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4585*4882a593Smuzhiyun 				ret = -EINVAL;
4586*4882a593Smuzhiyun 				goto exit;
4587*4882a593Smuzhiyun 			}
4588*4882a593Smuzhiyun 			cmd_data->rssi_attr.rssi_close_5g_val = nla_get_s8(iter);
4589*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_RSSI_CLOSE_5G_CONFIG;
4590*4882a593Smuzhiyun 			break;
4591*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSSI_MIDDLE_5G:
4592*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4593*4882a593Smuzhiyun 				ret = -EINVAL;
4594*4882a593Smuzhiyun 				goto exit;
4595*4882a593Smuzhiyun 			}
4596*4882a593Smuzhiyun 			cmd_data->rssi_attr.rssi_middle_5g_val = nla_get_s8(iter);
4597*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_RSSI_MIDDLE_5G_CONFIG;
4598*4882a593Smuzhiyun 			break;
4599*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSSI_PROXIMITY_5G:
4600*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4601*4882a593Smuzhiyun 				ret = -EINVAL;
4602*4882a593Smuzhiyun 				goto exit;
4603*4882a593Smuzhiyun 			}
4604*4882a593Smuzhiyun 			cmd_data->rssi_attr.rssi_proximity_5g_val = nla_get_s8(iter);
4605*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_RSSI_PROXIMITY_5G_CONFIG;
4606*4882a593Smuzhiyun 			break;
4607*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RSSI_WINDOW_SIZE:
4608*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4609*4882a593Smuzhiyun 				ret = -EINVAL;
4610*4882a593Smuzhiyun 				goto exit;
4611*4882a593Smuzhiyun 			}
4612*4882a593Smuzhiyun 			cmd_data->rssi_attr.rssi_window_size = nla_get_u8(iter);
4613*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_RSSI_WINDOW_SIZE_CONFIG;
4614*4882a593Smuzhiyun 			break;
4615*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
4616*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4617*4882a593Smuzhiyun 				ret = -EINVAL;
4618*4882a593Smuzhiyun 				goto exit;
4619*4882a593Smuzhiyun 			}
4620*4882a593Smuzhiyun 			cmd_data->csid = nla_get_u8(iter);
4621*4882a593Smuzhiyun 			WL_TRACE(("CSID = %u\n", cmd_data->csid));
4622*4882a593Smuzhiyun 			break;
4623*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SCID_LEN:
4624*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4625*4882a593Smuzhiyun 				ret = -EINVAL;
4626*4882a593Smuzhiyun 				goto exit;
4627*4882a593Smuzhiyun 			}
4628*4882a593Smuzhiyun 			if (cmd_data->scid.dlen) {
4629*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4630*4882a593Smuzhiyun 				ret = -EINVAL;
4631*4882a593Smuzhiyun 				goto exit;
4632*4882a593Smuzhiyun 			}
4633*4882a593Smuzhiyun 			cmd_data->scid.dlen = nla_get_u32(iter);
4634*4882a593Smuzhiyun 			if (cmd_data->scid.dlen > MAX_SCID_LEN) {
4635*4882a593Smuzhiyun 				ret = -EINVAL;
4636*4882a593Smuzhiyun 				WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_SCID_LEN));
4637*4882a593Smuzhiyun 				goto exit;
4638*4882a593Smuzhiyun 			}
4639*4882a593Smuzhiyun 			WL_TRACE(("valid scid length = %u\n", cmd_data->scid.dlen));
4640*4882a593Smuzhiyun 			break;
4641*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_SCID:
4642*4882a593Smuzhiyun 			if (!cmd_data->scid.dlen || (nla_len(iter) != cmd_data->scid.dlen)) {
4643*4882a593Smuzhiyun 				WL_ERR(("wrong scid len:%d,%d\n", cmd_data->scid.dlen,
4644*4882a593Smuzhiyun 					nla_len(iter)));
4645*4882a593Smuzhiyun 				ret = -EINVAL;
4646*4882a593Smuzhiyun 				goto exit;
4647*4882a593Smuzhiyun 			}
4648*4882a593Smuzhiyun 			if (cmd_data->scid.data) {
4649*4882a593Smuzhiyun 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4650*4882a593Smuzhiyun 				ret = -EINVAL;
4651*4882a593Smuzhiyun 				goto exit;
4652*4882a593Smuzhiyun 			}
4653*4882a593Smuzhiyun 
4654*4882a593Smuzhiyun 			cmd_data->scid.data = MALLOCZ(cfg->osh, cmd_data->scid.dlen);
4655*4882a593Smuzhiyun 			if (cmd_data->scid.data == NULL) {
4656*4882a593Smuzhiyun 				WL_ERR(("failed to allocate scid, len=%d\n",
4657*4882a593Smuzhiyun 					cmd_data->scid.dlen));
4658*4882a593Smuzhiyun 				ret = -ENOMEM;
4659*4882a593Smuzhiyun 				goto exit;
4660*4882a593Smuzhiyun 			}
4661*4882a593Smuzhiyun 			ret = memcpy_s(cmd_data->scid.data, cmd_data->scid.dlen,
4662*4882a593Smuzhiyun 					nla_data(iter), nla_len(iter));
4663*4882a593Smuzhiyun 			if (ret != BCME_OK) {
4664*4882a593Smuzhiyun 				WL_ERR(("Failed to scid data\n"));
4665*4882a593Smuzhiyun 				return ret;
4666*4882a593Smuzhiyun 			}
4667*4882a593Smuzhiyun 			break;
4668*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_2G_AWAKE_DW:
4669*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4670*4882a593Smuzhiyun 				ret = -EINVAL;
4671*4882a593Smuzhiyun 				goto exit;
4672*4882a593Smuzhiyun 			}
4673*4882a593Smuzhiyun 			if (nla_get_u32(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
4674*4882a593Smuzhiyun 				WL_ERR(("%s: Invalid/Out of bound value = %u\n",
4675*4882a593Smuzhiyun 						__FUNCTION__, nla_get_u32(iter)));
4676*4882a593Smuzhiyun 				ret = -EINVAL;
4677*4882a593Smuzhiyun 				goto exit;
4678*4882a593Smuzhiyun 			}
4679*4882a593Smuzhiyun 			if (nla_get_u32(iter)) {
4680*4882a593Smuzhiyun 				cmd_data->awake_dws.dw_interval_2g =
4681*4882a593Smuzhiyun 					1 << (nla_get_u32(iter)-1);
4682*4882a593Smuzhiyun 			}
4683*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_2G_DW_CONFIG;
4684*4882a593Smuzhiyun 			break;
4685*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_5G_AWAKE_DW:
4686*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4687*4882a593Smuzhiyun 				ret = -EINVAL;
4688*4882a593Smuzhiyun 				goto exit;
4689*4882a593Smuzhiyun 			}
4690*4882a593Smuzhiyun 			if (nla_get_u32(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
4691*4882a593Smuzhiyun 				WL_ERR(("%s: Invalid/Out of bound value = %u\n",
4692*4882a593Smuzhiyun 						__FUNCTION__, nla_get_u32(iter)));
4693*4882a593Smuzhiyun 				ret = BCME_BADARG;
4694*4882a593Smuzhiyun 				break;
4695*4882a593Smuzhiyun 			}
4696*4882a593Smuzhiyun 			if (nla_get_u32(iter)) {
4697*4882a593Smuzhiyun 				cmd_data->awake_dws.dw_interval_5g =
4698*4882a593Smuzhiyun 					1 << (nla_get_u32(iter)-1);
4699*4882a593Smuzhiyun 			}
4700*4882a593Smuzhiyun 			*nan_attr_mask |= NAN_ATTR_5G_DW_CONFIG;
4701*4882a593Smuzhiyun 			break;
4702*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_DISC_IND_CFG:
4703*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint8)) {
4704*4882a593Smuzhiyun 				ret = -EINVAL;
4705*4882a593Smuzhiyun 				goto exit;
4706*4882a593Smuzhiyun 			}
4707*4882a593Smuzhiyun 			cmd_data->disc_ind_cfg = nla_get_u8(iter);
4708*4882a593Smuzhiyun 			break;
4709*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_MAC_ADDR:
4710*4882a593Smuzhiyun 			if (nla_len(iter) != ETHER_ADDR_LEN) {
4711*4882a593Smuzhiyun 				ret = -EINVAL;
4712*4882a593Smuzhiyun 				goto exit;
4713*4882a593Smuzhiyun 			}
4714*4882a593Smuzhiyun 			ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
4715*4882a593Smuzhiyun 					(char*)nla_data(iter), nla_len(iter));
4716*4882a593Smuzhiyun 			if (ret != BCME_OK) {
4717*4882a593Smuzhiyun 				WL_ERR(("Failed to copy mac addr\n"));
4718*4882a593Smuzhiyun 				return ret;
4719*4882a593Smuzhiyun 			}
4720*4882a593Smuzhiyun 			break;
4721*4882a593Smuzhiyun 		case NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL:
4722*4882a593Smuzhiyun 			if (nla_len(iter) != sizeof(uint32)) {
4723*4882a593Smuzhiyun 				ret = -EINVAL;
4724*4882a593Smuzhiyun 				goto exit;
4725*4882a593Smuzhiyun 			}
4726*4882a593Smuzhiyun 			cmd_data->nmi_rand_intvl = nla_get_u8(iter);
4727*4882a593Smuzhiyun 			if (cmd_data->nmi_rand_intvl > 0) {
4728*4882a593Smuzhiyun 				cfg->nancfg.mac_rand = true;
4729*4882a593Smuzhiyun 			} else {
4730*4882a593Smuzhiyun 				cfg->nancfg.mac_rand = false;
4731*4882a593Smuzhiyun 			}
4732*4882a593Smuzhiyun 			break;
4733*4882a593Smuzhiyun 		default:
4734*4882a593Smuzhiyun 			WL_ERR(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
4735*4882a593Smuzhiyun 			ret = -EINVAL;
4736*4882a593Smuzhiyun 			goto exit;
4737*4882a593Smuzhiyun 		}
4738*4882a593Smuzhiyun 	}
4739*4882a593Smuzhiyun 
4740*4882a593Smuzhiyun exit:
4741*4882a593Smuzhiyun 	/* We need to call set_config_handler b/f calling start enable TBD */
4742*4882a593Smuzhiyun 	NAN_DBG_EXIT();
4743*4882a593Smuzhiyun 	if (ret) {
4744*4882a593Smuzhiyun 		WL_ERR(("%s: Failed to parse attribute %d ret %d",
4745*4882a593Smuzhiyun 			__FUNCTION__, attr_type, ret));
4746*4882a593Smuzhiyun 	}
4747*4882a593Smuzhiyun 	return ret;
4748*4882a593Smuzhiyun 
4749*4882a593Smuzhiyun }
4750*4882a593Smuzhiyun 
4751*4882a593Smuzhiyun static int
wl_cfgvendor_nan_dp_estb_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)4752*4882a593Smuzhiyun wl_cfgvendor_nan_dp_estb_event_data_filler(struct sk_buff *msg,
4753*4882a593Smuzhiyun 	nan_event_data_t *event_data) {
4754*4882a593Smuzhiyun 	int ret = BCME_OK;
4755*4882a593Smuzhiyun 	ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
4756*4882a593Smuzhiyun 	if (unlikely(ret)) {
4757*4882a593Smuzhiyun 		WL_ERR(("Failed to put NDP ID, ret=%d\n", ret));
4758*4882a593Smuzhiyun 		goto fail;
4759*4882a593Smuzhiyun 	}
4760*4882a593Smuzhiyun 	/*
4761*4882a593Smuzhiyun 	 * NDI mac address of the peer
4762*4882a593Smuzhiyun 	 * (required to derive target ipv6 address)
4763*4882a593Smuzhiyun 	 */
4764*4882a593Smuzhiyun 	ret = nla_put(msg, NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR, ETH_ALEN,
4765*4882a593Smuzhiyun 			event_data->responder_ndi.octet);
4766*4882a593Smuzhiyun 	if (unlikely(ret)) {
4767*4882a593Smuzhiyun 		WL_ERR(("Failed to put resp ndi, ret=%d\n", ret));
4768*4882a593Smuzhiyun 		goto fail;
4769*4882a593Smuzhiyun 	}
4770*4882a593Smuzhiyun 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_RSP_CODE, event_data->status);
4771*4882a593Smuzhiyun 	if (unlikely(ret)) {
4772*4882a593Smuzhiyun 		WL_ERR(("Failed to put response code, ret=%d\n", ret));
4773*4882a593Smuzhiyun 		goto fail;
4774*4882a593Smuzhiyun 	}
4775*4882a593Smuzhiyun 	if (event_data->svc_info.dlen && event_data->svc_info.data) {
4776*4882a593Smuzhiyun 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
4777*4882a593Smuzhiyun 				event_data->svc_info.dlen);
4778*4882a593Smuzhiyun 		if (unlikely(ret)) {
4779*4882a593Smuzhiyun 			WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
4780*4882a593Smuzhiyun 			goto fail;
4781*4882a593Smuzhiyun 		}
4782*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
4783*4882a593Smuzhiyun 				event_data->svc_info.dlen, event_data->svc_info.data);
4784*4882a593Smuzhiyun 		if (unlikely(ret)) {
4785*4882a593Smuzhiyun 			WL_ERR(("Failed to put svc info, ret=%d\n", ret));
4786*4882a593Smuzhiyun 			goto fail;
4787*4882a593Smuzhiyun 		}
4788*4882a593Smuzhiyun 	}
4789*4882a593Smuzhiyun 
4790*4882a593Smuzhiyun fail:
4791*4882a593Smuzhiyun 	return ret;
4792*4882a593Smuzhiyun }
4793*4882a593Smuzhiyun static int
wl_cfgvendor_nan_dp_ind_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)4794*4882a593Smuzhiyun wl_cfgvendor_nan_dp_ind_event_data_filler(struct sk_buff *msg,
4795*4882a593Smuzhiyun 		nan_event_data_t *event_data) {
4796*4882a593Smuzhiyun 	int ret = BCME_OK;
4797*4882a593Smuzhiyun 
4798*4882a593Smuzhiyun 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID,
4799*4882a593Smuzhiyun 			event_data->pub_id);
4800*4882a593Smuzhiyun 	if (unlikely(ret)) {
4801*4882a593Smuzhiyun 		WL_ERR(("Failed to put pub ID, ret=%d\n", ret));
4802*4882a593Smuzhiyun 		goto fail;
4803*4882a593Smuzhiyun 	}
4804*4882a593Smuzhiyun 	ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
4805*4882a593Smuzhiyun 	if (unlikely(ret)) {
4806*4882a593Smuzhiyun 		WL_ERR(("Failed to put NDP ID, ret=%d\n", ret));
4807*4882a593Smuzhiyun 		goto fail;
4808*4882a593Smuzhiyun 	}
4809*4882a593Smuzhiyun 	/* Discovery MAC addr of the peer/initiator */
4810*4882a593Smuzhiyun 	ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETH_ALEN,
4811*4882a593Smuzhiyun 			event_data->remote_nmi.octet);
4812*4882a593Smuzhiyun 	if (unlikely(ret)) {
4813*4882a593Smuzhiyun 		WL_ERR(("Failed to put remote NMI, ret=%d\n", ret));
4814*4882a593Smuzhiyun 		goto fail;
4815*4882a593Smuzhiyun 	}
4816*4882a593Smuzhiyun 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_SECURITY, event_data->security);
4817*4882a593Smuzhiyun 	if (unlikely(ret)) {
4818*4882a593Smuzhiyun 		WL_ERR(("Failed to put security, ret=%d\n", ret));
4819*4882a593Smuzhiyun 		goto fail;
4820*4882a593Smuzhiyun 	}
4821*4882a593Smuzhiyun 	if (event_data->svc_info.dlen && event_data->svc_info.data) {
4822*4882a593Smuzhiyun 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
4823*4882a593Smuzhiyun 				event_data->svc_info.dlen);
4824*4882a593Smuzhiyun 		if (unlikely(ret)) {
4825*4882a593Smuzhiyun 			WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
4826*4882a593Smuzhiyun 			goto fail;
4827*4882a593Smuzhiyun 		}
4828*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
4829*4882a593Smuzhiyun 				event_data->svc_info.dlen, event_data->svc_info.data);
4830*4882a593Smuzhiyun 		if (unlikely(ret)) {
4831*4882a593Smuzhiyun 			WL_ERR(("Failed to put svc info, ret=%d\n", ret));
4832*4882a593Smuzhiyun 			goto fail;
4833*4882a593Smuzhiyun 		}
4834*4882a593Smuzhiyun 	}
4835*4882a593Smuzhiyun 
4836*4882a593Smuzhiyun fail:
4837*4882a593Smuzhiyun 	return ret;
4838*4882a593Smuzhiyun }
4839*4882a593Smuzhiyun 
4840*4882a593Smuzhiyun static int
wl_cfgvendor_nan_tx_followup_ind_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)4841*4882a593Smuzhiyun wl_cfgvendor_nan_tx_followup_ind_event_data_filler(struct sk_buff *msg,
4842*4882a593Smuzhiyun 	nan_event_data_t *event_data) {
4843*4882a593Smuzhiyun 	int ret = BCME_OK;
4844*4882a593Smuzhiyun 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_TRANSAC_ID, event_data->token);
4845*4882a593Smuzhiyun 	if (unlikely(ret)) {
4846*4882a593Smuzhiyun 		WL_ERR(("Failed to put transaction id, ret=%d\n", ret));
4847*4882a593Smuzhiyun 		goto fail;
4848*4882a593Smuzhiyun 	}
4849*4882a593Smuzhiyun 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->local_inst_id);
4850*4882a593Smuzhiyun 	if (unlikely(ret)) {
4851*4882a593Smuzhiyun 		WL_ERR(("Failed to put handle, ret=%d\n", ret));
4852*4882a593Smuzhiyun 		goto fail;
4853*4882a593Smuzhiyun 	}
4854*4882a593Smuzhiyun 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
4855*4882a593Smuzhiyun 	if (unlikely(ret)) {
4856*4882a593Smuzhiyun 		WL_ERR(("Failed to put nan status, ret=%d\n", ret));
4857*4882a593Smuzhiyun 		goto fail;
4858*4882a593Smuzhiyun 	}
4859*4882a593Smuzhiyun 	if (event_data->status == NAN_STATUS_SUCCESS) {
4860*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
4861*4882a593Smuzhiyun 				strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
4862*4882a593Smuzhiyun 		if (unlikely(ret)) {
4863*4882a593Smuzhiyun 			WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
4864*4882a593Smuzhiyun 			goto fail;
4865*4882a593Smuzhiyun 		}
4866*4882a593Smuzhiyun 	} else {
4867*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
4868*4882a593Smuzhiyun 				strlen("NAN_STATUS_NO_OTA_ACK"), event_data->nan_reason);
4869*4882a593Smuzhiyun 		if (unlikely(ret)) {
4870*4882a593Smuzhiyun 			WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
4871*4882a593Smuzhiyun 			goto fail;
4872*4882a593Smuzhiyun 		}
4873*4882a593Smuzhiyun 	}
4874*4882a593Smuzhiyun fail:
4875*4882a593Smuzhiyun 	return ret;
4876*4882a593Smuzhiyun }
4877*4882a593Smuzhiyun 
4878*4882a593Smuzhiyun static int
wl_cfgvendor_nan_svc_terminate_event_filler(struct sk_buff * msg,struct bcm_cfg80211 * cfg,int event_id,nan_event_data_t * event_data)4879*4882a593Smuzhiyun wl_cfgvendor_nan_svc_terminate_event_filler(struct sk_buff *msg,
4880*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg, int event_id, nan_event_data_t *event_data) {
4881*4882a593Smuzhiyun 	int ret = BCME_OK;
4882*4882a593Smuzhiyun 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->local_inst_id);
4883*4882a593Smuzhiyun 	if (unlikely(ret)) {
4884*4882a593Smuzhiyun 		WL_ERR(("Failed to put handle, ret=%d\n", ret));
4885*4882a593Smuzhiyun 		goto fail;
4886*4882a593Smuzhiyun 	}
4887*4882a593Smuzhiyun 
4888*4882a593Smuzhiyun 	if (event_id == GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED) {
4889*4882a593Smuzhiyun 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SUBSCRIBE_ID,
4890*4882a593Smuzhiyun 				event_data->local_inst_id);
4891*4882a593Smuzhiyun 		if (unlikely(ret)) {
4892*4882a593Smuzhiyun 			WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
4893*4882a593Smuzhiyun 			goto fail;
4894*4882a593Smuzhiyun 		}
4895*4882a593Smuzhiyun 	} else {
4896*4882a593Smuzhiyun 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID,
4897*4882a593Smuzhiyun 				event_data->local_inst_id);
4898*4882a593Smuzhiyun 		if (unlikely(ret)) {
4899*4882a593Smuzhiyun 			WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
4900*4882a593Smuzhiyun 			goto fail;
4901*4882a593Smuzhiyun 		}
4902*4882a593Smuzhiyun 	}
4903*4882a593Smuzhiyun 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
4904*4882a593Smuzhiyun 	if (unlikely(ret)) {
4905*4882a593Smuzhiyun 		WL_ERR(("Failed to put status, ret=%d\n", ret));
4906*4882a593Smuzhiyun 		goto fail;
4907*4882a593Smuzhiyun 	}
4908*4882a593Smuzhiyun 	if (event_data->status == NAN_STATUS_SUCCESS) {
4909*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
4910*4882a593Smuzhiyun 				strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
4911*4882a593Smuzhiyun 		if (unlikely(ret)) {
4912*4882a593Smuzhiyun 			WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
4913*4882a593Smuzhiyun 			goto fail;
4914*4882a593Smuzhiyun 		}
4915*4882a593Smuzhiyun 	} else {
4916*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
4917*4882a593Smuzhiyun 				strlen("NAN_STATUS_INTERNAL_FAILURE"), event_data->nan_reason);
4918*4882a593Smuzhiyun 		if (unlikely(ret)) {
4919*4882a593Smuzhiyun 			WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
4920*4882a593Smuzhiyun 			goto fail;
4921*4882a593Smuzhiyun 		}
4922*4882a593Smuzhiyun 	}
4923*4882a593Smuzhiyun 
4924*4882a593Smuzhiyun 	ret = wl_cfgnan_remove_inst_id(cfg, event_data->local_inst_id);
4925*4882a593Smuzhiyun 	if (ret) {
4926*4882a593Smuzhiyun 		WL_ERR(("failed to free svc instance-id[%d], ret=%d, event_id = %d\n",
4927*4882a593Smuzhiyun 				event_data->local_inst_id, ret, event_id));
4928*4882a593Smuzhiyun 		goto fail;
4929*4882a593Smuzhiyun 	}
4930*4882a593Smuzhiyun fail:
4931*4882a593Smuzhiyun 	return ret;
4932*4882a593Smuzhiyun }
4933*4882a593Smuzhiyun 
4934*4882a593Smuzhiyun static int
wl_cfgvendor_nan_opt_params_filler(struct sk_buff * msg,nan_event_data_t * event_data)4935*4882a593Smuzhiyun wl_cfgvendor_nan_opt_params_filler(struct sk_buff *msg,
4936*4882a593Smuzhiyun 	nan_event_data_t *event_data) {
4937*4882a593Smuzhiyun 	int ret = BCME_OK;
4938*4882a593Smuzhiyun 	/* service specific info data */
4939*4882a593Smuzhiyun 	if (event_data->svc_info.dlen && event_data->svc_info.data) {
4940*4882a593Smuzhiyun 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
4941*4882a593Smuzhiyun 				event_data->svc_info.dlen);
4942*4882a593Smuzhiyun 		if (unlikely(ret)) {
4943*4882a593Smuzhiyun 			WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
4944*4882a593Smuzhiyun 			goto fail;
4945*4882a593Smuzhiyun 		}
4946*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
4947*4882a593Smuzhiyun 				event_data->svc_info.dlen, event_data->svc_info.data);
4948*4882a593Smuzhiyun 		if (unlikely(ret)) {
4949*4882a593Smuzhiyun 			WL_ERR(("Failed to put svc info, ret=%d\n", ret));
4950*4882a593Smuzhiyun 			goto fail;
4951*4882a593Smuzhiyun 		}
4952*4882a593Smuzhiyun 		WL_TRACE(("svc info len = %d\n", event_data->svc_info.dlen));
4953*4882a593Smuzhiyun 	}
4954*4882a593Smuzhiyun 
4955*4882a593Smuzhiyun 	/* sdea service specific info data */
4956*4882a593Smuzhiyun 	if (event_data->sde_svc_info.dlen && event_data->sde_svc_info.data) {
4957*4882a593Smuzhiyun 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
4958*4882a593Smuzhiyun 				event_data->sde_svc_info.dlen);
4959*4882a593Smuzhiyun 		if (unlikely(ret)) {
4960*4882a593Smuzhiyun 			WL_ERR(("Failed to put sdea svc info len, ret=%d\n", ret));
4961*4882a593Smuzhiyun 			goto fail;
4962*4882a593Smuzhiyun 		}
4963*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
4964*4882a593Smuzhiyun 				event_data->sde_svc_info.dlen,
4965*4882a593Smuzhiyun 				event_data->sde_svc_info.data);
4966*4882a593Smuzhiyun 		if (unlikely(ret)) {
4967*4882a593Smuzhiyun 			WL_ERR(("Failed to put sdea svc info, ret=%d\n", ret));
4968*4882a593Smuzhiyun 			goto fail;
4969*4882a593Smuzhiyun 		}
4970*4882a593Smuzhiyun 		WL_TRACE(("sdea svc info len = %d\n", event_data->sde_svc_info.dlen));
4971*4882a593Smuzhiyun 	}
4972*4882a593Smuzhiyun 	/* service control discovery range limit */
4973*4882a593Smuzhiyun 	/* TODO: */
4974*4882a593Smuzhiyun 
4975*4882a593Smuzhiyun 	/* service control binding bitmap */
4976*4882a593Smuzhiyun 	/* TODO: */
4977*4882a593Smuzhiyun fail:
4978*4882a593Smuzhiyun 	return ret;
4979*4882a593Smuzhiyun }
4980*4882a593Smuzhiyun 
4981*4882a593Smuzhiyun static int
wl_cfgvendor_nan_tx_followup_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)4982*4882a593Smuzhiyun wl_cfgvendor_nan_tx_followup_event_filler(struct sk_buff *msg,
4983*4882a593Smuzhiyun 		nan_event_data_t *event_data) {
4984*4882a593Smuzhiyun 	int ret = BCME_OK;
4985*4882a593Smuzhiyun 	/* In followup pkt, instance id and requestor instance id are configured
4986*4882a593Smuzhiyun 	 * from the transmitter perspective. As the event is processed with the
4987*4882a593Smuzhiyun 	 * role of receiver, the local handle should use requestor instance
4988*4882a593Smuzhiyun 	 * id (peer_inst_id)
4989*4882a593Smuzhiyun 	 */
4990*4882a593Smuzhiyun 	WL_TRACE(("handle=%d\n", event_data->requestor_id));
4991*4882a593Smuzhiyun 	WL_TRACE(("inst id (local id)=%d\n", event_data->local_inst_id));
4992*4882a593Smuzhiyun 	WL_TRACE(("peer id (remote id)=%d\n", event_data->requestor_id));
4993*4882a593Smuzhiyun 	WL_TRACE(("peer mac addr=" MACDBG "\n",
4994*4882a593Smuzhiyun 			MAC2STRDBG(event_data->remote_nmi.octet)));
4995*4882a593Smuzhiyun 	WL_TRACE(("peer rssi: %d\n", event_data->fup_rssi));
4996*4882a593Smuzhiyun 	WL_TRACE(("attribute no: %d\n", event_data->attr_num));
4997*4882a593Smuzhiyun 	WL_TRACE(("attribute len: %d\n", event_data->attr_list_len));
4998*4882a593Smuzhiyun 
4999*4882a593Smuzhiyun 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->requestor_id);
5000*4882a593Smuzhiyun 	if (unlikely(ret)) {
5001*4882a593Smuzhiyun 		WL_ERR(("Failed to put handle, ret=%d\n", ret));
5002*4882a593Smuzhiyun 		goto fail;
5003*4882a593Smuzhiyun 	}
5004*4882a593Smuzhiyun 	ret = nla_put_u32(msg, NAN_ATTRIBUTE_INST_ID, event_data->local_inst_id);
5005*4882a593Smuzhiyun 	if (unlikely(ret)) {
5006*4882a593Smuzhiyun 		WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
5007*4882a593Smuzhiyun 		goto fail;
5008*4882a593Smuzhiyun 	}
5009*4882a593Smuzhiyun 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_PEER_ID, event_data->requestor_id);
5010*4882a593Smuzhiyun 	if (unlikely(ret)) {
5011*4882a593Smuzhiyun 		WL_ERR(("Failed to put requestor inst id, ret=%d\n", ret));
5012*4882a593Smuzhiyun 		goto fail;
5013*4882a593Smuzhiyun 	}
5014*4882a593Smuzhiyun 	ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETHER_ADDR_LEN,
5015*4882a593Smuzhiyun 			event_data->remote_nmi.octet);
5016*4882a593Smuzhiyun 	if (unlikely(ret)) {
5017*4882a593Smuzhiyun 		WL_ERR(("Failed to put remote nmi, ret=%d\n", ret));
5018*4882a593Smuzhiyun 		goto fail;
5019*4882a593Smuzhiyun 	}
5020*4882a593Smuzhiyun 	ret = nla_put_s8(msg, NAN_ATTRIBUTE_RSSI_PROXIMITY,
5021*4882a593Smuzhiyun 			event_data->fup_rssi);
5022*4882a593Smuzhiyun 	if (unlikely(ret)) {
5023*4882a593Smuzhiyun 		WL_ERR(("Failed to put fup rssi, ret=%d\n", ret));
5024*4882a593Smuzhiyun 		goto fail;
5025*4882a593Smuzhiyun 	}
5026*4882a593Smuzhiyun fail:
5027*4882a593Smuzhiyun 	return ret;
5028*4882a593Smuzhiyun }
5029*4882a593Smuzhiyun 
5030*4882a593Smuzhiyun static int
wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)5031*4882a593Smuzhiyun wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff *msg,
5032*4882a593Smuzhiyun 	nan_event_data_t *event_data) {
5033*4882a593Smuzhiyun 	int ret = BCME_OK;
5034*4882a593Smuzhiyun 	WL_TRACE(("handle (sub_id)=%d\n", event_data->sub_id));
5035*4882a593Smuzhiyun 	WL_TRACE(("pub id=%d\n", event_data->pub_id));
5036*4882a593Smuzhiyun 	WL_TRACE(("sub id=%d\n", event_data->sub_id));
5037*4882a593Smuzhiyun 	WL_TRACE(("pub mac addr=" MACDBG "\n",
5038*4882a593Smuzhiyun 			MAC2STRDBG(event_data->remote_nmi.octet)));
5039*4882a593Smuzhiyun 	WL_TRACE(("attr no: %d\n", event_data->attr_num));
5040*4882a593Smuzhiyun 	WL_TRACE(("attr len: %d\n", event_data->attr_list_len));
5041*4882a593Smuzhiyun 
5042*4882a593Smuzhiyun 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->sub_id);
5043*4882a593Smuzhiyun 	if (unlikely(ret)) {
5044*4882a593Smuzhiyun 		WL_ERR(("Failed to put handle, ret=%d\n", ret));
5045*4882a593Smuzhiyun 		goto fail;
5046*4882a593Smuzhiyun 	}
5047*4882a593Smuzhiyun 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID, event_data->pub_id);
5048*4882a593Smuzhiyun 	if (unlikely(ret)) {
5049*4882a593Smuzhiyun 		WL_ERR(("Failed to put pub id, ret=%d\n", ret));
5050*4882a593Smuzhiyun 		goto fail;
5051*4882a593Smuzhiyun 	}
5052*4882a593Smuzhiyun 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_SUBSCRIBE_ID, event_data->sub_id);
5053*4882a593Smuzhiyun 	if (unlikely(ret)) {
5054*4882a593Smuzhiyun 		WL_ERR(("Failed to put Sub Id, ret=%d\n", ret));
5055*4882a593Smuzhiyun 		goto fail;
5056*4882a593Smuzhiyun 	}
5057*4882a593Smuzhiyun 	ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETHER_ADDR_LEN,
5058*4882a593Smuzhiyun 			event_data->remote_nmi.octet);
5059*4882a593Smuzhiyun 	if (unlikely(ret)) {
5060*4882a593Smuzhiyun 		WL_ERR(("Failed to put remote NMI, ret=%d\n", ret));
5061*4882a593Smuzhiyun 		goto fail;
5062*4882a593Smuzhiyun 	}
5063*4882a593Smuzhiyun 	if (event_data->publish_rssi) {
5064*4882a593Smuzhiyun 		event_data->publish_rssi = -event_data->publish_rssi;
5065*4882a593Smuzhiyun 		ret = nla_put_u8(msg, NAN_ATTRIBUTE_RSSI_PROXIMITY,
5066*4882a593Smuzhiyun 				event_data->publish_rssi);
5067*4882a593Smuzhiyun 		if (unlikely(ret)) {
5068*4882a593Smuzhiyun 			WL_ERR(("Failed to put publish rssi, ret=%d\n", ret));
5069*4882a593Smuzhiyun 			goto fail;
5070*4882a593Smuzhiyun 		}
5071*4882a593Smuzhiyun 	}
5072*4882a593Smuzhiyun 	if (event_data->ranging_result_present) {
5073*4882a593Smuzhiyun 		ret = nla_put_u32(msg, NAN_ATTRIBUTE_RANGING_INDICATION,
5074*4882a593Smuzhiyun 				event_data->ranging_ind);
5075*4882a593Smuzhiyun 		if (unlikely(ret)) {
5076*4882a593Smuzhiyun 			WL_ERR(("Failed to put ranging ind, ret=%d\n", ret));
5077*4882a593Smuzhiyun 			goto fail;
5078*4882a593Smuzhiyun 		}
5079*4882a593Smuzhiyun 		ret = nla_put_u32(msg, NAN_ATTRIBUTE_RANGING_RESULT,
5080*4882a593Smuzhiyun 				event_data->range_measurement_cm);
5081*4882a593Smuzhiyun 		if (unlikely(ret)) {
5082*4882a593Smuzhiyun 			WL_ERR(("Failed to put range measurement cm, ret=%d\n",
5083*4882a593Smuzhiyun 					ret));
5084*4882a593Smuzhiyun 			goto fail;
5085*4882a593Smuzhiyun 		}
5086*4882a593Smuzhiyun 	}
5087*4882a593Smuzhiyun 	/*
5088*4882a593Smuzhiyun 	 * handling optional service control, service response filter
5089*4882a593Smuzhiyun 	 */
5090*4882a593Smuzhiyun 	if (event_data->tx_match_filter.dlen && event_data->tx_match_filter.data) {
5091*4882a593Smuzhiyun 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN,
5092*4882a593Smuzhiyun 				event_data->tx_match_filter.dlen);
5093*4882a593Smuzhiyun 		if (unlikely(ret)) {
5094*4882a593Smuzhiyun 			WL_ERR(("Failed to put tx match filter len, ret=%d\n",
5095*4882a593Smuzhiyun 					ret));
5096*4882a593Smuzhiyun 			goto fail;
5097*4882a593Smuzhiyun 		}
5098*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_TX_MATCH_FILTER,
5099*4882a593Smuzhiyun 				event_data->tx_match_filter.dlen,
5100*4882a593Smuzhiyun 				event_data->tx_match_filter.data);
5101*4882a593Smuzhiyun 		if (unlikely(ret)) {
5102*4882a593Smuzhiyun 			WL_ERR(("Failed to put tx match filter data, ret=%d\n",
5103*4882a593Smuzhiyun 					ret));
5104*4882a593Smuzhiyun 			goto fail;
5105*4882a593Smuzhiyun 		}
5106*4882a593Smuzhiyun 		WL_TRACE(("tx matching filter (%d):\n",
5107*4882a593Smuzhiyun 				event_data->tx_match_filter.dlen));
5108*4882a593Smuzhiyun 	}
5109*4882a593Smuzhiyun 
5110*4882a593Smuzhiyun fail:
5111*4882a593Smuzhiyun 	return ret;
5112*4882a593Smuzhiyun }
5113*4882a593Smuzhiyun 
5114*4882a593Smuzhiyun static int
wl_cfgvendor_nan_de_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)5115*4882a593Smuzhiyun wl_cfgvendor_nan_de_event_filler(struct sk_buff *msg, nan_event_data_t *event_data)
5116*4882a593Smuzhiyun {
5117*4882a593Smuzhiyun 	int ret = BCME_OK;
5118*4882a593Smuzhiyun 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_ENABLE_STATUS, event_data->enabled);
5119*4882a593Smuzhiyun 	if (unlikely(ret)) {
5120*4882a593Smuzhiyun 		WL_ERR(("Failed to put event_data->enabled, ret=%d\n", ret));
5121*4882a593Smuzhiyun 		goto fail;
5122*4882a593Smuzhiyun 	}
5123*4882a593Smuzhiyun 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_DE_EVENT_TYPE,
5124*4882a593Smuzhiyun 			event_data->nan_de_evt_type);
5125*4882a593Smuzhiyun 	if (unlikely(ret)) {
5126*4882a593Smuzhiyun 		WL_ERR(("Failed to put nan_de_evt_type, ret=%d\n", ret));
5127*4882a593Smuzhiyun 		goto fail;
5128*4882a593Smuzhiyun 	}
5129*4882a593Smuzhiyun 	ret = nla_put(msg, NAN_ATTRIBUTE_CLUSTER_ID, ETH_ALEN,
5130*4882a593Smuzhiyun 			event_data->clus_id.octet);
5131*4882a593Smuzhiyun 	if (unlikely(ret)) {
5132*4882a593Smuzhiyun 		WL_ERR(("Failed to put clust id, ret=%d\n", ret));
5133*4882a593Smuzhiyun 		goto fail;
5134*4882a593Smuzhiyun 	}
5135*4882a593Smuzhiyun 	/* OOB tests requires local nmi */
5136*4882a593Smuzhiyun 	ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETH_ALEN,
5137*4882a593Smuzhiyun 			event_data->local_nmi.octet);
5138*4882a593Smuzhiyun 	if (unlikely(ret)) {
5139*4882a593Smuzhiyun 		WL_ERR(("Failed to put NMI, ret=%d\n", ret));
5140*4882a593Smuzhiyun 		goto fail;
5141*4882a593Smuzhiyun 	}
5142*4882a593Smuzhiyun fail:
5143*4882a593Smuzhiyun 	return ret;
5144*4882a593Smuzhiyun }
5145*4882a593Smuzhiyun 
5146*4882a593Smuzhiyun #ifdef RTT_SUPPORT
5147*4882a593Smuzhiyun s32
wl_cfgvendor_send_as_rtt_legacy_event(struct wiphy * wiphy,struct net_device * dev,wl_nan_ev_rng_rpt_ind_t * range_res,uint32 status)5148*4882a593Smuzhiyun wl_cfgvendor_send_as_rtt_legacy_event(struct wiphy *wiphy, struct net_device *dev,
5149*4882a593Smuzhiyun 	wl_nan_ev_rng_rpt_ind_t *range_res, uint32 status)
5150*4882a593Smuzhiyun {
5151*4882a593Smuzhiyun 	s32 ret = BCME_OK;
5152*4882a593Smuzhiyun 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5153*4882a593Smuzhiyun 	rtt_report_t *report = NULL;
5154*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5155*4882a593Smuzhiyun 	struct sk_buff *msg = NULL;
5156*4882a593Smuzhiyun 	struct nlattr *rtt_nl_hdr;
5157*4882a593Smuzhiyun 
5158*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5159*4882a593Smuzhiyun 
5160*4882a593Smuzhiyun 	report = MALLOCZ(cfg->osh, sizeof(*report));
5161*4882a593Smuzhiyun 	if (!report) {
5162*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5163*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5164*4882a593Smuzhiyun 		goto exit;
5165*4882a593Smuzhiyun 	}
5166*4882a593Smuzhiyun 	if (range_res) {
5167*4882a593Smuzhiyun 		report->distance = range_res->dist_mm/10;
5168*4882a593Smuzhiyun 		ret = memcpy_s(&report->addr, ETHER_ADDR_LEN,
5169*4882a593Smuzhiyun 				&range_res->peer_m_addr, ETHER_ADDR_LEN);
5170*4882a593Smuzhiyun 		if (ret != BCME_OK) {
5171*4882a593Smuzhiyun 			WL_ERR(("Failed to copy peer_m_addr\n"));
5172*4882a593Smuzhiyun 			goto exit;
5173*4882a593Smuzhiyun 		}
5174*4882a593Smuzhiyun 	}
5175*4882a593Smuzhiyun 	report->status = (rtt_reason_t)status;
5176*4882a593Smuzhiyun 	report->type   = RTT_TWO_WAY;
5177*4882a593Smuzhiyun 
5178*4882a593Smuzhiyun #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
5179*4882a593Smuzhiyun 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
5180*4882a593Smuzhiyun 	msg = cfg80211_vendor_event_alloc(wiphy, NULL, 100,
5181*4882a593Smuzhiyun 			GOOGLE_RTT_COMPLETE_EVENT, kflags);
5182*4882a593Smuzhiyun #else
5183*4882a593Smuzhiyun 	msg = cfg80211_vendor_event_alloc(wiphy, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags);
5184*4882a593Smuzhiyun #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
5185*4882a593Smuzhiyun 	/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
5186*4882a593Smuzhiyun 	if (!msg) {
5187*4882a593Smuzhiyun 		WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
5188*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5189*4882a593Smuzhiyun 		goto exit;
5190*4882a593Smuzhiyun 	}
5191*4882a593Smuzhiyun 
5192*4882a593Smuzhiyun 	ret = nla_put_u32(msg, RTT_ATTRIBUTE_RESULTS_COMPLETE, 1);
5193*4882a593Smuzhiyun 	if (ret < 0) {
5194*4882a593Smuzhiyun 		WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
5195*4882a593Smuzhiyun 		goto exit;
5196*4882a593Smuzhiyun 	}
5197*4882a593Smuzhiyun 	rtt_nl_hdr = nla_nest_start(msg, RTT_ATTRIBUTE_RESULTS_PER_TARGET);
5198*4882a593Smuzhiyun 	if (!rtt_nl_hdr) {
5199*4882a593Smuzhiyun 		WL_ERR(("rtt_nl_hdr is NULL\n"));
5200*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5201*4882a593Smuzhiyun 		goto exit;
5202*4882a593Smuzhiyun 	}
5203*4882a593Smuzhiyun 	ret = nla_put(msg, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &report->addr);
5204*4882a593Smuzhiyun 	if (ret < 0) {
5205*4882a593Smuzhiyun 		WL_ERR(("Failed to put RTT_ATTRIBUTE_TARGET_MAC\n"));
5206*4882a593Smuzhiyun 		goto exit;
5207*4882a593Smuzhiyun 	}
5208*4882a593Smuzhiyun 	ret = nla_put_u32(msg, RTT_ATTRIBUTE_RESULT_CNT, 1);
5209*4882a593Smuzhiyun 	if (ret < 0) {
5210*4882a593Smuzhiyun 		WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_CNT\n"));
5211*4882a593Smuzhiyun 		goto exit;
5212*4882a593Smuzhiyun 	}
5213*4882a593Smuzhiyun 	ret = nla_put(msg, RTT_ATTRIBUTE_RESULT,
5214*4882a593Smuzhiyun 			sizeof(*report), report);
5215*4882a593Smuzhiyun 	if (ret < 0) {
5216*4882a593Smuzhiyun 		WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS\n"));
5217*4882a593Smuzhiyun 		goto exit;
5218*4882a593Smuzhiyun 	}
5219*4882a593Smuzhiyun 	nla_nest_end(msg, rtt_nl_hdr);
5220*4882a593Smuzhiyun 	cfg80211_vendor_event(msg, kflags);
5221*4882a593Smuzhiyun 	if (report) {
5222*4882a593Smuzhiyun 		MFREE(cfg->osh, report, sizeof(*report));
5223*4882a593Smuzhiyun 	}
5224*4882a593Smuzhiyun 
5225*4882a593Smuzhiyun 	return ret;
5226*4882a593Smuzhiyun exit:
5227*4882a593Smuzhiyun 	if (msg)
5228*4882a593Smuzhiyun 		dev_kfree_skb_any(msg);
5229*4882a593Smuzhiyun 	WL_ERR(("Failed to send event GOOGLE_RTT_COMPLETE_EVENT,"
5230*4882a593Smuzhiyun 				" -- Free skb, ret = %d\n", ret));
5231*4882a593Smuzhiyun 	if (report)
5232*4882a593Smuzhiyun 		MFREE(cfg->osh, report, sizeof(*report));
5233*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5234*4882a593Smuzhiyun 	return ret;
5235*4882a593Smuzhiyun }
5236*4882a593Smuzhiyun #endif /* RTT_SUPPORT */
5237*4882a593Smuzhiyun 
5238*4882a593Smuzhiyun int
wl_cfgvendor_send_nan_event(struct wiphy * wiphy,struct net_device * dev,int event_id,nan_event_data_t * event_data)5239*4882a593Smuzhiyun wl_cfgvendor_send_nan_event(struct wiphy *wiphy, struct net_device *dev,
5240*4882a593Smuzhiyun 	int event_id, nan_event_data_t *event_data)
5241*4882a593Smuzhiyun {
5242*4882a593Smuzhiyun 	int ret = BCME_OK;
5243*4882a593Smuzhiyun 	int buf_len = NAN_EVENT_BUFFER_SIZE_LARGE;
5244*4882a593Smuzhiyun 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5245*4882a593Smuzhiyun 
5246*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5247*4882a593Smuzhiyun 	struct sk_buff *msg;
5248*4882a593Smuzhiyun 
5249*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5250*4882a593Smuzhiyun 
5251*4882a593Smuzhiyun 	/* Allocate the skb for vendor event */
5252*4882a593Smuzhiyun #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
5253*4882a593Smuzhiyun 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
5254*4882a593Smuzhiyun 	msg = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev), buf_len, event_id, kflags);
5255*4882a593Smuzhiyun #else
5256*4882a593Smuzhiyun 	msg = cfg80211_vendor_event_alloc(wiphy, buf_len, event_id, kflags);
5257*4882a593Smuzhiyun #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
5258*4882a593Smuzhiyun 	/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
5259*4882a593Smuzhiyun 
5260*4882a593Smuzhiyun 	if (!msg) {
5261*4882a593Smuzhiyun 		WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
5262*4882a593Smuzhiyun 		return -ENOMEM;
5263*4882a593Smuzhiyun 	}
5264*4882a593Smuzhiyun 
5265*4882a593Smuzhiyun 	switch (event_id) {
5266*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_DE_EVENT: {
5267*4882a593Smuzhiyun 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_DE_EVENT cluster id=" MACDBG "nmi= " MACDBG "\n",
5268*4882a593Smuzhiyun 			MAC2STRDBG(event_data->clus_id.octet),
5269*4882a593Smuzhiyun 			MAC2STRDBG(event_data->local_nmi.octet)));
5270*4882a593Smuzhiyun 		ret = wl_cfgvendor_nan_de_event_filler(msg, event_data);
5271*4882a593Smuzhiyun 		if (unlikely(ret)) {
5272*4882a593Smuzhiyun 			WL_ERR(("Failed to fill de event data, ret=%d\n", ret));
5273*4882a593Smuzhiyun 			goto fail;
5274*4882a593Smuzhiyun 		}
5275*4882a593Smuzhiyun 		break;
5276*4882a593Smuzhiyun 	}
5277*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH:
5278*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_FOLLOWUP: {
5279*4882a593Smuzhiyun 		if (event_id == GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH) {
5280*4882a593Smuzhiyun 			WL_DBG(("GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH\n"));
5281*4882a593Smuzhiyun 			ret = wl_cfgvendor_nan_sub_match_event_filler(msg, event_data);
5282*4882a593Smuzhiyun 			if (unlikely(ret)) {
5283*4882a593Smuzhiyun 				WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5284*4882a593Smuzhiyun 				goto fail;
5285*4882a593Smuzhiyun 			}
5286*4882a593Smuzhiyun 		} else if (event_id == GOOGLE_NAN_EVENT_FOLLOWUP) {
5287*4882a593Smuzhiyun 			WL_DBG(("GOOGLE_NAN_EVENT_FOLLOWUP\n"));
5288*4882a593Smuzhiyun 			ret = wl_cfgvendor_nan_tx_followup_event_filler(msg, event_data);
5289*4882a593Smuzhiyun 			if (unlikely(ret)) {
5290*4882a593Smuzhiyun 				WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5291*4882a593Smuzhiyun 				goto fail;
5292*4882a593Smuzhiyun 			}
5293*4882a593Smuzhiyun 		}
5294*4882a593Smuzhiyun 		ret = wl_cfgvendor_nan_opt_params_filler(msg, event_data);
5295*4882a593Smuzhiyun 		if (unlikely(ret)) {
5296*4882a593Smuzhiyun 			WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5297*4882a593Smuzhiyun 			goto fail;
5298*4882a593Smuzhiyun 		}
5299*4882a593Smuzhiyun 		break;
5300*4882a593Smuzhiyun 	}
5301*4882a593Smuzhiyun 
5302*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_DISABLED: {
5303*4882a593Smuzhiyun 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DISABLED\n"));
5304*4882a593Smuzhiyun 		ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, 0);
5305*4882a593Smuzhiyun 		if (unlikely(ret)) {
5306*4882a593Smuzhiyun 			WL_ERR(("Failed to put handle, ret=%d\n", ret));
5307*4882a593Smuzhiyun 			goto fail;
5308*4882a593Smuzhiyun 		}
5309*4882a593Smuzhiyun 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
5310*4882a593Smuzhiyun 		if (unlikely(ret)) {
5311*4882a593Smuzhiyun 			WL_ERR(("Failed to put status, ret=%d\n", ret));
5312*4882a593Smuzhiyun 			goto fail;
5313*4882a593Smuzhiyun 		}
5314*4882a593Smuzhiyun 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5315*4882a593Smuzhiyun 			strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
5316*4882a593Smuzhiyun 		if (unlikely(ret)) {
5317*4882a593Smuzhiyun 			WL_ERR(("Failed to put reason code, ret=%d\n", ret));
5318*4882a593Smuzhiyun 			goto fail;
5319*4882a593Smuzhiyun 		}
5320*4882a593Smuzhiyun 		break;
5321*4882a593Smuzhiyun 	}
5322*4882a593Smuzhiyun 
5323*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED:
5324*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_PUBLISH_TERMINATED: {
5325*4882a593Smuzhiyun 		WL_DBG(("GOOGLE_NAN_SVC_TERMINATED, %d\n", event_id));
5326*4882a593Smuzhiyun 		ret = wl_cfgvendor_nan_svc_terminate_event_filler(msg, cfg, event_id, event_data);
5327*4882a593Smuzhiyun 		if (unlikely(ret)) {
5328*4882a593Smuzhiyun 			WL_ERR(("Failed to fill svc terminate event data, ret=%d\n", ret));
5329*4882a593Smuzhiyun 			goto fail;
5330*4882a593Smuzhiyun 		}
5331*4882a593Smuzhiyun 		break;
5332*4882a593Smuzhiyun 	}
5333*4882a593Smuzhiyun 
5334*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND: {
5335*4882a593Smuzhiyun 		WL_DBG(("GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND %d\n",
5336*4882a593Smuzhiyun 			GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND));
5337*4882a593Smuzhiyun 		ret = wl_cfgvendor_nan_tx_followup_ind_event_data_filler(msg, event_data);
5338*4882a593Smuzhiyun 		if (unlikely(ret)) {
5339*4882a593Smuzhiyun 			WL_ERR(("Failed to fill tx follow up ind event data, ret=%d\n", ret));
5340*4882a593Smuzhiyun 			goto fail;
5341*4882a593Smuzhiyun 		}
5342*4882a593Smuzhiyun 
5343*4882a593Smuzhiyun 		break;
5344*4882a593Smuzhiyun 	}
5345*4882a593Smuzhiyun 
5346*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_DATA_REQUEST: {
5347*4882a593Smuzhiyun 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_REQUEST\n"));
5348*4882a593Smuzhiyun 		ret = wl_cfgvendor_nan_dp_ind_event_data_filler(msg, event_data);
5349*4882a593Smuzhiyun 		if (unlikely(ret)) {
5350*4882a593Smuzhiyun 			WL_ERR(("Failed to fill dp ind event data, ret=%d\n", ret));
5351*4882a593Smuzhiyun 			goto fail;
5352*4882a593Smuzhiyun 		}
5353*4882a593Smuzhiyun 		break;
5354*4882a593Smuzhiyun 	}
5355*4882a593Smuzhiyun 
5356*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_DATA_CONFIRMATION: {
5357*4882a593Smuzhiyun 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_CONFIRMATION\n"));
5358*4882a593Smuzhiyun 
5359*4882a593Smuzhiyun 		ret = wl_cfgvendor_nan_dp_estb_event_data_filler(msg, event_data);
5360*4882a593Smuzhiyun 		if (unlikely(ret)) {
5361*4882a593Smuzhiyun 			WL_ERR(("Failed to fill dp estb event data, ret=%d\n", ret));
5362*4882a593Smuzhiyun 			goto fail;
5363*4882a593Smuzhiyun 		}
5364*4882a593Smuzhiyun 		break;
5365*4882a593Smuzhiyun 	}
5366*4882a593Smuzhiyun 
5367*4882a593Smuzhiyun 	case GOOGLE_NAN_EVENT_DATA_END: {
5368*4882a593Smuzhiyun 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_END\n"));
5369*4882a593Smuzhiyun 		ret = nla_put_u8(msg, NAN_ATTRIBUTE_INST_COUNT, 1);
5370*4882a593Smuzhiyun 		if (unlikely(ret)) {
5371*4882a593Smuzhiyun 			WL_ERR(("Failed to put inst count, ret=%d\n", ret));
5372*4882a593Smuzhiyun 			goto fail;
5373*4882a593Smuzhiyun 		}
5374*4882a593Smuzhiyun 		ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
5375*4882a593Smuzhiyun 		if (unlikely(ret)) {
5376*4882a593Smuzhiyun 			WL_ERR(("Failed to put ndp id, ret=%d\n", ret));
5377*4882a593Smuzhiyun 			goto fail;
5378*4882a593Smuzhiyun 		}
5379*4882a593Smuzhiyun 		break;
5380*4882a593Smuzhiyun 	}
5381*4882a593Smuzhiyun 
5382*4882a593Smuzhiyun 	default:
5383*4882a593Smuzhiyun 		goto fail;
5384*4882a593Smuzhiyun 	}
5385*4882a593Smuzhiyun 
5386*4882a593Smuzhiyun 	cfg80211_vendor_event(msg, kflags);
5387*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5388*4882a593Smuzhiyun 	return ret;
5389*4882a593Smuzhiyun 
5390*4882a593Smuzhiyun fail:
5391*4882a593Smuzhiyun 	dev_kfree_skb_any(msg);
5392*4882a593Smuzhiyun 	WL_ERR(("Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n",
5393*4882a593Smuzhiyun 			event_id, ret));
5394*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5395*4882a593Smuzhiyun 	return ret;
5396*4882a593Smuzhiyun }
5397*4882a593Smuzhiyun 
5398*4882a593Smuzhiyun static int
wl_cfgvendor_nan_req_subscribe(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5399*4882a593Smuzhiyun wl_cfgvendor_nan_req_subscribe(struct wiphy *wiphy,
5400*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5401*4882a593Smuzhiyun {
5402*4882a593Smuzhiyun 	int ret = 0;
5403*4882a593Smuzhiyun 	nan_discover_cmd_data_t *cmd_data = NULL;
5404*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5405*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5406*4882a593Smuzhiyun 
5407*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5408*4882a593Smuzhiyun 	/* Blocking Subscribe if NAN is not enable */
5409*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
5410*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled, subscribe blocked\n"));
5411*4882a593Smuzhiyun 		ret = BCME_ERROR;
5412*4882a593Smuzhiyun 		goto exit;
5413*4882a593Smuzhiyun 	}
5414*4882a593Smuzhiyun 	cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5415*4882a593Smuzhiyun 	if (!cmd_data) {
5416*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5417*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5418*4882a593Smuzhiyun 		goto exit;
5419*4882a593Smuzhiyun 	}
5420*4882a593Smuzhiyun 
5421*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5422*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
5423*4882a593Smuzhiyun 	if (ret) {
5424*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan disc vendor args, ret = %d\n", ret));
5425*4882a593Smuzhiyun 		goto exit;
5426*4882a593Smuzhiyun 	}
5427*4882a593Smuzhiyun 
5428*4882a593Smuzhiyun 	if (cmd_data->sub_id == 0) {
5429*4882a593Smuzhiyun 		ret = wl_cfgnan_generate_inst_id(cfg, &cmd_data->sub_id);
5430*4882a593Smuzhiyun 		if (ret) {
5431*4882a593Smuzhiyun 			WL_ERR(("failed to generate instance-id for subscribe\n"));
5432*4882a593Smuzhiyun 			goto exit;
5433*4882a593Smuzhiyun 		}
5434*4882a593Smuzhiyun 	} else {
5435*4882a593Smuzhiyun 		cmd_data->svc_update = true;
5436*4882a593Smuzhiyun 	}
5437*4882a593Smuzhiyun 
5438*4882a593Smuzhiyun 	ret = wl_cfgnan_subscribe_handler(wdev->netdev, cfg, cmd_data);
5439*4882a593Smuzhiyun 	if (unlikely(ret) || unlikely(cmd_data->status)) {
5440*4882a593Smuzhiyun 		WL_ERR(("failed to subscribe error[%d], status = [%d]\n",
5441*4882a593Smuzhiyun 				ret, cmd_data->status));
5442*4882a593Smuzhiyun 		wl_cfgnan_remove_inst_id(cfg, cmd_data->sub_id);
5443*4882a593Smuzhiyun 		goto exit;
5444*4882a593Smuzhiyun 	}
5445*4882a593Smuzhiyun 
5446*4882a593Smuzhiyun 	WL_DBG(("subscriber instance id=%d\n", cmd_data->sub_id));
5447*4882a593Smuzhiyun 
5448*4882a593Smuzhiyun 	if (cmd_data->status == WL_NAN_E_OK) {
5449*4882a593Smuzhiyun 		nan_req_resp.instance_id = cmd_data->sub_id;
5450*4882a593Smuzhiyun 	} else {
5451*4882a593Smuzhiyun 		nan_req_resp.instance_id = 0;
5452*4882a593Smuzhiyun 	}
5453*4882a593Smuzhiyun exit:
5454*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_REQUEST_SUBSCRIBE,
5455*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5456*4882a593Smuzhiyun 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
5457*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5458*4882a593Smuzhiyun 	return ret;
5459*4882a593Smuzhiyun }
5460*4882a593Smuzhiyun 
5461*4882a593Smuzhiyun static int
wl_cfgvendor_nan_req_publish(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5462*4882a593Smuzhiyun wl_cfgvendor_nan_req_publish(struct wiphy *wiphy,
5463*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5464*4882a593Smuzhiyun {
5465*4882a593Smuzhiyun 	int ret = 0;
5466*4882a593Smuzhiyun 	nan_discover_cmd_data_t *cmd_data = NULL;
5467*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5468*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5469*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5470*4882a593Smuzhiyun 
5471*4882a593Smuzhiyun 	/* Blocking Publish if NAN is not enable */
5472*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
5473*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled publish blocked\n"));
5474*4882a593Smuzhiyun 		ret = BCME_ERROR;
5475*4882a593Smuzhiyun 		goto exit;
5476*4882a593Smuzhiyun 	}
5477*4882a593Smuzhiyun 	cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5478*4882a593Smuzhiyun 	if (!cmd_data) {
5479*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5480*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5481*4882a593Smuzhiyun 		goto exit;
5482*4882a593Smuzhiyun 	}
5483*4882a593Smuzhiyun 
5484*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5485*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
5486*4882a593Smuzhiyun 	if (ret) {
5487*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan disc vendor args, ret = %d\n", ret));
5488*4882a593Smuzhiyun 		goto exit;
5489*4882a593Smuzhiyun 	}
5490*4882a593Smuzhiyun 
5491*4882a593Smuzhiyun 	if (cmd_data->pub_id == 0) {
5492*4882a593Smuzhiyun 		ret = wl_cfgnan_generate_inst_id(cfg, &cmd_data->pub_id);
5493*4882a593Smuzhiyun 		if (ret) {
5494*4882a593Smuzhiyun 			WL_ERR(("failed to generate instance-id for publisher\n"));
5495*4882a593Smuzhiyun 			goto exit;
5496*4882a593Smuzhiyun 		}
5497*4882a593Smuzhiyun 	} else {
5498*4882a593Smuzhiyun 		cmd_data->svc_update = true;
5499*4882a593Smuzhiyun 	}
5500*4882a593Smuzhiyun 
5501*4882a593Smuzhiyun 	ret = wl_cfgnan_publish_handler(wdev->netdev, cfg, cmd_data);
5502*4882a593Smuzhiyun 	if (unlikely(ret) || unlikely(cmd_data->status)) {
5503*4882a593Smuzhiyun 		WL_ERR(("failed to publish error[%d], status[%d]\n",
5504*4882a593Smuzhiyun 				ret, cmd_data->status));
5505*4882a593Smuzhiyun 		wl_cfgnan_remove_inst_id(cfg, cmd_data->pub_id);
5506*4882a593Smuzhiyun 		goto exit;
5507*4882a593Smuzhiyun 	}
5508*4882a593Smuzhiyun 
5509*4882a593Smuzhiyun 	WL_DBG(("publisher instance id=%d\n", cmd_data->pub_id));
5510*4882a593Smuzhiyun 
5511*4882a593Smuzhiyun 	if (cmd_data->status == WL_NAN_E_OK) {
5512*4882a593Smuzhiyun 		nan_req_resp.instance_id = cmd_data->pub_id;
5513*4882a593Smuzhiyun 	} else {
5514*4882a593Smuzhiyun 		nan_req_resp.instance_id = 0;
5515*4882a593Smuzhiyun 	}
5516*4882a593Smuzhiyun exit:
5517*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_REQUEST_PUBLISH,
5518*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5519*4882a593Smuzhiyun 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
5520*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5521*4882a593Smuzhiyun 	return ret;
5522*4882a593Smuzhiyun }
5523*4882a593Smuzhiyun 
5524*4882a593Smuzhiyun static int
wl_cfgvendor_nan_start_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5525*4882a593Smuzhiyun wl_cfgvendor_nan_start_handler(struct wiphy *wiphy,
5526*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
5527*4882a593Smuzhiyun {
5528*4882a593Smuzhiyun 	int ret = 0;
5529*4882a593Smuzhiyun 	nan_config_cmd_data_t *cmd_data;
5530*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5531*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5532*4882a593Smuzhiyun 	uint32 nan_attr_mask = 0;
5533*4882a593Smuzhiyun 
5534*4882a593Smuzhiyun 	cmd_data = (nan_config_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5535*4882a593Smuzhiyun 	if (!cmd_data) {
5536*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5537*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5538*4882a593Smuzhiyun 		goto exit;
5539*4882a593Smuzhiyun 	}
5540*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5541*4882a593Smuzhiyun 
5542*4882a593Smuzhiyun 	if (cfg->nan_enable) {
5543*4882a593Smuzhiyun 		WL_ERR(("nan is already enabled\n"));
5544*4882a593Smuzhiyun 		ret = BCME_OK;
5545*4882a593Smuzhiyun 		goto exit;
5546*4882a593Smuzhiyun 	}
5547*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5548*4882a593Smuzhiyun 
5549*4882a593Smuzhiyun 	cmd_data->sid_beacon.sid_enable = NAN_SID_ENABLE_FLAG_INVALID; /* Setting to some default */
5550*4882a593Smuzhiyun 	cmd_data->sid_beacon.sid_count = NAN_SID_BEACON_COUNT_INVALID; /* Setting to some default */
5551*4882a593Smuzhiyun 
5552*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask);
5553*4882a593Smuzhiyun 	if (ret) {
5554*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan vendor args, ret %d\n", ret));
5555*4882a593Smuzhiyun 		goto exit;
5556*4882a593Smuzhiyun 	}
5557*4882a593Smuzhiyun 
5558*4882a593Smuzhiyun 	ret = wl_cfgnan_start_handler(wdev->netdev, cfg, cmd_data, nan_attr_mask);
5559*4882a593Smuzhiyun 	if (ret) {
5560*4882a593Smuzhiyun 		WL_ERR(("failed to start nan error[%d]\n", ret));
5561*4882a593Smuzhiyun 		goto exit;
5562*4882a593Smuzhiyun 	}
5563*4882a593Smuzhiyun 	/* Initializing Instance Id List */
5564*4882a593Smuzhiyun 	bzero(cfg->nan_inst_ctrl, NAN_ID_CTRL_SIZE * sizeof(nan_svc_inst_t));
5565*4882a593Smuzhiyun exit:
5566*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_ENABLE,
5567*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5568*4882a593Smuzhiyun 	if (cmd_data) {
5569*4882a593Smuzhiyun 		if (cmd_data->scid.data) {
5570*4882a593Smuzhiyun 			MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen);
5571*4882a593Smuzhiyun 			cmd_data->scid.dlen = 0;
5572*4882a593Smuzhiyun 		}
5573*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
5574*4882a593Smuzhiyun 	}
5575*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5576*4882a593Smuzhiyun 	return ret;
5577*4882a593Smuzhiyun }
5578*4882a593Smuzhiyun 
5579*4882a593Smuzhiyun static int
wl_cfgvendor_nan_stop_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5580*4882a593Smuzhiyun wl_cfgvendor_nan_stop_handler(struct wiphy *wiphy,
5581*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5582*4882a593Smuzhiyun {
5583*4882a593Smuzhiyun 	int ret = 0;
5584*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5585*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5586*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5587*4882a593Smuzhiyun 
5588*4882a593Smuzhiyun 	if (!cfg->nan_init_state) {
5589*4882a593Smuzhiyun 		WL_ERR(("nan is not initialized/nmi doesnt exists\n"));
5590*4882a593Smuzhiyun 		ret = BCME_OK;
5591*4882a593Smuzhiyun 		goto exit;
5592*4882a593Smuzhiyun 	}
5593*4882a593Smuzhiyun 
5594*4882a593Smuzhiyun 	mutex_lock(&cfg->if_sync);
5595*4882a593Smuzhiyun 	if (cfg->nan_enable) {
5596*4882a593Smuzhiyun 		ret = wl_cfgnan_disable(cfg, NAN_USER_INITIATED);
5597*4882a593Smuzhiyun 		if (ret) {
5598*4882a593Smuzhiyun 			WL_ERR(("failed to disable nan, error[%d]\n", ret));
5599*4882a593Smuzhiyun 		}
5600*4882a593Smuzhiyun 	}
5601*4882a593Smuzhiyun 	mutex_unlock(&cfg->if_sync);
5602*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5603*4882a593Smuzhiyun exit:
5604*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DISABLE,
5605*4882a593Smuzhiyun 		&nan_req_resp, ret, BCME_OK);
5606*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5607*4882a593Smuzhiyun 	return ret;
5608*4882a593Smuzhiyun }
5609*4882a593Smuzhiyun 
5610*4882a593Smuzhiyun static int
wl_cfgvendor_nan_config_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5611*4882a593Smuzhiyun wl_cfgvendor_nan_config_handler(struct wiphy *wiphy,
5612*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
5613*4882a593Smuzhiyun {
5614*4882a593Smuzhiyun 	int ret = 0;
5615*4882a593Smuzhiyun 	nan_config_cmd_data_t *cmd_data;
5616*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5617*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5618*4882a593Smuzhiyun 	uint32 nan_attr_mask = 0;
5619*4882a593Smuzhiyun 
5620*4882a593Smuzhiyun 	cmd_data = MALLOCZ(cfg->osh, sizeof(*cmd_data));
5621*4882a593Smuzhiyun 	if (!cmd_data) {
5622*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5623*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5624*4882a593Smuzhiyun 		goto exit;
5625*4882a593Smuzhiyun 	}
5626*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5627*4882a593Smuzhiyun 
5628*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5629*4882a593Smuzhiyun 
5630*4882a593Smuzhiyun 	cmd_data->avail_params.duration = NAN_BAND_INVALID;  /* Setting to some default */
5631*4882a593Smuzhiyun 	cmd_data->sid_beacon.sid_enable = NAN_SID_ENABLE_FLAG_INVALID; /* Setting to some default */
5632*4882a593Smuzhiyun 	cmd_data->sid_beacon.sid_count = NAN_SID_BEACON_COUNT_INVALID; /* Setting to some default */
5633*4882a593Smuzhiyun 
5634*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask);
5635*4882a593Smuzhiyun 	if (ret) {
5636*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan vendor args, ret = %d\n", ret));
5637*4882a593Smuzhiyun 		goto exit;
5638*4882a593Smuzhiyun 	}
5639*4882a593Smuzhiyun 
5640*4882a593Smuzhiyun 	ret = wl_cfgnan_config_handler(wdev->netdev, cfg, cmd_data, nan_attr_mask);
5641*4882a593Smuzhiyun 	if (ret) {
5642*4882a593Smuzhiyun 		WL_ERR(("failed in config request, nan error[%d]\n", ret));
5643*4882a593Smuzhiyun 		goto exit;
5644*4882a593Smuzhiyun 	}
5645*4882a593Smuzhiyun exit:
5646*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CONFIG,
5647*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5648*4882a593Smuzhiyun 	if (cmd_data) {
5649*4882a593Smuzhiyun 		if (cmd_data->scid.data) {
5650*4882a593Smuzhiyun 			MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen);
5651*4882a593Smuzhiyun 			cmd_data->scid.dlen = 0;
5652*4882a593Smuzhiyun 		}
5653*4882a593Smuzhiyun 		MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
5654*4882a593Smuzhiyun 	}
5655*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5656*4882a593Smuzhiyun 	return ret;
5657*4882a593Smuzhiyun }
5658*4882a593Smuzhiyun 
5659*4882a593Smuzhiyun static int
wl_cfgvendor_nan_cancel_publish(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5660*4882a593Smuzhiyun wl_cfgvendor_nan_cancel_publish(struct wiphy *wiphy,
5661*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5662*4882a593Smuzhiyun {
5663*4882a593Smuzhiyun 	int ret = 0;
5664*4882a593Smuzhiyun 	nan_discover_cmd_data_t *cmd_data = NULL;
5665*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5666*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5667*4882a593Smuzhiyun 
5668*4882a593Smuzhiyun 	/* Blocking Cancel_Publish if NAN is not enable */
5669*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
5670*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled, cancel publish blocked\n"));
5671*4882a593Smuzhiyun 		ret = BCME_ERROR;
5672*4882a593Smuzhiyun 		goto exit;
5673*4882a593Smuzhiyun 	}
5674*4882a593Smuzhiyun 	cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5675*4882a593Smuzhiyun 	if (!cmd_data) {
5676*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5677*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5678*4882a593Smuzhiyun 		goto exit;
5679*4882a593Smuzhiyun 	}
5680*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5681*4882a593Smuzhiyun 
5682*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5683*4882a593Smuzhiyun 
5684*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
5685*4882a593Smuzhiyun 	if (ret) {
5686*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
5687*4882a593Smuzhiyun 		goto exit;
5688*4882a593Smuzhiyun 	}
5689*4882a593Smuzhiyun 	nan_req_resp.instance_id = cmd_data->pub_id;
5690*4882a593Smuzhiyun 	WL_INFORM_MEM(("[NAN] cancel publish instance_id=%d\n", cmd_data->pub_id));
5691*4882a593Smuzhiyun 
5692*4882a593Smuzhiyun 	ret = wl_cfgnan_cancel_pub_handler(wdev->netdev, cfg, cmd_data);
5693*4882a593Smuzhiyun 	if (ret) {
5694*4882a593Smuzhiyun 		WL_ERR(("failed to cancel publish nan instance-id[%d] error[%d]\n",
5695*4882a593Smuzhiyun 			cmd_data->pub_id, ret));
5696*4882a593Smuzhiyun 		goto exit;
5697*4882a593Smuzhiyun 	}
5698*4882a593Smuzhiyun exit:
5699*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CANCEL_PUBLISH,
5700*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5701*4882a593Smuzhiyun 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
5702*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5703*4882a593Smuzhiyun 	return ret;
5704*4882a593Smuzhiyun }
5705*4882a593Smuzhiyun 
5706*4882a593Smuzhiyun static int
wl_cfgvendor_nan_cancel_subscribe(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5707*4882a593Smuzhiyun wl_cfgvendor_nan_cancel_subscribe(struct wiphy *wiphy,
5708*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5709*4882a593Smuzhiyun {
5710*4882a593Smuzhiyun 	int ret = 0;
5711*4882a593Smuzhiyun 	nan_discover_cmd_data_t *cmd_data = NULL;
5712*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5713*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5714*4882a593Smuzhiyun 
5715*4882a593Smuzhiyun 	/* Blocking Cancel_Subscribe if NAN is not enableb */
5716*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
5717*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled, cancel subscribe blocked\n"));
5718*4882a593Smuzhiyun 		ret = BCME_ERROR;
5719*4882a593Smuzhiyun 		goto exit;
5720*4882a593Smuzhiyun 	}
5721*4882a593Smuzhiyun 	cmd_data = MALLOCZ(cfg->osh, sizeof(*cmd_data));
5722*4882a593Smuzhiyun 	if (!cmd_data) {
5723*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5724*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5725*4882a593Smuzhiyun 		goto exit;
5726*4882a593Smuzhiyun 	}
5727*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5728*4882a593Smuzhiyun 
5729*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5730*4882a593Smuzhiyun 
5731*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
5732*4882a593Smuzhiyun 	if (ret) {
5733*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
5734*4882a593Smuzhiyun 		goto exit;
5735*4882a593Smuzhiyun 	}
5736*4882a593Smuzhiyun 	nan_req_resp.instance_id = cmd_data->sub_id;
5737*4882a593Smuzhiyun 	WL_INFORM_MEM(("[NAN] cancel subscribe instance_id=%d\n", cmd_data->sub_id));
5738*4882a593Smuzhiyun 
5739*4882a593Smuzhiyun 	ret = wl_cfgnan_cancel_sub_handler(wdev->netdev, cfg, cmd_data);
5740*4882a593Smuzhiyun 	if (ret) {
5741*4882a593Smuzhiyun 		WL_ERR(("failed to cancel subscribe nan instance-id[%d] error[%d]\n",
5742*4882a593Smuzhiyun 			cmd_data->sub_id, ret));
5743*4882a593Smuzhiyun 		goto exit;
5744*4882a593Smuzhiyun 	}
5745*4882a593Smuzhiyun exit:
5746*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CANCEL_SUBSCRIBE,
5747*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5748*4882a593Smuzhiyun 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
5749*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5750*4882a593Smuzhiyun 	return ret;
5751*4882a593Smuzhiyun }
5752*4882a593Smuzhiyun 
5753*4882a593Smuzhiyun static int
wl_cfgvendor_nan_transmit(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5754*4882a593Smuzhiyun wl_cfgvendor_nan_transmit(struct wiphy *wiphy,
5755*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5756*4882a593Smuzhiyun {
5757*4882a593Smuzhiyun 	int ret = 0;
5758*4882a593Smuzhiyun 	nan_discover_cmd_data_t *cmd_data = NULL;
5759*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5760*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5761*4882a593Smuzhiyun 
5762*4882a593Smuzhiyun 	/* Blocking Transmit if NAN is not enable */
5763*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
5764*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled, transmit blocked\n"));
5765*4882a593Smuzhiyun 		ret = BCME_ERROR;
5766*4882a593Smuzhiyun 		goto exit;
5767*4882a593Smuzhiyun 	}
5768*4882a593Smuzhiyun 	cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5769*4882a593Smuzhiyun 	if (!cmd_data) {
5770*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5771*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5772*4882a593Smuzhiyun 		goto exit;
5773*4882a593Smuzhiyun 	}
5774*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5775*4882a593Smuzhiyun 
5776*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5777*4882a593Smuzhiyun 
5778*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
5779*4882a593Smuzhiyun 	if (ret) {
5780*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
5781*4882a593Smuzhiyun 		goto exit;
5782*4882a593Smuzhiyun 	}
5783*4882a593Smuzhiyun 	nan_req_resp.instance_id = cmd_data->local_id;
5784*4882a593Smuzhiyun 	ret = wl_cfgnan_transmit_handler(wdev->netdev, cfg, cmd_data);
5785*4882a593Smuzhiyun 	if (ret) {
5786*4882a593Smuzhiyun 		WL_ERR(("failed to transmit-followup nan error[%d]\n", ret));
5787*4882a593Smuzhiyun 		goto exit;
5788*4882a593Smuzhiyun 	}
5789*4882a593Smuzhiyun exit:
5790*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_TRANSMIT,
5791*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5792*4882a593Smuzhiyun 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
5793*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5794*4882a593Smuzhiyun 	return ret;
5795*4882a593Smuzhiyun }
5796*4882a593Smuzhiyun 
5797*4882a593Smuzhiyun static int
wl_cfgvendor_nan_get_capablities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5798*4882a593Smuzhiyun wl_cfgvendor_nan_get_capablities(struct wiphy *wiphy,
5799*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5800*4882a593Smuzhiyun {
5801*4882a593Smuzhiyun 	int ret = 0;
5802*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5803*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5804*4882a593Smuzhiyun 
5805*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5806*4882a593Smuzhiyun 
5807*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5808*4882a593Smuzhiyun 	ret = wl_cfgnan_get_capablities_handler(wdev->netdev, cfg, &nan_req_resp.capabilities);
5809*4882a593Smuzhiyun 	if (ret) {
5810*4882a593Smuzhiyun 		WL_ERR(("Could not get capabilities\n"));
5811*4882a593Smuzhiyun 		ret = -EINVAL;
5812*4882a593Smuzhiyun 		goto exit;
5813*4882a593Smuzhiyun 	}
5814*4882a593Smuzhiyun exit:
5815*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_GET_CAPABILITIES,
5816*4882a593Smuzhiyun 		&nan_req_resp, ret, BCME_OK);
5817*4882a593Smuzhiyun 	wl_cfgvendor_send_cmd_reply(wiphy, &nan_req_resp, sizeof(nan_req_resp));
5818*4882a593Smuzhiyun 
5819*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5820*4882a593Smuzhiyun 	return ret;
5821*4882a593Smuzhiyun }
5822*4882a593Smuzhiyun 
5823*4882a593Smuzhiyun static int
wl_cfgvendor_nan_data_path_iface_create(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5824*4882a593Smuzhiyun wl_cfgvendor_nan_data_path_iface_create(struct wiphy *wiphy,
5825*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5826*4882a593Smuzhiyun {
5827*4882a593Smuzhiyun 	int ret = 0;
5828*4882a593Smuzhiyun 	nan_datapath_cmd_data_t *cmd_data = NULL;
5829*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5830*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5831*4882a593Smuzhiyun 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
5832*4882a593Smuzhiyun 
5833*4882a593Smuzhiyun 	if (!cfg->nan_init_state) {
5834*4882a593Smuzhiyun 		WL_ERR(("%s: NAN is not inited or Device doesn't support NAN \n", __func__));
5835*4882a593Smuzhiyun 		ret = -ENODEV;
5836*4882a593Smuzhiyun 		goto exit;
5837*4882a593Smuzhiyun 	}
5838*4882a593Smuzhiyun 
5839*4882a593Smuzhiyun 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5840*4882a593Smuzhiyun 	if (!cmd_data) {
5841*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5842*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5843*4882a593Smuzhiyun 		goto exit;
5844*4882a593Smuzhiyun 	}
5845*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5846*4882a593Smuzhiyun 
5847*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5848*4882a593Smuzhiyun 
5849*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
5850*4882a593Smuzhiyun 	if (ret) {
5851*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
5852*4882a593Smuzhiyun 		goto exit;
5853*4882a593Smuzhiyun 	}
5854*4882a593Smuzhiyun 
5855*4882a593Smuzhiyun 	if (cfg->nan_enable) { /* new framework Impl, iface create called after nan enab */
5856*4882a593Smuzhiyun 		ret = wl_cfgnan_data_path_iface_create_delete_handler(wdev->netdev,
5857*4882a593Smuzhiyun 			cfg, cmd_data->ndp_iface,
5858*4882a593Smuzhiyun 			NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE, dhdp->up);
5859*4882a593Smuzhiyun 		if (ret != BCME_OK) {
5860*4882a593Smuzhiyun 			WL_ERR(("failed to create iface, ret = %d\n", ret));
5861*4882a593Smuzhiyun 			goto exit;
5862*4882a593Smuzhiyun 		}
5863*4882a593Smuzhiyun 	}
5864*4882a593Smuzhiyun exit:
5865*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE,
5866*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5867*4882a593Smuzhiyun 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
5868*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5869*4882a593Smuzhiyun 	return ret;
5870*4882a593Smuzhiyun }
5871*4882a593Smuzhiyun 
5872*4882a593Smuzhiyun static int
wl_cfgvendor_nan_data_path_iface_delete(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5873*4882a593Smuzhiyun wl_cfgvendor_nan_data_path_iface_delete(struct wiphy *wiphy,
5874*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5875*4882a593Smuzhiyun {
5876*4882a593Smuzhiyun 	int ret = 0;
5877*4882a593Smuzhiyun 	nan_datapath_cmd_data_t *cmd_data = NULL;
5878*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5879*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5880*4882a593Smuzhiyun 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
5881*4882a593Smuzhiyun 
5882*4882a593Smuzhiyun 	if (cfg->nan_init_state == false) {
5883*4882a593Smuzhiyun 		WL_ERR(("%s: NAN is not inited or Device doesn't support NAN \n", __func__));
5884*4882a593Smuzhiyun 		/* Deinit has taken care of cleaing the virtual iface */
5885*4882a593Smuzhiyun 		ret = BCME_OK;
5886*4882a593Smuzhiyun 		goto exit;
5887*4882a593Smuzhiyun 	}
5888*4882a593Smuzhiyun 
5889*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5890*4882a593Smuzhiyun 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5891*4882a593Smuzhiyun 	if (!cmd_data) {
5892*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5893*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5894*4882a593Smuzhiyun 		goto exit;
5895*4882a593Smuzhiyun 	}
5896*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5897*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
5898*4882a593Smuzhiyun 	if (ret) {
5899*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
5900*4882a593Smuzhiyun 		goto exit;
5901*4882a593Smuzhiyun 	}
5902*4882a593Smuzhiyun 
5903*4882a593Smuzhiyun 	ret = wl_cfgnan_data_path_iface_create_delete_handler(wdev->netdev, cfg,
5904*4882a593Smuzhiyun 		(char*)cmd_data->ndp_iface,
5905*4882a593Smuzhiyun 		NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE, dhdp->up);
5906*4882a593Smuzhiyun 	if (ret) {
5907*4882a593Smuzhiyun 		WL_ERR(("failed to delete ndp iface [%d]\n", ret));
5908*4882a593Smuzhiyun 		goto exit;
5909*4882a593Smuzhiyun 	}
5910*4882a593Smuzhiyun exit:
5911*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE,
5912*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5913*4882a593Smuzhiyun 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
5914*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5915*4882a593Smuzhiyun 	return ret;
5916*4882a593Smuzhiyun }
5917*4882a593Smuzhiyun 
5918*4882a593Smuzhiyun static int
wl_cfgvendor_nan_data_path_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5919*4882a593Smuzhiyun wl_cfgvendor_nan_data_path_request(struct wiphy *wiphy,
5920*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5921*4882a593Smuzhiyun {
5922*4882a593Smuzhiyun 	int ret = 0;
5923*4882a593Smuzhiyun 	nan_datapath_cmd_data_t *cmd_data = NULL;
5924*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5925*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5926*4882a593Smuzhiyun 	uint8 ndp_instance_id = 0;
5927*4882a593Smuzhiyun 
5928*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
5929*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled, nan data path request blocked\n"));
5930*4882a593Smuzhiyun 		ret = BCME_ERROR;
5931*4882a593Smuzhiyun 		goto exit;
5932*4882a593Smuzhiyun 	}
5933*4882a593Smuzhiyun 
5934*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5935*4882a593Smuzhiyun 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5936*4882a593Smuzhiyun 	if (!cmd_data) {
5937*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5938*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5939*4882a593Smuzhiyun 		goto exit;
5940*4882a593Smuzhiyun 	}
5941*4882a593Smuzhiyun 
5942*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5943*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
5944*4882a593Smuzhiyun 	if (ret) {
5945*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
5946*4882a593Smuzhiyun 		goto exit;
5947*4882a593Smuzhiyun 	}
5948*4882a593Smuzhiyun 
5949*4882a593Smuzhiyun 	ret = wl_cfgnan_data_path_request_handler(wdev->netdev, cfg,
5950*4882a593Smuzhiyun 			cmd_data, &ndp_instance_id);
5951*4882a593Smuzhiyun 	if (ret) {
5952*4882a593Smuzhiyun 		WL_ERR(("failed to request nan data path [%d]\n", ret));
5953*4882a593Smuzhiyun 		goto exit;
5954*4882a593Smuzhiyun 	}
5955*4882a593Smuzhiyun 
5956*4882a593Smuzhiyun 	if (cmd_data->status == BCME_OK) {
5957*4882a593Smuzhiyun 		nan_req_resp.ndp_instance_id = cmd_data->ndp_instance_id;
5958*4882a593Smuzhiyun 	} else {
5959*4882a593Smuzhiyun 		nan_req_resp.ndp_instance_id = 0;
5960*4882a593Smuzhiyun 	}
5961*4882a593Smuzhiyun exit:
5962*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_REQUEST,
5963*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5964*4882a593Smuzhiyun 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
5965*4882a593Smuzhiyun 	NAN_DBG_EXIT();
5966*4882a593Smuzhiyun 	return ret;
5967*4882a593Smuzhiyun }
5968*4882a593Smuzhiyun 
5969*4882a593Smuzhiyun static int
wl_cfgvendor_nan_data_path_response(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5970*4882a593Smuzhiyun wl_cfgvendor_nan_data_path_response(struct wiphy *wiphy,
5971*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
5972*4882a593Smuzhiyun {
5973*4882a593Smuzhiyun 	int ret = 0;
5974*4882a593Smuzhiyun 	nan_datapath_cmd_data_t *cmd_data = NULL;
5975*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5976*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
5977*4882a593Smuzhiyun 
5978*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
5979*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled, nan data path response blocked\n"));
5980*4882a593Smuzhiyun 		ret = BCME_ERROR;
5981*4882a593Smuzhiyun 		goto exit;
5982*4882a593Smuzhiyun 	}
5983*4882a593Smuzhiyun 	NAN_DBG_ENTER();
5984*4882a593Smuzhiyun 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5985*4882a593Smuzhiyun 	if (!cmd_data) {
5986*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
5987*4882a593Smuzhiyun 		ret = BCME_NOMEM;
5988*4882a593Smuzhiyun 		goto exit;
5989*4882a593Smuzhiyun 	}
5990*4882a593Smuzhiyun 
5991*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5992*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
5993*4882a593Smuzhiyun 	if (ret) {
5994*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
5995*4882a593Smuzhiyun 		goto exit;
5996*4882a593Smuzhiyun 	}
5997*4882a593Smuzhiyun 	ret = wl_cfgnan_data_path_response_handler(wdev->netdev, cfg, cmd_data);
5998*4882a593Smuzhiyun 	if (ret) {
5999*4882a593Smuzhiyun 		WL_ERR(("failed to response nan data path [%d]\n", ret));
6000*4882a593Smuzhiyun 		goto exit;
6001*4882a593Smuzhiyun 	}
6002*4882a593Smuzhiyun exit:
6003*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_RESPONSE,
6004*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6005*4882a593Smuzhiyun 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6006*4882a593Smuzhiyun 	NAN_DBG_EXIT();
6007*4882a593Smuzhiyun 	return ret;
6008*4882a593Smuzhiyun }
6009*4882a593Smuzhiyun 
6010*4882a593Smuzhiyun static int
wl_cfgvendor_nan_data_path_end(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6011*4882a593Smuzhiyun wl_cfgvendor_nan_data_path_end(struct wiphy *wiphy,
6012*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void * data, int len)
6013*4882a593Smuzhiyun {
6014*4882a593Smuzhiyun 	int ret = 0;
6015*4882a593Smuzhiyun 	nan_datapath_cmd_data_t *cmd_data = NULL;
6016*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6017*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
6018*4882a593Smuzhiyun 
6019*4882a593Smuzhiyun 	NAN_DBG_ENTER();
6020*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
6021*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled, nan data path end blocked\n"));
6022*4882a593Smuzhiyun 		ret = BCME_OK;
6023*4882a593Smuzhiyun 		goto exit;
6024*4882a593Smuzhiyun 	}
6025*4882a593Smuzhiyun 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6026*4882a593Smuzhiyun 	if (!cmd_data) {
6027*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
6028*4882a593Smuzhiyun 		ret = BCME_NOMEM;
6029*4882a593Smuzhiyun 		goto exit;
6030*4882a593Smuzhiyun 	}
6031*4882a593Smuzhiyun 
6032*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6033*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6034*4882a593Smuzhiyun 	if (ret) {
6035*4882a593Smuzhiyun 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6036*4882a593Smuzhiyun 		goto exit;
6037*4882a593Smuzhiyun 	}
6038*4882a593Smuzhiyun 	ret = wl_cfgnan_data_path_end_handler(wdev->netdev, cfg, cmd_data);
6039*4882a593Smuzhiyun 	if (ret) {
6040*4882a593Smuzhiyun 		WL_ERR(("failed to end nan data path [%d]\n", ret));
6041*4882a593Smuzhiyun 		goto exit;
6042*4882a593Smuzhiyun 	}
6043*4882a593Smuzhiyun exit:
6044*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_END,
6045*4882a593Smuzhiyun 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6046*4882a593Smuzhiyun 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6047*4882a593Smuzhiyun 	NAN_DBG_EXIT();
6048*4882a593Smuzhiyun 	return ret;
6049*4882a593Smuzhiyun }
6050*4882a593Smuzhiyun 
6051*4882a593Smuzhiyun #ifdef WL_NAN_DISC_CACHE
6052*4882a593Smuzhiyun static int
wl_cfgvendor_nan_data_path_sec_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6053*4882a593Smuzhiyun wl_cfgvendor_nan_data_path_sec_info(struct wiphy *wiphy,
6054*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
6055*4882a593Smuzhiyun {
6056*4882a593Smuzhiyun 	int ret = 0;
6057*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6058*4882a593Smuzhiyun 	nan_hal_resp_t nan_req_resp;
6059*4882a593Smuzhiyun 	nan_datapath_sec_info_cmd_data_t *cmd_data = NULL;
6060*4882a593Smuzhiyun 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6061*4882a593Smuzhiyun 
6062*4882a593Smuzhiyun 	NAN_DBG_ENTER();
6063*4882a593Smuzhiyun 	if (!cfg->nan_enable) {
6064*4882a593Smuzhiyun 		WL_ERR(("nan is not enabled\n"));
6065*4882a593Smuzhiyun 		ret = BCME_UNSUPPORTED;
6066*4882a593Smuzhiyun 		goto exit;
6067*4882a593Smuzhiyun 	}
6068*4882a593Smuzhiyun 	cmd_data = MALLOCZ(dhdp->osh, sizeof(*cmd_data));
6069*4882a593Smuzhiyun 	if (!cmd_data) {
6070*4882a593Smuzhiyun 		WL_ERR(("%s: memory allocation failed\n", __func__));
6071*4882a593Smuzhiyun 		ret = BCME_NOMEM;
6072*4882a593Smuzhiyun 		goto exit;
6073*4882a593Smuzhiyun 	}
6074*4882a593Smuzhiyun 
6075*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_parse_dp_sec_info_args(wiphy, data, len, cmd_data);
6076*4882a593Smuzhiyun 	if (ret) {
6077*4882a593Smuzhiyun 		WL_ERR(("failed to parse sec info args\n"));
6078*4882a593Smuzhiyun 		goto exit;
6079*4882a593Smuzhiyun 	}
6080*4882a593Smuzhiyun 
6081*4882a593Smuzhiyun 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6082*4882a593Smuzhiyun 	ret = wl_cfgnan_sec_info_handler(cfg, cmd_data, &nan_req_resp);
6083*4882a593Smuzhiyun 	if (ret) {
6084*4882a593Smuzhiyun 		WL_ERR(("failed to retrieve svc hash/pub nmi error[%d]\n", ret));
6085*4882a593Smuzhiyun 		goto exit;
6086*4882a593Smuzhiyun 	}
6087*4882a593Smuzhiyun exit:
6088*4882a593Smuzhiyun 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_SEC_INFO,
6089*4882a593Smuzhiyun 		&nan_req_resp, ret, BCME_OK);
6090*4882a593Smuzhiyun 	if (cmd_data) {
6091*4882a593Smuzhiyun 		MFREE(dhdp->osh, cmd_data, sizeof(*cmd_data));
6092*4882a593Smuzhiyun 	}
6093*4882a593Smuzhiyun 	NAN_DBG_EXIT();
6094*4882a593Smuzhiyun 	return ret;
6095*4882a593Smuzhiyun }
6096*4882a593Smuzhiyun #endif /* WL_NAN_DISC_CACHE */
6097*4882a593Smuzhiyun 
6098*4882a593Smuzhiyun static int
wl_cfgvendor_nan_version_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6099*4882a593Smuzhiyun wl_cfgvendor_nan_version_info(struct wiphy *wiphy,
6100*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
6101*4882a593Smuzhiyun {
6102*4882a593Smuzhiyun 	int ret = BCME_OK;
6103*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6104*4882a593Smuzhiyun 	uint32 version = NAN_HAL_VERSION_1;
6105*4882a593Smuzhiyun 
6106*4882a593Smuzhiyun 	BCM_REFERENCE(cfg);
6107*4882a593Smuzhiyun 	WL_DBG(("Enter %s version %d\n", __FUNCTION__, version));
6108*4882a593Smuzhiyun 	ret = wl_cfgvendor_send_cmd_reply(wiphy, &version, sizeof(version));
6109*4882a593Smuzhiyun 	return ret;
6110*4882a593Smuzhiyun }
6111*4882a593Smuzhiyun 
6112*4882a593Smuzhiyun #endif /* WL_NAN */
6113*4882a593Smuzhiyun 
6114*4882a593Smuzhiyun #ifdef LINKSTAT_SUPPORT
6115*4882a593Smuzhiyun 
6116*4882a593Smuzhiyun #define NUM_RATE 32
6117*4882a593Smuzhiyun #define NUM_PEER 1
6118*4882a593Smuzhiyun #define NUM_CHAN 11
6119*4882a593Smuzhiyun #define HEADER_SIZE sizeof(ver_len)
6120*4882a593Smuzhiyun 
wl_cfgvendor_lstats_get_bcn_mbss(char * buf,uint32 * rxbeaconmbss)6121*4882a593Smuzhiyun static int wl_cfgvendor_lstats_get_bcn_mbss(char *buf, uint32 *rxbeaconmbss)
6122*4882a593Smuzhiyun {
6123*4882a593Smuzhiyun 	wl_cnt_info_t *cbuf = (wl_cnt_info_t *)buf;
6124*4882a593Smuzhiyun 	const void *cnt;
6125*4882a593Smuzhiyun 
6126*4882a593Smuzhiyun 	if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6127*4882a593Smuzhiyun 		WL_CNT_XTLV_CNTV_LE10_UCODE, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6128*4882a593Smuzhiyun 		*rxbeaconmbss = ((const wl_cnt_v_le10_mcst_t *)cnt)->rxbeaconmbss;
6129*4882a593Smuzhiyun 	} else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6130*4882a593Smuzhiyun 		WL_CNT_XTLV_LT40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6131*4882a593Smuzhiyun 		*rxbeaconmbss = ((const wl_cnt_lt40mcst_v1_t *)cnt)->rxbeaconmbss;
6132*4882a593Smuzhiyun 	} else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6133*4882a593Smuzhiyun 		WL_CNT_XTLV_GE40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6134*4882a593Smuzhiyun 		*rxbeaconmbss = ((const wl_cnt_ge40mcst_v1_t *)cnt)->rxbeaconmbss;
6135*4882a593Smuzhiyun 	} else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6136*4882a593Smuzhiyun 		WL_CNT_XTLV_GE80_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6137*4882a593Smuzhiyun 		*rxbeaconmbss = ((const wl_cnt_ge80mcst_v1_t *)cnt)->rxbeaconmbss;
6138*4882a593Smuzhiyun 	} else {
6139*4882a593Smuzhiyun 		*rxbeaconmbss = 0;
6140*4882a593Smuzhiyun 		return BCME_NOTFOUND;
6141*4882a593Smuzhiyun 	}
6142*4882a593Smuzhiyun 
6143*4882a593Smuzhiyun 	return BCME_OK;
6144*4882a593Smuzhiyun }
6145*4882a593Smuzhiyun 
wl_cfgvendor_lstats_get_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6146*4882a593Smuzhiyun static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy,
6147*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6148*4882a593Smuzhiyun {
6149*4882a593Smuzhiyun 	static char iovar_buf[WLC_IOCTL_MAXLEN];
6150*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6151*4882a593Smuzhiyun 	int err = 0, i;
6152*4882a593Smuzhiyun 	wifi_radio_stat *radio;
6153*4882a593Smuzhiyun 	wifi_radio_stat_h radio_h;
6154*4882a593Smuzhiyun 	wl_wme_cnt_t *wl_wme_cnt;
6155*4882a593Smuzhiyun 	const wl_cnt_wlc_t *wlc_cnt;
6156*4882a593Smuzhiyun 	scb_val_t scbval;
6157*4882a593Smuzhiyun 	char *output = NULL;
6158*4882a593Smuzhiyun 	char *outdata = NULL;
6159*4882a593Smuzhiyun 	wifi_rate_stat_v1 *p_wifi_rate_stat_v1 = NULL;
6160*4882a593Smuzhiyun 	wifi_rate_stat *p_wifi_rate_stat = NULL;
6161*4882a593Smuzhiyun 	uint total_len = 0;
6162*4882a593Smuzhiyun 	uint32 rxbeaconmbss;
6163*4882a593Smuzhiyun 	wifi_iface_stat iface;
6164*4882a593Smuzhiyun 	wlc_rev_info_t revinfo;
6165*4882a593Smuzhiyun 
6166*4882a593Smuzhiyun 	WL_INFORM_MEM(("%s: Enter \n", __func__));
6167*4882a593Smuzhiyun 	RETURN_EIO_IF_NOT_UP(cfg);
6168*4882a593Smuzhiyun 
6169*4882a593Smuzhiyun 	/* Get the device rev info */
6170*4882a593Smuzhiyun 	bzero(&revinfo, sizeof(revinfo));
6171*4882a593Smuzhiyun 	err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_REVINFO, &revinfo,
6172*4882a593Smuzhiyun 			sizeof(revinfo));
6173*4882a593Smuzhiyun 	if (err != BCME_OK) {
6174*4882a593Smuzhiyun 		goto exit;
6175*4882a593Smuzhiyun 	}
6176*4882a593Smuzhiyun 
6177*4882a593Smuzhiyun 	outdata = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
6178*4882a593Smuzhiyun 	if (outdata == NULL) {
6179*4882a593Smuzhiyun 		WL_ERR(("%s: alloc failed\n", __func__));
6180*4882a593Smuzhiyun 		return -ENOMEM;
6181*4882a593Smuzhiyun 	}
6182*4882a593Smuzhiyun 
6183*4882a593Smuzhiyun 	bzero(&scbval, sizeof(scb_val_t));
6184*4882a593Smuzhiyun 	bzero(outdata, WLC_IOCTL_MAXLEN);
6185*4882a593Smuzhiyun 	output = outdata;
6186*4882a593Smuzhiyun 
6187*4882a593Smuzhiyun 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0,
6188*4882a593Smuzhiyun 		iovar_buf, WLC_IOCTL_MAXLEN, NULL);
6189*4882a593Smuzhiyun 	if (err != BCME_OK && err != BCME_UNSUPPORTED) {
6190*4882a593Smuzhiyun 		WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wifi_radio_stat)));
6191*4882a593Smuzhiyun 		goto exit;
6192*4882a593Smuzhiyun 	}
6193*4882a593Smuzhiyun 	radio = (wifi_radio_stat *)iovar_buf;
6194*4882a593Smuzhiyun 
6195*4882a593Smuzhiyun 	bzero(&radio_h, sizeof(wifi_radio_stat_h));
6196*4882a593Smuzhiyun 	radio_h.on_time = radio->on_time;
6197*4882a593Smuzhiyun 	radio_h.tx_time = radio->tx_time;
6198*4882a593Smuzhiyun 	radio_h.rx_time = radio->rx_time;
6199*4882a593Smuzhiyun 	radio_h.on_time_scan = radio->on_time_scan;
6200*4882a593Smuzhiyun 	radio_h.on_time_nbd = radio->on_time_nbd;
6201*4882a593Smuzhiyun 	radio_h.on_time_gscan = radio->on_time_gscan;
6202*4882a593Smuzhiyun 	radio_h.on_time_roam_scan = radio->on_time_roam_scan;
6203*4882a593Smuzhiyun 	radio_h.on_time_pno_scan = radio->on_time_pno_scan;
6204*4882a593Smuzhiyun 	radio_h.on_time_hs20 = radio->on_time_hs20;
6205*4882a593Smuzhiyun 	radio_h.num_channels = NUM_CHAN;
6206*4882a593Smuzhiyun 
6207*4882a593Smuzhiyun 	memcpy(output, &radio_h, sizeof(wifi_radio_stat_h));
6208*4882a593Smuzhiyun 
6209*4882a593Smuzhiyun 	output += sizeof(wifi_radio_stat_h);
6210*4882a593Smuzhiyun 	output += (NUM_CHAN * sizeof(wifi_channel_stat));
6211*4882a593Smuzhiyun 
6212*4882a593Smuzhiyun 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "wme_counters", NULL, 0,
6213*4882a593Smuzhiyun 		iovar_buf, WLC_IOCTL_MAXLEN, NULL);
6214*4882a593Smuzhiyun 	if (unlikely(err)) {
6215*4882a593Smuzhiyun 		WL_ERR(("error (%d)\n", err));
6216*4882a593Smuzhiyun 		goto exit;
6217*4882a593Smuzhiyun 	}
6218*4882a593Smuzhiyun 	wl_wme_cnt = (wl_wme_cnt_t *)iovar_buf;
6219*4882a593Smuzhiyun 
6220*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].ac, WIFI_AC_VO);
6221*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].tx_mpdu, wl_wme_cnt->tx[AC_VO].packets);
6222*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].rx_mpdu, wl_wme_cnt->rx[AC_VO].packets);
6223*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].mpdu_lost,
6224*4882a593Smuzhiyun 		wl_wme_cnt->tx_failed[WIFI_AC_VO].packets);
6225*4882a593Smuzhiyun 
6226*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].ac, WIFI_AC_VI);
6227*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].tx_mpdu, wl_wme_cnt->tx[AC_VI].packets);
6228*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].rx_mpdu, wl_wme_cnt->rx[AC_VI].packets);
6229*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].mpdu_lost,
6230*4882a593Smuzhiyun 		wl_wme_cnt->tx_failed[WIFI_AC_VI].packets);
6231*4882a593Smuzhiyun 
6232*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].ac, WIFI_AC_BE);
6233*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu, wl_wme_cnt->tx[AC_BE].packets);
6234*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu, wl_wme_cnt->rx[AC_BE].packets);
6235*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost,
6236*4882a593Smuzhiyun 		wl_wme_cnt->tx_failed[WIFI_AC_BE].packets);
6237*4882a593Smuzhiyun 
6238*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].ac, WIFI_AC_BK);
6239*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].tx_mpdu, wl_wme_cnt->tx[AC_BK].packets);
6240*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].rx_mpdu, wl_wme_cnt->rx[AC_BK].packets);
6241*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].mpdu_lost,
6242*4882a593Smuzhiyun 		wl_wme_cnt->tx_failed[WIFI_AC_BK].packets);
6243*4882a593Smuzhiyun 
6244*4882a593Smuzhiyun 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0,
6245*4882a593Smuzhiyun 		iovar_buf, WLC_IOCTL_MAXLEN, NULL);
6246*4882a593Smuzhiyun 	if (unlikely(err)) {
6247*4882a593Smuzhiyun 		WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_cnt_wlc_t)));
6248*4882a593Smuzhiyun 		goto exit;
6249*4882a593Smuzhiyun 	}
6250*4882a593Smuzhiyun 
6251*4882a593Smuzhiyun 	CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MAXLEN);
6252*4882a593Smuzhiyun 	/* Translate traditional (ver <= 10) counters struct to new xtlv type struct */
6253*4882a593Smuzhiyun 	err = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WLC_IOCTL_MAXLEN, revinfo.corerev);
6254*4882a593Smuzhiyun 	if (err != BCME_OK) {
6255*4882a593Smuzhiyun 		WL_ERR(("%s wl_cntbuf_to_xtlv_format ERR %d\n",
6256*4882a593Smuzhiyun 			__FUNCTION__, err));
6257*4882a593Smuzhiyun 		goto exit;
6258*4882a593Smuzhiyun 	}
6259*4882a593Smuzhiyun 
6260*4882a593Smuzhiyun 	if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
6261*4882a593Smuzhiyun 		WL_ERR(("%s wlc_cnt NULL!\n", __FUNCTION__));
6262*4882a593Smuzhiyun 		err = BCME_ERROR;
6263*4882a593Smuzhiyun 		goto exit;
6264*4882a593Smuzhiyun 	}
6265*4882a593Smuzhiyun 
6266*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, wlc_cnt->txretry);
6267*4882a593Smuzhiyun 
6268*4882a593Smuzhiyun 	err = wl_cfgvendor_lstats_get_bcn_mbss(iovar_buf, &rxbeaconmbss);
6269*4882a593Smuzhiyun 	if (unlikely(err)) {
6270*4882a593Smuzhiyun 		WL_ERR(("get_bcn_mbss error (%d)\n", err));
6271*4882a593Smuzhiyun 		goto exit;
6272*4882a593Smuzhiyun 	}
6273*4882a593Smuzhiyun 
6274*4882a593Smuzhiyun 	err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval);
6275*4882a593Smuzhiyun 	if (unlikely(err)) {
6276*4882a593Smuzhiyun 		WL_ERR(("get_rssi error (%d)\n", err));
6277*4882a593Smuzhiyun 		goto exit;
6278*4882a593Smuzhiyun 	}
6279*4882a593Smuzhiyun 
6280*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, beacon_rx, rxbeaconmbss);
6281*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, rssi_mgmt, scbval.val);
6282*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, num_peers, NUM_PEER);
6283*4882a593Smuzhiyun 	COMPAT_ASSIGN_VALUE(iface, peer_info->num_rate, NUM_RATE);
6284*4882a593Smuzhiyun 
6285*4882a593Smuzhiyun 	{
6286*4882a593Smuzhiyun 		memcpy(output, &iface, sizeof(iface));
6287*4882a593Smuzhiyun 		output += (sizeof(iface) - sizeof(wifi_rate_stat));
6288*4882a593Smuzhiyun 	}
6289*4882a593Smuzhiyun 
6290*4882a593Smuzhiyun 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0,
6291*4882a593Smuzhiyun 		iovar_buf, WLC_IOCTL_MAXLEN, NULL);
6292*4882a593Smuzhiyun 	if (err != BCME_OK && err != BCME_UNSUPPORTED) {
6293*4882a593Smuzhiyun 		WL_ERR(("error (%d) - size = %zu\n", err, NUM_RATE*sizeof(wifi_rate_stat)));
6294*4882a593Smuzhiyun 		goto exit;
6295*4882a593Smuzhiyun 	}
6296*4882a593Smuzhiyun 	for (i = 0; i < NUM_RATE; i++) {
6297*4882a593Smuzhiyun 		p_wifi_rate_stat =
6298*4882a593Smuzhiyun 			(wifi_rate_stat *)(iovar_buf + i*sizeof(wifi_rate_stat));
6299*4882a593Smuzhiyun 		p_wifi_rate_stat_v1 = (wifi_rate_stat_v1 *)output;
6300*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->rate.preamble = p_wifi_rate_stat->rate.preamble;
6301*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->rate.nss = p_wifi_rate_stat->rate.nss;
6302*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->rate.bw = p_wifi_rate_stat->rate.bw;
6303*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->rate.rateMcsIdx = p_wifi_rate_stat->rate.rateMcsIdx;
6304*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->rate.reserved = p_wifi_rate_stat->rate.reserved;
6305*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->rate.bitrate = p_wifi_rate_stat->rate.bitrate;
6306*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->tx_mpdu = p_wifi_rate_stat->tx_mpdu;
6307*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->rx_mpdu = p_wifi_rate_stat->rx_mpdu;
6308*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->mpdu_lost = p_wifi_rate_stat->mpdu_lost;
6309*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->retries = p_wifi_rate_stat->retries;
6310*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->retries_short = p_wifi_rate_stat->retries_short;
6311*4882a593Smuzhiyun 		p_wifi_rate_stat_v1->retries_long = p_wifi_rate_stat->retries_long;
6312*4882a593Smuzhiyun 		output = (char *) &(p_wifi_rate_stat_v1->retries_long);
6313*4882a593Smuzhiyun 		output += sizeof(p_wifi_rate_stat_v1->retries_long);
6314*4882a593Smuzhiyun 	}
6315*4882a593Smuzhiyun 
6316*4882a593Smuzhiyun 	total_len = sizeof(wifi_radio_stat_h) +
6317*4882a593Smuzhiyun 		NUM_CHAN * sizeof(wifi_channel_stat);
6318*4882a593Smuzhiyun 
6319*4882a593Smuzhiyun 	{
6320*4882a593Smuzhiyun 		total_len += sizeof(wifi_iface_stat);
6321*4882a593Smuzhiyun 	}
6322*4882a593Smuzhiyun 
6323*4882a593Smuzhiyun 	total_len = total_len - sizeof(wifi_peer_info) +
6324*4882a593Smuzhiyun 		NUM_PEER * (sizeof(wifi_peer_info) - sizeof(wifi_rate_stat_v1) +
6325*4882a593Smuzhiyun 			NUM_RATE * sizeof(wifi_rate_stat_v1));
6326*4882a593Smuzhiyun 
6327*4882a593Smuzhiyun 	if (total_len > WLC_IOCTL_MAXLEN) {
6328*4882a593Smuzhiyun 		WL_ERR(("Error! total_len:%d is unexpected value\n", total_len));
6329*4882a593Smuzhiyun 		err = BCME_BADLEN;
6330*4882a593Smuzhiyun 		goto exit;
6331*4882a593Smuzhiyun 	}
6332*4882a593Smuzhiyun 	err =  wl_cfgvendor_send_cmd_reply(wiphy, outdata, total_len);
6333*4882a593Smuzhiyun 
6334*4882a593Smuzhiyun 	if (unlikely(err))
6335*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
6336*4882a593Smuzhiyun 
6337*4882a593Smuzhiyun exit:
6338*4882a593Smuzhiyun 	if (outdata) {
6339*4882a593Smuzhiyun 		MFREE(cfg->osh, outdata, WLC_IOCTL_MAXLEN);
6340*4882a593Smuzhiyun 	}
6341*4882a593Smuzhiyun 	return err;
6342*4882a593Smuzhiyun }
6343*4882a593Smuzhiyun #endif /* LINKSTAT_SUPPORT */
6344*4882a593Smuzhiyun 
6345*4882a593Smuzhiyun #ifdef DHD_LOG_DUMP
6346*4882a593Smuzhiyun static int
wl_cfgvendor_get_buf_data(const struct nlattr * iter,struct buf_data ** buf)6347*4882a593Smuzhiyun wl_cfgvendor_get_buf_data(const struct nlattr *iter, struct buf_data **buf)
6348*4882a593Smuzhiyun {
6349*4882a593Smuzhiyun 	int ret = BCME_OK;
6350*4882a593Smuzhiyun 
6351*4882a593Smuzhiyun 	if (nla_len(iter) != sizeof(struct buf_data)) {
6352*4882a593Smuzhiyun 		WL_ERR(("Invalid len : %d\n", nla_len(iter)));
6353*4882a593Smuzhiyun 		ret = BCME_BADLEN;
6354*4882a593Smuzhiyun 	}
6355*4882a593Smuzhiyun 	(*buf) = (struct buf_data *)nla_data(iter);
6356*4882a593Smuzhiyun 	if (!(*buf) || (((*buf)->len) <= 0) || !((*buf)->data_buf[0])) {
6357*4882a593Smuzhiyun 		WL_ERR(("Invalid buffer\n"));
6358*4882a593Smuzhiyun 		ret = BCME_ERROR;
6359*4882a593Smuzhiyun 	}
6360*4882a593Smuzhiyun 	return ret;
6361*4882a593Smuzhiyun }
6362*4882a593Smuzhiyun 
6363*4882a593Smuzhiyun static int
wl_cfgvendor_dbg_file_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6364*4882a593Smuzhiyun wl_cfgvendor_dbg_file_dump(struct wiphy *wiphy,
6365*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void *data, int len)
6366*4882a593Smuzhiyun {
6367*4882a593Smuzhiyun 	int ret = BCME_OK, rem, type = 0;
6368*4882a593Smuzhiyun 	const struct nlattr *iter;
6369*4882a593Smuzhiyun 	char *mem_buf = NULL;
6370*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
6371*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6372*4882a593Smuzhiyun 	struct buf_data *buf;
6373*4882a593Smuzhiyun 	int pos = 0;
6374*4882a593Smuzhiyun 
6375*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
6376*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
6377*4882a593Smuzhiyun 	if (!skb) {
6378*4882a593Smuzhiyun 		WL_ERR(("skb allocation is failed\n"));
6379*4882a593Smuzhiyun 		ret = BCME_NOMEM;
6380*4882a593Smuzhiyun 		goto exit;
6381*4882a593Smuzhiyun 	}
6382*4882a593Smuzhiyun 	WL_ERR(("%s\n", __FUNCTION__));
6383*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
6384*4882a593Smuzhiyun 		type = nla_type(iter);
6385*4882a593Smuzhiyun 		ret = wl_cfgvendor_get_buf_data(iter, &buf);
6386*4882a593Smuzhiyun 		if (ret)
6387*4882a593Smuzhiyun 			goto exit;
6388*4882a593Smuzhiyun 		switch (type) {
6389*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_MEMDUMP:
6390*4882a593Smuzhiyun 				ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf,
6391*4882a593Smuzhiyun 					(uint32 *)(&(buf->len)));
6392*4882a593Smuzhiyun 				if (ret) {
6393*4882a593Smuzhiyun 					WL_ERR(("failed to get_socram_dump : %d\n", ret));
6394*4882a593Smuzhiyun 					goto exit;
6395*4882a593Smuzhiyun 				}
6396*4882a593Smuzhiyun 				ret = dhd_export_debug_data(mem_buf, NULL, buf->data_buf[0],
6397*4882a593Smuzhiyun 					(int)buf->len, &pos);
6398*4882a593Smuzhiyun 				break;
6399*4882a593Smuzhiyun 
6400*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_TIMESTAMP :
6401*4882a593Smuzhiyun 				ret = dhd_print_time_str(buf->data_buf[0], NULL,
6402*4882a593Smuzhiyun 					(uint32)buf->len, &pos);
6403*4882a593Smuzhiyun 				break;
6404*4882a593Smuzhiyun #ifdef EWP_ECNTRS_LOGGING
6405*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_ECNTRS :
6406*4882a593Smuzhiyun 				ret = dhd_print_ecntrs_data(bcmcfg_to_prmry_ndev(cfg), NULL,
6407*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
6408*4882a593Smuzhiyun 				break;
6409*4882a593Smuzhiyun #endif /* EWP_ECNTRS_LOGGING */
6410*4882a593Smuzhiyun #ifdef DHD_STATUS_LOGGING
6411*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_STATUS_LOG :
6412*4882a593Smuzhiyun 				ret = dhd_print_status_log_data(bcmcfg_to_prmry_ndev(cfg), NULL,
6413*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
6414*4882a593Smuzhiyun 				break;
6415*4882a593Smuzhiyun #endif /* DHD_STATUS_LOGGING */
6416*4882a593Smuzhiyun #ifdef EWP_RTT_LOGGING
6417*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_RTT_LOG :
6418*4882a593Smuzhiyun 				ret = dhd_print_rtt_data(bcmcfg_to_prmry_ndev(cfg), NULL,
6419*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
6420*4882a593Smuzhiyun 				break;
6421*4882a593Smuzhiyun #endif /* EWP_RTT_LOGGING */
6422*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_DHD_DUMP :
6423*4882a593Smuzhiyun 				ret = dhd_print_dump_data(bcmcfg_to_prmry_ndev(cfg), NULL,
6424*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
6425*4882a593Smuzhiyun 				break;
6426*4882a593Smuzhiyun #if defined(BCMPCIE)
6427*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_EXT_TRAP :
6428*4882a593Smuzhiyun 				ret = dhd_print_ext_trap_data(bcmcfg_to_prmry_ndev(cfg), NULL,
6429*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
6430*4882a593Smuzhiyun 				break;
6431*4882a593Smuzhiyun #endif /* BCMPCIE */
6432*4882a593Smuzhiyun #if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT)
6433*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_HEALTH_CHK :
6434*4882a593Smuzhiyun 				ret = dhd_print_health_chk_data(bcmcfg_to_prmry_ndev(cfg), NULL,
6435*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
6436*4882a593Smuzhiyun 				break;
6437*4882a593Smuzhiyun #endif // endif
6438*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_COOKIE :
6439*4882a593Smuzhiyun 				ret = dhd_print_cookie_data(bcmcfg_to_prmry_ndev(cfg), NULL,
6440*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
6441*4882a593Smuzhiyun 				break;
6442*4882a593Smuzhiyun #ifdef DHD_DUMP_PCIE_RINGS
6443*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_FLOWRING_DUMP :
6444*4882a593Smuzhiyun 				ret = dhd_print_flowring_data(bcmcfg_to_prmry_ndev(cfg), NULL,
6445*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
6446*4882a593Smuzhiyun 				break;
6447*4882a593Smuzhiyun #endif // endif
6448*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_GENERAL_LOG :
6449*4882a593Smuzhiyun 				ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
6450*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len,
6451*4882a593Smuzhiyun 					DLD_BUF_TYPE_GENERAL, &pos);
6452*4882a593Smuzhiyun 				break;
6453*4882a593Smuzhiyun 
6454*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_PRESERVE_LOG :
6455*4882a593Smuzhiyun 				ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
6456*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len,
6457*4882a593Smuzhiyun 					DLD_BUF_TYPE_PRESERVE, &pos);
6458*4882a593Smuzhiyun 				break;
6459*4882a593Smuzhiyun 
6460*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_SPECIAL_LOG :
6461*4882a593Smuzhiyun 				ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
6462*4882a593Smuzhiyun 					buf->data_buf[0], NULL, (uint32)buf->len,
6463*4882a593Smuzhiyun 					DLD_BUF_TYPE_SPECIAL, &pos);
6464*4882a593Smuzhiyun 				break;
6465*4882a593Smuzhiyun #ifdef DHD_SSSR_DUMP
6466*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_SSSR_C0_D11_BEFORE :
6467*4882a593Smuzhiyun 				ret = dhd_sssr_dump_d11_buf_before(bcmcfg_to_prmry_ndev(cfg),
6468*4882a593Smuzhiyun 					buf->data_buf[0], (uint32)buf->len, 0);
6469*4882a593Smuzhiyun 				break;
6470*4882a593Smuzhiyun 
6471*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_SSSR_C0_D11_AFTER :
6472*4882a593Smuzhiyun 				ret = dhd_sssr_dump_d11_buf_after(bcmcfg_to_prmry_ndev(cfg),
6473*4882a593Smuzhiyun 					buf->data_buf[0], (uint32)buf->len, 0);
6474*4882a593Smuzhiyun 				break;
6475*4882a593Smuzhiyun 
6476*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_SSSR_C1_D11_BEFORE :
6477*4882a593Smuzhiyun 				ret = dhd_sssr_dump_d11_buf_before(bcmcfg_to_prmry_ndev(cfg),
6478*4882a593Smuzhiyun 					buf->data_buf[0], (uint32)buf->len, 1);
6479*4882a593Smuzhiyun 				break;
6480*4882a593Smuzhiyun 
6481*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_SSSR_C1_D11_AFTER :
6482*4882a593Smuzhiyun 				ret = dhd_sssr_dump_d11_buf_after(bcmcfg_to_prmry_ndev(cfg),
6483*4882a593Smuzhiyun 					buf->data_buf[0], (uint32)buf->len, 1);
6484*4882a593Smuzhiyun 				break;
6485*4882a593Smuzhiyun 
6486*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_SSSR_DIG_BEFORE :
6487*4882a593Smuzhiyun 				ret = dhd_sssr_dump_dig_buf_before(bcmcfg_to_prmry_ndev(cfg),
6488*4882a593Smuzhiyun 					buf->data_buf[0], (uint32)buf->len);
6489*4882a593Smuzhiyun 				break;
6490*4882a593Smuzhiyun 
6491*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_SSSR_DIG_AFTER :
6492*4882a593Smuzhiyun 				ret = dhd_sssr_dump_dig_buf_after(bcmcfg_to_prmry_ndev(cfg),
6493*4882a593Smuzhiyun 					buf->data_buf[0], (uint32)buf->len);
6494*4882a593Smuzhiyun 				break;
6495*4882a593Smuzhiyun #endif /* DHD_SSSR_DUMP */
6496*4882a593Smuzhiyun #ifdef DHD_PKT_LOGGING
6497*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_PKTLOG:
6498*4882a593Smuzhiyun 				ret = dhd_os_get_pktlog_dump(bcmcfg_to_prmry_ndev(cfg),
6499*4882a593Smuzhiyun 					buf->data_buf[0], (uint32)buf->len);
6500*4882a593Smuzhiyun 				break;
6501*4882a593Smuzhiyun #endif /* DHD_PKT_LOGGING */
6502*4882a593Smuzhiyun #ifdef DNGL_AXI_ERROR_LOGGING
6503*4882a593Smuzhiyun 			case DUMP_BUF_ATTR_AXI_ERROR:
6504*4882a593Smuzhiyun 				ret = dhd_os_get_axi_error_dump(bcmcfg_to_prmry_ndev(cfg),
6505*4882a593Smuzhiyun 					buf->data_buf[0], (uint32)buf->len);
6506*4882a593Smuzhiyun 				break;
6507*4882a593Smuzhiyun #endif /* DNGL_AXI_ERROR_LOGGING */
6508*4882a593Smuzhiyun 			default:
6509*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
6510*4882a593Smuzhiyun 				ret = BCME_ERROR;
6511*4882a593Smuzhiyun 				goto exit;
6512*4882a593Smuzhiyun 		}
6513*4882a593Smuzhiyun 	}
6514*4882a593Smuzhiyun 
6515*4882a593Smuzhiyun 	if (ret)
6516*4882a593Smuzhiyun 		goto exit;
6517*4882a593Smuzhiyun 
6518*4882a593Smuzhiyun 	ret = nla_put_u32(skb, type, (uint32)(ret));
6519*4882a593Smuzhiyun 	if (ret < 0) {
6520*4882a593Smuzhiyun 		WL_ERR(("Failed to put type, ret:%d\n", ret));
6521*4882a593Smuzhiyun 		goto exit;
6522*4882a593Smuzhiyun 	}
6523*4882a593Smuzhiyun 	ret = cfg80211_vendor_cmd_reply(skb);
6524*4882a593Smuzhiyun 	if (ret) {
6525*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
6526*4882a593Smuzhiyun 	}
6527*4882a593Smuzhiyun 	return ret;
6528*4882a593Smuzhiyun exit:
6529*4882a593Smuzhiyun 	if (skb) {
6530*4882a593Smuzhiyun 		/* Free skb memory */
6531*4882a593Smuzhiyun 		kfree_skb(skb);
6532*4882a593Smuzhiyun 	}
6533*4882a593Smuzhiyun 	return ret;
6534*4882a593Smuzhiyun }
6535*4882a593Smuzhiyun #endif /* DHD_LOG_DUMP */
6536*4882a593Smuzhiyun 
6537*4882a593Smuzhiyun #ifdef DEBUGABILITY
6538*4882a593Smuzhiyun static int
wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6539*4882a593Smuzhiyun wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
6540*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void  *data, int len)
6541*4882a593Smuzhiyun {
6542*4882a593Smuzhiyun 	int ret = BCME_OK;
6543*4882a593Smuzhiyun 	uint32 alloc_len;
6544*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
6545*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6546*4882a593Smuzhiyun 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6547*4882a593Smuzhiyun 
6548*4882a593Smuzhiyun 	WL_ERR(("wl_cfgvendor_dbg_trigger_mem_dump %d\n", __LINE__));
6549*4882a593Smuzhiyun 
6550*4882a593Smuzhiyun 	dhdp->memdump_type = DUMP_TYPE_CFG_VENDOR_TRIGGERED;
6551*4882a593Smuzhiyun 	ret = dhd_os_socram_dump(bcmcfg_to_prmry_ndev(cfg), &alloc_len);
6552*4882a593Smuzhiyun 	if (ret) {
6553*4882a593Smuzhiyun 		WL_ERR(("failed to call dhd_os_socram_dump : %d\n", ret));
6554*4882a593Smuzhiyun 		goto exit;
6555*4882a593Smuzhiyun 	}
6556*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
6557*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
6558*4882a593Smuzhiyun 	if (!skb) {
6559*4882a593Smuzhiyun 		WL_ERR(("skb allocation is failed\n"));
6560*4882a593Smuzhiyun 		ret = BCME_NOMEM;
6561*4882a593Smuzhiyun 		goto exit;
6562*4882a593Smuzhiyun 	}
6563*4882a593Smuzhiyun 	ret = nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, alloc_len);
6564*4882a593Smuzhiyun 
6565*4882a593Smuzhiyun 	if (unlikely(ret)) {
6566*4882a593Smuzhiyun 		WL_ERR(("Failed to put fw dump length, ret=%d\n", ret));
6567*4882a593Smuzhiyun 		goto exit;
6568*4882a593Smuzhiyun 	}
6569*4882a593Smuzhiyun 
6570*4882a593Smuzhiyun 	ret = cfg80211_vendor_cmd_reply(skb);
6571*4882a593Smuzhiyun 
6572*4882a593Smuzhiyun 	if (ret) {
6573*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
6574*4882a593Smuzhiyun 		goto exit;
6575*4882a593Smuzhiyun 	}
6576*4882a593Smuzhiyun 	return ret;
6577*4882a593Smuzhiyun exit:
6578*4882a593Smuzhiyun 	/* Free skb memory */
6579*4882a593Smuzhiyun 	if (skb) {
6580*4882a593Smuzhiyun 		kfree_skb(skb);
6581*4882a593Smuzhiyun 	}
6582*4882a593Smuzhiyun 	return ret;
6583*4882a593Smuzhiyun }
6584*4882a593Smuzhiyun 
6585*4882a593Smuzhiyun static int
wl_cfgvendor_dbg_get_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6586*4882a593Smuzhiyun wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
6587*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void *data, int len)
6588*4882a593Smuzhiyun {
6589*4882a593Smuzhiyun 	int ret = BCME_OK, rem, type;
6590*4882a593Smuzhiyun 	int buf_len = 0;
6591*4882a593Smuzhiyun 	uintptr_t user_buf = (uintptr_t)NULL;
6592*4882a593Smuzhiyun 	const struct nlattr *iter;
6593*4882a593Smuzhiyun 	char *mem_buf = NULL;
6594*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
6595*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6596*4882a593Smuzhiyun 
6597*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
6598*4882a593Smuzhiyun 		type = nla_type(iter);
6599*4882a593Smuzhiyun 		switch (type) {
6600*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_FW_DUMP_LEN:
6601*4882a593Smuzhiyun 				/* Check if the iter is valid and
6602*4882a593Smuzhiyun 				 * buffer length is not already initialized.
6603*4882a593Smuzhiyun 				 */
6604*4882a593Smuzhiyun 				if ((nla_len(iter) == sizeof(uint32)) &&
6605*4882a593Smuzhiyun 						!buf_len) {
6606*4882a593Smuzhiyun 					buf_len = nla_get_u32(iter);
6607*4882a593Smuzhiyun 					if (buf_len <= 0) {
6608*4882a593Smuzhiyun 						ret = BCME_ERROR;
6609*4882a593Smuzhiyun 						goto exit;
6610*4882a593Smuzhiyun 					}
6611*4882a593Smuzhiyun 				} else {
6612*4882a593Smuzhiyun 					ret = BCME_ERROR;
6613*4882a593Smuzhiyun 					goto exit;
6614*4882a593Smuzhiyun 				}
6615*4882a593Smuzhiyun 				break;
6616*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_FW_DUMP_DATA:
6617*4882a593Smuzhiyun 				if (nla_len(iter) != sizeof(uint64)) {
6618*4882a593Smuzhiyun 					WL_ERR(("Invalid len\n"));
6619*4882a593Smuzhiyun 					ret = BCME_ERROR;
6620*4882a593Smuzhiyun 					goto exit;
6621*4882a593Smuzhiyun 				}
6622*4882a593Smuzhiyun 				user_buf = (uintptr_t)nla_get_u64(iter);
6623*4882a593Smuzhiyun 				if (!user_buf) {
6624*4882a593Smuzhiyun 					ret = BCME_ERROR;
6625*4882a593Smuzhiyun 					goto exit;
6626*4882a593Smuzhiyun 				}
6627*4882a593Smuzhiyun 				break;
6628*4882a593Smuzhiyun 			default:
6629*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
6630*4882a593Smuzhiyun 				ret = BCME_ERROR;
6631*4882a593Smuzhiyun 				goto exit;
6632*4882a593Smuzhiyun 		}
6633*4882a593Smuzhiyun 	}
6634*4882a593Smuzhiyun 	if (buf_len > 0 && user_buf) {
6635*4882a593Smuzhiyun 		mem_buf = vmalloc(buf_len);
6636*4882a593Smuzhiyun 		if (!mem_buf) {
6637*4882a593Smuzhiyun 			WL_ERR(("failed to allocate mem_buf with size : %d\n", buf_len));
6638*4882a593Smuzhiyun 			ret = BCME_NOMEM;
6639*4882a593Smuzhiyun 			goto exit;
6640*4882a593Smuzhiyun 		}
6641*4882a593Smuzhiyun 		ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf, &buf_len);
6642*4882a593Smuzhiyun 		if (ret) {
6643*4882a593Smuzhiyun 			WL_ERR(("failed to get_socram_dump : %d\n", ret));
6644*4882a593Smuzhiyun 			goto free_mem;
6645*4882a593Smuzhiyun 		}
6646*4882a593Smuzhiyun 		{
6647*4882a593Smuzhiyun 			ret = copy_to_user((void*)user_buf, mem_buf, buf_len);
6648*4882a593Smuzhiyun 			if (ret) {
6649*4882a593Smuzhiyun 				WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
6650*4882a593Smuzhiyun 				goto free_mem;
6651*4882a593Smuzhiyun 			}
6652*4882a593Smuzhiyun 		}
6653*4882a593Smuzhiyun 		/* Alloc the SKB for vendor_event */
6654*4882a593Smuzhiyun 		skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
6655*4882a593Smuzhiyun 		if (!skb) {
6656*4882a593Smuzhiyun 			WL_ERR(("skb allocation is failed\n"));
6657*4882a593Smuzhiyun 			ret = BCME_NOMEM;
6658*4882a593Smuzhiyun 			goto free_mem;
6659*4882a593Smuzhiyun 		}
6660*4882a593Smuzhiyun 		/* Indicate the memdump is succesfully copied */
6661*4882a593Smuzhiyun 		ret = nla_put(skb, DEBUG_ATTRIBUTE_FW_DUMP_DATA, sizeof(ret), &ret);
6662*4882a593Smuzhiyun 		if (ret < 0) {
6663*4882a593Smuzhiyun 			WL_ERR(("Failed to put DEBUG_ATTRIBUTE_FW_DUMP_DATA, ret:%d\n", ret));
6664*4882a593Smuzhiyun 			goto free_mem;
6665*4882a593Smuzhiyun 		}
6666*4882a593Smuzhiyun 
6667*4882a593Smuzhiyun 		ret = cfg80211_vendor_cmd_reply(skb);
6668*4882a593Smuzhiyun 
6669*4882a593Smuzhiyun 		if (ret) {
6670*4882a593Smuzhiyun 			WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
6671*4882a593Smuzhiyun 		}
6672*4882a593Smuzhiyun 		skb = NULL;
6673*4882a593Smuzhiyun 	}
6674*4882a593Smuzhiyun 
6675*4882a593Smuzhiyun free_mem:
6676*4882a593Smuzhiyun 	vfree(mem_buf);
6677*4882a593Smuzhiyun 	/* Free skb memory */
6678*4882a593Smuzhiyun 	if (skb) {
6679*4882a593Smuzhiyun 		kfree_skb(skb);
6680*4882a593Smuzhiyun 	}
6681*4882a593Smuzhiyun exit:
6682*4882a593Smuzhiyun 	return ret;
6683*4882a593Smuzhiyun }
6684*4882a593Smuzhiyun 
wl_cfgvendor_dbg_start_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6685*4882a593Smuzhiyun static int wl_cfgvendor_dbg_start_logging(struct wiphy *wiphy,
6686*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6687*4882a593Smuzhiyun {
6688*4882a593Smuzhiyun 	int ret = BCME_OK, rem, type;
6689*4882a593Smuzhiyun 	char ring_name[DBGRING_NAME_MAX] = {0};
6690*4882a593Smuzhiyun 	int log_level = 0, flags = 0, time_intval = 0, threshold = 0;
6691*4882a593Smuzhiyun 	const struct nlattr *iter;
6692*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6693*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
6694*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
6695*4882a593Smuzhiyun 		type = nla_type(iter);
6696*4882a593Smuzhiyun 		switch (type) {
6697*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_RING_NAME:
6698*4882a593Smuzhiyun 				strncpy(ring_name, nla_data(iter),
6699*4882a593Smuzhiyun 					MIN(sizeof(ring_name) -1, nla_len(iter)));
6700*4882a593Smuzhiyun 				break;
6701*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_LOG_LEVEL:
6702*4882a593Smuzhiyun 				log_level = nla_get_u32(iter);
6703*4882a593Smuzhiyun 				break;
6704*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_RING_FLAGS:
6705*4882a593Smuzhiyun 				flags = nla_get_u32(iter);
6706*4882a593Smuzhiyun 				break;
6707*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_LOG_TIME_INTVAL:
6708*4882a593Smuzhiyun 				time_intval = nla_get_u32(iter);
6709*4882a593Smuzhiyun 				break;
6710*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE:
6711*4882a593Smuzhiyun 				threshold = nla_get_u32(iter);
6712*4882a593Smuzhiyun 				break;
6713*4882a593Smuzhiyun 			default:
6714*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
6715*4882a593Smuzhiyun 				ret = BCME_BADADDR;
6716*4882a593Smuzhiyun 				goto exit;
6717*4882a593Smuzhiyun 		}
6718*4882a593Smuzhiyun 	}
6719*4882a593Smuzhiyun 
6720*4882a593Smuzhiyun 	ret = dhd_os_start_logging(dhd_pub, ring_name, log_level, flags, time_intval, threshold);
6721*4882a593Smuzhiyun 	if (ret < 0) {
6722*4882a593Smuzhiyun 		WL_ERR(("start_logging is failed ret: %d\n", ret));
6723*4882a593Smuzhiyun 	}
6724*4882a593Smuzhiyun exit:
6725*4882a593Smuzhiyun 	return ret;
6726*4882a593Smuzhiyun }
6727*4882a593Smuzhiyun 
wl_cfgvendor_dbg_reset_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6728*4882a593Smuzhiyun static int wl_cfgvendor_dbg_reset_logging(struct wiphy *wiphy,
6729*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6730*4882a593Smuzhiyun {
6731*4882a593Smuzhiyun 	int ret = BCME_OK;
6732*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6733*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
6734*4882a593Smuzhiyun 
6735*4882a593Smuzhiyun 	ret = dhd_os_reset_logging(dhd_pub);
6736*4882a593Smuzhiyun 	if (ret < 0) {
6737*4882a593Smuzhiyun 		WL_ERR(("reset logging is failed ret: %d\n", ret));
6738*4882a593Smuzhiyun 	}
6739*4882a593Smuzhiyun 
6740*4882a593Smuzhiyun 	return ret;
6741*4882a593Smuzhiyun }
6742*4882a593Smuzhiyun 
wl_cfgvendor_dbg_get_ring_status(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6743*4882a593Smuzhiyun static int wl_cfgvendor_dbg_get_ring_status(struct wiphy *wiphy,
6744*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6745*4882a593Smuzhiyun {
6746*4882a593Smuzhiyun 	int ret = BCME_OK;
6747*4882a593Smuzhiyun 	int ring_id, i;
6748*4882a593Smuzhiyun 	int ring_cnt;
6749*4882a593Smuzhiyun 	struct sk_buff *skb;
6750*4882a593Smuzhiyun 	dhd_dbg_ring_status_t dbg_ring_status[DEBUG_RING_ID_MAX];
6751*4882a593Smuzhiyun 	dhd_dbg_ring_status_t ring_status;
6752*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6753*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
6754*4882a593Smuzhiyun 	bzero(dbg_ring_status, DBG_RING_STATUS_SIZE * DEBUG_RING_ID_MAX);
6755*4882a593Smuzhiyun 	ring_cnt = 0;
6756*4882a593Smuzhiyun 	for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
6757*4882a593Smuzhiyun 		ret = dhd_os_get_ring_status(dhd_pub, ring_id, &ring_status);
6758*4882a593Smuzhiyun 		if (ret == BCME_NOTFOUND) {
6759*4882a593Smuzhiyun 			WL_DBG(("The ring (%d) is not found \n", ring_id));
6760*4882a593Smuzhiyun 		} else if (ret == BCME_OK) {
6761*4882a593Smuzhiyun 			dbg_ring_status[ring_cnt++] = ring_status;
6762*4882a593Smuzhiyun 		}
6763*4882a593Smuzhiyun 	}
6764*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
6765*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
6766*4882a593Smuzhiyun 		nla_total_size(DBG_RING_STATUS_SIZE) * ring_cnt + nla_total_size(sizeof(ring_cnt)));
6767*4882a593Smuzhiyun 	if (!skb) {
6768*4882a593Smuzhiyun 		WL_ERR(("skb allocation is failed\n"));
6769*4882a593Smuzhiyun 		ret = BCME_NOMEM;
6770*4882a593Smuzhiyun 		goto exit;
6771*4882a593Smuzhiyun 	}
6772*4882a593Smuzhiyun 
6773*4882a593Smuzhiyun 	/* Ignore return of nla_put_u32 and nla_put since the skb allocated
6774*4882a593Smuzhiyun 	 * above has a requested size for all payload
6775*4882a593Smuzhiyun 	 */
6776*4882a593Smuzhiyun 	(void)nla_put_u32(skb, DEBUG_ATTRIBUTE_RING_NUM, ring_cnt);
6777*4882a593Smuzhiyun 	for (i = 0; i < ring_cnt; i++) {
6778*4882a593Smuzhiyun 		(void)nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, DBG_RING_STATUS_SIZE,
6779*4882a593Smuzhiyun 				&dbg_ring_status[i]);
6780*4882a593Smuzhiyun 	}
6781*4882a593Smuzhiyun 	ret = cfg80211_vendor_cmd_reply(skb);
6782*4882a593Smuzhiyun 
6783*4882a593Smuzhiyun 	if (ret) {
6784*4882a593Smuzhiyun 		WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
6785*4882a593Smuzhiyun 	}
6786*4882a593Smuzhiyun exit:
6787*4882a593Smuzhiyun 	return ret;
6788*4882a593Smuzhiyun }
6789*4882a593Smuzhiyun 
wl_cfgvendor_dbg_get_ring_data(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6790*4882a593Smuzhiyun static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy,
6791*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6792*4882a593Smuzhiyun {
6793*4882a593Smuzhiyun 	int ret = BCME_OK, rem, type;
6794*4882a593Smuzhiyun 	char ring_name[DBGRING_NAME_MAX] = {0};
6795*4882a593Smuzhiyun 	const struct nlattr *iter;
6796*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6797*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
6798*4882a593Smuzhiyun 
6799*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
6800*4882a593Smuzhiyun 		type = nla_type(iter);
6801*4882a593Smuzhiyun 		switch (type) {
6802*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_RING_NAME:
6803*4882a593Smuzhiyun 				strlcpy(ring_name, nla_data(iter), sizeof(ring_name));
6804*4882a593Smuzhiyun 				break;
6805*4882a593Smuzhiyun 			default:
6806*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
6807*4882a593Smuzhiyun 				return ret;
6808*4882a593Smuzhiyun 		}
6809*4882a593Smuzhiyun 	}
6810*4882a593Smuzhiyun 
6811*4882a593Smuzhiyun 	ret = dhd_os_trigger_get_ring_data(dhd_pub, ring_name);
6812*4882a593Smuzhiyun 	if (ret < 0) {
6813*4882a593Smuzhiyun 		WL_ERR(("trigger_get_data failed ret:%d\n", ret));
6814*4882a593Smuzhiyun 	}
6815*4882a593Smuzhiyun 
6816*4882a593Smuzhiyun 	return ret;
6817*4882a593Smuzhiyun }
6818*4882a593Smuzhiyun #else
6819*4882a593Smuzhiyun static int
wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6820*4882a593Smuzhiyun wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
6821*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void  *data, int len)
6822*4882a593Smuzhiyun {
6823*4882a593Smuzhiyun 	return WIFI_ERROR_NOT_SUPPORTED;
6824*4882a593Smuzhiyun }
6825*4882a593Smuzhiyun 
6826*4882a593Smuzhiyun static int
wl_cfgvendor_dbg_get_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6827*4882a593Smuzhiyun wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
6828*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void *data, int len)
6829*4882a593Smuzhiyun {
6830*4882a593Smuzhiyun 	return WIFI_ERROR_NOT_SUPPORTED;
6831*4882a593Smuzhiyun }
6832*4882a593Smuzhiyun 
wl_cfgvendor_dbg_start_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6833*4882a593Smuzhiyun static int wl_cfgvendor_dbg_start_logging(struct wiphy *wiphy,
6834*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6835*4882a593Smuzhiyun {
6836*4882a593Smuzhiyun 	return WIFI_ERROR_NOT_SUPPORTED;
6837*4882a593Smuzhiyun }
6838*4882a593Smuzhiyun 
wl_cfgvendor_dbg_reset_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6839*4882a593Smuzhiyun static int wl_cfgvendor_dbg_reset_logging(struct wiphy *wiphy,
6840*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6841*4882a593Smuzhiyun {
6842*4882a593Smuzhiyun 	return WIFI_ERROR_NOT_SUPPORTED;
6843*4882a593Smuzhiyun }
6844*4882a593Smuzhiyun 
wl_cfgvendor_dbg_get_ring_status(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6845*4882a593Smuzhiyun static int wl_cfgvendor_dbg_get_ring_status(struct wiphy *wiphy,
6846*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6847*4882a593Smuzhiyun {
6848*4882a593Smuzhiyun 	return WIFI_ERROR_NOT_SUPPORTED;
6849*4882a593Smuzhiyun }
6850*4882a593Smuzhiyun 
wl_cfgvendor_dbg_get_ring_data(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6851*4882a593Smuzhiyun static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy,
6852*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6853*4882a593Smuzhiyun {
6854*4882a593Smuzhiyun 	return WIFI_ERROR_NOT_SUPPORTED;
6855*4882a593Smuzhiyun }
6856*4882a593Smuzhiyun #endif /* DEBUGABILITY */
6857*4882a593Smuzhiyun 
wl_cfgvendor_dbg_get_feature(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6858*4882a593Smuzhiyun static int wl_cfgvendor_dbg_get_feature(struct wiphy *wiphy,
6859*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
6860*4882a593Smuzhiyun {
6861*4882a593Smuzhiyun 	int ret = BCME_OK;
6862*4882a593Smuzhiyun 	u32 supported_features = 0;
6863*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6864*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
6865*4882a593Smuzhiyun 
6866*4882a593Smuzhiyun 	ret = dhd_os_dbg_get_feature(dhd_pub, &supported_features);
6867*4882a593Smuzhiyun 	if (ret < 0) {
6868*4882a593Smuzhiyun 		WL_ERR(("dbg_get_feature failed ret:%d\n", ret));
6869*4882a593Smuzhiyun 		goto exit;
6870*4882a593Smuzhiyun 	}
6871*4882a593Smuzhiyun 	ret = wl_cfgvendor_send_cmd_reply(wiphy, &supported_features,
6872*4882a593Smuzhiyun 		sizeof(supported_features));
6873*4882a593Smuzhiyun exit:
6874*4882a593Smuzhiyun 	return ret;
6875*4882a593Smuzhiyun }
6876*4882a593Smuzhiyun 
6877*4882a593Smuzhiyun #ifdef DEBUGABILITY
wl_cfgvendor_dbg_ring_send_evt(void * ctx,const int ring_id,const void * data,const uint32 len,const dhd_dbg_ring_status_t ring_status)6878*4882a593Smuzhiyun static void wl_cfgvendor_dbg_ring_send_evt(void *ctx,
6879*4882a593Smuzhiyun 	const int ring_id, const void *data, const uint32 len,
6880*4882a593Smuzhiyun 	const dhd_dbg_ring_status_t ring_status)
6881*4882a593Smuzhiyun {
6882*4882a593Smuzhiyun 	struct net_device *ndev = ctx;
6883*4882a593Smuzhiyun 	struct wiphy *wiphy;
6884*4882a593Smuzhiyun 	gfp_t kflags;
6885*4882a593Smuzhiyun 	struct sk_buff *skb;
6886*4882a593Smuzhiyun 	if (!ndev) {
6887*4882a593Smuzhiyun 		WL_ERR(("ndev is NULL\n"));
6888*4882a593Smuzhiyun 		return;
6889*4882a593Smuzhiyun 	}
6890*4882a593Smuzhiyun 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
6891*4882a593Smuzhiyun 	wiphy = ndev->ieee80211_ptr->wiphy;
6892*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
6893*4882a593Smuzhiyun #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
6894*4882a593Smuzhiyun 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
6895*4882a593Smuzhiyun 	skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + 100,
6896*4882a593Smuzhiyun 			GOOGLE_DEBUG_RING_EVENT, kflags);
6897*4882a593Smuzhiyun #else
6898*4882a593Smuzhiyun 	skb = cfg80211_vendor_event_alloc(wiphy, len + 100,
6899*4882a593Smuzhiyun 			GOOGLE_DEBUG_RING_EVENT, kflags);
6900*4882a593Smuzhiyun #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
6901*4882a593Smuzhiyun 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
6902*4882a593Smuzhiyun 	if (!skb) {
6903*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
6904*4882a593Smuzhiyun 		return;
6905*4882a593Smuzhiyun 	}
6906*4882a593Smuzhiyun 	nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, sizeof(ring_status), &ring_status);
6907*4882a593Smuzhiyun 	nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
6908*4882a593Smuzhiyun 	cfg80211_vendor_event(skb, kflags);
6909*4882a593Smuzhiyun }
6910*4882a593Smuzhiyun #endif /* DEBUGABILITY */
6911*4882a593Smuzhiyun 
6912*4882a593Smuzhiyun #ifdef DHD_LOG_DUMP
wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff * skb,struct net_device * ndev)6913*4882a593Smuzhiyun static int wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff *skb,
6914*4882a593Smuzhiyun 		struct net_device *ndev)
6915*4882a593Smuzhiyun {
6916*4882a593Smuzhiyun 	int ret = BCME_OK;
6917*4882a593Smuzhiyun #ifdef DHD_SSSR_DUMP
6918*4882a593Smuzhiyun 	uint32 arr_len[DUMP_SSSR_ATTR_COUNT];
6919*4882a593Smuzhiyun 	int i = 0, j = 0;
6920*4882a593Smuzhiyun #endif /* DHD_SSSR_DUMP */
6921*4882a593Smuzhiyun 	char memdump_path[MEMDUMP_PATH_LEN];
6922*4882a593Smuzhiyun 
6923*4882a593Smuzhiyun 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
6924*4882a593Smuzhiyun 		"sssr_dump_core_0_before_SR");
6925*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP, memdump_path);
6926*4882a593Smuzhiyun 	if (unlikely(ret)) {
6927*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put sssr core 0 before dump path, ret=%d\n", ret));
6928*4882a593Smuzhiyun 		goto exit;
6929*4882a593Smuzhiyun 	}
6930*4882a593Smuzhiyun 
6931*4882a593Smuzhiyun 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
6932*4882a593Smuzhiyun 		"sssr_dump_core_0_after_SR");
6933*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP, memdump_path);
6934*4882a593Smuzhiyun 	if (unlikely(ret)) {
6935*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put sssr core 1 after dump path, ret=%d\n", ret));
6936*4882a593Smuzhiyun 		goto exit;
6937*4882a593Smuzhiyun 	}
6938*4882a593Smuzhiyun 
6939*4882a593Smuzhiyun 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
6940*4882a593Smuzhiyun 		"sssr_dump_core_1_before_SR");
6941*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP, memdump_path);
6942*4882a593Smuzhiyun 	if (unlikely(ret)) {
6943*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put sssr core 1 before dump path, ret=%d\n", ret));
6944*4882a593Smuzhiyun 		goto exit;
6945*4882a593Smuzhiyun 	}
6946*4882a593Smuzhiyun 
6947*4882a593Smuzhiyun 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
6948*4882a593Smuzhiyun 		"sssr_dump_core_1_after_SR");
6949*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP, memdump_path);
6950*4882a593Smuzhiyun 	if (unlikely(ret)) {
6951*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put sssr core 1 after dump path, ret=%d\n", ret));
6952*4882a593Smuzhiyun 		goto exit;
6953*4882a593Smuzhiyun 	}
6954*4882a593Smuzhiyun 
6955*4882a593Smuzhiyun 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
6956*4882a593Smuzhiyun 		"sssr_dump_dig_before_SR");
6957*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP, memdump_path);
6958*4882a593Smuzhiyun 	if (unlikely(ret)) {
6959*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put sssr dig before dump path, ret=%d\n", ret));
6960*4882a593Smuzhiyun 		goto exit;
6961*4882a593Smuzhiyun 	}
6962*4882a593Smuzhiyun 
6963*4882a593Smuzhiyun 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
6964*4882a593Smuzhiyun 		"sssr_dump_dig_after_SR");
6965*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP, memdump_path);
6966*4882a593Smuzhiyun 	if (unlikely(ret)) {
6967*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put sssr dig after dump path, ret=%d\n", ret));
6968*4882a593Smuzhiyun 		goto exit;
6969*4882a593Smuzhiyun 	}
6970*4882a593Smuzhiyun 
6971*4882a593Smuzhiyun #ifdef DHD_SSSR_DUMP
6972*4882a593Smuzhiyun 	memset(arr_len, 0, sizeof(arr_len));
6973*4882a593Smuzhiyun 	dhd_nla_put_sssr_dump_len(ndev, arr_len);
6974*4882a593Smuzhiyun 
6975*4882a593Smuzhiyun 	for (i = 0, j = DUMP_SSSR_ATTR_START; i < DUMP_SSSR_ATTR_COUNT; i++, j++) {
6976*4882a593Smuzhiyun 		if (arr_len[i]) {
6977*4882a593Smuzhiyun 			ret = nla_put_u32(skb, j, arr_len[i]);
6978*4882a593Smuzhiyun 			if (unlikely(ret)) {
6979*4882a593Smuzhiyun 				WL_ERR(("Failed to nla put sssr dump len, ret=%d\n", ret));
6980*4882a593Smuzhiyun 				goto exit;
6981*4882a593Smuzhiyun 			}
6982*4882a593Smuzhiyun 		}
6983*4882a593Smuzhiyun 	}
6984*4882a593Smuzhiyun #endif /* DHD_SSSR_DUMP */
6985*4882a593Smuzhiyun 
6986*4882a593Smuzhiyun exit:
6987*4882a593Smuzhiyun 	return ret;
6988*4882a593Smuzhiyun }
6989*4882a593Smuzhiyun 
wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff * skb,struct net_device * ndev)6990*4882a593Smuzhiyun static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb,
6991*4882a593Smuzhiyun 		struct net_device *ndev)
6992*4882a593Smuzhiyun {
6993*4882a593Smuzhiyun 	int ret = BCME_OK;
6994*4882a593Smuzhiyun 	uint32 len = 0;
6995*4882a593Smuzhiyun 	char dump_path[128];
6996*4882a593Smuzhiyun 
6997*4882a593Smuzhiyun 	ret = dhd_get_debug_dump_file_name(ndev, NULL, dump_path, sizeof(dump_path));
6998*4882a593Smuzhiyun 	if (ret < 0) {
6999*4882a593Smuzhiyun 		WL_ERR(("%s: Failed to get debug dump filename\n", __FUNCTION__));
7000*4882a593Smuzhiyun 		goto exit;
7001*4882a593Smuzhiyun 	}
7002*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_DEBUG_DUMP, dump_path);
7003*4882a593Smuzhiyun 	if (unlikely(ret)) {
7004*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put debug dump path, ret=%d\n", ret));
7005*4882a593Smuzhiyun 		goto exit;
7006*4882a593Smuzhiyun 	}
7007*4882a593Smuzhiyun 	WL_ERR(("debug_dump path = %s%s\n", dump_path, FILE_NAME_HAL_TAG));
7008*4882a593Smuzhiyun 	wl_print_verinfo(wl_get_cfg(ndev));
7009*4882a593Smuzhiyun 
7010*4882a593Smuzhiyun 	len = dhd_get_time_str_len();
7011*4882a593Smuzhiyun 	if (len) {
7012*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_TIMESTAMP, len);
7013*4882a593Smuzhiyun 		if (unlikely(ret)) {
7014*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put time stamp length, ret=%d\n", ret));
7015*4882a593Smuzhiyun 			goto exit;
7016*4882a593Smuzhiyun 		}
7017*4882a593Smuzhiyun 	}
7018*4882a593Smuzhiyun 
7019*4882a593Smuzhiyun 	len = dhd_get_dld_len(DLD_BUF_TYPE_GENERAL);
7020*4882a593Smuzhiyun 	if (len) {
7021*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_GENERAL_LOG, len);
7022*4882a593Smuzhiyun 		if (unlikely(ret)) {
7023*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put general log length, ret=%d\n", ret));
7024*4882a593Smuzhiyun 			goto exit;
7025*4882a593Smuzhiyun 		}
7026*4882a593Smuzhiyun 	}
7027*4882a593Smuzhiyun #ifdef EWP_ECNTRS_LOGGING
7028*4882a593Smuzhiyun 	len = dhd_get_ecntrs_len(ndev, NULL);
7029*4882a593Smuzhiyun 	if (len) {
7030*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_ECNTRS, len);
7031*4882a593Smuzhiyun 		if (unlikely(ret)) {
7032*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put ecntrs length, ret=%d\n", ret));
7033*4882a593Smuzhiyun 			goto exit;
7034*4882a593Smuzhiyun 		}
7035*4882a593Smuzhiyun 	}
7036*4882a593Smuzhiyun #endif /* EWP_ECNTRS_LOGGING */
7037*4882a593Smuzhiyun 	len = dhd_get_dld_len(DLD_BUF_TYPE_SPECIAL);
7038*4882a593Smuzhiyun 	if (len) {
7039*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_SPECIAL_LOG, len);
7040*4882a593Smuzhiyun 		if (unlikely(ret)) {
7041*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put special log length, ret=%d\n", ret));
7042*4882a593Smuzhiyun 			goto exit;
7043*4882a593Smuzhiyun 		}
7044*4882a593Smuzhiyun 	}
7045*4882a593Smuzhiyun 	len = dhd_get_dhd_dump_len(ndev, NULL);
7046*4882a593Smuzhiyun 	if (len) {
7047*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_DHD_DUMP, len);
7048*4882a593Smuzhiyun 		if (unlikely(ret)) {
7049*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put dhd dump length, ret=%d\n", ret));
7050*4882a593Smuzhiyun 			goto exit;
7051*4882a593Smuzhiyun 		}
7052*4882a593Smuzhiyun 	}
7053*4882a593Smuzhiyun 
7054*4882a593Smuzhiyun #if defined(BCMPCIE)
7055*4882a593Smuzhiyun 	len = dhd_get_ext_trap_len(ndev, NULL);
7056*4882a593Smuzhiyun 	if (len) {
7057*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_EXT_TRAP, len);
7058*4882a593Smuzhiyun 		if (unlikely(ret)) {
7059*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put ext trap length, ret=%d\n", ret));
7060*4882a593Smuzhiyun 			goto exit;
7061*4882a593Smuzhiyun 		}
7062*4882a593Smuzhiyun 	}
7063*4882a593Smuzhiyun #endif /* BCMPCIE */
7064*4882a593Smuzhiyun 
7065*4882a593Smuzhiyun #if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT)
7066*4882a593Smuzhiyun 	len = dhd_get_health_chk_len(ndev, NULL);
7067*4882a593Smuzhiyun 	if (len) {
7068*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_HEALTH_CHK, len);
7069*4882a593Smuzhiyun 		if (unlikely(ret)) {
7070*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put health check length, ret=%d\n", ret));
7071*4882a593Smuzhiyun 			goto exit;
7072*4882a593Smuzhiyun 		}
7073*4882a593Smuzhiyun 	}
7074*4882a593Smuzhiyun #endif // endif
7075*4882a593Smuzhiyun 
7076*4882a593Smuzhiyun 	len = dhd_get_dld_len(DLD_BUF_TYPE_PRESERVE);
7077*4882a593Smuzhiyun 	if (len) {
7078*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_PRESERVE_LOG, len);
7079*4882a593Smuzhiyun 		if (unlikely(ret)) {
7080*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put preserve log length, ret=%d\n", ret));
7081*4882a593Smuzhiyun 			goto exit;
7082*4882a593Smuzhiyun 		}
7083*4882a593Smuzhiyun 	}
7084*4882a593Smuzhiyun 
7085*4882a593Smuzhiyun 	len = dhd_get_cookie_log_len(ndev, NULL);
7086*4882a593Smuzhiyun 	if (len) {
7087*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_COOKIE, len);
7088*4882a593Smuzhiyun 		if (unlikely(ret)) {
7089*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put cookie length, ret=%d\n", ret));
7090*4882a593Smuzhiyun 			goto exit;
7091*4882a593Smuzhiyun 		}
7092*4882a593Smuzhiyun 	}
7093*4882a593Smuzhiyun #ifdef DHD_DUMP_PCIE_RINGS
7094*4882a593Smuzhiyun 	len = dhd_get_flowring_len(ndev, NULL);
7095*4882a593Smuzhiyun 	if (len) {
7096*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_FLOWRING_DUMP, len);
7097*4882a593Smuzhiyun 		if (unlikely(ret)) {
7098*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put flowring dump length, ret=%d\n", ret));
7099*4882a593Smuzhiyun 			goto exit;
7100*4882a593Smuzhiyun 		}
7101*4882a593Smuzhiyun 	}
7102*4882a593Smuzhiyun #endif // endif
7103*4882a593Smuzhiyun #ifdef DHD_STATUS_LOGGING
7104*4882a593Smuzhiyun 	len = dhd_get_status_log_len(ndev, NULL);
7105*4882a593Smuzhiyun 	if (len) {
7106*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_STATUS_LOG, len);
7107*4882a593Smuzhiyun 		if (unlikely(ret)) {
7108*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put status log length, ret=%d\n", ret));
7109*4882a593Smuzhiyun 			goto exit;
7110*4882a593Smuzhiyun 		}
7111*4882a593Smuzhiyun 	}
7112*4882a593Smuzhiyun #endif /* DHD_STATUS_LOGGING */
7113*4882a593Smuzhiyun #ifdef EWP_RTT_LOGGING
7114*4882a593Smuzhiyun 	len = dhd_get_rtt_len(ndev, NULL);
7115*4882a593Smuzhiyun 	if (len) {
7116*4882a593Smuzhiyun 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_RTT_LOG, len);
7117*4882a593Smuzhiyun 		if (unlikely(ret)) {
7118*4882a593Smuzhiyun 			WL_ERR(("Failed to nla put rtt log length, ret=%d\n", ret));
7119*4882a593Smuzhiyun 			goto exit;
7120*4882a593Smuzhiyun 		}
7121*4882a593Smuzhiyun 	}
7122*4882a593Smuzhiyun #endif /* EWP_RTT_LOGGING */
7123*4882a593Smuzhiyun exit:
7124*4882a593Smuzhiyun 	return ret;
7125*4882a593Smuzhiyun }
7126*4882a593Smuzhiyun #ifdef DNGL_AXI_ERROR_LOGGING
wl_cfgvendor_nla_put_axi_error_data(struct sk_buff * skb,struct net_device * ndev)7127*4882a593Smuzhiyun static void wl_cfgvendor_nla_put_axi_error_data(struct sk_buff *skb,
7128*4882a593Smuzhiyun 		struct net_device *ndev)
7129*4882a593Smuzhiyun {
7130*4882a593Smuzhiyun 	int ret = 0;
7131*4882a593Smuzhiyun 	char axierrordump_path[MEMDUMP_PATH_LEN];
7132*4882a593Smuzhiyun 	int dumpsize = dhd_os_get_axi_error_dump_size(ndev);
7133*4882a593Smuzhiyun 	if (dumpsize <= 0) {
7134*4882a593Smuzhiyun 		WL_ERR(("Failed to calcuate axi error dump len\n"));
7135*4882a593Smuzhiyun 		return;
7136*4882a593Smuzhiyun 	}
7137*4882a593Smuzhiyun 	dhd_os_get_axi_error_filename(ndev, axierrordump_path, MEMDUMP_PATH_LEN);
7138*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_AXI_ERROR_DUMP, axierrordump_path);
7139*4882a593Smuzhiyun 	if (ret) {
7140*4882a593Smuzhiyun 		WL_ERR(("Failed to put filename\n"));
7141*4882a593Smuzhiyun 		return;
7142*4882a593Smuzhiyun 	}
7143*4882a593Smuzhiyun 	ret = nla_put_u32(skb, DUMP_LEN_ATTR_AXI_ERROR, dumpsize);
7144*4882a593Smuzhiyun 	if (ret) {
7145*4882a593Smuzhiyun 		WL_ERR(("Failed to put filesize\n"));
7146*4882a593Smuzhiyun 		return;
7147*4882a593Smuzhiyun 	}
7148*4882a593Smuzhiyun }
7149*4882a593Smuzhiyun #endif /* DNGL_AXI_ERROR_LOGGING */
7150*4882a593Smuzhiyun #ifdef DHD_PKT_LOGGING
wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff * skb,struct net_device * ndev)7151*4882a593Smuzhiyun static void wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff *skb,
7152*4882a593Smuzhiyun 		struct net_device *ndev)
7153*4882a593Smuzhiyun {
7154*4882a593Smuzhiyun 	int ret = 0;
7155*4882a593Smuzhiyun 	char pktlogdump_path[MEMDUMP_PATH_LEN];
7156*4882a593Smuzhiyun 	uint32 pktlog_dumpsize = dhd_os_get_pktlog_dump_size(ndev);
7157*4882a593Smuzhiyun 	if (pktlog_dumpsize == 0) {
7158*4882a593Smuzhiyun 		WL_ERR(("Failed to calcuate pktlog len\n"));
7159*4882a593Smuzhiyun 		return;
7160*4882a593Smuzhiyun 	}
7161*4882a593Smuzhiyun 	dhd_os_get_pktlogdump_filename(ndev, pktlogdump_path, MEMDUMP_PATH_LEN);
7162*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_PKTLOG_DUMP, pktlogdump_path);
7163*4882a593Smuzhiyun 	if (ret) {
7164*4882a593Smuzhiyun 		WL_ERR(("Failed to put filename\n"));
7165*4882a593Smuzhiyun 		return;
7166*4882a593Smuzhiyun 	}
7167*4882a593Smuzhiyun 	ret = nla_put_u32(skb, DUMP_LEN_ATTR_PKTLOG, pktlog_dumpsize);
7168*4882a593Smuzhiyun 	if (ret) {
7169*4882a593Smuzhiyun 		WL_ERR(("Failed to put filesize\n"));
7170*4882a593Smuzhiyun 		return;
7171*4882a593Smuzhiyun 	}
7172*4882a593Smuzhiyun }
7173*4882a593Smuzhiyun #endif /* DHD_PKT_LOGGING */
7174*4882a593Smuzhiyun 
wl_cfgvendor_nla_put_memdump_data(struct sk_buff * skb,struct net_device * ndev,const uint32 fw_len)7175*4882a593Smuzhiyun static int wl_cfgvendor_nla_put_memdump_data(struct sk_buff *skb,
7176*4882a593Smuzhiyun 		struct net_device *ndev, const uint32 fw_len)
7177*4882a593Smuzhiyun {
7178*4882a593Smuzhiyun 	char memdump_path[MEMDUMP_PATH_LEN];
7179*4882a593Smuzhiyun 	int ret = BCME_OK;
7180*4882a593Smuzhiyun 
7181*4882a593Smuzhiyun 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN, "mem_dump");
7182*4882a593Smuzhiyun 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_MEM_DUMP, memdump_path);
7183*4882a593Smuzhiyun 	if (unlikely(ret)) {
7184*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put mem dump path, ret=%d\n", ret));
7185*4882a593Smuzhiyun 		goto exit;
7186*4882a593Smuzhiyun 	}
7187*4882a593Smuzhiyun 	ret = nla_put_u32(skb, DUMP_LEN_ATTR_MEMDUMP, fw_len);
7188*4882a593Smuzhiyun 	if (unlikely(ret)) {
7189*4882a593Smuzhiyun 		WL_ERR(("Failed to nla put mem dump length, ret=%d\n", ret));
7190*4882a593Smuzhiyun 		goto exit;
7191*4882a593Smuzhiyun 	}
7192*4882a593Smuzhiyun 
7193*4882a593Smuzhiyun exit:
7194*4882a593Smuzhiyun 	return ret;
7195*4882a593Smuzhiyun }
7196*4882a593Smuzhiyun 
wl_cfgvendor_dbg_send_file_dump_evt(void * ctx,const void * data,const uint32 len,const uint32 fw_len)7197*4882a593Smuzhiyun static void wl_cfgvendor_dbg_send_file_dump_evt(void *ctx, const void *data,
7198*4882a593Smuzhiyun 	const uint32 len, const uint32 fw_len)
7199*4882a593Smuzhiyun {
7200*4882a593Smuzhiyun 	struct net_device *ndev = ctx;
7201*4882a593Smuzhiyun 	struct wiphy *wiphy;
7202*4882a593Smuzhiyun 	gfp_t kflags;
7203*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
7204*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg;
7205*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub;
7206*4882a593Smuzhiyun 	int ret = BCME_OK;
7207*4882a593Smuzhiyun 
7208*4882a593Smuzhiyun 	if (!ndev) {
7209*4882a593Smuzhiyun 		WL_ERR(("ndev is NULL\n"));
7210*4882a593Smuzhiyun 		return;
7211*4882a593Smuzhiyun 	}
7212*4882a593Smuzhiyun 
7213*4882a593Smuzhiyun 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
7214*4882a593Smuzhiyun 	wiphy = ndev->ieee80211_ptr->wiphy;
7215*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
7216*4882a593Smuzhiyun #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
7217*4882a593Smuzhiyun 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
7218*4882a593Smuzhiyun 	skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + CFG80211_VENDOR_EVT_SKB_SZ,
7219*4882a593Smuzhiyun 			GOOGLE_FILE_DUMP_EVENT, kflags);
7220*4882a593Smuzhiyun #else
7221*4882a593Smuzhiyun 	skb = cfg80211_vendor_event_alloc(wiphy, len + CFG80211_VENDOR_EVT_SKB_SZ,
7222*4882a593Smuzhiyun 			GOOGLE_FILE_DUMP_EVENT, kflags);
7223*4882a593Smuzhiyun #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
7224*4882a593Smuzhiyun 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
7225*4882a593Smuzhiyun 	if (!skb) {
7226*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
7227*4882a593Smuzhiyun 		return;
7228*4882a593Smuzhiyun 	}
7229*4882a593Smuzhiyun 
7230*4882a593Smuzhiyun 	cfg = wiphy_priv(wiphy);
7231*4882a593Smuzhiyun 	dhd_pub = cfg->pub;
7232*4882a593Smuzhiyun #ifdef DNGL_AXI_ERROR_LOGGING
7233*4882a593Smuzhiyun 	if (dhd_pub->smmu_fault_occurred) {
7234*4882a593Smuzhiyun 		wl_cfgvendor_nla_put_axi_error_data(skb, ndev);
7235*4882a593Smuzhiyun 	}
7236*4882a593Smuzhiyun #endif /* DNGL_AXI_ERROR_LOGGING */
7237*4882a593Smuzhiyun 	if (
7238*4882a593Smuzhiyun #ifdef DHD_FW_COREDUMP
7239*4882a593Smuzhiyun         dhd_pub->memdump_enabled ||
7240*4882a593Smuzhiyun #endif /* DHD_FW_COREDUMP */
7241*4882a593Smuzhiyun 	    (dhd_pub->memdump_type == DUMP_TYPE_BY_SYSDUMP)) {
7242*4882a593Smuzhiyun 		if (((ret = wl_cfgvendor_nla_put_memdump_data(skb, ndev, fw_len)) < 0) ||
7243*4882a593Smuzhiyun 			((ret = wl_cfgvendor_nla_put_debug_dump_data(skb, ndev)) < 0) ||
7244*4882a593Smuzhiyun 			((ret = wl_cfgvendor_nla_put_sssr_dump_data(skb, ndev)) < 0)) {
7245*4882a593Smuzhiyun 			WL_ERR(("nla put failed\n"));
7246*4882a593Smuzhiyun 			goto done;
7247*4882a593Smuzhiyun 		}
7248*4882a593Smuzhiyun #ifdef DHD_PKT_LOGGING
7249*4882a593Smuzhiyun 		wl_cfgvendor_nla_put_pktlogdump_data(skb, ndev);
7250*4882a593Smuzhiyun #endif /* DHD_PKT_LOGGING */
7251*4882a593Smuzhiyun 	}
7252*4882a593Smuzhiyun 	/* TODO : Similar to above function add for debug_dump, sssr_dump, and pktlog also. */
7253*4882a593Smuzhiyun 	cfg80211_vendor_event(skb, kflags);
7254*4882a593Smuzhiyun 	return;
7255*4882a593Smuzhiyun done:
7256*4882a593Smuzhiyun 	if (skb) {
7257*4882a593Smuzhiyun 		dev_kfree_skb_any(skb);
7258*4882a593Smuzhiyun 	}
7259*4882a593Smuzhiyun }
7260*4882a593Smuzhiyun #endif /* DHD_LOG_DUMP */
7261*4882a593Smuzhiyun 
wl_cfgvendor_priv_frameburst(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7262*4882a593Smuzhiyun static int wl_cfgvendor_priv_frameburst(struct wiphy *wiphy,
7263*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void *data, int len)
7264*4882a593Smuzhiyun {
7265*4882a593Smuzhiyun 	int ret = BCME_OK;
7266*4882a593Smuzhiyun 	int val = *(int *)data;
7267*4882a593Smuzhiyun 	int  get_frmbrst = 0;
7268*4882a593Smuzhiyun 	int err = 0;
7269*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7270*4882a593Smuzhiyun 
7271*4882a593Smuzhiyun 	if (val == 0xa) {
7272*4882a593Smuzhiyun 		ret = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg),
7273*4882a593Smuzhiyun 			WLC_GET_FAKEFRAG, &get_frmbrst, sizeof(int));
7274*4882a593Smuzhiyun 		if (ret) {
7275*4882a593Smuzhiyun 			WL_ERR(("Failed :  %d\n", ret));
7276*4882a593Smuzhiyun 		}
7277*4882a593Smuzhiyun 		WL_DBG(("Get Frameburst : %d\n", get_frmbrst));
7278*4882a593Smuzhiyun 		err =  wl_cfgvendor_send_cmd_reply(wiphy, &get_frmbrst, sizeof(int));
7279*4882a593Smuzhiyun 		if (unlikely(err))
7280*4882a593Smuzhiyun 			WL_ERR(("Vendor Command reply failed ret:%d \n", err));
7281*4882a593Smuzhiyun 	}
7282*4882a593Smuzhiyun 	else {
7283*4882a593Smuzhiyun 		WL_DBG(("Set frameburst %d\n", val));
7284*4882a593Smuzhiyun 		ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg),
7285*4882a593Smuzhiyun 			WLC_SET_FAKEFRAG, &val, sizeof(val));
7286*4882a593Smuzhiyun 		if (ret < 0) {
7287*4882a593Smuzhiyun 			WL_ERR(("Failed set frameburst, ret=%d\n", ret));
7288*4882a593Smuzhiyun 		} else {
7289*4882a593Smuzhiyun 			WL_ERR(("frameburst is %s\n", val ? "enabled" : "disabled"));
7290*4882a593Smuzhiyun 		}
7291*4882a593Smuzhiyun 	}
7292*4882a593Smuzhiyun 	return ret;
7293*4882a593Smuzhiyun }
7294*4882a593Smuzhiyun 
wl_cfgvendor_priv_mpc(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7295*4882a593Smuzhiyun static int wl_cfgvendor_priv_mpc(struct wiphy *wiphy,
7296*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void *data, int len)
7297*4882a593Smuzhiyun {
7298*4882a593Smuzhiyun 	int ret = BCME_OK;
7299*4882a593Smuzhiyun 	int val = *(int *)data;
7300*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7301*4882a593Smuzhiyun 	int  get_mpc = 0;
7302*4882a593Smuzhiyun 	int err = 0;
7303*4882a593Smuzhiyun 
7304*4882a593Smuzhiyun 	if (val == 0xa) {
7305*4882a593Smuzhiyun 		ret = wldev_iovar_getint(bcmcfg_to_prmry_ndev(cfg), "mpc", &get_mpc);
7306*4882a593Smuzhiyun 		if (ret) {
7307*4882a593Smuzhiyun 			WL_ERR(("Failed : %d\n", ret));
7308*4882a593Smuzhiyun 		}
7309*4882a593Smuzhiyun 		WL_DBG(("Get MPC : %d\n", get_mpc));
7310*4882a593Smuzhiyun 		err =  wl_cfgvendor_send_cmd_reply(wiphy, &get_mpc, sizeof(int));
7311*4882a593Smuzhiyun 		if (unlikely(err))
7312*4882a593Smuzhiyun 			WL_ERR(("Vendor Command reply failed ret:%d \n", err));
7313*4882a593Smuzhiyun 	}
7314*4882a593Smuzhiyun 	else {
7315*4882a593Smuzhiyun 		WL_DBG(("Set mpc val %d\n", val));
7316*4882a593Smuzhiyun 		ret = wldev_iovar_setint(bcmcfg_to_prmry_ndev(cfg), "mpc", val);
7317*4882a593Smuzhiyun 		if (ret < 0) {
7318*4882a593Smuzhiyun 			WL_ERR(("Failed set mpc, ret=%d\n", ret));
7319*4882a593Smuzhiyun 		} else {
7320*4882a593Smuzhiyun 			WL_INFORM_MEM(("mpc is %s\n", val ? "enabled" : "disabled"));
7321*4882a593Smuzhiyun 		}
7322*4882a593Smuzhiyun 	}
7323*4882a593Smuzhiyun 	return ret;
7324*4882a593Smuzhiyun }
7325*4882a593Smuzhiyun 
wl_cfgvendor_priv_band(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7326*4882a593Smuzhiyun static int wl_cfgvendor_priv_band(struct wiphy *wiphy,
7327*4882a593Smuzhiyun 		struct wireless_dev *wdev, const void *data, int len)
7328*4882a593Smuzhiyun {
7329*4882a593Smuzhiyun 	int ret = BCME_OK;
7330*4882a593Smuzhiyun 	uint val = *(uint *)data;
7331*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7332*4882a593Smuzhiyun 	int  get_band = 0;
7333*4882a593Smuzhiyun 	int err = 0;
7334*4882a593Smuzhiyun 
7335*4882a593Smuzhiyun 	if (val == 0xa) {
7336*4882a593Smuzhiyun 		ret = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg),
7337*4882a593Smuzhiyun 			WLC_GET_BAND, &get_band, sizeof(int));
7338*4882a593Smuzhiyun 		if (ret) {
7339*4882a593Smuzhiyun 			WL_ERR(("Failed : %d\n", ret));
7340*4882a593Smuzhiyun 		}
7341*4882a593Smuzhiyun 		WL_DBG(("Get band : %d\n", get_band));
7342*4882a593Smuzhiyun 		err =  wl_cfgvendor_send_cmd_reply(wiphy, &get_band, sizeof(int));
7343*4882a593Smuzhiyun 		if (unlikely(err))
7344*4882a593Smuzhiyun 			WL_ERR(("Vendor Command reply failed ret:%d \n", err));
7345*4882a593Smuzhiyun 	}
7346*4882a593Smuzhiyun 	else {
7347*4882a593Smuzhiyun 		WL_DBG(("Set band val %d\n", val));
7348*4882a593Smuzhiyun 		if ((val == WLC_BAND_AUTO) || (val == WLC_BAND_5G) || (val == WLC_BAND_2G)) {
7349*4882a593Smuzhiyun 			ret = wldev_ioctl_set(bcmcfg_to_prmry_ndev(cfg),
7350*4882a593Smuzhiyun 				WLC_SET_BAND, &val, sizeof(val));
7351*4882a593Smuzhiyun 			if (!ret)
7352*4882a593Smuzhiyun 				dhd_bus_band_set(bcmcfg_to_prmry_ndev(cfg), val);
7353*4882a593Smuzhiyun 		}
7354*4882a593Smuzhiyun 
7355*4882a593Smuzhiyun 	}
7356*4882a593Smuzhiyun 	return ret;
7357*4882a593Smuzhiyun }
7358*4882a593Smuzhiyun 
wl_cfgvendor_dbg_get_version(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7359*4882a593Smuzhiyun static int wl_cfgvendor_dbg_get_version(struct wiphy *wiphy,
7360*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
7361*4882a593Smuzhiyun {
7362*4882a593Smuzhiyun 	int ret = BCME_OK, rem, type;
7363*4882a593Smuzhiyun 	int buf_len = 1024;
7364*4882a593Smuzhiyun 	bool dhd_ver = FALSE;
7365*4882a593Smuzhiyun 	char *buf_ptr;
7366*4882a593Smuzhiyun 	const struct nlattr *iter;
7367*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7368*4882a593Smuzhiyun 
7369*4882a593Smuzhiyun 	buf_ptr = (char *)MALLOCZ(cfg->osh, buf_len);
7370*4882a593Smuzhiyun 	if (!buf_ptr) {
7371*4882a593Smuzhiyun 		WL_ERR(("failed to allocate the buffer for version n"));
7372*4882a593Smuzhiyun 		ret = BCME_NOMEM;
7373*4882a593Smuzhiyun 		goto exit;
7374*4882a593Smuzhiyun 	}
7375*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
7376*4882a593Smuzhiyun 		type = nla_type(iter);
7377*4882a593Smuzhiyun 		switch (type) {
7378*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_GET_DRIVER:
7379*4882a593Smuzhiyun 				dhd_ver = TRUE;
7380*4882a593Smuzhiyun 				break;
7381*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_GET_FW:
7382*4882a593Smuzhiyun 				dhd_ver = FALSE;
7383*4882a593Smuzhiyun 				break;
7384*4882a593Smuzhiyun 			default:
7385*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
7386*4882a593Smuzhiyun 				ret = BCME_ERROR;
7387*4882a593Smuzhiyun 				goto exit;
7388*4882a593Smuzhiyun 		}
7389*4882a593Smuzhiyun 	}
7390*4882a593Smuzhiyun 	ret = dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg), dhd_ver, &buf_ptr, buf_len);
7391*4882a593Smuzhiyun 	if (ret < 0) {
7392*4882a593Smuzhiyun 		WL_ERR(("failed to get the version %d\n", ret));
7393*4882a593Smuzhiyun 		goto exit;
7394*4882a593Smuzhiyun 	}
7395*4882a593Smuzhiyun 	ret = wl_cfgvendor_send_cmd_reply(wiphy, buf_ptr, strlen(buf_ptr));
7396*4882a593Smuzhiyun exit:
7397*4882a593Smuzhiyun 	MFREE(cfg->osh, buf_ptr, buf_len);
7398*4882a593Smuzhiyun 	return ret;
7399*4882a593Smuzhiyun }
7400*4882a593Smuzhiyun 
7401*4882a593Smuzhiyun #ifdef DBG_PKT_MON
wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7402*4882a593Smuzhiyun static int wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy *wiphy,
7403*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
7404*4882a593Smuzhiyun {
7405*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7406*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
7407*4882a593Smuzhiyun 	int ret;
7408*4882a593Smuzhiyun 
7409*4882a593Smuzhiyun 	ret = dhd_os_dbg_attach_pkt_monitor(dhd_pub);
7410*4882a593Smuzhiyun 	if (unlikely(ret)) {
7411*4882a593Smuzhiyun 		WL_ERR(("failed to start pkt fate monitoring, ret=%d", ret));
7412*4882a593Smuzhiyun 	}
7413*4882a593Smuzhiyun 
7414*4882a593Smuzhiyun 	return ret;
7415*4882a593Smuzhiyun }
7416*4882a593Smuzhiyun 
7417*4882a593Smuzhiyun typedef int (*dbg_mon_get_pkts_t) (dhd_pub_t *dhdp, void __user *user_buf,
7418*4882a593Smuzhiyun 	uint16 req_count, uint16 *resp_count);
7419*4882a593Smuzhiyun 
__wl_cfgvendor_dbg_get_pkt_fates(struct wiphy * wiphy,const void * data,int len,dbg_mon_get_pkts_t dbg_mon_get_pkts)7420*4882a593Smuzhiyun static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy *wiphy,
7421*4882a593Smuzhiyun 	const void *data, int len, dbg_mon_get_pkts_t dbg_mon_get_pkts)
7422*4882a593Smuzhiyun {
7423*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7424*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
7425*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
7426*4882a593Smuzhiyun 	const struct nlattr *iter;
7427*4882a593Smuzhiyun 	void __user *user_buf = NULL;
7428*4882a593Smuzhiyun 	uint16 req_count = 0, resp_count = 0;
7429*4882a593Smuzhiyun 	int ret, tmp, type, mem_needed;
7430*4882a593Smuzhiyun 
7431*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
7432*4882a593Smuzhiyun 		type = nla_type(iter);
7433*4882a593Smuzhiyun 		switch (type) {
7434*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_PKT_FATE_NUM:
7435*4882a593Smuzhiyun 				req_count = nla_get_u32(iter);
7436*4882a593Smuzhiyun 				break;
7437*4882a593Smuzhiyun 			case DEBUG_ATTRIBUTE_PKT_FATE_DATA:
7438*4882a593Smuzhiyun 				user_buf = (void __user *)(unsigned long) nla_get_u64(iter);
7439*4882a593Smuzhiyun 				break;
7440*4882a593Smuzhiyun 			default:
7441*4882a593Smuzhiyun 				WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
7442*4882a593Smuzhiyun 				ret = -EINVAL;
7443*4882a593Smuzhiyun 				goto exit;
7444*4882a593Smuzhiyun 		}
7445*4882a593Smuzhiyun 	}
7446*4882a593Smuzhiyun 
7447*4882a593Smuzhiyun 	if (!req_count || !user_buf) {
7448*4882a593Smuzhiyun 		WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n",
7449*4882a593Smuzhiyun 			__FUNCTION__, user_buf, req_count));
7450*4882a593Smuzhiyun 		ret = -EINVAL;
7451*4882a593Smuzhiyun 		goto exit;
7452*4882a593Smuzhiyun 	}
7453*4882a593Smuzhiyun 
7454*4882a593Smuzhiyun 	ret = dbg_mon_get_pkts(dhd_pub, user_buf, req_count, &resp_count);
7455*4882a593Smuzhiyun 	if (unlikely(ret)) {
7456*4882a593Smuzhiyun 		WL_ERR(("failed to get packets, ret:%d \n", ret));
7457*4882a593Smuzhiyun 		goto exit;
7458*4882a593Smuzhiyun 	}
7459*4882a593Smuzhiyun 
7460*4882a593Smuzhiyun 	mem_needed = VENDOR_REPLY_OVERHEAD + ATTRIBUTE_U32_LEN;
7461*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
7462*4882a593Smuzhiyun 	if (unlikely(!skb)) {
7463*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
7464*4882a593Smuzhiyun 		ret = -ENOMEM;
7465*4882a593Smuzhiyun 		goto exit;
7466*4882a593Smuzhiyun 	}
7467*4882a593Smuzhiyun 
7468*4882a593Smuzhiyun 	ret = nla_put_u32(skb, DEBUG_ATTRIBUTE_PKT_FATE_NUM, resp_count);
7469*4882a593Smuzhiyun 	if (ret < 0) {
7470*4882a593Smuzhiyun 		WL_ERR(("Failed to put DEBUG_ATTRIBUTE_PKT_FATE_NUM, ret:%d\n", ret));
7471*4882a593Smuzhiyun 		goto exit;
7472*4882a593Smuzhiyun 	}
7473*4882a593Smuzhiyun 
7474*4882a593Smuzhiyun 	ret = cfg80211_vendor_cmd_reply(skb);
7475*4882a593Smuzhiyun 	if (unlikely(ret)) {
7476*4882a593Smuzhiyun 		WL_ERR(("vendor Command reply failed ret:%d \n", ret));
7477*4882a593Smuzhiyun 	}
7478*4882a593Smuzhiyun 	return ret;
7479*4882a593Smuzhiyun 
7480*4882a593Smuzhiyun exit:
7481*4882a593Smuzhiyun 	/* Free skb memory */
7482*4882a593Smuzhiyun 	if (skb) {
7483*4882a593Smuzhiyun 		kfree_skb(skb);
7484*4882a593Smuzhiyun 	}
7485*4882a593Smuzhiyun 	return ret;
7486*4882a593Smuzhiyun }
7487*4882a593Smuzhiyun 
wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7488*4882a593Smuzhiyun static int wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy *wiphy,
7489*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
7490*4882a593Smuzhiyun {
7491*4882a593Smuzhiyun 	int ret;
7492*4882a593Smuzhiyun 
7493*4882a593Smuzhiyun 	ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
7494*4882a593Smuzhiyun 			dhd_os_dbg_monitor_get_tx_pkts);
7495*4882a593Smuzhiyun 	if (unlikely(ret)) {
7496*4882a593Smuzhiyun 		WL_ERR(("failed to get tx packets, ret:%d \n", ret));
7497*4882a593Smuzhiyun 	}
7498*4882a593Smuzhiyun 
7499*4882a593Smuzhiyun 	return ret;
7500*4882a593Smuzhiyun }
7501*4882a593Smuzhiyun 
wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7502*4882a593Smuzhiyun static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy *wiphy,
7503*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
7504*4882a593Smuzhiyun {
7505*4882a593Smuzhiyun 	int ret;
7506*4882a593Smuzhiyun 
7507*4882a593Smuzhiyun 	ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
7508*4882a593Smuzhiyun 			dhd_os_dbg_monitor_get_rx_pkts);
7509*4882a593Smuzhiyun 	if (unlikely(ret)) {
7510*4882a593Smuzhiyun 		WL_ERR(("failed to get rx packets, ret:%d \n", ret));
7511*4882a593Smuzhiyun 	}
7512*4882a593Smuzhiyun 
7513*4882a593Smuzhiyun 	return ret;
7514*4882a593Smuzhiyun }
7515*4882a593Smuzhiyun #endif /* DBG_PKT_MON */
7516*4882a593Smuzhiyun 
7517*4882a593Smuzhiyun #ifdef KEEP_ALIVE
wl_cfgvendor_start_mkeep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7518*4882a593Smuzhiyun static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
7519*4882a593Smuzhiyun 	const void *data, int len)
7520*4882a593Smuzhiyun {
7521*4882a593Smuzhiyun 	/* max size of IP packet for keep alive */
7522*4882a593Smuzhiyun 	const int MKEEP_ALIVE_IP_PKT_MAX = 256;
7523*4882a593Smuzhiyun 
7524*4882a593Smuzhiyun 	int ret = BCME_OK, rem, type;
7525*4882a593Smuzhiyun 	uint8 mkeep_alive_id = 0;
7526*4882a593Smuzhiyun 	uint8 *ip_pkt = NULL;
7527*4882a593Smuzhiyun 	uint16 ip_pkt_len = 0;
7528*4882a593Smuzhiyun 	uint8 src_mac[ETHER_ADDR_LEN];
7529*4882a593Smuzhiyun 	uint8 dst_mac[ETHER_ADDR_LEN];
7530*4882a593Smuzhiyun 	uint32 period_msec = 0;
7531*4882a593Smuzhiyun 	const struct nlattr *iter;
7532*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7533*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
7534*4882a593Smuzhiyun 
7535*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
7536*4882a593Smuzhiyun 		type = nla_type(iter);
7537*4882a593Smuzhiyun 		switch (type) {
7538*4882a593Smuzhiyun 			case MKEEP_ALIVE_ATTRIBUTE_ID:
7539*4882a593Smuzhiyun 				mkeep_alive_id = nla_get_u8(iter);
7540*4882a593Smuzhiyun 				break;
7541*4882a593Smuzhiyun 			case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
7542*4882a593Smuzhiyun 				ip_pkt_len = nla_get_u16(iter);
7543*4882a593Smuzhiyun 				if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
7544*4882a593Smuzhiyun 					ret = BCME_BADARG;
7545*4882a593Smuzhiyun 					goto exit;
7546*4882a593Smuzhiyun 				}
7547*4882a593Smuzhiyun 				break;
7548*4882a593Smuzhiyun 			case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
7549*4882a593Smuzhiyun 				if (ip_pkt) {
7550*4882a593Smuzhiyun 					ret = BCME_BADARG;
7551*4882a593Smuzhiyun 					WL_ERR(("ip_pkt already allocated\n"));
7552*4882a593Smuzhiyun 					goto exit;
7553*4882a593Smuzhiyun 				}
7554*4882a593Smuzhiyun 				if (!ip_pkt_len) {
7555*4882a593Smuzhiyun 					ret = BCME_BADARG;
7556*4882a593Smuzhiyun 					WL_ERR(("ip packet length is 0\n"));
7557*4882a593Smuzhiyun 					goto exit;
7558*4882a593Smuzhiyun 				}
7559*4882a593Smuzhiyun 				ip_pkt = (u8 *)MALLOCZ(cfg->osh, ip_pkt_len);
7560*4882a593Smuzhiyun 				if (ip_pkt == NULL) {
7561*4882a593Smuzhiyun 					ret = BCME_NOMEM;
7562*4882a593Smuzhiyun 					WL_ERR(("Failed to allocate mem for ip packet\n"));
7563*4882a593Smuzhiyun 					goto exit;
7564*4882a593Smuzhiyun 				}
7565*4882a593Smuzhiyun 				memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len);
7566*4882a593Smuzhiyun 				break;
7567*4882a593Smuzhiyun 			case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
7568*4882a593Smuzhiyun 				memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN);
7569*4882a593Smuzhiyun 				break;
7570*4882a593Smuzhiyun 			case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
7571*4882a593Smuzhiyun 				memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN);
7572*4882a593Smuzhiyun 				break;
7573*4882a593Smuzhiyun 			case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
7574*4882a593Smuzhiyun 				period_msec = nla_get_u32(iter);
7575*4882a593Smuzhiyun 				break;
7576*4882a593Smuzhiyun 			default:
7577*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
7578*4882a593Smuzhiyun 				ret = BCME_BADARG;
7579*4882a593Smuzhiyun 				goto exit;
7580*4882a593Smuzhiyun 		}
7581*4882a593Smuzhiyun 	}
7582*4882a593Smuzhiyun 
7583*4882a593Smuzhiyun 	if (ip_pkt == NULL) {
7584*4882a593Smuzhiyun 		ret = BCME_BADARG;
7585*4882a593Smuzhiyun 		WL_ERR(("ip packet is NULL\n"));
7586*4882a593Smuzhiyun 		goto exit;
7587*4882a593Smuzhiyun 	}
7588*4882a593Smuzhiyun 
7589*4882a593Smuzhiyun 	ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac,
7590*4882a593Smuzhiyun 		dst_mac, period_msec);
7591*4882a593Smuzhiyun 	if (ret < 0) {
7592*4882a593Smuzhiyun 		WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret));
7593*4882a593Smuzhiyun 	}
7594*4882a593Smuzhiyun 
7595*4882a593Smuzhiyun exit:
7596*4882a593Smuzhiyun 	if (ip_pkt) {
7597*4882a593Smuzhiyun 		MFREE(cfg->osh, ip_pkt, ip_pkt_len);
7598*4882a593Smuzhiyun 	}
7599*4882a593Smuzhiyun 
7600*4882a593Smuzhiyun 	return ret;
7601*4882a593Smuzhiyun }
7602*4882a593Smuzhiyun 
wl_cfgvendor_stop_mkeep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7603*4882a593Smuzhiyun static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
7604*4882a593Smuzhiyun 	const void *data, int len)
7605*4882a593Smuzhiyun {
7606*4882a593Smuzhiyun 	int ret = BCME_OK, rem, type;
7607*4882a593Smuzhiyun 	uint8 mkeep_alive_id = 0;
7608*4882a593Smuzhiyun 	const struct nlattr *iter;
7609*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7610*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
7611*4882a593Smuzhiyun 
7612*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
7613*4882a593Smuzhiyun 		type = nla_type(iter);
7614*4882a593Smuzhiyun 		switch (type) {
7615*4882a593Smuzhiyun 			case MKEEP_ALIVE_ATTRIBUTE_ID:
7616*4882a593Smuzhiyun 				mkeep_alive_id = nla_get_u8(iter);
7617*4882a593Smuzhiyun 				break;
7618*4882a593Smuzhiyun 			default:
7619*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
7620*4882a593Smuzhiyun 				ret = BCME_BADARG;
7621*4882a593Smuzhiyun 				break;
7622*4882a593Smuzhiyun 		}
7623*4882a593Smuzhiyun 	}
7624*4882a593Smuzhiyun 
7625*4882a593Smuzhiyun 	ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id);
7626*4882a593Smuzhiyun 	if (ret < 0) {
7627*4882a593Smuzhiyun 		WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret));
7628*4882a593Smuzhiyun 	}
7629*4882a593Smuzhiyun 
7630*4882a593Smuzhiyun 	return ret;
7631*4882a593Smuzhiyun }
7632*4882a593Smuzhiyun #endif /* KEEP_ALIVE */
7633*4882a593Smuzhiyun 
7634*4882a593Smuzhiyun #if defined(PKT_FILTER_SUPPORT) && defined(APF)
7635*4882a593Smuzhiyun static int
wl_cfgvendor_apf_get_capabilities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7636*4882a593Smuzhiyun wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy,
7637*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
7638*4882a593Smuzhiyun {
7639*4882a593Smuzhiyun 	struct net_device *ndev = wdev_to_ndev(wdev);
7640*4882a593Smuzhiyun 	struct sk_buff *skb = NULL;
7641*4882a593Smuzhiyun 	int ret, ver, max_len, mem_needed;
7642*4882a593Smuzhiyun 
7643*4882a593Smuzhiyun 	/* APF version */
7644*4882a593Smuzhiyun 	ver = 0;
7645*4882a593Smuzhiyun 	ret = dhd_dev_apf_get_version(ndev, &ver);
7646*4882a593Smuzhiyun 	if (unlikely(ret)) {
7647*4882a593Smuzhiyun 		WL_ERR(("APF get version failed, ret=%d\n", ret));
7648*4882a593Smuzhiyun 		return ret;
7649*4882a593Smuzhiyun 	}
7650*4882a593Smuzhiyun 
7651*4882a593Smuzhiyun 	/* APF memory size limit */
7652*4882a593Smuzhiyun 	max_len = 0;
7653*4882a593Smuzhiyun 	ret = dhd_dev_apf_get_max_len(ndev, &max_len);
7654*4882a593Smuzhiyun 	if (unlikely(ret)) {
7655*4882a593Smuzhiyun 		WL_ERR(("APF get maximum length failed, ret=%d\n", ret));
7656*4882a593Smuzhiyun 		return ret;
7657*4882a593Smuzhiyun 	}
7658*4882a593Smuzhiyun 
7659*4882a593Smuzhiyun 	mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
7660*4882a593Smuzhiyun 
7661*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
7662*4882a593Smuzhiyun 	if (unlikely(!skb)) {
7663*4882a593Smuzhiyun 		WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
7664*4882a593Smuzhiyun 		return -ENOMEM;
7665*4882a593Smuzhiyun 	}
7666*4882a593Smuzhiyun 
7667*4882a593Smuzhiyun 	ret = nla_put_u32(skb, APF_ATTRIBUTE_VERSION, ver);
7668*4882a593Smuzhiyun 	if (ret < 0) {
7669*4882a593Smuzhiyun 		WL_ERR(("Failed to put APF_ATTRIBUTE_VERSION, ret:%d\n", ret));
7670*4882a593Smuzhiyun 		goto exit;
7671*4882a593Smuzhiyun 	}
7672*4882a593Smuzhiyun 	ret = nla_put_u32(skb, APF_ATTRIBUTE_MAX_LEN, max_len);
7673*4882a593Smuzhiyun 	if (ret < 0) {
7674*4882a593Smuzhiyun 		WL_ERR(("Failed to put APF_ATTRIBUTE_MAX_LEN, ret:%d\n", ret));
7675*4882a593Smuzhiyun 		goto exit;
7676*4882a593Smuzhiyun 	}
7677*4882a593Smuzhiyun 
7678*4882a593Smuzhiyun 	ret = cfg80211_vendor_cmd_reply(skb);
7679*4882a593Smuzhiyun 	if (unlikely(ret)) {
7680*4882a593Smuzhiyun 		WL_ERR(("vendor command reply failed, ret=%d\n", ret));
7681*4882a593Smuzhiyun 	}
7682*4882a593Smuzhiyun 	return ret;
7683*4882a593Smuzhiyun exit:
7684*4882a593Smuzhiyun 	/* Free skb memory */
7685*4882a593Smuzhiyun 	kfree_skb(skb);
7686*4882a593Smuzhiyun 	return ret;
7687*4882a593Smuzhiyun }
7688*4882a593Smuzhiyun 
7689*4882a593Smuzhiyun static int
wl_cfgvendor_apf_set_filter(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7690*4882a593Smuzhiyun wl_cfgvendor_apf_set_filter(struct wiphy *wiphy,
7691*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
7692*4882a593Smuzhiyun {
7693*4882a593Smuzhiyun 	struct net_device *ndev = wdev_to_ndev(wdev);
7694*4882a593Smuzhiyun 	const struct nlattr *iter;
7695*4882a593Smuzhiyun 	u8 *program = NULL;
7696*4882a593Smuzhiyun 	u32 program_len = 0;
7697*4882a593Smuzhiyun 	int ret, tmp, type;
7698*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7699*4882a593Smuzhiyun 
7700*4882a593Smuzhiyun 	if (len <= 0) {
7701*4882a593Smuzhiyun 		WL_ERR(("Invalid len: %d\n", len));
7702*4882a593Smuzhiyun 		ret = -EINVAL;
7703*4882a593Smuzhiyun 		goto exit;
7704*4882a593Smuzhiyun 	}
7705*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, tmp) {
7706*4882a593Smuzhiyun 		type = nla_type(iter);
7707*4882a593Smuzhiyun 		switch (type) {
7708*4882a593Smuzhiyun 			case APF_ATTRIBUTE_PROGRAM_LEN:
7709*4882a593Smuzhiyun 				/* check if the iter value is valid and program_len
7710*4882a593Smuzhiyun 				 * is not already initialized.
7711*4882a593Smuzhiyun 				 */
7712*4882a593Smuzhiyun 				if (nla_len(iter) == sizeof(uint32) && !program_len) {
7713*4882a593Smuzhiyun 					program_len = nla_get_u32(iter);
7714*4882a593Smuzhiyun 				} else {
7715*4882a593Smuzhiyun 					ret = -EINVAL;
7716*4882a593Smuzhiyun 					goto exit;
7717*4882a593Smuzhiyun 				}
7718*4882a593Smuzhiyun 
7719*4882a593Smuzhiyun 				if (program_len > WL_APF_PROGRAM_MAX_SIZE) {
7720*4882a593Smuzhiyun 					WL_ERR(("program len is more than expected len\n"));
7721*4882a593Smuzhiyun 					ret = -EINVAL;
7722*4882a593Smuzhiyun 					goto exit;
7723*4882a593Smuzhiyun 				}
7724*4882a593Smuzhiyun 
7725*4882a593Smuzhiyun 				if (unlikely(!program_len)) {
7726*4882a593Smuzhiyun 					WL_ERR(("zero program length\n"));
7727*4882a593Smuzhiyun 					ret = -EINVAL;
7728*4882a593Smuzhiyun 					goto exit;
7729*4882a593Smuzhiyun 				}
7730*4882a593Smuzhiyun 				break;
7731*4882a593Smuzhiyun 			case APF_ATTRIBUTE_PROGRAM:
7732*4882a593Smuzhiyun 				if (unlikely(program)) {
7733*4882a593Smuzhiyun 					WL_ERR(("program already allocated\n"));
7734*4882a593Smuzhiyun 					ret = -EINVAL;
7735*4882a593Smuzhiyun 					goto exit;
7736*4882a593Smuzhiyun 				}
7737*4882a593Smuzhiyun 				if (unlikely(!program_len)) {
7738*4882a593Smuzhiyun 					WL_ERR(("program len is not set\n"));
7739*4882a593Smuzhiyun 					ret = -EINVAL;
7740*4882a593Smuzhiyun 					goto exit;
7741*4882a593Smuzhiyun 				}
7742*4882a593Smuzhiyun 				if (nla_len(iter) != program_len) {
7743*4882a593Smuzhiyun 					WL_ERR(("program_len is not same\n"));
7744*4882a593Smuzhiyun 					ret = -EINVAL;
7745*4882a593Smuzhiyun 					goto exit;
7746*4882a593Smuzhiyun 				}
7747*4882a593Smuzhiyun 				program = MALLOCZ(cfg->osh, program_len);
7748*4882a593Smuzhiyun 				if (unlikely(!program)) {
7749*4882a593Smuzhiyun 					WL_ERR(("%s: can't allocate %d bytes\n",
7750*4882a593Smuzhiyun 					      __FUNCTION__, program_len));
7751*4882a593Smuzhiyun 					ret = -ENOMEM;
7752*4882a593Smuzhiyun 					goto exit;
7753*4882a593Smuzhiyun 				}
7754*4882a593Smuzhiyun 				memcpy(program, (u8*)nla_data(iter), program_len);
7755*4882a593Smuzhiyun 				break;
7756*4882a593Smuzhiyun 			default:
7757*4882a593Smuzhiyun 				WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
7758*4882a593Smuzhiyun 				ret = -EINVAL;
7759*4882a593Smuzhiyun 				goto exit;
7760*4882a593Smuzhiyun 		}
7761*4882a593Smuzhiyun 	}
7762*4882a593Smuzhiyun 
7763*4882a593Smuzhiyun 	ret = dhd_dev_apf_add_filter(ndev, program, program_len);
7764*4882a593Smuzhiyun 
7765*4882a593Smuzhiyun exit:
7766*4882a593Smuzhiyun 	if (program) {
7767*4882a593Smuzhiyun 		MFREE(cfg->osh, program, program_len);
7768*4882a593Smuzhiyun 	}
7769*4882a593Smuzhiyun 	return ret;
7770*4882a593Smuzhiyun }
7771*4882a593Smuzhiyun #endif /* PKT_FILTER_SUPPORT && APF */
7772*4882a593Smuzhiyun 
7773*4882a593Smuzhiyun #ifdef NDO_CONFIG_SUPPORT
wl_cfgvendor_configure_nd_offload(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7774*4882a593Smuzhiyun static int wl_cfgvendor_configure_nd_offload(struct wiphy *wiphy,
7775*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
7776*4882a593Smuzhiyun {
7777*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7778*4882a593Smuzhiyun 	const struct nlattr *iter;
7779*4882a593Smuzhiyun 	int ret = BCME_OK, rem, type;
7780*4882a593Smuzhiyun 	u8 enable = 0;
7781*4882a593Smuzhiyun 
7782*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
7783*4882a593Smuzhiyun 		type = nla_type(iter);
7784*4882a593Smuzhiyun 		switch (type) {
7785*4882a593Smuzhiyun 			case ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE:
7786*4882a593Smuzhiyun 				enable = nla_get_u8(iter);
7787*4882a593Smuzhiyun 				break;
7788*4882a593Smuzhiyun 			default:
7789*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
7790*4882a593Smuzhiyun 				ret = BCME_BADARG;
7791*4882a593Smuzhiyun 				goto exit;
7792*4882a593Smuzhiyun 		}
7793*4882a593Smuzhiyun 	}
7794*4882a593Smuzhiyun 
7795*4882a593Smuzhiyun 	ret = dhd_dev_ndo_cfg(bcmcfg_to_prmry_ndev(cfg), enable);
7796*4882a593Smuzhiyun 	if (ret < 0) {
7797*4882a593Smuzhiyun 		WL_ERR(("dhd_dev_ndo_cfg() failed: %d\n", ret));
7798*4882a593Smuzhiyun 	}
7799*4882a593Smuzhiyun 
7800*4882a593Smuzhiyun exit:
7801*4882a593Smuzhiyun 	return ret;
7802*4882a593Smuzhiyun }
7803*4882a593Smuzhiyun #endif /* NDO_CONFIG_SUPPORT */
7804*4882a593Smuzhiyun 
7805*4882a593Smuzhiyun /* for kernel >= 4.13 NL80211 wl_cfg80211_set_pmk have to be used. */
7806*4882a593Smuzhiyun #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
wl_cfgvendor_set_pmk(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7807*4882a593Smuzhiyun static int wl_cfgvendor_set_pmk(struct wiphy *wiphy,
7808*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void *data, int len)
7809*4882a593Smuzhiyun {
7810*4882a593Smuzhiyun 	int ret = 0;
7811*4882a593Smuzhiyun 	wsec_pmk_t pmk;
7812*4882a593Smuzhiyun 	const struct nlattr *iter;
7813*4882a593Smuzhiyun 	int rem, type;
7814*4882a593Smuzhiyun 	struct net_device *ndev = wdev_to_ndev(wdev);
7815*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7816*4882a593Smuzhiyun 	struct wl_security *sec;
7817*4882a593Smuzhiyun 
7818*4882a593Smuzhiyun 	nla_for_each_attr(iter, data, len, rem) {
7819*4882a593Smuzhiyun 		type = nla_type(iter);
7820*4882a593Smuzhiyun 		switch (type) {
7821*4882a593Smuzhiyun 			case BRCM_ATTR_DRIVER_KEY_PMK:
7822*4882a593Smuzhiyun 				if (nla_len(iter) > sizeof(pmk.key)) {
7823*4882a593Smuzhiyun 					ret = -EINVAL;
7824*4882a593Smuzhiyun 					goto exit;
7825*4882a593Smuzhiyun 				}
7826*4882a593Smuzhiyun 				pmk.flags = 0;
7827*4882a593Smuzhiyun 				pmk.key_len = htod16(nla_len(iter));
7828*4882a593Smuzhiyun 				bcopy((uint8 *)nla_data(iter), pmk.key, len);
7829*4882a593Smuzhiyun 				break;
7830*4882a593Smuzhiyun 			default:
7831*4882a593Smuzhiyun 				WL_ERR(("Unknown type: %d\n", type));
7832*4882a593Smuzhiyun 				ret = BCME_BADARG;
7833*4882a593Smuzhiyun 				goto exit;
7834*4882a593Smuzhiyun 		}
7835*4882a593Smuzhiyun 	}
7836*4882a593Smuzhiyun 
7837*4882a593Smuzhiyun 	sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
7838*4882a593Smuzhiyun 	if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
7839*4882a593Smuzhiyun 		(sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
7840*4882a593Smuzhiyun 		ret = wldev_iovar_setbuf(ndev, "okc_info_pmk", pmk.key, pmk.key_len, cfg->ioctl_buf,
7841*4882a593Smuzhiyun 			WLC_IOCTL_SMLEN,  &cfg->ioctl_buf_sync);
7842*4882a593Smuzhiyun 		if (ret) {
7843*4882a593Smuzhiyun 			/* could fail in case that 'okc' is not supported */
7844*4882a593Smuzhiyun 			WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
7845*4882a593Smuzhiyun 		}
7846*4882a593Smuzhiyun 	}
7847*4882a593Smuzhiyun 
7848*4882a593Smuzhiyun 	ret = wldev_ioctl_set(ndev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
7849*4882a593Smuzhiyun 	WL_INFORM_MEM(("IOVAR set_pmk ret:%d", ret));
7850*4882a593Smuzhiyun exit:
7851*4882a593Smuzhiyun 	return ret;
7852*4882a593Smuzhiyun }
7853*4882a593Smuzhiyun #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
7854*4882a593Smuzhiyun 
wl_cfgvendor_get_driver_feature(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7855*4882a593Smuzhiyun static int wl_cfgvendor_get_driver_feature(struct wiphy *wiphy,
7856*4882a593Smuzhiyun 	struct wireless_dev *wdev, const void  *data, int len)
7857*4882a593Smuzhiyun {
7858*4882a593Smuzhiyun 	int ret = BCME_OK;
7859*4882a593Smuzhiyun 	u8 supported[(BRCM_WLAN_VENDOR_FEATURES_MAX / 8) + 1] = {0};
7860*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7861*4882a593Smuzhiyun 	dhd_pub_t *dhd_pub = cfg->pub;
7862*4882a593Smuzhiyun 	struct sk_buff *skb;
7863*4882a593Smuzhiyun 	int32 mem_needed;
7864*4882a593Smuzhiyun 
7865*4882a593Smuzhiyun 	mem_needed = VENDOR_REPLY_OVERHEAD + NLA_HDRLEN + sizeof(supported);
7866*4882a593Smuzhiyun 
7867*4882a593Smuzhiyun 	BCM_REFERENCE(dhd_pub);
7868*4882a593Smuzhiyun 
7869*4882a593Smuzhiyun #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
7870*4882a593Smuzhiyun 	if (FW_SUPPORTED(dhd_pub, idsup)) {
7871*4882a593Smuzhiyun 		ret = wl_features_set(supported, sizeof(supported),
7872*4882a593Smuzhiyun 				BRCM_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD);
7873*4882a593Smuzhiyun 	}
7874*4882a593Smuzhiyun #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
7875*4882a593Smuzhiyun 
7876*4882a593Smuzhiyun 	/* Alloc the SKB for vendor_event */
7877*4882a593Smuzhiyun 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
7878*4882a593Smuzhiyun 	if (unlikely(!skb)) {
7879*4882a593Smuzhiyun 		WL_ERR(("skb alloc failed"));
7880*4882a593Smuzhiyun 		ret = BCME_NOMEM;
7881*4882a593Smuzhiyun 		goto exit;
7882*4882a593Smuzhiyun 	}
7883*4882a593Smuzhiyun 
7884*4882a593Smuzhiyun 	ret = nla_put(skb, BRCM_ATTR_DRIVER_FEATURE_FLAGS, sizeof(supported), supported);
7885*4882a593Smuzhiyun 	if (ret) {
7886*4882a593Smuzhiyun 		kfree_skb(skb);
7887*4882a593Smuzhiyun 		goto exit;
7888*4882a593Smuzhiyun 	}
7889*4882a593Smuzhiyun 	ret = cfg80211_vendor_cmd_reply(skb);
7890*4882a593Smuzhiyun exit:
7891*4882a593Smuzhiyun 	return ret;
7892*4882a593Smuzhiyun }
7893*4882a593Smuzhiyun 
7894*4882a593Smuzhiyun #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
7895*4882a593Smuzhiyun #define WL_VENDOR_POLICY_RAW_DATA .policy = VENDOR_CMD_RAW_DATA
7896*4882a593Smuzhiyun #else
7897*4882a593Smuzhiyun #define WL_VENDOR_POLICY_RAW_DATA
7898*4882a593Smuzhiyun #endif /* LINUX_VER >= 5.3 */
7899*4882a593Smuzhiyun 
7900*4882a593Smuzhiyun static const struct wiphy_vendor_command wl_vendor_cmds [] = {
7901*4882a593Smuzhiyun 	{
7902*4882a593Smuzhiyun 		{
7903*4882a593Smuzhiyun 			.vendor_id = OUI_BRCM,
7904*4882a593Smuzhiyun 			.subcmd = BRCM_VENDOR_SCMD_FRAMEBURST
7905*4882a593Smuzhiyun 		},
7906*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7907*4882a593Smuzhiyun 		.doit = wl_cfgvendor_priv_frameburst,
7908*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7909*4882a593Smuzhiyun 	},
7910*4882a593Smuzhiyun 	{
7911*4882a593Smuzhiyun 		{
7912*4882a593Smuzhiyun 			.vendor_id = OUI_BRCM,
7913*4882a593Smuzhiyun 			.subcmd = BRCM_VENDOR_SCMD_MPC
7914*4882a593Smuzhiyun 		},
7915*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7916*4882a593Smuzhiyun 		.doit = wl_cfgvendor_priv_mpc,
7917*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7918*4882a593Smuzhiyun 	},
7919*4882a593Smuzhiyun 	{
7920*4882a593Smuzhiyun 		{
7921*4882a593Smuzhiyun 			.vendor_id = OUI_BRCM,
7922*4882a593Smuzhiyun 			.subcmd = BRCM_VENDOR_SCMD_BAND
7923*4882a593Smuzhiyun 		},
7924*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7925*4882a593Smuzhiyun 		.doit = wl_cfgvendor_priv_band,
7926*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7927*4882a593Smuzhiyun 	},
7928*4882a593Smuzhiyun 	{
7929*4882a593Smuzhiyun 		{
7930*4882a593Smuzhiyun 			.vendor_id = OUI_BRCM,
7931*4882a593Smuzhiyun 			.subcmd = BRCM_VENDOR_SCMD_PRIV_STR
7932*4882a593Smuzhiyun 		},
7933*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7934*4882a593Smuzhiyun 		.doit = wl_cfgvendor_priv_string_handler,
7935*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7936*4882a593Smuzhiyun 	},
7937*4882a593Smuzhiyun #ifdef BCM_PRIV_CMD_SUPPORT
7938*4882a593Smuzhiyun 	{
7939*4882a593Smuzhiyun 		{
7940*4882a593Smuzhiyun 			.vendor_id = OUI_BRCM,
7941*4882a593Smuzhiyun 			.subcmd = BRCM_VENDOR_SCMD_BCM_STR
7942*4882a593Smuzhiyun 		},
7943*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7944*4882a593Smuzhiyun 		.doit = wl_cfgvendor_priv_bcm_handler,
7945*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7946*4882a593Smuzhiyun 	},
7947*4882a593Smuzhiyun #endif /* BCM_PRIV_CMD_SUPPORT */
7948*4882a593Smuzhiyun #ifdef WL_SAE
7949*4882a593Smuzhiyun 	{
7950*4882a593Smuzhiyun 		{
7951*4882a593Smuzhiyun 			.vendor_id = OUI_BRCM,
7952*4882a593Smuzhiyun 			.subcmd = BRCM_VENDOR_SCMD_BCM_PSK
7953*4882a593Smuzhiyun 		},
7954*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7955*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_sae_password,
7956*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7957*4882a593Smuzhiyun 	},
7958*4882a593Smuzhiyun #endif /* WL_SAE */
7959*4882a593Smuzhiyun #ifdef GSCAN_SUPPORT
7960*4882a593Smuzhiyun 	{
7961*4882a593Smuzhiyun 		{
7962*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
7963*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
7964*4882a593Smuzhiyun 		},
7965*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7966*4882a593Smuzhiyun 		.doit = wl_cfgvendor_gscan_get_capabilities,
7967*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7968*4882a593Smuzhiyun 	},
7969*4882a593Smuzhiyun 	{
7970*4882a593Smuzhiyun 		{
7971*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
7972*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_SET_CONFIG
7973*4882a593Smuzhiyun 		},
7974*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7975*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_scan_cfg,
7976*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7977*4882a593Smuzhiyun 	},
7978*4882a593Smuzhiyun 	{
7979*4882a593Smuzhiyun 		{
7980*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
7981*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
7982*4882a593Smuzhiyun 		},
7983*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7984*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_batch_scan_cfg,
7985*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7986*4882a593Smuzhiyun 	},
7987*4882a593Smuzhiyun 	{
7988*4882a593Smuzhiyun 		{
7989*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
7990*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
7991*4882a593Smuzhiyun 		},
7992*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
7993*4882a593Smuzhiyun 		.doit = wl_cfgvendor_initiate_gscan,
7994*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
7995*4882a593Smuzhiyun 	},
7996*4882a593Smuzhiyun 	{
7997*4882a593Smuzhiyun 		{
7998*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
7999*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
8000*4882a593Smuzhiyun 		},
8001*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8002*4882a593Smuzhiyun 		.doit = wl_cfgvendor_enable_full_scan_result,
8003*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8004*4882a593Smuzhiyun 	},
8005*4882a593Smuzhiyun 	{
8006*4882a593Smuzhiyun 		{
8007*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8008*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_SET_HOTLIST
8009*4882a593Smuzhiyun 		},
8010*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8011*4882a593Smuzhiyun 		.doit = wl_cfgvendor_hotlist_cfg,
8012*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8013*4882a593Smuzhiyun 	},
8014*4882a593Smuzhiyun 	{
8015*4882a593Smuzhiyun 		{
8016*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8017*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
8018*4882a593Smuzhiyun 		},
8019*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8020*4882a593Smuzhiyun 		.doit = wl_cfgvendor_gscan_get_batch_results,
8021*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8022*4882a593Smuzhiyun 	},
8023*4882a593Smuzhiyun #endif /* GSCAN_SUPPORT */
8024*4882a593Smuzhiyun #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
8025*4882a593Smuzhiyun 	{
8026*4882a593Smuzhiyun 		{
8027*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8028*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
8029*4882a593Smuzhiyun 		},
8030*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8031*4882a593Smuzhiyun 		.doit = wl_cfgvendor_gscan_get_channel_list,
8032*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8033*4882a593Smuzhiyun 	},
8034*4882a593Smuzhiyun #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
8035*4882a593Smuzhiyun #ifdef RTT_SUPPORT
8036*4882a593Smuzhiyun 	{
8037*4882a593Smuzhiyun 		{
8038*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8039*4882a593Smuzhiyun 			.subcmd = RTT_SUBCMD_SET_CONFIG
8040*4882a593Smuzhiyun 		},
8041*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8042*4882a593Smuzhiyun 		.doit = wl_cfgvendor_rtt_set_config,
8043*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8044*4882a593Smuzhiyun 	},
8045*4882a593Smuzhiyun 	{
8046*4882a593Smuzhiyun 		{
8047*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8048*4882a593Smuzhiyun 			.subcmd = RTT_SUBCMD_CANCEL_CONFIG
8049*4882a593Smuzhiyun 		},
8050*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8051*4882a593Smuzhiyun 		.doit = wl_cfgvendor_rtt_cancel_config,
8052*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8053*4882a593Smuzhiyun 	},
8054*4882a593Smuzhiyun 	{
8055*4882a593Smuzhiyun 		{
8056*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8057*4882a593Smuzhiyun 			.subcmd = RTT_SUBCMD_GETCAPABILITY
8058*4882a593Smuzhiyun 		},
8059*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8060*4882a593Smuzhiyun 		.doit = wl_cfgvendor_rtt_get_capability,
8061*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8062*4882a593Smuzhiyun 	},
8063*4882a593Smuzhiyun 	{
8064*4882a593Smuzhiyun 		{
8065*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8066*4882a593Smuzhiyun 			.subcmd = RTT_SUBCMD_GETAVAILCHANNEL
8067*4882a593Smuzhiyun 		},
8068*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8069*4882a593Smuzhiyun 		.doit = wl_cfgvendor_rtt_get_responder_info,
8070*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8071*4882a593Smuzhiyun 	},
8072*4882a593Smuzhiyun 	{
8073*4882a593Smuzhiyun 		{
8074*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8075*4882a593Smuzhiyun 			.subcmd = RTT_SUBCMD_SET_RESPONDER
8076*4882a593Smuzhiyun 		},
8077*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8078*4882a593Smuzhiyun 		.doit = wl_cfgvendor_rtt_set_responder,
8079*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8080*4882a593Smuzhiyun 	},
8081*4882a593Smuzhiyun 	{
8082*4882a593Smuzhiyun 		{
8083*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8084*4882a593Smuzhiyun 			.subcmd = RTT_SUBCMD_CANCEL_RESPONDER
8085*4882a593Smuzhiyun 		},
8086*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8087*4882a593Smuzhiyun 		.doit = wl_cfgvendor_rtt_cancel_responder,
8088*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8089*4882a593Smuzhiyun 	},
8090*4882a593Smuzhiyun #endif /* RTT_SUPPORT */
8091*4882a593Smuzhiyun 	{
8092*4882a593Smuzhiyun 		{
8093*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8094*4882a593Smuzhiyun 			.subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
8095*4882a593Smuzhiyun 		},
8096*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8097*4882a593Smuzhiyun 		.doit = wl_cfgvendor_get_feature_set,
8098*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8099*4882a593Smuzhiyun 	},
8100*4882a593Smuzhiyun 	{
8101*4882a593Smuzhiyun 		{
8102*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8103*4882a593Smuzhiyun 			.subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
8104*4882a593Smuzhiyun 		},
8105*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8106*4882a593Smuzhiyun 		.doit = wl_cfgvendor_get_feature_set_matrix,
8107*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8108*4882a593Smuzhiyun 	},
8109*4882a593Smuzhiyun 	{
8110*4882a593Smuzhiyun 		{
8111*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8112*4882a593Smuzhiyun 			.subcmd = ANDR_WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI
8113*4882a593Smuzhiyun 		},
8114*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8115*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_pno_rand_mac_oui,
8116*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8117*4882a593Smuzhiyun 	},
8118*4882a593Smuzhiyun #ifdef CUSTOM_FORCE_NODFS_FLAG
8119*4882a593Smuzhiyun 	{
8120*4882a593Smuzhiyun 		{
8121*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8122*4882a593Smuzhiyun 			.subcmd = ANDR_WIFI_NODFS_CHANNELS
8123*4882a593Smuzhiyun 		},
8124*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8125*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_nodfs_flag,
8126*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8127*4882a593Smuzhiyun 	},
8128*4882a593Smuzhiyun #endif /* CUSTOM_FORCE_NODFS_FLAG */
8129*4882a593Smuzhiyun 	{
8130*4882a593Smuzhiyun 		{
8131*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8132*4882a593Smuzhiyun 			.subcmd = ANDR_WIFI_SET_COUNTRY
8133*4882a593Smuzhiyun 		},
8134*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8135*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_country,
8136*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8137*4882a593Smuzhiyun 	},
8138*4882a593Smuzhiyun #ifdef LINKSTAT_SUPPORT
8139*4882a593Smuzhiyun 	{
8140*4882a593Smuzhiyun 		{
8141*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8142*4882a593Smuzhiyun 			.subcmd = LSTATS_SUBCMD_GET_INFO
8143*4882a593Smuzhiyun 		},
8144*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8145*4882a593Smuzhiyun 		.doit = wl_cfgvendor_lstats_get_info,
8146*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8147*4882a593Smuzhiyun 	},
8148*4882a593Smuzhiyun #endif /* LINKSTAT_SUPPORT */
8149*4882a593Smuzhiyun 
8150*4882a593Smuzhiyun #ifdef GSCAN_SUPPORT
8151*4882a593Smuzhiyun 	{
8152*4882a593Smuzhiyun 		{
8153*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8154*4882a593Smuzhiyun 			.subcmd = GSCAN_SUBCMD_SET_EPNO_SSID
8155*4882a593Smuzhiyun 		},
8156*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8157*4882a593Smuzhiyun 		.doit = wl_cfgvendor_epno_cfg,
8158*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8159*4882a593Smuzhiyun 	},
8160*4882a593Smuzhiyun 	{
8161*4882a593Smuzhiyun 		{
8162*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8163*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
8164*4882a593Smuzhiyun 		},
8165*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8166*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_lazy_roam_cfg,
8167*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8168*4882a593Smuzhiyun 	},
8169*4882a593Smuzhiyun 	{
8170*4882a593Smuzhiyun 		{
8171*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8172*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM
8173*4882a593Smuzhiyun 		},
8174*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8175*4882a593Smuzhiyun 		.doit = wl_cfgvendor_enable_lazy_roam,
8176*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8177*4882a593Smuzhiyun 
8178*4882a593Smuzhiyun 	},
8179*4882a593Smuzhiyun 	{
8180*4882a593Smuzhiyun 		{
8181*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8182*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_SET_BSSID_PREF
8183*4882a593Smuzhiyun 		},
8184*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8185*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_bssid_pref,
8186*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8187*4882a593Smuzhiyun 
8188*4882a593Smuzhiyun 	},
8189*4882a593Smuzhiyun #endif /* GSCAN_SUPPORT */
8190*4882a593Smuzhiyun #if defined(GSCAN_SUPPORT) || defined(ROAMEXP_SUPPORT)
8191*4882a593Smuzhiyun 	{
8192*4882a593Smuzhiyun 		{
8193*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8194*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST
8195*4882a593Smuzhiyun 		},
8196*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8197*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_ssid_whitelist,
8198*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8199*4882a593Smuzhiyun 
8200*4882a593Smuzhiyun 	},
8201*4882a593Smuzhiyun 	{
8202*4882a593Smuzhiyun 		{
8203*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8204*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST
8205*4882a593Smuzhiyun 		},
8206*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8207*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_bssid_blacklist,
8208*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8209*4882a593Smuzhiyun 	},
8210*4882a593Smuzhiyun #endif /* GSCAN_SUPPORT || ROAMEXP_SUPPORT */
8211*4882a593Smuzhiyun #ifdef ROAMEXP_SUPPORT
8212*4882a593Smuzhiyun 	{
8213*4882a593Smuzhiyun 		{
8214*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8215*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_FW_ROAM_POLICY
8216*4882a593Smuzhiyun 		},
8217*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8218*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_fw_roaming_state,
8219*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8220*4882a593Smuzhiyun 	},
8221*4882a593Smuzhiyun 	{
8222*4882a593Smuzhiyun 		{
8223*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8224*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_ROAM_CAPABILITY
8225*4882a593Smuzhiyun 		},
8226*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8227*4882a593Smuzhiyun 		.doit = wl_cfgvendor_fw_roam_get_capability,
8228*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8229*4882a593Smuzhiyun 	},
8230*4882a593Smuzhiyun #endif /* ROAMEXP_SUPPORT */
8231*4882a593Smuzhiyun 	{
8232*4882a593Smuzhiyun 		{
8233*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8234*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_VER
8235*4882a593Smuzhiyun 		},
8236*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8237*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_get_version,
8238*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8239*4882a593Smuzhiyun 	},
8240*4882a593Smuzhiyun #ifdef DHD_LOG_DUMP
8241*4882a593Smuzhiyun 	{
8242*4882a593Smuzhiyun 		{
8243*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8244*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_FILE_DUMP_BUF
8245*4882a593Smuzhiyun 		},
8246*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8247*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_file_dump,
8248*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8249*4882a593Smuzhiyun 	},
8250*4882a593Smuzhiyun #endif /* DHD_LOG_DUMP */
8251*4882a593Smuzhiyun 	{
8252*4882a593Smuzhiyun 		{
8253*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8254*4882a593Smuzhiyun 			.subcmd = DEBUG_TRIGGER_MEM_DUMP
8255*4882a593Smuzhiyun 		},
8256*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8257*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_trigger_mem_dump,
8258*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8259*4882a593Smuzhiyun 	},
8260*4882a593Smuzhiyun 	{
8261*4882a593Smuzhiyun 		{
8262*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8263*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_MEM_DUMP
8264*4882a593Smuzhiyun 		},
8265*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8266*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_get_mem_dump,
8267*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8268*4882a593Smuzhiyun 	},
8269*4882a593Smuzhiyun 	{
8270*4882a593Smuzhiyun 		{
8271*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8272*4882a593Smuzhiyun 			.subcmd = DEBUG_START_LOGGING
8273*4882a593Smuzhiyun 		},
8274*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8275*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_start_logging,
8276*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8277*4882a593Smuzhiyun 	},
8278*4882a593Smuzhiyun 	{
8279*4882a593Smuzhiyun 		{
8280*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8281*4882a593Smuzhiyun 			.subcmd = DEBUG_RESET_LOGGING
8282*4882a593Smuzhiyun 		},
8283*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8284*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_reset_logging,
8285*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8286*4882a593Smuzhiyun 	},
8287*4882a593Smuzhiyun 	{
8288*4882a593Smuzhiyun 		{
8289*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8290*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_RING_STATUS
8291*4882a593Smuzhiyun 		},
8292*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8293*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_get_ring_status,
8294*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8295*4882a593Smuzhiyun 	},
8296*4882a593Smuzhiyun 	{
8297*4882a593Smuzhiyun 		{
8298*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8299*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_RING_DATA
8300*4882a593Smuzhiyun 		},
8301*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8302*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_get_ring_data,
8303*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8304*4882a593Smuzhiyun 	},
8305*4882a593Smuzhiyun 	{
8306*4882a593Smuzhiyun 		{
8307*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8308*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_FEATURE
8309*4882a593Smuzhiyun 		},
8310*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8311*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_get_feature,
8312*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8313*4882a593Smuzhiyun 	},
8314*4882a593Smuzhiyun #ifdef DBG_PKT_MON
8315*4882a593Smuzhiyun 	{
8316*4882a593Smuzhiyun 		{
8317*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8318*4882a593Smuzhiyun 			.subcmd = DEBUG_START_PKT_FATE_MONITORING
8319*4882a593Smuzhiyun 		},
8320*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8321*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_start_pkt_fate_monitoring,
8322*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8323*4882a593Smuzhiyun 	},
8324*4882a593Smuzhiyun 	{
8325*4882a593Smuzhiyun 		{
8326*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8327*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_TX_PKT_FATES
8328*4882a593Smuzhiyun 		},
8329*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8330*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_get_tx_pkt_fates,
8331*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8332*4882a593Smuzhiyun 	},
8333*4882a593Smuzhiyun 	{
8334*4882a593Smuzhiyun 		{
8335*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8336*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_RX_PKT_FATES
8337*4882a593Smuzhiyun 		},
8338*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8339*4882a593Smuzhiyun 		.doit = wl_cfgvendor_dbg_get_rx_pkt_fates,
8340*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8341*4882a593Smuzhiyun 	},
8342*4882a593Smuzhiyun #endif /* DBG_PKT_MON */
8343*4882a593Smuzhiyun #ifdef KEEP_ALIVE
8344*4882a593Smuzhiyun 	{
8345*4882a593Smuzhiyun 		{
8346*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8347*4882a593Smuzhiyun 			.subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
8348*4882a593Smuzhiyun 		},
8349*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8350*4882a593Smuzhiyun 		.doit = wl_cfgvendor_start_mkeep_alive,
8351*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8352*4882a593Smuzhiyun 	},
8353*4882a593Smuzhiyun 	{
8354*4882a593Smuzhiyun 		{
8355*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8356*4882a593Smuzhiyun 			.subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
8357*4882a593Smuzhiyun 		},
8358*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8359*4882a593Smuzhiyun 		.doit = wl_cfgvendor_stop_mkeep_alive,
8360*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8361*4882a593Smuzhiyun 	},
8362*4882a593Smuzhiyun #endif /* KEEP_ALIVE */
8363*4882a593Smuzhiyun #ifdef WL_NAN
8364*4882a593Smuzhiyun 	{
8365*4882a593Smuzhiyun 		{
8366*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8367*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_ENABLE
8368*4882a593Smuzhiyun 		},
8369*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8370*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_start_handler,
8371*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8372*4882a593Smuzhiyun 	},
8373*4882a593Smuzhiyun 	{
8374*4882a593Smuzhiyun 		{
8375*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8376*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_DISABLE
8377*4882a593Smuzhiyun 		},
8378*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8379*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_stop_handler,
8380*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8381*4882a593Smuzhiyun 	},
8382*4882a593Smuzhiyun 	{
8383*4882a593Smuzhiyun 		{
8384*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8385*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_CONFIG
8386*4882a593Smuzhiyun 		},
8387*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8388*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_config_handler,
8389*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8390*4882a593Smuzhiyun 	},
8391*4882a593Smuzhiyun 	{
8392*4882a593Smuzhiyun 		{
8393*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8394*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_REQUEST_PUBLISH
8395*4882a593Smuzhiyun 		},
8396*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8397*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_req_publish,
8398*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8399*4882a593Smuzhiyun 	},
8400*4882a593Smuzhiyun 	{
8401*4882a593Smuzhiyun 		{
8402*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8403*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_REQUEST_SUBSCRIBE
8404*4882a593Smuzhiyun 		},
8405*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8406*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_req_subscribe,
8407*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8408*4882a593Smuzhiyun 	},
8409*4882a593Smuzhiyun 	{
8410*4882a593Smuzhiyun 		{
8411*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8412*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_CANCEL_PUBLISH
8413*4882a593Smuzhiyun 		},
8414*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8415*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_cancel_publish,
8416*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8417*4882a593Smuzhiyun 	},
8418*4882a593Smuzhiyun 	{
8419*4882a593Smuzhiyun 		{
8420*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8421*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_CANCEL_SUBSCRIBE
8422*4882a593Smuzhiyun 		},
8423*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8424*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_cancel_subscribe,
8425*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8426*4882a593Smuzhiyun 	},
8427*4882a593Smuzhiyun 	{
8428*4882a593Smuzhiyun 		{
8429*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8430*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_TRANSMIT
8431*4882a593Smuzhiyun 		},
8432*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8433*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_transmit,
8434*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8435*4882a593Smuzhiyun 	},
8436*4882a593Smuzhiyun 	{
8437*4882a593Smuzhiyun 		{
8438*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8439*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_GET_CAPABILITIES
8440*4882a593Smuzhiyun 		},
8441*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8442*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_get_capablities,
8443*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8444*4882a593Smuzhiyun 	},
8445*4882a593Smuzhiyun 
8446*4882a593Smuzhiyun 	{
8447*4882a593Smuzhiyun 		{
8448*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8449*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE
8450*4882a593Smuzhiyun 		},
8451*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8452*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_data_path_iface_create,
8453*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8454*4882a593Smuzhiyun 	},
8455*4882a593Smuzhiyun 	{
8456*4882a593Smuzhiyun 		{
8457*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8458*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE
8459*4882a593Smuzhiyun 		},
8460*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8461*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_data_path_iface_delete,
8462*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8463*4882a593Smuzhiyun 	},
8464*4882a593Smuzhiyun 	{
8465*4882a593Smuzhiyun 		{
8466*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8467*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_REQUEST
8468*4882a593Smuzhiyun 		},
8469*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8470*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_data_path_request,
8471*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8472*4882a593Smuzhiyun 	},
8473*4882a593Smuzhiyun 	{
8474*4882a593Smuzhiyun 		{
8475*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8476*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_RESPONSE
8477*4882a593Smuzhiyun 		},
8478*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8479*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_data_path_response,
8480*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8481*4882a593Smuzhiyun 	},
8482*4882a593Smuzhiyun 	{
8483*4882a593Smuzhiyun 		{
8484*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8485*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_END
8486*4882a593Smuzhiyun 		},
8487*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8488*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_data_path_end,
8489*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8490*4882a593Smuzhiyun 	},
8491*4882a593Smuzhiyun #ifdef WL_NAN_DISC_CACHE
8492*4882a593Smuzhiyun 	{
8493*4882a593Smuzhiyun 		{
8494*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8495*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_SEC_INFO
8496*4882a593Smuzhiyun 		},
8497*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8498*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_data_path_sec_info,
8499*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8500*4882a593Smuzhiyun 	},
8501*4882a593Smuzhiyun #endif /* WL_NAN_DISC_CACHE */
8502*4882a593Smuzhiyun 	{
8503*4882a593Smuzhiyun 		{
8504*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8505*4882a593Smuzhiyun 			.subcmd = NAN_WIFI_SUBCMD_VERSION_INFO
8506*4882a593Smuzhiyun 		},
8507*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8508*4882a593Smuzhiyun 		.doit = wl_cfgvendor_nan_version_info,
8509*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8510*4882a593Smuzhiyun 	},
8511*4882a593Smuzhiyun #endif /* WL_NAN */
8512*4882a593Smuzhiyun #if defined(PKT_FILTER_SUPPORT) && defined(APF)
8513*4882a593Smuzhiyun 	{
8514*4882a593Smuzhiyun 		{
8515*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8516*4882a593Smuzhiyun 			.subcmd = APF_SUBCMD_GET_CAPABILITIES
8517*4882a593Smuzhiyun 		},
8518*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8519*4882a593Smuzhiyun 		.doit = wl_cfgvendor_apf_get_capabilities,
8520*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8521*4882a593Smuzhiyun 	},
8522*4882a593Smuzhiyun 
8523*4882a593Smuzhiyun 	{
8524*4882a593Smuzhiyun 		{
8525*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8526*4882a593Smuzhiyun 			.subcmd = APF_SUBCMD_SET_FILTER
8527*4882a593Smuzhiyun 		},
8528*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8529*4882a593Smuzhiyun 		.doit = wl_cfgvendor_apf_set_filter,
8530*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8531*4882a593Smuzhiyun 	},
8532*4882a593Smuzhiyun #endif /* PKT_FILTER_SUPPORT && APF */
8533*4882a593Smuzhiyun #ifdef NDO_CONFIG_SUPPORT
8534*4882a593Smuzhiyun 	{
8535*4882a593Smuzhiyun 		{
8536*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8537*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_CONFIG_ND_OFFLOAD
8538*4882a593Smuzhiyun 		},
8539*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8540*4882a593Smuzhiyun 		.doit = wl_cfgvendor_configure_nd_offload,
8541*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8542*4882a593Smuzhiyun 	},
8543*4882a593Smuzhiyun #endif /* NDO_CONFIG_SUPPORT */
8544*4882a593Smuzhiyun #ifdef RSSI_MONITOR_SUPPORT
8545*4882a593Smuzhiyun 	{
8546*4882a593Smuzhiyun 		{
8547*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8548*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR
8549*4882a593Smuzhiyun 		},
8550*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8551*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_rssi_monitor,
8552*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8553*4882a593Smuzhiyun 	},
8554*4882a593Smuzhiyun #endif /* RSSI_MONITOR_SUPPORT */
8555*4882a593Smuzhiyun #ifdef DHD_WAKE_STATUS
8556*4882a593Smuzhiyun 	{
8557*4882a593Smuzhiyun 		{
8558*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8559*4882a593Smuzhiyun 			.subcmd = DEBUG_GET_WAKE_REASON_STATS
8560*4882a593Smuzhiyun 		},
8561*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8562*4882a593Smuzhiyun 		.doit = wl_cfgvendor_get_wake_reason_stats,
8563*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8564*4882a593Smuzhiyun 	},
8565*4882a593Smuzhiyun #endif /* DHD_WAKE_STATUS */
8566*4882a593Smuzhiyun #ifdef DHDTCPACK_SUPPRESS
8567*4882a593Smuzhiyun 	{
8568*4882a593Smuzhiyun 		{
8569*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8570*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_CONFIG_TCPACK_SUP
8571*4882a593Smuzhiyun 		},
8572*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8573*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_tcpack_sup_mode,
8574*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8575*4882a593Smuzhiyun 	},
8576*4882a593Smuzhiyun #endif /* DHDTCPACK_SUPPRESS */
8577*4882a593Smuzhiyun #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
8578*4882a593Smuzhiyun 	{
8579*4882a593Smuzhiyun 		{
8580*4882a593Smuzhiyun 			.vendor_id = OUI_BRCM,
8581*4882a593Smuzhiyun 			.subcmd = BRCM_VENDOR_SCMD_SET_PMK
8582*4882a593Smuzhiyun 		},
8583*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8584*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_pmk,
8585*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8586*4882a593Smuzhiyun 	},
8587*4882a593Smuzhiyun #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
8588*4882a593Smuzhiyun 	{
8589*4882a593Smuzhiyun 		{
8590*4882a593Smuzhiyun 			.vendor_id = OUI_BRCM,
8591*4882a593Smuzhiyun 			.subcmd = BRCM_VENDOR_SCMD_GET_FEATURES
8592*4882a593Smuzhiyun 		},
8593*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8594*4882a593Smuzhiyun 		.doit = wl_cfgvendor_get_driver_feature,
8595*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8596*4882a593Smuzhiyun 	},
8597*4882a593Smuzhiyun #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT)
8598*4882a593Smuzhiyun 	{
8599*4882a593Smuzhiyun 		{
8600*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8601*4882a593Smuzhiyun 			.subcmd = DEBUG_FILE_DUMP_DONE_IND
8602*4882a593Smuzhiyun 		},
8603*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8604*4882a593Smuzhiyun 		.doit = wl_cfgvendor_notify_dump_completion,
8605*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8606*4882a593Smuzhiyun 	},
8607*4882a593Smuzhiyun #endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */
8608*4882a593Smuzhiyun #if defined(WL_CFG80211)
8609*4882a593Smuzhiyun 	{
8610*4882a593Smuzhiyun 		{
8611*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8612*4882a593Smuzhiyun 			.subcmd = DEBUG_SET_HAL_START
8613*4882a593Smuzhiyun 		},
8614*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8615*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_hal_started,
8616*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8617*4882a593Smuzhiyun 	},
8618*4882a593Smuzhiyun 	{
8619*4882a593Smuzhiyun 		{
8620*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8621*4882a593Smuzhiyun 			.subcmd = DEBUG_SET_HAL_STOP
8622*4882a593Smuzhiyun 		},
8623*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8624*4882a593Smuzhiyun 		.doit = wl_cfgvendor_stop_hal,
8625*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8626*4882a593Smuzhiyun 	},
8627*4882a593Smuzhiyun #endif /* WL_CFG80211 */
8628*4882a593Smuzhiyun 	{
8629*4882a593Smuzhiyun 		{
8630*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8631*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_SET_LATENCY_MODE
8632*4882a593Smuzhiyun 		},
8633*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8634*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_latency_mode,
8635*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8636*4882a593Smuzhiyun 	},
8637*4882a593Smuzhiyun 	{
8638*4882a593Smuzhiyun 		{
8639*4882a593Smuzhiyun 			.vendor_id = OUI_GOOGLE,
8640*4882a593Smuzhiyun 			.subcmd = WIFI_SUBCMD_TX_POWER_SCENARIO
8641*4882a593Smuzhiyun 		},
8642*4882a593Smuzhiyun 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
8643*4882a593Smuzhiyun 		.doit = wl_cfgvendor_set_tx_power_scenario,
8644*4882a593Smuzhiyun 		WL_VENDOR_POLICY_RAW_DATA
8645*4882a593Smuzhiyun 	}
8646*4882a593Smuzhiyun 
8647*4882a593Smuzhiyun };
8648*4882a593Smuzhiyun 
8649*4882a593Smuzhiyun static const struct  nl80211_vendor_cmd_info wl_vendor_events [] = {
8650*4882a593Smuzhiyun 		{ OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
8651*4882a593Smuzhiyun 		{ OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
8652*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
8653*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
8654*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
8655*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
8656*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
8657*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
8658*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT },
8659*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
8660*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
8661*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
8662*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
8663*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
8664*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT },
8665*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_ENABLED},
8666*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DISABLED},
8667*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH},
8668*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_REPLIED},
8669*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_PUBLISH_TERMINATED},
8670*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED},
8671*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DE_EVENT},
8672*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_FOLLOWUP},
8673*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND},
8674*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_REQUEST},
8675*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_CONFIRMATION},
8676*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_END},
8677*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_BEACON},
8678*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_SDF},
8679*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_TCA},
8680*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH},
8681*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_UNKNOWN},
8682*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_ROAM_EVENT_START},
8683*4882a593Smuzhiyun 		{ OUI_BRCM, BRCM_VENDOR_EVENT_HANGED},
8684*4882a593Smuzhiyun 		{ OUI_BRCM, BRCM_VENDOR_EVENT_SAE_KEY},
8685*4882a593Smuzhiyun 		{ OUI_BRCM, BRCM_VENDOR_EVENT_BEACON_RECV},
8686*4882a593Smuzhiyun 		{ OUI_BRCM, BRCM_VENDOR_EVENT_PORT_AUTHORIZED},
8687*4882a593Smuzhiyun 		{ OUI_GOOGLE, GOOGLE_FILE_DUMP_EVENT },
8688*4882a593Smuzhiyun 		{ OUI_BRCM, BRCM_VENDOR_EVENT_CU},
8689*4882a593Smuzhiyun 		{ OUI_BRCM, BRCM_VENDOR_EVENT_WIPS}
8690*4882a593Smuzhiyun };
8691*4882a593Smuzhiyun 
wl_cfgvendor_attach(struct wiphy * wiphy,dhd_pub_t * dhd)8692*4882a593Smuzhiyun int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd)
8693*4882a593Smuzhiyun {
8694*4882a593Smuzhiyun 
8695*4882a593Smuzhiyun 	WL_INFORM_MEM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
8696*4882a593Smuzhiyun 		NL80211_CMD_VENDOR));
8697*4882a593Smuzhiyun 
8698*4882a593Smuzhiyun 	wiphy->vendor_commands	= wl_vendor_cmds;
8699*4882a593Smuzhiyun 	wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
8700*4882a593Smuzhiyun 	wiphy->vendor_events	= wl_vendor_events;
8701*4882a593Smuzhiyun 	wiphy->n_vendor_events	= ARRAY_SIZE(wl_vendor_events);
8702*4882a593Smuzhiyun 
8703*4882a593Smuzhiyun #ifdef DEBUGABILITY
8704*4882a593Smuzhiyun 	dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
8705*4882a593Smuzhiyun 	dhd_os_dbg_register_callback(DHD_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
8706*4882a593Smuzhiyun #endif /* DEBUGABILITY */
8707*4882a593Smuzhiyun #ifdef DHD_LOG_DUMP
8708*4882a593Smuzhiyun 	dhd_os_dbg_register_urgent_notifier(dhd, wl_cfgvendor_dbg_send_file_dump_evt);
8709*4882a593Smuzhiyun #endif /* DHD_LOG_DUMP */
8710*4882a593Smuzhiyun 
8711*4882a593Smuzhiyun 	return 0;
8712*4882a593Smuzhiyun }
8713*4882a593Smuzhiyun 
wl_cfgvendor_detach(struct wiphy * wiphy)8714*4882a593Smuzhiyun int wl_cfgvendor_detach(struct wiphy *wiphy)
8715*4882a593Smuzhiyun {
8716*4882a593Smuzhiyun 	WL_INFORM_MEM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
8717*4882a593Smuzhiyun 
8718*4882a593Smuzhiyun 	wiphy->vendor_commands  = NULL;
8719*4882a593Smuzhiyun 	wiphy->vendor_events    = NULL;
8720*4882a593Smuzhiyun 	wiphy->n_vendor_commands = 0;
8721*4882a593Smuzhiyun 	wiphy->n_vendor_events  = 0;
8722*4882a593Smuzhiyun 
8723*4882a593Smuzhiyun 	return 0;
8724*4882a593Smuzhiyun }
8725*4882a593Smuzhiyun #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
8726*4882a593Smuzhiyun 
8727*4882a593Smuzhiyun #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
8728*4882a593Smuzhiyun void
wl_cfgvendor_send_hang_event(struct net_device * dev,u16 reason,char * string,int hang_info_cnt)8729*4882a593Smuzhiyun wl_cfgvendor_send_hang_event(struct net_device *dev, u16 reason, char *string, int hang_info_cnt)
8730*4882a593Smuzhiyun {
8731*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
8732*4882a593Smuzhiyun 	struct wiphy *wiphy;
8733*4882a593Smuzhiyun 	char *hang_info;
8734*4882a593Smuzhiyun 	int len = 0;
8735*4882a593Smuzhiyun 	int bytes_written;
8736*4882a593Smuzhiyun 	uint32 dummy_data = 0;
8737*4882a593Smuzhiyun 	int reason_hang_info = 0;
8738*4882a593Smuzhiyun 	int cnt = 0;
8739*4882a593Smuzhiyun 	dhd_pub_t *dhd;
8740*4882a593Smuzhiyun 	int hang_reason_mismatch = FALSE;
8741*4882a593Smuzhiyun 
8742*4882a593Smuzhiyun 	if (!cfg || !cfg->wdev) {
8743*4882a593Smuzhiyun 		WL_ERR(("cfg=%p wdev=%p\n", cfg, (cfg ? cfg->wdev : NULL)));
8744*4882a593Smuzhiyun 		return;
8745*4882a593Smuzhiyun 	}
8746*4882a593Smuzhiyun 
8747*4882a593Smuzhiyun 	wiphy = cfg->wdev->wiphy;
8748*4882a593Smuzhiyun 
8749*4882a593Smuzhiyun 	if (!wiphy) {
8750*4882a593Smuzhiyun 		WL_ERR(("wiphy is NULL\n"));
8751*4882a593Smuzhiyun 		return;
8752*4882a593Smuzhiyun 	}
8753*4882a593Smuzhiyun 
8754*4882a593Smuzhiyun 	hang_info = MALLOCZ(cfg->osh, VENDOR_SEND_HANG_EXT_INFO_LEN);
8755*4882a593Smuzhiyun 	if (hang_info == NULL) {
8756*4882a593Smuzhiyun 		WL_ERR(("alloc hang_info failed\n"));
8757*4882a593Smuzhiyun 		return;
8758*4882a593Smuzhiyun 	}
8759*4882a593Smuzhiyun 
8760*4882a593Smuzhiyun 	dhd = (dhd_pub_t *)(cfg->pub);
8761*4882a593Smuzhiyun 
8762*4882a593Smuzhiyun #ifdef WL_BCNRECV
8763*4882a593Smuzhiyun 	/* check fakeapscan in progress then stop scan */
8764*4882a593Smuzhiyun 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
8765*4882a593Smuzhiyun 		wl_android_bcnrecv_stop(dev, WL_BCNRECV_HANG);
8766*4882a593Smuzhiyun 	}
8767*4882a593Smuzhiyun #endif /* WL_BCNRECV */
8768*4882a593Smuzhiyun 	sscanf(string, "%d", &reason_hang_info);
8769*4882a593Smuzhiyun 	bytes_written = 0;
8770*4882a593Smuzhiyun 	len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
8771*4882a593Smuzhiyun 	if (strlen(string) == 0 || (reason_hang_info != reason)) {
8772*4882a593Smuzhiyun 		WL_ERR(("hang reason mismatch: string len %d reason_hang_info %d\n",
8773*4882a593Smuzhiyun 			(int)strlen(string), reason_hang_info));
8774*4882a593Smuzhiyun 		hang_reason_mismatch = TRUE;
8775*4882a593Smuzhiyun 		if (dhd) {
8776*4882a593Smuzhiyun 			get_debug_dump_time(dhd->debug_dump_time_hang_str);
8777*4882a593Smuzhiyun 			copy_debug_dump_time(dhd->debug_dump_time_str,
8778*4882a593Smuzhiyun 					dhd->debug_dump_time_hang_str);
8779*4882a593Smuzhiyun 		}
8780*4882a593Smuzhiyun 		bytes_written += scnprintf(&hang_info[bytes_written], len,
8781*4882a593Smuzhiyun 				"%d %d %s %08x %08x %08x %08x %08x %08x %08x",
8782*4882a593Smuzhiyun 				reason, VENDOR_SEND_HANG_EXT_INFO_VER,
8783*4882a593Smuzhiyun 				dhd->debug_dump_time_hang_str,
8784*4882a593Smuzhiyun 				0, 0, 0, 0, 0, 0, 0);
8785*4882a593Smuzhiyun 		if (dhd) {
8786*4882a593Smuzhiyun 			clear_debug_dump_time(dhd->debug_dump_time_hang_str);
8787*4882a593Smuzhiyun 		}
8788*4882a593Smuzhiyun 	} else {
8789*4882a593Smuzhiyun 		bytes_written += scnprintf(&hang_info[bytes_written], len, "%s", string);
8790*4882a593Smuzhiyun 	}
8791*4882a593Smuzhiyun 
8792*4882a593Smuzhiyun 	WL_ERR(("hang reason: %d info cnt: %d\n", reason, hang_info_cnt));
8793*4882a593Smuzhiyun 
8794*4882a593Smuzhiyun 	if (hang_reason_mismatch == FALSE) {
8795*4882a593Smuzhiyun 		cnt = hang_info_cnt;
8796*4882a593Smuzhiyun 	} else {
8797*4882a593Smuzhiyun 		cnt = HANG_FIELD_MISMATCH_CNT;
8798*4882a593Smuzhiyun 	}
8799*4882a593Smuzhiyun 
8800*4882a593Smuzhiyun 	while (cnt < HANG_FIELD_CNT_MAX) {
8801*4882a593Smuzhiyun 		len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
8802*4882a593Smuzhiyun 		if (len <= 0) {
8803*4882a593Smuzhiyun 			break;
8804*4882a593Smuzhiyun 		}
8805*4882a593Smuzhiyun 		bytes_written += scnprintf(&hang_info[bytes_written], len,
8806*4882a593Smuzhiyun 				"%c%08x", HANG_RAW_DEL, dummy_data);
8807*4882a593Smuzhiyun 		cnt++;
8808*4882a593Smuzhiyun 	}
8809*4882a593Smuzhiyun 
8810*4882a593Smuzhiyun 	WL_ERR(("hang info cnt: %d len: %d\n", cnt, (int)strlen(hang_info)));
8811*4882a593Smuzhiyun 	WL_ERR(("hang info data: %s\n", hang_info));
8812*4882a593Smuzhiyun 
8813*4882a593Smuzhiyun 	wl_cfgvendor_send_async_event(wiphy,
8814*4882a593Smuzhiyun 			bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_HANGED,
8815*4882a593Smuzhiyun 			hang_info, (int)strlen(hang_info));
8816*4882a593Smuzhiyun 
8817*4882a593Smuzhiyun 	memset(string, 0, VENDOR_SEND_HANG_EXT_INFO_LEN);
8818*4882a593Smuzhiyun 
8819*4882a593Smuzhiyun 	if (hang_info) {
8820*4882a593Smuzhiyun 		MFREE(cfg->osh, hang_info, VENDOR_SEND_HANG_EXT_INFO_LEN);
8821*4882a593Smuzhiyun 	}
8822*4882a593Smuzhiyun 
8823*4882a593Smuzhiyun #ifdef DHD_LOG_DUMP
8824*4882a593Smuzhiyun 	dhd_logdump_cookie_save(dhd, dhd->debug_dump_time_hang_str, "HANG");
8825*4882a593Smuzhiyun #endif /*  DHD_LOG_DUMP */
8826*4882a593Smuzhiyun 
8827*4882a593Smuzhiyun 	if (dhd) {
8828*4882a593Smuzhiyun 		clear_debug_dump_time(dhd->debug_dump_time_str);
8829*4882a593Smuzhiyun 	}
8830*4882a593Smuzhiyun }
8831*4882a593Smuzhiyun 
8832*4882a593Smuzhiyun void
wl_copy_hang_info_if_falure(struct net_device * dev,u16 reason,s32 ret)8833*4882a593Smuzhiyun wl_copy_hang_info_if_falure(struct net_device *dev, u16 reason, s32 ret)
8834*4882a593Smuzhiyun {
8835*4882a593Smuzhiyun 	struct bcm_cfg80211 *cfg = NULL;
8836*4882a593Smuzhiyun 	dhd_pub_t *dhd;
8837*4882a593Smuzhiyun 	s32 err = 0;
8838*4882a593Smuzhiyun 	char ioctl_buf[WLC_IOCTL_SMLEN];
8839*4882a593Smuzhiyun 	memuse_info_t mu;
8840*4882a593Smuzhiyun 	int bytes_written = 0;
8841*4882a593Smuzhiyun 	int remain_len = 0;
8842*4882a593Smuzhiyun 
8843*4882a593Smuzhiyun 	if (!dev) {
8844*4882a593Smuzhiyun 		WL_ERR(("dev is null"));
8845*4882a593Smuzhiyun 		return;
8846*4882a593Smuzhiyun 
8847*4882a593Smuzhiyun 	}
8848*4882a593Smuzhiyun 
8849*4882a593Smuzhiyun 	cfg = wl_get_cfg(dev);
8850*4882a593Smuzhiyun 	if (!cfg) {
8851*4882a593Smuzhiyun 		WL_ERR(("dev=%p cfg=%p\n", dev, cfg));
8852*4882a593Smuzhiyun 		return;
8853*4882a593Smuzhiyun 	}
8854*4882a593Smuzhiyun 
8855*4882a593Smuzhiyun 	dhd = (dhd_pub_t *)(cfg->pub);
8856*4882a593Smuzhiyun 
8857*4882a593Smuzhiyun 	if (!dhd || !dhd->hang_info) {
8858*4882a593Smuzhiyun 		WL_ERR(("%s dhd=%p hang_info=%p\n", __FUNCTION__,
8859*4882a593Smuzhiyun 			dhd, (dhd ? dhd->hang_info : NULL)));
8860*4882a593Smuzhiyun 		return;
8861*4882a593Smuzhiyun 	}
8862*4882a593Smuzhiyun 
8863*4882a593Smuzhiyun 	err = wldev_iovar_getbuf_bsscfg(dev, "memuse",
8864*4882a593Smuzhiyun 			NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
8865*4882a593Smuzhiyun 	if (unlikely(err)) {
8866*4882a593Smuzhiyun 		WL_ERR(("error (%d)\n", err));
8867*4882a593Smuzhiyun 		return;
8868*4882a593Smuzhiyun 	}
8869*4882a593Smuzhiyun 
8870*4882a593Smuzhiyun 	memcpy(&mu, ioctl_buf, sizeof(memuse_info_t));
8871*4882a593Smuzhiyun 
8872*4882a593Smuzhiyun 	if (mu.len >= sizeof(memuse_info_t)) {
8873*4882a593Smuzhiyun 		WL_ERR(("Heap Total: %d(%dK)\n", mu.arena_size, KB(mu.arena_size)));
8874*4882a593Smuzhiyun 		WL_ERR(("Free: %d(%dK), LWM: %d(%dK)\n",
8875*4882a593Smuzhiyun 			mu.arena_free, KB(mu.arena_free),
8876*4882a593Smuzhiyun 			mu.free_lwm, KB(mu.free_lwm)));
8877*4882a593Smuzhiyun 		WL_ERR(("In use: %d(%dK), HWM: %d(%dK)\n",
8878*4882a593Smuzhiyun 			mu.inuse_size, KB(mu.inuse_size),
8879*4882a593Smuzhiyun 			mu.inuse_hwm, KB(mu.inuse_hwm)));
8880*4882a593Smuzhiyun 		WL_ERR(("Malloc failure count: %d\n", mu.mf_count));
8881*4882a593Smuzhiyun 	}
8882*4882a593Smuzhiyun 
8883*4882a593Smuzhiyun 	memset(dhd->hang_info, 0, VENDOR_SEND_HANG_EXT_INFO_LEN);
8884*4882a593Smuzhiyun 	remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
8885*4882a593Smuzhiyun 
8886*4882a593Smuzhiyun 	get_debug_dump_time(dhd->debug_dump_time_hang_str);
8887*4882a593Smuzhiyun 	copy_debug_dump_time(dhd->debug_dump_time_str, dhd->debug_dump_time_hang_str);
8888*4882a593Smuzhiyun 
8889*4882a593Smuzhiyun 	bytes_written += scnprintf(&dhd->hang_info[bytes_written], remain_len,
8890*4882a593Smuzhiyun 			"%d %d %s %d %d %d %d %d %08x %08x",
8891*4882a593Smuzhiyun 			reason, VENDOR_SEND_HANG_EXT_INFO_VER,
8892*4882a593Smuzhiyun 			dhd->debug_dump_time_hang_str,
8893*4882a593Smuzhiyun 			ret, mu.arena_size, mu.arena_free, mu.inuse_size, mu.mf_count, 0, 0);
8894*4882a593Smuzhiyun 
8895*4882a593Smuzhiyun 	dhd->hang_info_cnt = HANG_FIELD_IF_FAILURE_CNT;
8896*4882a593Smuzhiyun 
8897*4882a593Smuzhiyun 	clear_debug_dump_time(dhd->debug_dump_time_hang_str);
8898*4882a593Smuzhiyun 
8899*4882a593Smuzhiyun 	return;
8900*4882a593Smuzhiyun }
8901*4882a593Smuzhiyun #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
8902