xref: /OK3568_Linux_fs/external/rkwifibt/drivers/bcmdhd/wl_cfgvendor.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Linux cfg80211 Vendor Extension Code
3  *
4  * Copyright (C) 2020, Broadcom.
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *
21  * <<Broadcom-WL-IPTag/Dual:>>
22  */
23 
24 /*
25  * New vendor interface additon to nl80211/cfg80211 to allow vendors
26  * to implement proprietary features over the cfg80211 stack.
27 */
28 
29 #include <typedefs.h>
30 #include <linuxver.h>
31 #include <osl.h>
32 #include <linux/kernel.h>
33 #include <linux/vmalloc.h>
34 
35 #include <bcmutils.h>
36 #include <bcmwifi_channels.h>
37 #include <bcmendian.h>
38 #include <ethernet.h>
39 #include <802.11.h>
40 #include <linux/if_arp.h>
41 #include <asm/uaccess.h>
42 
43 #if defined(BCMDONGLEHOST)
44 #include <dngl_stats.h>
45 #include "wifi_stats.h"
46 #include <dhd.h>
47 #include <dhd_debug.h>
48 #include <dhdioctl.h>
49 #include <wlioctl.h>
50 #include <wlioctl_utils.h>
51 #include <dhd_cfg80211.h>
52 #ifdef DHD_PKT_LOGGING
53 #include <dhd_pktlog.h>
54 #endif /* DHD_PKT_LOGGING */
55 #ifdef PNO_SUPPORT
56 #include <dhd_pno.h>
57 #endif /* PNO_SUPPORT */
58 #ifdef RTT_SUPPORT
59 #include <dhd_rtt.h>
60 #endif /* RTT_SUPPORT */
61 #endif /* defined(BCMDONGLEHOST) */
62 
63 #include <ethernet.h>
64 #include <linux/kernel.h>
65 #include <linux/kthread.h>
66 #include <linux/netdevice.h>
67 #include <linux/sched.h>
68 #include <linux/etherdevice.h>
69 #include <linux/wireless.h>
70 #include <linux/ieee80211.h>
71 #include <linux/wait.h>
72 #include <net/cfg80211.h>
73 #include <net/rtnetlink.h>
74 
75 #include <wlioctl.h>
76 #include <wldev_common.h>
77 #include <wl_cfg80211.h>
78 #include <wl_cfgp2p.h>
79 #include <wl_cfgscan.h>
80 #ifdef WL_NAN
81 #include <wl_cfgnan.h>
82 #endif /* WL_NAN */
83 
84 #ifdef OEM_ANDROID
85 #include <wl_android.h>
86 #endif /* OEM_ANDROID */
87 
88 #include <wl_cfgvendor.h>
89 #ifdef PROP_TXSTATUS
90 #include <dhd_wlfc.h>
91 #endif
92 #include <brcm_nl80211.h>
93 
94 char*
wl_get_kernel_timestamp(void)95 wl_get_kernel_timestamp(void)
96 {
97 	static char buf[32];
98 	u64 ts_nsec;
99 	unsigned long rem_nsec;
100 
101 	ts_nsec = local_clock();
102 	rem_nsec = DIV_AND_MOD_U64_BY_U32(ts_nsec, NSEC_PER_SEC);
103 	snprintf(buf, sizeof(buf), "%5lu.%06lu",
104 		(unsigned long)ts_nsec, rem_nsec / NSEC_PER_USEC);
105 
106 	return buf;
107 }
108 
109 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
110 #if defined(WL_SUPP_EVENT)
111 int
wl_cfgvendor_send_supp_eventstring(const char * func_name,const char * fmt,...)112 wl_cfgvendor_send_supp_eventstring(const char *func_name, const char *fmt, ...)
113 {
114 	char buf[SUPP_LOG_LEN] = {0};
115 	struct bcm_cfg80211 *cfg;
116 	struct wiphy *wiphy;
117 	va_list args;
118 	int len;
119 	int prefix_len;
120 	int rem_len;
121 
122 	cfg = wl_cfg80211_get_bcmcfg();
123 	if (!cfg || !cfg->wdev) {
124 		WL_DBG(("supp evt invalid arg\n"));
125 		return BCME_OK;
126 	}
127 
128 	wiphy = cfg->wdev->wiphy;
129 	prefix_len = snprintf(buf, SUPP_LOG_LEN, "[DHD]<%s> %s: ",
130 		wl_get_kernel_timestamp(), __func__);
131 	/* Remaining buffer len */
132 	rem_len = SUPP_LOG_LEN - (prefix_len + 1);
133 	/* Print the arg list on to the remaining part of the buffer */
134 	va_start(args, fmt);
135 	len = vsnprintf((buf + prefix_len), rem_len, fmt, args);
136 	va_end(args);
137 	if (len < 0) {
138 		return -EINVAL;
139 	}
140 
141 	if (len > rem_len) {
142 		/* If return length is greater than buffer len,
143 		 * then its truncated buffer case.
144 		 */
145 		len = rem_len;
146 	}
147 
148 	/* Ensure the buffer is null terminated */
149 	len += prefix_len;
150 	buf[len] = '\0';
151 	len++;
152 
153 	return wl_cfgvendor_send_async_event(wiphy,
154 		bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_PRIV_STR, buf, len);
155 }
156 
157 int
wl_cfgvendor_notify_supp_event_str(const char * evt_name,const char * fmt,...)158 wl_cfgvendor_notify_supp_event_str(const char *evt_name, const char *fmt, ...)
159 {
160 	char buf[SUPP_LOG_LEN] = {0};
161 	struct bcm_cfg80211 *cfg;
162 	struct wiphy *wiphy;
163 	va_list args;
164 	int len;
165 	int prefix_len;
166 	int rem_len;
167 
168 	cfg = wl_cfg80211_get_bcmcfg();
169 	if (!cfg || !cfg->wdev) {
170 		WL_DBG(("supp evt invalid arg\n"));
171 		return BCME_OK;
172 	}
173 	wiphy = cfg->wdev->wiphy;
174 	prefix_len = snprintf(buf, SUPP_LOG_LEN, "%s ", evt_name);
175 	/* Remaining buffer len */
176 	rem_len = SUPP_LOG_LEN - (prefix_len + 1);
177 	/* Print the arg list on to the remaining part of the buffer */
178 	va_start(args, fmt);
179 	len = vsnprintf((buf + prefix_len), rem_len, fmt, args);
180 	va_end(args);
181 	if (len < 0) {
182 		return -EINVAL;
183 	}
184 
185 	if (len > rem_len) {
186 		/* If return length is greater than buffer len,
187 		 * then its truncated buffer case.
188 		 */
189 		len = rem_len;
190 	}
191 
192 	/* Ensure the buffer is null terminated */
193 	len += prefix_len;
194 	buf[len] = '\0';
195 	len++;
196 
197 	return wl_cfgvendor_send_async_event(wiphy,
198 		bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_PRIV_STR, buf, len);
199 }
200 #endif /* WL_SUPP_EVENT */
201 
202 /*
203  * This API is to be used for asynchronous vendor events. This
204  * shouldn't be used in response to a vendor command from its
205  * do_it handler context (instead wl_cfgvendor_send_cmd_reply should
206  * be used).
207  */
wl_cfgvendor_send_async_event(struct wiphy * wiphy,struct net_device * dev,int event_id,const void * data,int len)208 int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
209 	struct net_device *dev, int event_id, const void  *data, int len)
210 {
211 	gfp_t kflags;
212 	struct sk_buff *skb;
213 
214 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
215 
216 	/* Alloc the SKB for vendor_event */
217 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
218 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
219 	skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev), len, event_id, kflags);
220 #else
221 	skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
222 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
223 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
224 	if (!skb) {
225 		WL_ERR(("skb alloc failed"));
226 		return -ENOMEM;
227 	}
228 
229 	/* Push the data to the skb */
230 	nla_put_nohdr(skb, len, data);
231 
232 	cfg80211_vendor_event(skb, kflags);
233 
234 	return 0;
235 }
236 
237 static int
wl_cfgvendor_send_cmd_reply(struct wiphy * wiphy,const void * data,int len)238 wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
239 	const void  *data, int len)
240 {
241 	struct sk_buff *skb;
242 	int err;
243 
244 	/* Alloc the SKB for vendor_event */
245 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
246 	if (unlikely(!skb)) {
247 		WL_ERR(("skb alloc failed"));
248 		err = -ENOMEM;
249 		goto exit;
250 	}
251 
252 	/* Push the data to the skb */
253 	nla_put_nohdr(skb, len, data);
254 	err = cfg80211_vendor_cmd_reply(skb);
255 exit:
256 	WL_DBG(("status %d\n", err));
257 	return err;
258 }
259 
260 static int
wl_cfgvendor_get_feature_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)261 wl_cfgvendor_get_feature_set(struct wiphy *wiphy,
262 	struct wireless_dev *wdev, const void  *data, int len)
263 {
264 	int err = 0;
265 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
266 	int reply;
267 
268 	reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg));
269 
270 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &reply, sizeof(int));
271 	if (unlikely(err))
272 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
273 
274 	return err;
275 }
276 
277 static int
wl_cfgvendor_get_feature_set_matrix(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)278 wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
279 	struct wireless_dev *wdev, const void  *data, int len)
280 {
281 	int err = 0;
282 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
283 	struct sk_buff *skb;
284 	int reply;
285 	int mem_needed, i;
286 
287 	mem_needed = VENDOR_REPLY_OVERHEAD +
288 		(ATTRIBUTE_U32_LEN * MAX_FEATURE_SET_CONCURRRENT_GROUPS) + ATTRIBUTE_U32_LEN;
289 
290 	/* Alloc the SKB for vendor_event */
291 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
292 	if (unlikely(!skb)) {
293 		WL_ERR(("skb alloc failed"));
294 		err = -ENOMEM;
295 		goto exit;
296 	}
297 
298 	err = nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
299 		MAX_FEATURE_SET_CONCURRRENT_GROUPS);
300 	if (unlikely(err)) {
301 		kfree_skb(skb);
302 		goto exit;
303 	}
304 	for (i = 0; i < MAX_FEATURE_SET_CONCURRRENT_GROUPS; i++) {
305 		reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), i);
306 		if (reply != WIFI_FEATURE_INVALID) {
307 			err = nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
308 				reply);
309 			if (unlikely(err)) {
310 				kfree_skb(skb);
311 				goto exit;
312 			}
313 		}
314 	}
315 
316 	err =  cfg80211_vendor_cmd_reply(skb);
317 
318 	if (unlikely(err)) {
319 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
320 	}
321 exit:
322 	return err;
323 }
324 
325 static int
wl_cfgvendor_set_rand_mac_oui(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)326 wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy,
327 	struct wireless_dev *wdev, const void  *data, int len)
328 {
329 	int err = -EINVAL;
330 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
331 	int type;
332 
333 	if (!data) {
334 		WL_ERR(("data is not available\n"));
335 		goto exit;
336 	}
337 
338 	if (len <= 0) {
339 		WL_ERR(("invalid len %d\n", len));
340 		goto exit;
341 	}
342 
343 	type = nla_type(data);
344 
345 	if (type == ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI) {
346 		if (nla_len(data) != DOT11_OUI_LEN) {
347 			WL_ERR(("nla_len not matched.\n"));
348 			goto exit;
349 		}
350 		err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), nla_data(data));
351 
352 		if (unlikely(err))
353 			WL_ERR(("Bad OUI, could not set:%d \n", err));
354 	}
355 exit:
356 	return err;
357 }
358 #ifdef CUSTOM_FORCE_NODFS_FLAG
359 static int
wl_cfgvendor_set_nodfs_flag(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)360 wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy,
361 	struct wireless_dev *wdev, const void *data, int len)
362 {
363 	int err = -EINVAL;
364 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
365 	int type;
366 	u32 nodfs;
367 
368 	if (!data) {
369 		WL_ERR(("data is not available\n"));
370 		return -EINVAL;
371 	}
372 
373 	if (len <= 0) {
374 		WL_ERR(("invalid len %d\n", len));
375 		return -EINVAL;
376 	}
377 
378 	type = nla_type(data);
379 	if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) {
380 		nodfs = nla_get_u32(data);
381 		err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs);
382 	}
383 
384 	return err;
385 }
386 #endif /* CUSTOM_FORCE_NODFS_FLAG */
387 
388 static int
wl_cfgvendor_set_country(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)389 wl_cfgvendor_set_country(struct wiphy *wiphy,
390 	struct wireless_dev *wdev, const void *data, int len)
391 {
392 	int err = BCME_ERROR, rem, type;
393 	char country_code[WLC_CNTRY_BUF_SZ] = {0};
394 	const struct nlattr *iter;
395 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
396 	struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
397 
398 	nla_for_each_attr(iter, data, len, rem) {
399 		type = nla_type(iter);
400 		switch (type) {
401 			case ANDR_WIFI_ATTRIBUTE_COUNTRY:
402 				err = memcpy_s(country_code, WLC_CNTRY_BUF_SZ,
403 					nla_data(iter), nla_len(iter));
404 				if (err) {
405 					WL_ERR(("Failed to copy country code: %d\n", err));
406 					return err;
407 				}
408 				break;
409 			default:
410 				WL_ERR(("Unknown type: %d\n", type));
411 				return err;
412 		}
413 	}
414 	/* country code is unique for dongle..hence using primary interface. */
415 	err = wl_cfg80211_set_country_code(primary_ndev, country_code, true, true, 0);
416 	if (err < 0) {
417 		WL_ERR(("Set country failed ret:%d\n", err));
418 	}
419 
420 	return err;
421 }
422 
423 #ifdef GSCAN_SUPPORT
424 int
wl_cfgvendor_send_hotlist_event(struct wiphy * wiphy,struct net_device * dev,void * data,int len,wl_vendor_event_t event)425 wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
426 	struct net_device *dev, void  *data, int len, wl_vendor_event_t event)
427 {
428 	gfp_t kflags;
429 	const void *ptr;
430 	struct sk_buff *skb;
431 	int malloc_len, total, iter_cnt_to_send, cnt;
432 	gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
433 
434 	total = len/sizeof(wifi_gscan_result_t);
435 	while (total > 0) {
436 		malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD;
437 		if (malloc_len > NLMSG_DEFAULT_SIZE) {
438 			malloc_len = NLMSG_DEFAULT_SIZE;
439 		}
440 		iter_cnt_to_send =
441 		   (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t);
442 		total = total - iter_cnt_to_send;
443 
444 		kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
445 
446 		/* Alloc the SKB for vendor_event */
447 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
448 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
449 		skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev),
450 		malloc_len, event, kflags);
451 #else
452 		skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags);
453 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
454 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
455 		if (!skb) {
456 			WL_ERR(("skb alloc failed"));
457 			return -ENOMEM;
458 		}
459 
460 		while (cache && iter_cnt_to_send) {
461 			ptr = (const void *) &cache->results[cache->tot_consumed];
462 
463 			if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) {
464 				cnt = iter_cnt_to_send;
465 			} else {
466 				cnt = (cache->tot_count - cache->tot_consumed);
467 			}
468 
469 			iter_cnt_to_send -= cnt;
470 			cache->tot_consumed += cnt;
471 			/* Push the data to the skb */
472 #ifdef ANDROID13_KERNEL515_BKPORT
473 			nla_put_nohdr(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
474 #else
475 			nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
476 #endif
477 			if (cache->tot_consumed == cache->tot_count) {
478 				cache = cache->next;
479 			}
480 
481 		}
482 
483 		cfg80211_vendor_event(skb, kflags);
484 	}
485 
486 	return 0;
487 }
488 
489 static int
wl_cfgvendor_gscan_get_capabilities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)490 wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
491 	struct wireless_dev *wdev, const void  *data, int len)
492 {
493 	int err = 0;
494 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
495 	dhd_pno_gscan_capabilities_t *reply = NULL;
496 	uint32 reply_len = 0;
497 
498 	reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
499 	   DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
500 	if (!reply) {
501 		WL_ERR(("Could not get capabilities\n"));
502 		err = -EINVAL;
503 		return err;
504 	}
505 
506 	err =  wl_cfgvendor_send_cmd_reply(wiphy, reply, reply_len);
507 	if (unlikely(err)) {
508 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
509 	}
510 
511 	MFREE(cfg->osh, reply, reply_len);
512 	return err;
513 }
514 
515 static int
wl_cfgvendor_gscan_get_batch_results(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)516 wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
517 	struct wireless_dev *wdev, const void  *data, int len)
518 {
519 	int err = 0;
520 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
521 	gscan_results_cache_t *results, *iter;
522 	uint32 reply_len, is_done = 1;
523 	int32 mem_needed, num_results_iter;
524 	wifi_gscan_result_t *ptr;
525 	uint16 num_scan_ids, num_results;
526 	struct sk_buff *skb;
527 	struct nlattr *scan_hdr, *complete_flag;
528 
529 	err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
530 	if (err != BCME_OK)
531 		return -EBUSY;
532 
533 	err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
534 	if (err != BCME_OK) {
535 		WL_ERR(("Can't obtain lock to access batch results %d\n", err));
536 		return -EBUSY;
537 	}
538 	results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
539 	             DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
540 
541 	if (!results) {
542 		WL_ERR(("No results to send %d\n", err));
543 		err =  wl_cfgvendor_send_cmd_reply(wiphy, results, 0);
544 
545 		if (unlikely(err))
546 			WL_ERR(("Vendor Command reply failed ret:%d \n", err));
547 		dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
548 		return err;
549 	}
550 	num_scan_ids = reply_len & 0xFFFF;
551 	num_results = (reply_len & 0xFFFF0000) >> 16;
552 	mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
553 	             (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
554 	             VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
555 
556 	if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
557 		mem_needed = (int32)NLMSG_DEFAULT_SIZE;
558 	}
559 
560 	WL_TRACE(("is_done %d mem_needed %d max_mem %d\n", is_done, mem_needed,
561 		(int)NLMSG_DEFAULT_SIZE));
562 	/* Alloc the SKB for vendor_event */
563 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
564 	if (unlikely(!skb)) {
565 		WL_ERR(("skb alloc failed"));
566 		dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
567 		return -ENOMEM;
568 	}
569 	iter = results;
570 	complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,
571 	                    sizeof(is_done));
572 
573 	if (unlikely(!complete_flag)) {
574 		WL_ERR(("complete_flag could not be reserved"));
575 		kfree_skb(skb);
576 		dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
577 		return -ENOMEM;
578 	}
579 	mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
580 
581 	while (iter) {
582 		num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN);
583 		num_results_iter /= (int32)sizeof(wifi_gscan_result_t);
584 		if (num_results_iter <= 0 ||
585 		    ((iter->tot_count - iter->tot_consumed) > num_results_iter)) {
586 			break;
587 		}
588 		scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
589 		/* no more room? we are done then (for now) */
590 		if (scan_hdr == NULL) {
591 			is_done = 0;
592 			break;
593 		}
594 		err = nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
595 		if (unlikely(err)) {
596 			goto fail;
597 		}
598 		err = nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
599 		if (unlikely(err)) {
600 			goto fail;
601 		}
602 		err = nla_put_u32(skb, GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK, iter->scan_ch_bucket);
603 		if (unlikely(err)) {
604 			goto fail;
605 		}
606 		num_results_iter = iter->tot_count - iter->tot_consumed;
607 
608 		err = nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
609 		if (unlikely(err)) {
610 			goto fail;
611 		}
612 		if (num_results_iter) {
613 			ptr = &iter->results[iter->tot_consumed];
614 			err = nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
615 			 num_results_iter * sizeof(wifi_gscan_result_t), ptr);
616 			if (unlikely(err)) {
617 				goto fail;
618 			}
619 			iter->tot_consumed += num_results_iter;
620 		}
621 		nla_nest_end(skb, scan_hdr);
622 		mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
623 		    (num_results_iter * sizeof(wifi_gscan_result_t));
624 		iter = iter->next;
625 	}
626 	/* Cleans up consumed results and returns TRUE if all results are consumed */
627 	is_done = dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
628 	memcpy(nla_data(complete_flag), &is_done, sizeof(is_done));
629 	dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
630 	return cfg80211_vendor_cmd_reply(skb);
631 fail:
632 	/* Free up consumed results which will now not be sent */
633 	(void)dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
634 	kfree_skb(skb);
635 	dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
636 	return err;
637 }
638 
639 static int
wl_cfgvendor_initiate_gscan(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)640 wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
641 	struct wireless_dev *wdev, const void  *data, int len)
642 {
643 	int err = 0;
644 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
645 	int type, tmp = len;
646 	int run = 0xFF;
647 	int flush = 0;
648 	const struct nlattr *iter;
649 
650 	nla_for_each_attr(iter, data, len, tmp) {
651 		type = nla_type(iter);
652 		if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
653 			run = nla_get_u32(iter);
654 		else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
655 			flush = nla_get_u32(iter);
656 	}
657 
658 	if (run != 0xFF) {
659 		err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
660 
661 		if (unlikely(err)) {
662 			WL_ERR(("Could not run gscan:%d \n", err));
663 		}
664 		return err;
665 	} else {
666 		return -EINVAL;
667 	}
668 
669 }
670 
671 static int
wl_cfgvendor_enable_full_scan_result(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)672 wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
673 	struct wireless_dev *wdev, const void  *data, int len)
674 {
675 	int err = 0;
676 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
677 	int type;
678 	bool real_time = FALSE;
679 
680 	if (!data) {
681 		WL_ERR(("data is not available\n"));
682 		return -EINVAL;
683 	}
684 
685 	if (len <= 0) {
686 		WL_ERR(("invalid len %d\n", len));
687 		return -EINVAL;
688 	}
689 
690 	type = nla_type(data);
691 
692 	if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
693 		real_time = nla_get_u32(data);
694 
695 		err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
696 
697 		if (unlikely(err)) {
698 			WL_ERR(("Could not run gscan:%d \n", err));
699 		}
700 
701 	} else {
702 		err = -EINVAL;
703 	}
704 
705 	return err;
706 }
707 
708 static int
wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr * prev,gscan_scan_params_t * scan_param,int num)709 wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev,
710 	gscan_scan_params_t *scan_param, int num)
711 {
712 	struct dhd_pno_gscan_channel_bucket  *ch_bucket;
713 	int k = 0;
714 	int type, err = 0, rem;
715 	const struct nlattr *cur, *next;
716 
717 	nla_for_each_nested(cur, prev, rem) {
718 		type = nla_type(cur);
719 		ch_bucket = scan_param->channel_bucket;
720 		switch (type) {
721 		case GSCAN_ATTRIBUTE_BUCKET_ID:
722 			break;
723 		case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
724 			if (nla_len(cur) != sizeof(uint32)) {
725 				err = -EINVAL;
726 				goto exit;
727 			}
728 
729 			ch_bucket[num].bucket_freq_multiple =
730 				nla_get_u32(cur) / MSEC_PER_SEC;
731 			break;
732 		case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
733 			if (nla_len(cur) != sizeof(uint32)) {
734 				err = -EINVAL;
735 				goto exit;
736 			}
737 			ch_bucket[num].num_channels = nla_get_u32(cur);
738 			if (ch_bucket[num].num_channels >
739 				GSCAN_MAX_CHANNELS_IN_BUCKET) {
740 				WL_ERR(("channel range:%d,bucket:%d\n",
741 					ch_bucket[num].num_channels,
742 					num));
743 				err = -EINVAL;
744 				goto exit;
745 			}
746 			break;
747 		case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
748 			nla_for_each_nested(next, cur, rem) {
749 				if (k >= GSCAN_MAX_CHANNELS_IN_BUCKET)
750 					break;
751 				if (nla_len(next) != sizeof(uint32)) {
752 					err = -EINVAL;
753 					goto exit;
754 				}
755 				ch_bucket[num].chan_list[k] = nla_get_u32(next);
756 				k++;
757 			}
758 			break;
759 		case GSCAN_ATTRIBUTE_BUCKETS_BAND:
760 			if (nla_len(cur) != sizeof(uint32)) {
761 				err = -EINVAL;
762 				goto exit;
763 			}
764 			ch_bucket[num].band = (uint16)nla_get_u32(cur);
765 			break;
766 		case GSCAN_ATTRIBUTE_REPORT_EVENTS:
767 			if (nla_len(cur) != sizeof(uint32)) {
768 				err = -EINVAL;
769 				goto exit;
770 			}
771 			ch_bucket[num].report_flag = (uint8)nla_get_u32(cur);
772 			break;
773 		case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT:
774 			if (nla_len(cur) != sizeof(uint32)) {
775 				err = -EINVAL;
776 				goto exit;
777 			}
778 			ch_bucket[num].repeat = (uint16)nla_get_u32(cur);
779 			break;
780 		case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD:
781 			if (nla_len(cur) != sizeof(uint32)) {
782 				err = -EINVAL;
783 				goto exit;
784 			}
785 			ch_bucket[num].bucket_max_multiple =
786 				nla_get_u32(cur) / MSEC_PER_SEC;
787 			break;
788 		default:
789 			WL_ERR(("unknown attr type:%d\n", type));
790 			err = -EINVAL;
791 			goto exit;
792 		}
793 	}
794 
795 exit:
796 	return err;
797 }
798 
799 static int
wl_cfgvendor_set_scan_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)800 wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, struct wireless_dev *wdev,
801 	const void  *data, int len)
802 {
803 	int err = 0;
804 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
805 	gscan_scan_params_t *scan_param;
806 	int j = 0;
807 	int type, tmp;
808 	const struct nlattr *iter;
809 
810 	scan_param = (gscan_scan_params_t *)MALLOCZ(cfg->osh,
811 		sizeof(gscan_scan_params_t));
812 	if (!scan_param) {
813 		WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
814 		err = -EINVAL;
815 		return err;
816 
817 	}
818 
819 	scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
820 	nla_for_each_attr(iter, data, len, tmp) {
821 		type = nla_type(iter);
822 
823 		if (j >= GSCAN_MAX_CH_BUCKETS) {
824 			break;
825 		}
826 
827 		switch (type) {
828 			case GSCAN_ATTRIBUTE_BASE_PERIOD:
829 				if (nla_len(iter) != sizeof(uint32)) {
830 					err = -EINVAL;
831 					goto exit;
832 				}
833 				scan_param->scan_fr = nla_get_u32(iter) / MSEC_PER_SEC;
834 				break;
835 			case GSCAN_ATTRIBUTE_NUM_BUCKETS:
836 				if (nla_len(iter) != sizeof(uint32)) {
837 					err = -EINVAL;
838 					goto exit;
839 				}
840 				scan_param->nchannel_buckets = nla_get_u32(iter);
841 				if (scan_param->nchannel_buckets >=
842 				    GSCAN_MAX_CH_BUCKETS) {
843 					WL_ERR(("ncha_buck out of range %d\n",
844 					scan_param->nchannel_buckets));
845 					err = -EINVAL;
846 					goto exit;
847 				}
848 				break;
849 			case GSCAN_ATTRIBUTE_CH_BUCKET_1:
850 			case GSCAN_ATTRIBUTE_CH_BUCKET_2:
851 			case GSCAN_ATTRIBUTE_CH_BUCKET_3:
852 			case GSCAN_ATTRIBUTE_CH_BUCKET_4:
853 			case GSCAN_ATTRIBUTE_CH_BUCKET_5:
854 			case GSCAN_ATTRIBUTE_CH_BUCKET_6:
855 			case GSCAN_ATTRIBUTE_CH_BUCKET_7:
856 				err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j);
857 				if (err < 0) {
858 					WL_ERR(("set_scan_cfg_buck error:%d\n", err));
859 					goto exit;
860 				}
861 				j++;
862 				break;
863 			default:
864 				WL_ERR(("Unknown type %d\n", type));
865 				err = -EINVAL;
866 				goto exit;
867 		}
868 	}
869 
870 	err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
871 	     DHD_PNO_SCAN_CFG_ID, scan_param, FALSE);
872 
873 	if (err < 0) {
874 		WL_ERR(("Could not set GSCAN scan cfg\n"));
875 		err = -EINVAL;
876 	}
877 
878 exit:
879 	MFREE(cfg->osh, scan_param, sizeof(gscan_scan_params_t));
880 	return err;
881 
882 }
883 
884 static int
wl_cfgvendor_hotlist_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)885 wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
886 	struct wireless_dev *wdev, const void  *data, int len)
887 {
888 	int err = 0;
889 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
890 	gscan_hotlist_scan_params_t *hotlist_params;
891 	int tmp, tmp1, tmp2, type, j = 0, dummy;
892 	const struct nlattr *outer, *inner = NULL, *iter;
893 	bool flush = FALSE;
894 	struct bssid_t *pbssid;
895 
896 	BCM_REFERENCE(dummy);
897 
898 	if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) {
899 		WL_ERR(("buffer length :%d wrong - bail out.\n", len));
900 		return -EINVAL;
901 	}
902 
903 	hotlist_params = (gscan_hotlist_scan_params_t *)MALLOCZ(cfg->osh,
904 		sizeof(*hotlist_params)
905 		+ (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)));
906 
907 	if (!hotlist_params) {
908 		WL_ERR(("Cannot Malloc memory.\n"));
909 		return -ENOMEM;
910 	}
911 
912 	hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
913 
914 	nla_for_each_attr(iter, data, len, tmp2) {
915 		type = nla_type(iter);
916 		switch (type) {
917 		case GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT:
918 			if (nla_len(iter) != sizeof(uint32)) {
919 				WL_DBG(("type:%d length:%d not matching.\n",
920 					type, nla_len(iter)));
921 				err = -EINVAL;
922 				goto exit;
923 			}
924 			hotlist_params->nbssid = (uint16)nla_get_u32(iter);
925 			if ((hotlist_params->nbssid == 0) ||
926 			    (hotlist_params->nbssid > PFN_SWC_MAX_NUM_APS)) {
927 				WL_ERR(("nbssid:%d exceed limit.\n",
928 					hotlist_params->nbssid));
929 				err = -EINVAL;
930 				goto exit;
931 			}
932 			break;
933 		case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
934 			if (hotlist_params->nbssid == 0) {
935 				WL_ERR(("nbssid not retrieved.\n"));
936 				err = -EINVAL;
937 				goto exit;
938 			}
939 			pbssid = hotlist_params->bssid;
940 			nla_for_each_nested(outer, iter, tmp) {
941 				if (j >= hotlist_params->nbssid)
942 					break;
943 				nla_for_each_nested(inner, outer, tmp1) {
944 					type = nla_type(inner);
945 
946 					switch (type) {
947 					case GSCAN_ATTRIBUTE_BSSID:
948 						if (nla_len(inner) != sizeof(pbssid[j].macaddr)) {
949 							WL_ERR(("type:%d length:%d not matching.\n",
950 								type, nla_len(inner)));
951 							err = -EINVAL;
952 							goto exit;
953 						}
954 						memcpy(
955 							&(pbssid[j].macaddr),
956 							nla_data(inner),
957 							sizeof(pbssid[j].macaddr));
958 						break;
959 					case GSCAN_ATTRIBUTE_RSSI_LOW:
960 						if (nla_len(inner) != sizeof(uint8)) {
961 							WL_ERR(("type:%d length:%d not matching.\n",
962 								type, nla_len(inner)));
963 							err = -EINVAL;
964 							goto exit;
965 						}
966 						pbssid[j].rssi_reporting_threshold =
967 							(int8)nla_get_u8(inner);
968 						break;
969 					case GSCAN_ATTRIBUTE_RSSI_HIGH:
970 						if (nla_len(inner) != sizeof(uint8)) {
971 							WL_ERR(("type:%d length:%d not matching.\n",
972 								type, nla_len(inner)));
973 							err = -EINVAL;
974 							goto exit;
975 						}
976 						dummy = (int8)nla_get_u8(inner);
977 						WL_DBG(("dummy %d\n", dummy));
978 						break;
979 					default:
980 						WL_ERR(("ATTR unknown %d\n", type));
981 						err = -EINVAL;
982 						goto exit;
983 					}
984 				}
985 				j++;
986 			}
987 			if (j != hotlist_params->nbssid) {
988 				WL_ERR(("bssid_cnt:%d != nbssid:%d.\n", j,
989 					hotlist_params->nbssid));
990 				err = -EINVAL;
991 				goto exit;
992 			}
993 			break;
994 		case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
995 			if (nla_len(iter) != sizeof(uint8)) {
996 				WL_ERR(("type:%d length:%d not matching.\n",
997 					type, nla_len(iter)));
998 				err = -EINVAL;
999 				goto exit;
1000 			}
1001 			flush = nla_get_u8(iter);
1002 			break;
1003 		case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
1004 			if (nla_len(iter) != sizeof(uint32)) {
1005 				WL_ERR(("type:%d length:%d not matching.\n",
1006 					type, nla_len(iter)));
1007 				err = -EINVAL;
1008 				goto exit;
1009 			}
1010 			hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter);
1011 			break;
1012 		default:
1013 			WL_ERR(("Unknown type %d\n", type));
1014 			err = -EINVAL;
1015 			goto exit;
1016 		}
1017 
1018 	}
1019 
1020 	if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1021 	      DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
1022 		WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err));
1023 		err = -EINVAL;
1024 		goto exit;
1025 	}
1026 exit:
1027 	MFREE(cfg->osh, hotlist_params, sizeof(*hotlist_params)
1028 		+ (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)));
1029 	return err;
1030 }
1031 
wl_cfgvendor_epno_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1032 static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy,
1033 	struct wireless_dev *wdev, const void  *data, int len)
1034 {
1035 	int err = 0;
1036 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1037 	dhd_pno_ssid_t *ssid_elem = NULL;
1038 	int tmp, tmp1, tmp2, type = 0, num = 0;
1039 	const struct nlattr *outer, *inner, *iter;
1040 	uint8 flush = FALSE, i = 0;
1041 	wl_ssid_ext_params_t params;
1042 
1043 	nla_for_each_attr(iter, data, len, tmp2) {
1044 		type = nla_type(iter);
1045 		switch (type) {
1046 			case GSCAN_ATTRIBUTE_EPNO_SSID_LIST:
1047 				nla_for_each_nested(outer, iter, tmp) {
1048 					ssid_elem = (dhd_pno_ssid_t *)
1049 						dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
1050 						DHD_PNO_GET_NEW_EPNO_SSID_ELEM,
1051 						NULL, &num);
1052 					if (!ssid_elem) {
1053 						WL_ERR(("Failed to get SSID LIST buffer\n"));
1054 						err = -ENOMEM;
1055 						goto exit;
1056 					}
1057 					i++;
1058 					nla_for_each_nested(inner, outer, tmp1) {
1059 						type = nla_type(inner);
1060 
1061 						switch (type) {
1062 							case GSCAN_ATTRIBUTE_EPNO_SSID:
1063 								memcpy(ssid_elem->SSID,
1064 								  nla_data(inner),
1065 								  DOT11_MAX_SSID_LEN);
1066 								break;
1067 							case GSCAN_ATTRIBUTE_EPNO_SSID_LEN:
1068 								ssid_elem->SSID_len =
1069 									nla_get_u32(inner);
1070 								if (ssid_elem->SSID_len >
1071 									DOT11_MAX_SSID_LEN) {
1072 									WL_ERR(("SSID too"
1073 									"long %d\n",
1074 									ssid_elem->SSID_len));
1075 									err = -EINVAL;
1076 									MFREE(cfg->osh, ssid_elem,
1077 										num);
1078 									goto exit;
1079 								}
1080 								break;
1081 							case GSCAN_ATTRIBUTE_EPNO_FLAGS:
1082 								ssid_elem->flags =
1083 									nla_get_u32(inner);
1084 								ssid_elem->hidden =
1085 									((ssid_elem->flags &
1086 									DHD_EPNO_HIDDEN_SSID) != 0);
1087 								break;
1088 							case GSCAN_ATTRIBUTE_EPNO_AUTH:
1089 								ssid_elem->wpa_auth =
1090 								        nla_get_u32(inner);
1091 								break;
1092 						}
1093 					}
1094 					if (!ssid_elem->SSID_len) {
1095 						WL_ERR(("Broadcast SSID is illegal for ePNO\n"));
1096 						err = -EINVAL;
1097 						MFREE(cfg->osh, ssid_elem, num);
1098 						goto exit;
1099 					}
1100 					dhd_pno_translate_epno_fw_flags(&ssid_elem->flags);
1101 					dhd_pno_set_epno_auth_flag(&ssid_elem->wpa_auth);
1102 					MFREE(cfg->osh, ssid_elem, num);
1103 				}
1104 				break;
1105 			case GSCAN_ATTRIBUTE_EPNO_SSID_NUM:
1106 				num = nla_get_u8(iter);
1107 				break;
1108 			case GSCAN_ATTRIBUTE_EPNO_FLUSH:
1109 				flush = (bool)nla_get_u32(iter);
1110 				/* Flush attribute is expected before any ssid attribute */
1111 				if (i && flush) {
1112 					WL_ERR(("Bad attributes\n"));
1113 					err = -EINVAL;
1114 					goto exit;
1115 				}
1116 				/* Need to flush driver and FW cfg */
1117 				dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1118 				DHD_PNO_EPNO_CFG_ID, NULL, flush);
1119 				dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
1120 				break;
1121 			case GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR:
1122 				params.min5G_rssi = nla_get_s8(iter);
1123 				break;
1124 			case GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR:
1125 				params.min2G_rssi = nla_get_s8(iter);
1126 				break;
1127 			case GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX:
1128 				params.init_score_max = nla_get_s16(iter);
1129 				break;
1130 			case GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS:
1131 				params.cur_bssid_bonus = nla_get_s16(iter);
1132 				break;
1133 			case GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS:
1134 				params.same_ssid_bonus = nla_get_s16(iter);
1135 				break;
1136 			case GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS:
1137 				params.secure_bonus = nla_get_s16(iter);
1138 				break;
1139 			case GSCAN_ATTRIBUTE_EPNO_5G_BONUS:
1140 				params.band_5g_bonus = nla_get_s16(iter);
1141 				break;
1142 			default:
1143 				WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1144 				err = -EINVAL;
1145 				goto exit;
1146 			}
1147 	}
1148 	if (i != num) {
1149 		WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__,
1150 		     num, i));
1151 		err = -EINVAL;
1152 	}
1153 exit:
1154 	/* Flush all configs if error condition */
1155 	if (err < 0) {
1156 		dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1157 		   DHD_PNO_EPNO_CFG_ID, NULL, TRUE);
1158 		dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
1159 	} else if (type != GSCAN_ATTRIBUTE_EPNO_FLUSH) {
1160 		/* If the last attribute was FLUSH, nothing else to do */
1161 		dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1162 		DHD_PNO_EPNO_PARAMS_ID, &params, FALSE);
1163 		err = dhd_dev_set_epno(bcmcfg_to_prmry_ndev(cfg));
1164 	}
1165 	return err;
1166 }
1167 
1168 static int
wl_cfgvendor_set_batch_scan_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1169 wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
1170 	struct wireless_dev *wdev, const void  *data, int len)
1171 {
1172 	int err = 0, tmp, type;
1173 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1174 	gscan_batch_params_t batch_param;
1175 	const struct nlattr *iter;
1176 
1177 	batch_param.mscan = batch_param.bestn = 0;
1178 	batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
1179 
1180 	nla_for_each_attr(iter, data, len, tmp) {
1181 		type = nla_type(iter);
1182 
1183 		switch (type) {
1184 			case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
1185 				batch_param.bestn = nla_get_u32(iter);
1186 				break;
1187 			case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
1188 				batch_param.mscan = nla_get_u32(iter);
1189 				break;
1190 			case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
1191 				batch_param.buffer_threshold = nla_get_u32(iter);
1192 				break;
1193 			default:
1194 				WL_ERR(("Unknown type %d\n", type));
1195 				break;
1196 		}
1197 	}
1198 
1199 	if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1200 	       DHD_PNO_BATCH_SCAN_CFG_ID, &batch_param, FALSE) < 0) {
1201 		WL_ERR(("Could not set batch cfg\n"));
1202 		err = -EINVAL;
1203 		return err;
1204 	}
1205 
1206 	return err;
1207 }
1208 
1209 #endif /* GSCAN_SUPPORT */
1210 #if defined (GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
1211 static int
wl_cfgvendor_gscan_get_channel_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1212 wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
1213 	struct wireless_dev *wdev, const void  *data, int len)
1214 {
1215 	int err = 0, type, band;
1216 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1217 	uint32 *reply = NULL;
1218 	uint32 reply_len = 0, num_channels, mem_needed;
1219 	struct sk_buff *skb;
1220 	dhd_pub_t *dhdp;
1221 	struct net_device *ndev = wdev->netdev;
1222 
1223 	if (!ndev) {
1224 		WL_ERR(("ndev null\n"));
1225 		return -EINVAL;
1226 	}
1227 
1228 	dhdp = wl_cfg80211_get_dhdp(ndev);
1229 	if (!dhdp) {
1230 		WL_ERR(("dhdp null\n"));
1231 		return -EINVAL;
1232 	}
1233 
1234 	if (!data) {
1235 		WL_ERR(("data is not available\n"));
1236 		return -EINVAL;
1237 	}
1238 
1239 	if (len <= 0) {
1240 		WL_ERR(("invalid len %d\n", len));
1241 		return -EINVAL;
1242 	}
1243 
1244 	type = nla_type(data);
1245 	if (type == GSCAN_ATTRIBUTE_BAND) {
1246 		band = nla_get_u32(data);
1247 	} else {
1248 		return -EINVAL;
1249 	}
1250 
1251 	reply = MALLOCZ(cfg->osh, CHANINFO_LIST_BUF_SIZE);
1252 	if (reply == NULL) {
1253 		WL_ERR(("failed to allocate chanspec buffer\n"));
1254 		return -ENOMEM;
1255 	}
1256 	err = wl_cfgscan_get_band_freq_list(cfg, band, reply, &num_channels);
1257 	if (err != BCME_OK && err != BCME_UNSUPPORTED) {
1258 		WL_ERR(("%s: failed to get valid channel list\n",
1259 				__FUNCTION__));
1260 		err = -EINVAL;
1261 		goto exit;
1262 	} else if (err == BCME_OK) {
1263 		reply_len = (num_channels * sizeof(uint32));
1264 	} else if (err == BCME_UNSUPPORTED) {
1265 		reply = dhd_pno_get_gscan(dhdp,
1266 			DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
1267 		if (!reply) {
1268 			WL_ERR(("Could not get channel list\n"));
1269 			err = -EINVAL;
1270 			return err;
1271 		}
1272 		num_channels =  reply_len/sizeof(uint32);
1273 	}
1274 	mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
1275 
1276 	/* Alloc the SKB for vendor_event */
1277 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1278 	if (unlikely(!skb)) {
1279 		WL_ERR(("skb alloc failed"));
1280 		err = -ENOMEM;
1281 		goto exit;
1282 	}
1283 
1284 	nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
1285 	nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
1286 
1287 	err =  cfg80211_vendor_cmd_reply(skb);
1288 
1289 	if (unlikely(err)) {
1290 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1291 	}
1292 exit:
1293 	MFREE(cfg->osh, reply, CHANINFO_LIST_BUF_SIZE);
1294 	return err;
1295 }
1296 #endif	/* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
1297 
1298 #ifdef RSSI_MONITOR_SUPPORT
wl_cfgvendor_set_rssi_monitor(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1299 static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy,
1300 	struct wireless_dev *wdev, const void  *data, int len)
1301 {
1302 	int err = 0, tmp, type, start = 0;
1303 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1304 	int8 max_rssi = 0, min_rssi = 0;
1305 	const struct nlattr *iter;
1306 
1307 	if (!wl_get_drv_status(cfg, CONNECTED, wdev_to_ndev(wdev))) {
1308 		WL_ERR(("Sta is not connected to an AP, rssi monitoring is not allowed\n"));
1309 		return -EINVAL;
1310 	}
1311 
1312 	nla_for_each_attr(iter, data, len, tmp) {
1313 		type = nla_type(iter);
1314 		switch (type) {
1315 			case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI:
1316 				max_rssi = (int8) nla_get_u32(iter);
1317 				break;
1318 			case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI:
1319 				min_rssi = (int8) nla_get_u32(iter);
1320 				break;
1321 			case RSSI_MONITOR_ATTRIBUTE_START:
1322 				start = nla_get_u32(iter);
1323 		}
1324 	}
1325 
1326 	if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
1327 	       start, max_rssi, min_rssi) < 0) {
1328 		WL_ERR(("Could not set rssi monitor cfg\n"));
1329 		err = -EINVAL;
1330 	}
1331 	return err;
1332 }
1333 #endif /* RSSI_MONITOR_SUPPORT */
1334 
1335 #ifdef DHD_WAKE_STATUS
1336 static int
wl_cfgvendor_get_wake_reason_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1337 wl_cfgvendor_get_wake_reason_stats(struct wiphy *wiphy,
1338         struct wireless_dev *wdev, const void *data, int len)
1339 {
1340 	struct net_device *ndev = wdev_to_ndev(wdev);
1341 	wake_counts_t *pwake_count_info;
1342 	int ret, mem_needed;
1343 #if defined(DHD_DEBUG) && defined(DHD_WAKE_EVENT_STATUS)
1344 	int flowid;
1345 #endif /* DHD_DEBUG && DHD_WAKE_EVENT_STATUS */
1346 	struct sk_buff *skb = NULL;
1347 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
1348 
1349 	WL_DBG(("Recv get wake status info cmd.\n"));
1350 
1351 	pwake_count_info = dhd_get_wakecount(dhdp);
1352 	mem_needed =  VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 20) +
1353 		(WLC_E_LAST * sizeof(uint));
1354 
1355 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1356 	if (unlikely(!skb)) {
1357 		WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
1358 		ret = -ENOMEM;
1359 		goto exit;
1360 	}
1361 #ifdef DHD_WAKE_EVENT_STATUS
1362 	WL_ERR(("pwake_count_info->rcwake %d\n", pwake_count_info->rcwake));
1363 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, pwake_count_info->rcwake);
1364 	if (unlikely(ret)) {
1365 		WL_ERR(("Failed to put Total count of CMD event, ret=%d\n", ret));
1366 		goto exit;
1367 	}
1368 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED, WLC_E_LAST);
1369 	if (unlikely(ret)) {
1370 		WL_ERR(("Failed to put Max count of event used, ret=%d\n", ret));
1371 		goto exit;
1372 	}
1373 	ret = nla_put(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE, (WLC_E_LAST * sizeof(uint)),
1374 		pwake_count_info->rc_event);
1375 	if (unlikely(ret)) {
1376 		WL_ERR(("Failed to put Event wake data, ret=%d\n", ret));
1377 		goto exit;
1378 	}
1379 #ifdef DHD_DEBUG
1380 	for (flowid = 0; flowid < WLC_E_LAST; flowid++) {
1381 		if (pwake_count_info->rc_event[flowid] != 0) {
1382 			WL_ERR((" %s = %u\n", bcmevent_get_name(flowid),
1383 				pwake_count_info->rc_event[flowid]));
1384 		}
1385 	}
1386 #endif /* DHD_DEBUG */
1387 #endif /* DHD_WAKE_EVENT_STATUS */
1388 #ifdef DHD_WAKE_RX_STATUS
1389 	WL_ERR(("pwake_count_info->rxwake %d\n", pwake_count_info->rxwake));
1390 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE, pwake_count_info->rxwake);
1391 	if (unlikely(ret)) {
1392 		WL_ERR(("Failed to put Total Wake due RX data, ret=%d\n", ret));
1393 		goto exit;
1394 	}
1395 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT, pwake_count_info->rx_ucast);
1396 	if (unlikely(ret)) {
1397 		WL_ERR(("Failed to put Total wake due to RX unicast, ret=%d\n", ret));
1398 		goto exit;
1399 	}
1400 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT, pwake_count_info->rx_mcast);
1401 	if (unlikely(ret)) {
1402 		WL_ERR(("Failed to put Total wake due RX multicast, ret=%d\n", ret));
1403 		goto exit;
1404 	}
1405 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT, pwake_count_info->rx_bcast);
1406 	if (unlikely(ret)) {
1407 		WL_ERR(("Failed to put Total wake due to RX broadcast, ret=%d\n", ret));
1408 		goto exit;
1409 	}
1410 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT, pwake_count_info->rx_arp);
1411 	if (unlikely(ret)) {
1412 		WL_ERR(("Failed to put Total wake due to ICMP pkt, ret=%d\n", ret));
1413 		goto exit;
1414 	}
1415 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT, pwake_count_info->rx_icmpv6);
1416 	if (unlikely(ret)) {
1417 		WL_ERR(("Failed to put Total wake due ICMPV6 pkt, ret=%d\n", ret));
1418 		goto exit;
1419 	}
1420 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA, pwake_count_info->rx_icmpv6_ra);
1421 	if (unlikely(ret)) {
1422 		WL_ERR(("Failed to put Total wake due to ICMPV6_RA, ret=%d\n", ret));
1423 		goto exit;
1424 	}
1425 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA, pwake_count_info->rx_icmpv6_na);
1426 	if (unlikely(ret)) {
1427 		WL_ERR(("Failed to put Total wake due to ICMPV6_NA, ret=%d\n", ret));
1428 		goto exit;
1429 	}
1430 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS, pwake_count_info->rx_icmpv6_ns);
1431 	if (unlikely(ret)) {
1432 		WL_ERR(("Failed to put Total wake due to ICMPV6_NS, ret=%d\n", ret));
1433 		goto exit;
1434 	}
1435 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
1436 		pwake_count_info->rx_multi_ipv4);
1437 	if (unlikely(ret)) {
1438 		WL_ERR(("Failed to put Total wake due to RX IPV4 MULTICAST, ret=%d\n", ret));
1439 		goto exit;
1440 	}
1441 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
1442 		pwake_count_info->rx_multi_ipv6);
1443 	if (unlikely(ret)) {
1444 		WL_ERR(("Failed to put Total wake due to RX IPV6 MULTICAST, ret=%d\n", ret));
1445 		goto exit;
1446 	}
1447 	ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT,
1448 		pwake_count_info->rx_multi_other);
1449 	if (unlikely(ret)) {
1450 		WL_ERR(("Failed to put Total wake due to Other RX Multicast, ret=%d\n", ret));
1451 		goto exit;
1452 	}
1453 #endif /* #ifdef DHD_WAKE_RX_STATUS */
1454 	ret = cfg80211_vendor_cmd_reply(skb);
1455 	if (unlikely(ret)) {
1456 		WL_ERR(("Vendor cmd reply for -get wake status failed:%d \n", ret));
1457 	}
1458 	/* On cfg80211_vendor_cmd_reply() skb is consumed and freed in case of success or failure */
1459 	return ret;
1460 
1461 exit:
1462 	/* Free skb memory */
1463 	if (skb) {
1464 		kfree_skb(skb);
1465 	}
1466 	return ret;
1467 }
1468 #endif /* DHD_WAKE_STATUS */
1469 
1470 #ifdef DHDTCPACK_SUPPRESS
1471 static int
wl_cfgvendor_set_tcpack_sup_mode(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1472 wl_cfgvendor_set_tcpack_sup_mode(struct wiphy *wiphy,
1473 	struct wireless_dev *wdev, const void *data, int len)
1474 {
1475 	int err = BCME_OK, type;
1476 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1477 	struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1478 	uint8 enable = 0;
1479 
1480 	if (!data) {
1481 		WL_ERR(("data is not available\n"));
1482 		err = BCME_BADARG;
1483 		goto exit;
1484 	}
1485 
1486 	if (len <= 0) {
1487 		WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
1488 		err = BCME_BADARG;
1489 		goto exit;
1490 	}
1491 
1492 	type = nla_type(data);
1493 	if (type == ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE) {
1494 		enable = (uint8) nla_get_u32(data);
1495 		err = dhd_dev_set_tcpack_sup_mode_cfg(ndev, enable);
1496 		if (unlikely(err)) {
1497 			WL_ERR(("Could not set TCP Ack Suppress mode cfg: %d\n", err));
1498 		}
1499 	} else {
1500 		err = BCME_BADARG;
1501 	}
1502 
1503 exit:
1504 	return err;
1505 }
1506 #endif /* DHDTCPACK_SUPPRESS */
1507 
1508 #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT)
1509 static int
wl_cfgvendor_notify_dump_completion(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1510 wl_cfgvendor_notify_dump_completion(struct wiphy *wiphy,
1511         struct wireless_dev *wdev, const void *data, int len)
1512 {
1513 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1514 	dhd_pub_t *dhd_pub = cfg->pub;
1515 	unsigned long flags = 0;
1516 
1517 	WL_INFORM(("%s, [DUMP] received file dump notification from HAL\n", __FUNCTION__));
1518 
1519 	DHD_GENERAL_LOCK(dhd_pub, flags);
1520 	/* call wmb() to synchronize with the previous memory operations */
1521 	OSL_SMP_WMB();
1522 	DHD_BUS_BUSY_CLEAR_IN_HALDUMP(dhd_pub);
1523 	/* Call another wmb() to make sure wait_for_dump_completion value
1524 	 * gets updated before waking up waiting context.
1525 	 */
1526 	OSL_SMP_WMB();
1527 	dhd_os_busbusy_wake(dhd_pub);
1528 	DHD_GENERAL_UNLOCK(dhd_pub, flags);
1529 
1530 	return BCME_OK;
1531 }
1532 #endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */
1533 
1534 #if defined(WL_CFG80211)
1535 static int
wl_cfgvendor_set_hal_pid(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1536 wl_cfgvendor_set_hal_pid(struct wiphy *wiphy,
1537 		struct wireless_dev *wdev, const void  *data, int len)
1538 {
1539 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1540 	int ret = BCME_OK;
1541 	uint32 type;
1542 	if (!data) {
1543 		WL_DBG(("%s,data is not available\n", __FUNCTION__));
1544 	} else {
1545 		if (len > 0) {
1546 			type = nla_type(data);
1547 			if (type == SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID) {
1548 				if (nla_len(data)) {
1549 					WL_DBG(("HAL PID = %u\n", nla_get_u32(data)));
1550 					cfg->halpid = nla_get_u32(data);
1551 				}
1552 			}
1553 		} else {
1554 			WL_ERR(("invalid len %d\n", len));
1555 			ret = BCME_ERROR;
1556 		}
1557 	}
1558 	return ret;
1559 }
1560 
1561 static int
wl_cfgvendor_set_hal_started(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1562 wl_cfgvendor_set_hal_started(struct wiphy *wiphy,
1563 		struct wireless_dev *wdev, const void  *data, int len)
1564 {
1565 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1566 #ifdef WL_STA_ASSOC_RAND
1567 	struct ether_addr primary_mac;
1568 	dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1569 #endif /* WL_STA_ASSOC_RAND */
1570 	int ret = BCME_OK;
1571 #if defined(WIFI_TURNON_USE_HALINIT)
1572 	struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1573 	uint32 type;
1574 
1575 	if (!data) {
1576 		WL_DBG(("%s,data is not available\n", __FUNCTION__));
1577 	} else {
1578 		if (len > 0) {
1579 			type = nla_type(data);
1580 			WL_INFORM(("%s,type: %xh\n", __FUNCTION__, type));
1581 			if (type == SET_HAL_START_ATTRIBUTE_PRE_INIT) {
1582 				if (nla_len(data)) {
1583 					WL_INFORM(("%s, HAL version: %s\n", __FUNCTION__,
1584 							(char*)nla_data(data)));
1585 				}
1586 				WL_INFORM(("%s, dhd_open start\n", __FUNCTION__));
1587 				ret = dhd_open(ndev);
1588 				if (ret != BCME_OK) {
1589 					WL_INFORM(("%s, dhd_open failed\n", __FUNCTION__));
1590 					return ret;
1591 				} else {
1592 					WL_INFORM(("%s, dhd_open succeeded\n", __FUNCTION__));
1593 				}
1594 				return ret;
1595 			}
1596 		} else {
1597 			WL_ERR(("invalid len %d\n", len));
1598 		}
1599 	}
1600 #endif /* WIFI_TURNON_USE_HALINIT */
1601 	RETURN_EIO_IF_NOT_UP(cfg);
1602 	WL_INFORM(("%s,[DUMP] HAL STARTED\n", __FUNCTION__));
1603 
1604 	cfg->hal_started = true;
1605 #ifdef WL_STA_ASSOC_RAND
1606 	/* If mac randomization is enabled and primary macaddress is not
1607 	 * randomized, randomize it from HAL init context
1608 	 */
1609 	get_primary_mac(cfg, &primary_mac);
1610 	if ((!ETHER_IS_LOCALADDR(&primary_mac)) &&
1611 		(!wl_get_drv_status(cfg, CONNECTED, wdev_to_ndev(wdev)))) {
1612 		WL_DBG_MEM(("%s, Local admin bit not set, randomize"
1613 			"STA MAC address \n", __FUNCTION__));
1614 		if ((ret = dhd_update_rand_mac_addr(dhd)) < 0) {
1615 			WL_ERR(("%s: failed to set macaddress, ret = %d\n", __FUNCTION__, ret));
1616 			return ret;
1617 		}
1618 	}
1619 #endif /* WL_STA_ASSOC_RAND */
1620 	return ret;
1621 }
1622 
1623 static int
wl_cfgvendor_stop_hal(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1624 wl_cfgvendor_stop_hal(struct wiphy *wiphy,
1625 		struct wireless_dev *wdev, const void  *data, int len)
1626 {
1627 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1628 	WL_INFORM(("%s,[DUMP] HAL STOPPED\n", __FUNCTION__));
1629 
1630 	cfg->hal_started = false;
1631 	return BCME_OK;
1632 }
1633 #endif /* WL_CFG80211 */
1634 
1635 #ifdef WL_LATENCY_MODE
1636 static int
wl_cfgvendor_set_latency_mode(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1637 wl_cfgvendor_set_latency_mode(struct wiphy *wiphy,
1638 	struct wireless_dev *wdev, const void *data, int len)
1639 {
1640 	int err = BCME_OK, rem, type;
1641 	u32 latency_mode;
1642 	const struct nlattr *iter;
1643 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
1644 	bool enable;
1645 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
1646 #ifdef WL_AUTO_QOS
1647 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
1648 #endif /* WL_AUTO_QOS */
1649 
1650 	nla_for_each_attr(iter, data, len, rem) {
1651 		type = nla_type(iter);
1652 		switch (type) {
1653 			case ANDR_WIFI_ATTRIBUTE_LATENCY_MODE:
1654 				latency_mode = nla_get_u32(iter);
1655 				WL_DBG(("%s,Setting latency mode %u\n", __FUNCTION__,
1656 					latency_mode));
1657 #ifdef WL_AUTO_QOS
1658 				/* Enable/Disable qos monitoring */
1659 				dhd_wl_sock_qos_set_status(dhdp, latency_mode);
1660 #endif /* WL_AUTO_QOS */
1661 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
1662 				enable = latency_mode ? true : false;
1663 				err = wldev_iovar_setint(wdev->netdev,
1664 						"latency_critical_data", enable);
1665 				if (err != BCME_OK) {
1666 					WL_ERR(("failed to set latency_critical_data "
1667 						"enable %d, error = %d\n", enable, err));
1668 					/* Proceed with other optimizations possible */
1669 					err = BCME_OK;
1670 				}
1671 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
1672 				break;
1673 			default:
1674 				WL_ERR(("Unknown type: %d\n", type));
1675 				return err;
1676 		}
1677 	}
1678 
1679 	return err;
1680 }
1681 #endif /* WL_LATENCY_MODE */
1682 
1683 #ifdef RTT_SUPPORT
1684 void
wl_cfgvendor_rtt_evt(void * ctx,void * rtt_data)1685 wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
1686 {
1687 	struct wireless_dev *wdev = (struct wireless_dev *)ctx;
1688 	struct wiphy *wiphy;
1689 	struct sk_buff *skb = NULL;
1690 	uint32 evt_complete = 0;
1691 	gfp_t kflags;
1692 	rtt_result_t *rtt_result;
1693 	rtt_results_header_t *rtt_header;
1694 	struct list_head *rtt_cache_list;
1695 	struct nlattr *rtt_nl_hdr;
1696 	int ret = BCME_OK;
1697 	wiphy = wdev->wiphy;
1698 
1699 	WL_DBG(("In\n"));
1700 	/* Push the data to the skb */
1701 	if (!rtt_data) {
1702 		WL_ERR(("rtt_data is NULL\n"));
1703 		return;
1704 	}
1705 	rtt_cache_list = (struct list_head *)rtt_data;
1706 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1707 	if (list_empty(rtt_cache_list)) {
1708 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1709 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1710 		skb = cfg80211_vendor_event_alloc(wiphy, NULL, 100,
1711 			GOOGLE_RTT_COMPLETE_EVENT, kflags);
1712 #else
1713 		skb = cfg80211_vendor_event_alloc(wiphy, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags);
1714 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1715 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1716 		if (!skb) {
1717 			WL_ERR(("skb alloc failed"));
1718 			return;
1719 		}
1720 		evt_complete = 1;
1721 		ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1722 		if (ret < 0) {
1723 			WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
1724 			goto free_mem;
1725 		}
1726 		cfg80211_vendor_event(skb, kflags);
1727 		return;
1728 	}
1729 	GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1730 	list_for_each_entry(rtt_header, rtt_cache_list, list) {
1731 		/* Alloc the SKB for vendor_event */
1732 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1733 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1734 		skb = cfg80211_vendor_event_alloc(wiphy, NULL, rtt_header->result_tot_len + 100,
1735 			GOOGLE_RTT_COMPLETE_EVENT, kflags);
1736 #else
1737 		skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100,
1738 			GOOGLE_RTT_COMPLETE_EVENT, kflags);
1739 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1740 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1741 		if (!skb) {
1742 			WL_ERR(("skb alloc failed"));
1743 			return;
1744 		}
1745 		if (list_is_last(&rtt_header->list, rtt_cache_list)) {
1746 			evt_complete = 1;
1747 		}
1748 		ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1749 		if (ret < 0) {
1750 			WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
1751 			goto free_mem;
1752 		}
1753 		rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET);
1754 		if (!rtt_nl_hdr) {
1755 			WL_ERR(("rtt_nl_hdr is NULL\n"));
1756 		        dev_kfree_skb_any(skb);
1757 			break;
1758 		}
1759 		ret = nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN,
1760 				&rtt_header->peer_mac);
1761 		if (ret < 0) {
1762 			WL_ERR(("Failed to put RTT_ATTRIBUTE_TARGET_MAC, ret:%d\n", ret));
1763 			goto free_mem;
1764 		}
1765 		ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt);
1766 		if (ret < 0) {
1767 			WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_CNT, ret:%d\n", ret));
1768 			goto free_mem;
1769 		}
1770 		list_for_each_entry(rtt_result, &rtt_header->result_list, list) {
1771 			ret = nla_put(skb, RTT_ATTRIBUTE_RESULT,
1772 				rtt_result->report_len, &rtt_result->report);
1773 			if (ret < 0) {
1774 				WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT, ret:%d\n", ret));
1775 				goto free_mem;
1776 			}
1777 			ret = nla_put(skb, RTT_ATTRIBUTE_RESULT_DETAIL,
1778 				rtt_result->detail_len, &rtt_result->rtt_detail);
1779 			if (ret < 0) {
1780 				WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_DETAIL, ret:%d\n",
1781 					ret));
1782 				goto free_mem;
1783 			}
1784 		}
1785 		nla_nest_end(skb, rtt_nl_hdr);
1786 		cfg80211_vendor_event(skb, kflags);
1787 	}
1788 	GCC_DIAGNOSTIC_POP();
1789 
1790 	return;
1791 
1792 free_mem:
1793 	/* Free skb memory */
1794 	if (skb) {
1795 		kfree_skb(skb);
1796 	}
1797 }
1798 
1799 static int
wl_cfgvendor_rtt_set_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1800 wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1801 	const void *data, int len) {
1802 	int err = 0, rem, rem1, rem2, type;
1803 	int target_cnt = 0;
1804 	rtt_config_params_t rtt_param;
1805 	rtt_target_info_t* rtt_target = NULL;
1806 	const struct nlattr *iter, *iter1, *iter2;
1807 	int8 eabuf[ETHER_ADDR_STR_LEN];
1808 	int8 chanbuf[CHANSPEC_STR_LEN];
1809 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1810 	rtt_capabilities_t capability;
1811 
1812 	bzero(&rtt_param, sizeof(rtt_param));
1813 
1814 	WL_DBG(("In\n"));
1815 	err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
1816 	if (err < 0) {
1817 		WL_ERR(("failed to register rtt_noti_callback\n"));
1818 		goto exit;
1819 	}
1820 	err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1821 	if (err < 0) {
1822 		WL_ERR(("failed to get the capability\n"));
1823 		goto exit;
1824 	}
1825 
1826 	if (len <= 0) {
1827 		WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
1828 		err = BCME_ERROR;
1829 		goto exit;
1830 	}
1831 	nla_for_each_attr(iter, data, len, rem) {
1832 		type = nla_type(iter);
1833 		switch (type) {
1834 		case RTT_ATTRIBUTE_TARGET_CNT:
1835 			if (target_cnt != 0) {
1836 				WL_ERR(("attempt to overwrite target_cnt"));
1837 				err = -EINVAL;
1838 				goto exit;
1839 			}
1840 			target_cnt = nla_get_u8(iter);
1841 			if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) {
1842 				WL_ERR(("target_cnt is not valid : %d\n",
1843 					target_cnt));
1844 				err = BCME_RANGE;
1845 				goto exit;
1846 			}
1847 			rtt_param.rtt_target_cnt = target_cnt;
1848 
1849 			rtt_param.target_info = (rtt_target_info_t *)MALLOCZ(cfg->osh,
1850 				TARGET_INFO_SIZE(target_cnt));
1851 			if (rtt_param.target_info == NULL) {
1852 				WL_ERR(("failed to allocate target info for (%d)\n", target_cnt));
1853 				err = BCME_NOMEM;
1854 				goto exit;
1855 			}
1856 			break;
1857 		case RTT_ATTRIBUTE_TARGET_INFO:
1858 			/* Added this variable for safe check to avoid crash
1859 			 * incase the caller did not respect the order
1860 			 */
1861 			if (rtt_param.target_info == NULL) {
1862 				WL_ERR(("rtt_target_info is NULL\n"));
1863 				err = BCME_NOMEM;
1864 				goto exit;
1865 			}
1866 			rtt_target = rtt_param.target_info;
1867 			nla_for_each_nested(iter1, iter, rem1) {
1868 				if ((uint8 *)rtt_target >= ((uint8 *)rtt_param.target_info +
1869 					TARGET_INFO_SIZE(target_cnt))) {
1870 					WL_ERR(("rtt_target increased over its max size"));
1871 					err = -EINVAL;
1872 					goto exit;
1873 				}
1874 				nla_for_each_nested(iter2, iter1, rem2) {
1875 					type = nla_type(iter2);
1876 					switch (type) {
1877 					case RTT_ATTRIBUTE_TARGET_MAC:
1878 						if (nla_len(iter2) != ETHER_ADDR_LEN) {
1879 							WL_ERR(("mac_addr length not match\n"));
1880 							err = -EINVAL;
1881 							goto exit;
1882 						}
1883 						memcpy(&rtt_target->addr, nla_data(iter2),
1884 							ETHER_ADDR_LEN);
1885 						break;
1886 					case RTT_ATTRIBUTE_TARGET_TYPE:
1887 						rtt_target->type = nla_get_u8(iter2);
1888 						if (rtt_target->type == RTT_INVALID ||
1889 							(rtt_target->type == RTT_ONE_WAY &&
1890 							!capability.rtt_one_sided_supported)) {
1891 							WL_ERR(("doesn't support RTT type"
1892 								" : %d\n",
1893 								rtt_target->type));
1894 							err = -EINVAL;
1895 							goto exit;
1896 						}
1897 						break;
1898 					case RTT_ATTRIBUTE_TARGET_PEER:
1899 						rtt_target->peer = nla_get_u8(iter2);
1900 						break;
1901 					case RTT_ATTRIBUTE_TARGET_CHAN:
1902 						memcpy(&rtt_target->channel, nla_data(iter2),
1903 							sizeof(rtt_target->channel));
1904 						break;
1905 					case RTT_ATTRIBUTE_TARGET_PERIOD:
1906 						rtt_target->burst_period = nla_get_u32(iter2);
1907 						if (rtt_target->burst_period < 32) {
1908 							/* 100ms unit */
1909 							rtt_target->burst_period *= 100;
1910 						} else {
1911 							WL_ERR(("%d value must in (0-31)\n",
1912 								rtt_target->burst_period));
1913 							err = EINVAL;
1914 							goto exit;
1915 						}
1916 						break;
1917 					case RTT_ATTRIBUTE_TARGET_NUM_BURST:
1918 						rtt_target->num_burst = nla_get_u32(iter2);
1919 						if (rtt_target->num_burst > 16) {
1920 							WL_ERR(("%d value must in (0-15)\n",
1921 								rtt_target->num_burst));
1922 							err = -EINVAL;
1923 							goto exit;
1924 						}
1925 						rtt_target->num_burst = BIT(rtt_target->num_burst);
1926 						break;
1927 					case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST:
1928 						rtt_target->num_frames_per_burst =
1929 						nla_get_u32(iter2);
1930 						break;
1931 					case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM:
1932 						rtt_target->num_retries_per_ftm =
1933 						nla_get_u32(iter2);
1934 						break;
1935 					case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR:
1936 						rtt_target->num_retries_per_ftmr =
1937 						nla_get_u32(iter2);
1938 						if (rtt_target->num_retries_per_ftmr > 3) {
1939 							WL_ERR(("%d value must in (0-3)\n",
1940 								rtt_target->num_retries_per_ftmr));
1941 							err = -EINVAL;
1942 							goto exit;
1943 						}
1944 						break;
1945 					case RTT_ATTRIBUTE_TARGET_LCI:
1946 						rtt_target->LCI_request = nla_get_u8(iter2);
1947 						break;
1948 					case RTT_ATTRIBUTE_TARGET_LCR:
1949 						rtt_target->LCI_request = nla_get_u8(iter2);
1950 						break;
1951 					case RTT_ATTRIBUTE_TARGET_BURST_DURATION:
1952 						if ((nla_get_u32(iter2) > 1 &&
1953 							nla_get_u32(iter2) < 12)) {
1954 							rtt_target->burst_duration =
1955 							dhd_rtt_idx_to_burst_duration(
1956 								nla_get_u32(iter2));
1957 						} else if (nla_get_u32(iter2) == 15) {
1958 							/* use default value */
1959 							rtt_target->burst_duration = 0;
1960 						} else {
1961 							WL_ERR(("%d value must in (2-11) or 15\n",
1962 								nla_get_u32(iter2)));
1963 							err = -EINVAL;
1964 							goto exit;
1965 						}
1966 						break;
1967 					case RTT_ATTRIBUTE_TARGET_BW:
1968 						rtt_target->bw = nla_get_u8(iter2);
1969 						break;
1970 					case RTT_ATTRIBUTE_TARGET_PREAMBLE:
1971 						rtt_target->preamble = nla_get_u8(iter2);
1972 						break;
1973 					}
1974 				}
1975 				/* convert to chanspec value */
1976 				rtt_target->chanspec =
1977 					dhd_rtt_convert_to_chspec(rtt_target->channel);
1978 				if (rtt_target->chanspec == 0) {
1979 					WL_ERR(("Channel is not valid \n"));
1980 					err = -EINVAL;
1981 					goto exit;
1982 				}
1983 				WL_INFORM_MEM(("Target addr %s, Channel : %s for RTT \n",
1984 					bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr,
1985 					eabuf),
1986 					wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
1987 				rtt_target++;
1988 			}
1989 			break;
1990 		}
1991 	}
1992 	WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
1993 	if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
1994 		WL_ERR(("Could not set RTT configuration\n"));
1995 		err = -EINVAL;
1996 	}
1997 exit:
1998 	/* free the target info list */
1999 	if (rtt_param.target_info) {
2000 		MFREE(cfg->osh, rtt_param.target_info,
2001 			TARGET_INFO_SIZE(target_cnt));
2002 	}
2003 	return err;
2004 }
2005 
2006 static int
wl_cfgvendor_rtt_cancel_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2007 wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
2008 	const void *data, int len)
2009 {
2010 	int err = 0, rem, type, target_cnt = 0;
2011 	int target_idx = 0;
2012 	const struct nlattr *iter;
2013 	struct ether_addr *mac_list = NULL;
2014 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2015 
2016 	if (len <= 0) {
2017 		WL_ERR(("Length of nlattr is not valid len : %d\n", len));
2018 		err = -EINVAL;
2019 		goto exit;
2020 	}
2021 	nla_for_each_attr(iter, data, len, rem) {
2022 		type = nla_type(iter);
2023 		switch (type) {
2024 		case RTT_ATTRIBUTE_TARGET_CNT:
2025 			if (mac_list != NULL) {
2026 				WL_ERR(("mac_list is not NULL\n"));
2027 				err = -EINVAL;
2028 				goto exit;
2029 			}
2030 			target_cnt = nla_get_u8(iter);
2031 			if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) {
2032 				mac_list = (struct ether_addr *)MALLOCZ(cfg->osh,
2033 					target_cnt * ETHER_ADDR_LEN);
2034 				if (mac_list == NULL) {
2035 					WL_ERR(("failed to allocate mem for mac list\n"));
2036 					err = -EINVAL;
2037 					goto exit;
2038 				}
2039 			} else {
2040 				/* cancel the current whole RTT process */
2041 				goto cancel;
2042 			}
2043 			break;
2044 		case RTT_ATTRIBUTE_TARGET_MAC:
2045 			if (mac_list == NULL) {
2046 				WL_ERR(("ATTRIBUTE_TARGET_CNT not found before "
2047 						" ATTRIBUTE_TARGET_MAC\n"));
2048 				err = -EINVAL;
2049 				goto exit;
2050 			}
2051 
2052 			if (target_idx >= target_cnt) {
2053 				WL_ERR(("More TARGET_MAC entries found, "
2054 						"expected TARGET_CNT:%d\n", target_cnt));
2055 				err = -EINVAL;
2056 				goto exit;
2057 			}
2058 
2059 			if (nla_len(iter) != ETHER_ADDR_LEN) {
2060 				WL_ERR(("Invalid TARGET_MAC ATTR len :%d\n", nla_len(iter)));
2061 				err = -EINVAL;
2062 				goto exit;
2063 			}
2064 
2065 			memcpy(&mac_list[target_idx], nla_data(iter), ETHER_ADDR_LEN);
2066 			target_idx++;
2067 
2068 			break;
2069 		default:
2070 			WL_ERR(("Uknown type : %d\n", type));
2071 			err = -EINVAL;
2072 			goto exit;
2073 		}
2074 	}
2075 cancel:
2076 	if (mac_list && dhd_dev_rtt_cancel_cfg(
2077 		bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
2078 		WL_ERR(("Could not cancel RTT configuration\n"));
2079 		err = -EINVAL;
2080 	}
2081 
2082 exit:
2083 	if (mac_list) {
2084 		MFREE(cfg->osh, mac_list, target_cnt * ETHER_ADDR_LEN);
2085 	}
2086 	return err;
2087 }
2088 
2089 static int
wl_cfgvendor_rtt_get_capability(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2090 wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
2091 	const void *data, int len)
2092 {
2093 	int err = 0;
2094 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2095 	rtt_capabilities_t capability;
2096 
2097 	err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
2098 	if (unlikely(err)) {
2099 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2100 		goto exit;
2101 	}
2102 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &capability, sizeof(capability));
2103 
2104 	if (unlikely(err)) {
2105 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2106 	}
2107 exit:
2108 	return err;
2109 }
2110 static int
get_responder_info(struct bcm_cfg80211 * cfg,struct wifi_rtt_responder * responder_info)2111 get_responder_info(struct bcm_cfg80211 *cfg,
2112 	struct wifi_rtt_responder *responder_info)
2113 {
2114 	int err = 0;
2115 	rtt_capabilities_t capability;
2116 	err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
2117 	if (unlikely(err)) {
2118 		WL_ERR(("Could not get responder capability:%d \n", err));
2119 		return err;
2120 	}
2121 	if (capability.preamble_support & RTT_PREAMBLE_VHT) {
2122 		responder_info->preamble = RTT_PREAMBLE_VHT;
2123 	} else if (capability.preamble_support & RTT_PREAMBLE_HT) {
2124 		responder_info->preamble = RTT_PREAMBLE_HT;
2125 	} else {
2126 		responder_info->preamble = RTT_PREAMBLE_LEGACY;
2127 	}
2128 	err = dhd_dev_rtt_avail_channel(bcmcfg_to_prmry_ndev(cfg), &(responder_info->channel));
2129 	if (unlikely(err)) {
2130 		WL_ERR(("Could not get available channel:%d \n", err));
2131 		return err;
2132 	}
2133 	return err;
2134 }
2135 static int
wl_cfgvendor_rtt_get_responder_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2136 wl_cfgvendor_rtt_get_responder_info(struct wiphy *wiphy, struct wireless_dev *wdev,
2137 	const void *data, int len)
2138 {
2139 	int err = 0;
2140 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2141 	wifi_rtt_responder_t responder_info;
2142 
2143 	WL_DBG(("Recv -get_avail_ch command \n"));
2144 
2145 	bzero(&responder_info, sizeof(responder_info));
2146 	err = get_responder_info(cfg, &responder_info);
2147 	if (unlikely(err)) {
2148 		WL_ERR(("Failed to get responder info:%d \n", err));
2149 		return err;
2150 	}
2151 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &responder_info, sizeof(responder_info));
2152 	if (unlikely(err)) {
2153 		WL_ERR(("Vendor cmd reply for -get_avail_ch failed ret:%d \n", err));
2154 	}
2155 	return err;
2156 }
2157 
2158 static int
wl_cfgvendor_rtt_set_responder(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2159 wl_cfgvendor_rtt_set_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
2160 	const void *data, int len)
2161 {
2162 	int err = 0;
2163 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2164 	struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
2165 	wifi_rtt_responder_t responder_info;
2166 
2167 	WL_DBG(("Recv rtt -enable_resp cmd.\n"));
2168 
2169 	bzero(&responder_info, sizeof(responder_info));
2170 
2171 	/*
2172 	*Passing channel as NULL until implementation
2173 	*to get chan info from upper layers is donex
2174 	*/
2175 	err = dhd_dev_rtt_enable_responder(ndev, NULL);
2176 	if (unlikely(err)) {
2177 		WL_ERR(("Could not enable responder ret:%d \n", err));
2178 		goto done;
2179 	}
2180 	err = get_responder_info(cfg, &responder_info);
2181 	if (unlikely(err)) {
2182 		WL_ERR(("Failed to get responder info:%d \n", err));
2183 		dhd_dev_rtt_cancel_responder(ndev);
2184 		goto done;
2185 	}
2186 done:
2187 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &responder_info, sizeof(responder_info));
2188 	if (unlikely(err)) {
2189 		WL_ERR(("Vendor cmd reply for -enable_resp failed ret:%d \n", err));
2190 	}
2191 	return err;
2192 }
2193 
2194 static int
wl_cfgvendor_rtt_cancel_responder(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2195 wl_cfgvendor_rtt_cancel_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
2196 	const void *data, int len)
2197 {
2198 	int err = 0;
2199 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2200 
2201 	WL_DBG(("Recv rtt -cancel_resp cmd \n"));
2202 
2203 	err = dhd_dev_rtt_cancel_responder(bcmcfg_to_prmry_ndev(cfg));
2204 	if (unlikely(err)) {
2205 		WL_ERR(("Vendor cmd -cancel_resp failed ret:%d \n", err));
2206 	}
2207 	return err;
2208 }
2209 #endif /* RTT_SUPPORT */
2210 
2211 #ifdef GSCAN_SUPPORT
wl_cfgvendor_enable_lazy_roam(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2212 static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy,
2213 	struct wireless_dev *wdev, const void  *data, int len)
2214 {
2215 	int err = -EINVAL;
2216 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2217 	int type;
2218 	uint32 lazy_roam_enable_flag;
2219 
2220 	if (!data) {
2221 		WL_ERR(("data is not available\n"));
2222 		return -EINVAL;
2223 	}
2224 
2225 	if (len <= 0) {
2226 		WL_ERR(("invaild len %d\n", len));
2227 		return -EINVAL;
2228 	}
2229 
2230 	type = nla_type(data);
2231 
2232 	if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) {
2233 		lazy_roam_enable_flag = nla_get_u32(data);
2234 
2235 		err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg),
2236 		           lazy_roam_enable_flag);
2237 		if (unlikely(err))
2238 			WL_ERR(("Could not enable lazy roam:%d \n", err));
2239 	}
2240 
2241 	return err;
2242 }
2243 
wl_cfgvendor_set_lazy_roam_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2244 static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy,
2245 	struct wireless_dev *wdev, const void  *data, int len)
2246 {
2247 	int err = 0, tmp, type;
2248 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2249 	wlc_roam_exp_params_t roam_param;
2250 	const struct nlattr *iter;
2251 
2252 	bzero(&roam_param, sizeof(roam_param));
2253 
2254 	nla_for_each_attr(iter, data, len, tmp) {
2255 		type = nla_type(iter);
2256 		switch (type) {
2257 			case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD:
2258 				roam_param.a_band_boost_threshold = nla_get_u32(iter);
2259 				break;
2260 			case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD:
2261 				roam_param.a_band_penalty_threshold = nla_get_u32(iter);
2262 				break;
2263 			case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR:
2264 				roam_param.a_band_boost_factor = nla_get_u32(iter);
2265 				break;
2266 			case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR:
2267 				roam_param.a_band_penalty_factor = nla_get_u32(iter);
2268 				break;
2269 			case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST:
2270 				roam_param.a_band_max_boost = nla_get_u32(iter);
2271 				break;
2272 			case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS:
2273 				roam_param.cur_bssid_boost = nla_get_u32(iter);
2274 				break;
2275 			case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER:
2276 				roam_param.alert_roam_trigger_threshold = nla_get_u32(iter);
2277 				break;
2278 		}
2279 	}
2280 
2281 	if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) {
2282 		WL_ERR(("Could not set batch cfg\n"));
2283 		err = -EINVAL;
2284 	}
2285 	return err;
2286 }
2287 
2288 /* small helper function */
2289 static wl_bssid_pref_cfg_t *
create_bssid_pref_cfg(struct bcm_cfg80211 * cfg,uint32 num,uint32 * buf_len)2290 create_bssid_pref_cfg(struct bcm_cfg80211 *cfg, uint32 num, uint32 *buf_len)
2291 {
2292 	wl_bssid_pref_cfg_t *bssid_pref;
2293 
2294 	*buf_len = sizeof(wl_bssid_pref_cfg_t);
2295 	if (num) {
2296 		*buf_len += (num - 1) * sizeof(wl_bssid_pref_list_t);
2297 	}
2298 	bssid_pref = (wl_bssid_pref_cfg_t *)MALLOC(cfg->osh, *buf_len);
2299 
2300 	return bssid_pref;
2301 }
2302 
2303 static int
wl_cfgvendor_set_bssid_pref(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2304 wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy,
2305 	struct wireless_dev *wdev, const void  *data, int len)
2306 {
2307 	int err = 0;
2308 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2309 	wl_bssid_pref_cfg_t *bssid_pref = NULL;
2310 	wl_bssid_pref_list_t *bssids;
2311 	int tmp, tmp1, tmp2, type;
2312 	const struct nlattr *outer, *inner, *iter;
2313 	uint32 flush = 0, num = 0, buf_len = 0;
2314 	uint8 bssid_found = 0, rssi_found = 0;
2315 
2316 	/* Assumption: NUM attribute must come first */
2317 	nla_for_each_attr(iter, data, len, tmp2) {
2318 		type = nla_type(iter);
2319 		switch (type) {
2320 			case GSCAN_ATTRIBUTE_NUM_BSSID:
2321 				if (num) {
2322 					WL_ERR(("attempt overide bssid num.\n"));
2323 					err = -EINVAL;
2324 					goto exit;
2325 				}
2326 				if (nla_len(iter) != sizeof(uint32)) {
2327 					WL_ERR(("nla_len not match\n"));
2328 					err = -EINVAL;
2329 					goto exit;
2330 				}
2331 				num = nla_get_u32(iter);
2332 				if (num == 0 || num > MAX_BSSID_PREF_LIST_NUM) {
2333 					WL_ERR(("wrong BSSID num:%d\n", num));
2334 					err = -EINVAL;
2335 					goto exit;
2336 				}
2337 				if ((bssid_pref = create_bssid_pref_cfg(cfg, num, &buf_len))
2338 							== NULL) {
2339 					WL_ERR(("Can't malloc memory\n"));
2340 					err = -ENOMEM;
2341 					goto exit;
2342 				}
2343 				break;
2344 			case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH:
2345 				if (nla_len(iter) != sizeof(uint32)) {
2346 					WL_ERR(("nla_len not match\n"));
2347 					err = -EINVAL;
2348 					goto exit;
2349 				}
2350 				flush = nla_get_u32(iter);
2351 				if (flush != 1) {
2352 					WL_ERR(("wrong flush value\n"));
2353 					err = -EINVAL;
2354 					goto exit;
2355 				}
2356 				break;
2357 			case GSCAN_ATTRIBUTE_BSSID_PREF_LIST:
2358 				if (!num || !bssid_pref) {
2359 					WL_ERR(("bssid list count not set\n"));
2360 					err = -EINVAL;
2361 					goto exit;
2362 				}
2363 				bssid_pref->count = 0;
2364 				bssids = bssid_pref->bssids;
2365 				nla_for_each_nested(outer, iter, tmp) {
2366 					if (bssid_pref->count >= num) {
2367 						WL_ERR(("too many bssid list\n"));
2368 						err = -EINVAL;
2369 						goto exit;
2370 					}
2371 					bssid_found = 0;
2372 					rssi_found = 0;
2373 					nla_for_each_nested(inner, outer, tmp1) {
2374 						type = nla_type(inner);
2375 						switch (type) {
2376 						case GSCAN_ATTRIBUTE_BSSID_PREF:
2377 							if (nla_len(inner) != ETHER_ADDR_LEN) {
2378 								WL_ERR(("nla_len not match.\n"));
2379 								err = -EINVAL;
2380 								goto exit;
2381 							}
2382 							memcpy(&(bssids[bssid_pref->count].bssid),
2383 							  nla_data(inner), ETHER_ADDR_LEN);
2384 							/* not used for now */
2385 							bssids[bssid_pref->count].flags = 0;
2386 							bssid_found = 1;
2387 							break;
2388 						case GSCAN_ATTRIBUTE_RSSI_MODIFIER:
2389 							if (nla_len(inner) != sizeof(uint32)) {
2390 								WL_ERR(("nla_len not match.\n"));
2391 								err = -EINVAL;
2392 								goto exit;
2393 							}
2394 							bssids[bssid_pref->count].rssi_factor =
2395 							       (int8) nla_get_u32(inner);
2396 							rssi_found = 1;
2397 							break;
2398 						default:
2399 							WL_ERR(("wrong type:%d\n", type));
2400 							err = -EINVAL;
2401 							goto exit;
2402 						}
2403 						if (bssid_found && rssi_found) {
2404 							break;
2405 						}
2406 					}
2407 					bssid_pref->count++;
2408 				}
2409 				break;
2410 			default:
2411 				WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
2412 				break;
2413 			}
2414 	}
2415 
2416 	if (!bssid_pref) {
2417 		/* What if only flush is desired? */
2418 		if (flush) {
2419 			if ((bssid_pref = create_bssid_pref_cfg(cfg, 0, &buf_len)) == NULL) {
2420 				WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__));
2421 				err = -ENOMEM;
2422 				goto exit;
2423 			}
2424 			bssid_pref->count = 0;
2425 		} else {
2426 			err = -EINVAL;
2427 			goto exit;
2428 		}
2429 	}
2430 	err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg),
2431 	          bssid_pref, flush);
2432 exit:
2433 	if (bssid_pref) {
2434 		MFREE(cfg->osh, bssid_pref, buf_len);
2435 	}
2436 	return err;
2437 }
2438 #endif /* GSCAN_SUPPORT */
2439 #if defined(GSCAN_SUPPORT) || defined(ROAMEXP_SUPPORT)
2440 static int
wl_cfgvendor_set_bssid_blacklist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2441 wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy,
2442 	struct wireless_dev *wdev, const void  *data, int len)
2443 {
2444 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2445 	maclist_t *blacklist = NULL;
2446 	int err = 0;
2447 	int type, tmp;
2448 	const struct nlattr *iter;
2449 	uint32 mem_needed = 0, flush = 0, num = 0;
2450 
2451 	/* Assumption: NUM attribute must come first */
2452 	nla_for_each_attr(iter, data, len, tmp) {
2453 		type = nla_type(iter);
2454 		switch (type) {
2455 			case GSCAN_ATTRIBUTE_NUM_BSSID:
2456 				if (num != 0) {
2457 					WL_ERR(("attempt to change BSSID num\n"));
2458 					err = -EINVAL;
2459 					goto exit;
2460 				}
2461 				if (nla_len(iter) != sizeof(uint32)) {
2462 					WL_ERR(("not matching nla_len.\n"));
2463 					err = -EINVAL;
2464 					goto exit;
2465 				}
2466 				num = nla_get_u32(iter);
2467 				if (num == 0 || num > MAX_BSSID_BLACKLIST_NUM) {
2468 					WL_ERR(("wrong BSSID count:%d\n", num));
2469 					err = -EINVAL;
2470 					goto exit;
2471 				}
2472 				if (!blacklist) {
2473 					mem_needed = (uint32) (OFFSETOF(maclist_t, ea) +
2474 						sizeof(struct ether_addr) * (num));
2475 					blacklist = (maclist_t *)
2476 						MALLOCZ(cfg->osh, mem_needed);
2477 					if (!blacklist) {
2478 						WL_ERR(("MALLOCZ failed.\n"));
2479 						err = -ENOMEM;
2480 						goto exit;
2481 					}
2482 				}
2483 				break;
2484 			case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH:
2485 				if (nla_len(iter) != sizeof(uint32)) {
2486 					WL_ERR(("not matching nla_len.\n"));
2487 					err = -EINVAL;
2488 					goto exit;
2489 				}
2490 				flush = nla_get_u32(iter);
2491 				if (flush != 1) {
2492 					WL_ERR(("flush arg is worng:%d\n", flush));
2493 					err = -EINVAL;
2494 					goto exit;
2495 				}
2496 				break;
2497 			case GSCAN_ATTRIBUTE_BLACKLIST_BSSID:
2498 				if (num == 0 || !blacklist) {
2499 					WL_ERR(("number of BSSIDs not received.\n"));
2500 					err = -EINVAL;
2501 					goto exit;
2502 				}
2503 				if (nla_len(iter) != ETHER_ADDR_LEN) {
2504 					WL_ERR(("not matching nla_len.\n"));
2505 					err = -EINVAL;
2506 					goto exit;
2507 				}
2508 				if (blacklist->count >= num) {
2509 					WL_ERR(("too many BSSIDs than expected:%d\n",
2510 						blacklist->count));
2511 					err = -EINVAL;
2512 					goto exit;
2513 				}
2514 				memcpy(&(blacklist->ea[blacklist->count]), nla_data(iter),
2515 						ETHER_ADDR_LEN);
2516 				blacklist->count++;
2517 				break;
2518 		default:
2519 			WL_ERR(("No such attribute:%d\n", type));
2520 			break;
2521 		}
2522 	}
2523 
2524 	if (blacklist && (blacklist->count != num)) {
2525 		WL_ERR(("not matching bssid count:%d to expected:%d\n",
2526 				blacklist->count, num));
2527 		err = -EINVAL;
2528 		goto exit;
2529 	}
2530 
2531 	err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg),
2532 	          blacklist, mem_needed, flush);
2533 exit:
2534 	MFREE(cfg->osh, blacklist, mem_needed);
2535 	return err;
2536 }
2537 
2538 static int
wl_cfgvendor_set_ssid_whitelist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2539 wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy,
2540 	struct wireless_dev *wdev, const void  *data, int len)
2541 {
2542 	int err = 0;
2543 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2544 	wl_ssid_whitelist_t *ssid_whitelist = NULL;
2545 	wlc_ssid_t *ssid_elem;
2546 	int tmp, tmp1, mem_needed = 0, type;
2547 	const struct nlattr *iter, *iter1;
2548 	uint32 flush = 0, num = 0;
2549 	int ssid_found = 0;
2550 
2551 	/* Assumption: NUM attribute must come first */
2552 	nla_for_each_attr(iter, data, len, tmp) {
2553 		type = nla_type(iter);
2554 		switch (type) {
2555 		case GSCAN_ATTRIBUTE_NUM_WL_SSID:
2556 			if (num != 0) {
2557 				WL_ERR(("try to change SSID num\n"));
2558 				err = -EINVAL;
2559 				goto exit;
2560 			}
2561 			if (nla_len(iter) != sizeof(uint32)) {
2562 				WL_ERR(("not matching nla_len.\n"));
2563 				err = -EINVAL;
2564 				goto exit;
2565 			}
2566 			num = nla_get_u32(iter);
2567 			if (num == 0 || num > MAX_SSID_WHITELIST_NUM) {
2568 				WL_ERR(("wrong SSID count:%d\n", num));
2569 				err = -EINVAL;
2570 				goto exit;
2571 			}
2572 			mem_needed = sizeof(wl_ssid_whitelist_t) +
2573 				sizeof(wlc_ssid_t) * num;
2574 			ssid_whitelist = (wl_ssid_whitelist_t *)
2575 				MALLOCZ(cfg->osh, mem_needed);
2576 			if (ssid_whitelist == NULL) {
2577 				WL_ERR(("failed to alloc mem\n"));
2578 				err = -ENOMEM;
2579 				goto exit;
2580 			}
2581 			break;
2582 		case GSCAN_ATTRIBUTE_WL_SSID_FLUSH:
2583 			if (nla_len(iter) != sizeof(uint32)) {
2584 				WL_ERR(("not matching nla_len.\n"));
2585 				err = -EINVAL;
2586 				goto exit;
2587 			}
2588 			flush = nla_get_u32(iter);
2589 			if (flush != 1) {
2590 				WL_ERR(("flush arg worng:%d\n", flush));
2591 				err = -EINVAL;
2592 				goto exit;
2593 			}
2594 			break;
2595 		case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM:
2596 			if (!num || !ssid_whitelist) {
2597 				WL_ERR(("num ssid is not set!\n"));
2598 				err = -EINVAL;
2599 				goto exit;
2600 			}
2601 			if (ssid_whitelist->ssid_count >= num) {
2602 				WL_ERR(("too many SSIDs:%d\n",
2603 					ssid_whitelist->ssid_count));
2604 				err = -EINVAL;
2605 				goto exit;
2606 			}
2607 
2608 			ssid_elem = &ssid_whitelist->ssids[
2609 					ssid_whitelist->ssid_count];
2610 			ssid_found = 0;
2611 			nla_for_each_nested(iter1, iter, tmp1) {
2612 				type = nla_type(iter1);
2613 				switch (type) {
2614 				case GSCAN_ATTRIBUTE_WL_SSID_LEN:
2615 					if (nla_len(iter1) != sizeof(uint32)) {
2616 						WL_ERR(("not match nla_len\n"));
2617 						err = -EINVAL;
2618 						goto exit;
2619 					}
2620 					ssid_elem->SSID_len = nla_get_u32(iter1);
2621 					if (ssid_elem->SSID_len >
2622 							DOT11_MAX_SSID_LEN) {
2623 						WL_ERR(("wrong SSID len:%d\n",
2624 							ssid_elem->SSID_len));
2625 						err = -EINVAL;
2626 						goto exit;
2627 					}
2628 					break;
2629 				case GSCAN_ATTRIBUTE_WHITELIST_SSID:
2630 					if (ssid_elem->SSID_len == 0) {
2631 						WL_ERR(("SSID_len not received\n"));
2632 						err = -EINVAL;
2633 						goto exit;
2634 					}
2635 					if (nla_len(iter1) != ssid_elem->SSID_len) {
2636 						WL_ERR(("not match nla_len\n"));
2637 						err = -EINVAL;
2638 						goto exit;
2639 					}
2640 					memcpy(ssid_elem->SSID, nla_data(iter1),
2641 							ssid_elem->SSID_len);
2642 					ssid_found = 1;
2643 					break;
2644 				}
2645 				if (ssid_found) {
2646 					ssid_whitelist->ssid_count++;
2647 					break;
2648 				}
2649 			}
2650 			break;
2651 		default:
2652 			WL_ERR(("No such attribute: %d\n", type));
2653 			break;
2654 		}
2655 	}
2656 
2657 	if (ssid_whitelist && (ssid_whitelist->ssid_count != num)) {
2658 		WL_ERR(("not matching ssid count:%d to expected:%d\n",
2659 				ssid_whitelist->ssid_count, num));
2660 		err = -EINVAL;
2661 		goto exit;
2662 	}
2663 	err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg),
2664 	          ssid_whitelist, mem_needed, flush);
2665 	if (err == BCME_UNSUPPORTED) {
2666 		/* If firmware doesn't support feature, ignore the error
2667 		 * Android framework doesn't populate/use whitelist ssids
2668 		 * as of now, but invokes whitelist as part of roam config
2669 		 * API. so this handler cannot be compiled out. but its
2670 		 * safe to ignore.
2671 		 */
2672 		WL_ERR(("whilelist ssid not supported. Ignore."));
2673 		err = BCME_OK;
2674 	}
2675 exit:
2676 	MFREE(cfg->osh, ssid_whitelist, mem_needed);
2677 	return err;
2678 }
2679 #endif /* GSCAN_SUPPORT || ROAMEXP_SUPPORT */
2680 
2681 #ifdef ROAMEXP_SUPPORT
2682 typedef enum {
2683 	FW_ROAMING_ENABLE = 1,
2684 	FW_ROAMING_DISABLE,
2685 	FW_ROAMING_PAUSE,
2686 	FW_ROAMING_RESUME
2687 } fw_roaming_state_t;
2688 
2689 static int
wl_cfgvendor_set_fw_roaming_state(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2690 wl_cfgvendor_set_fw_roaming_state(struct wiphy *wiphy,
2691 	struct wireless_dev *wdev, const void  *data, int len)
2692 {
2693 	fw_roaming_state_t requested_roaming_state;
2694 	int type;
2695 	int err = 0;
2696 
2697 	if (!data) {
2698 		WL_ERR(("data is not available\n"));
2699 		return -EINVAL;
2700 	}
2701 
2702 	if (len <= 0) {
2703 		WL_ERR(("invalid len %d\n", len));
2704 		return -EINVAL;
2705 	}
2706 
2707 	/* Get the requested fw roaming state */
2708 	type = nla_type(data);
2709 	if (type != GSCAN_ATTRIBUTE_ROAM_STATE_SET) {
2710 		WL_ERR(("%s: Invalid attribute %d\n", __FUNCTION__, type));
2711 		return -EINVAL;
2712 	}
2713 
2714 	requested_roaming_state = nla_get_u32(data);
2715 	WL_INFORM(("setting FW roaming state to %d\n", requested_roaming_state));
2716 
2717 	if ((requested_roaming_state == FW_ROAMING_ENABLE) ||
2718 		(requested_roaming_state == FW_ROAMING_RESUME)) {
2719 		err = wldev_iovar_setint(wdev_to_ndev(wdev), "roam_off", FALSE);
2720 	} else if ((requested_roaming_state == FW_ROAMING_DISABLE) ||
2721 		(requested_roaming_state == FW_ROAMING_PAUSE)) {
2722 		err = wldev_iovar_setint(wdev_to_ndev(wdev), "roam_off", TRUE);
2723 	} else {
2724 		err = -EINVAL;
2725 	}
2726 
2727 	return err;
2728 }
2729 
2730 static int
wl_cfgvendor_fw_roam_get_capability(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2731 wl_cfgvendor_fw_roam_get_capability(struct wiphy *wiphy,
2732 	struct wireless_dev *wdev, const void  *data, int len)
2733 {
2734 	int err = 0;
2735 	wifi_roaming_capabilities_t roaming_capability;
2736 
2737 	/* Update max number of blacklist bssids supported */
2738 	roaming_capability.max_blacklist_size = MAX_BSSID_BLACKLIST_NUM;
2739 	roaming_capability.max_whitelist_size = MAX_SSID_WHITELIST_NUM;
2740 	err =  wl_cfgvendor_send_cmd_reply(wiphy, &roaming_capability,
2741 		sizeof(roaming_capability));
2742 	if (unlikely(err)) {
2743 		WL_ERR(("Vendor cmd reply for fw roam capability failed ret:%d \n", err));
2744 	}
2745 
2746 	return err;
2747 }
2748 #endif /* ROAMEXP_SUPPORT */
2749 
2750 static int
wl_cfgvendor_priv_string_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2751 wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
2752 	struct wireless_dev *wdev, const void  *data, int len)
2753 {
2754 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2755 	int ret = 0;
2756 	int ret_len = 0, payload = 0, msglen;
2757 	const struct bcm_nlmsg_hdr *nlioc = data;
2758 	void *buf = NULL, *cur;
2759 	int maxmsglen = PAGE_SIZE - 0x100;
2760 	struct sk_buff *reply;
2761 
2762 #if defined(OEM_ANDROID)
2763 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
2764 
2765 	/* send to dongle only if we are not waiting for reload already */
2766 	if (dhdp && dhdp->hang_was_sent) {
2767 		WL_INFORM(("Bus down. HANG was sent up earlier\n"));
2768 		DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, DHD_EVENT_TIMEOUT_MS);
2769 		DHD_OS_WAKE_UNLOCK(dhdp);
2770 		return OSL_ERROR(BCME_DONGLE_DOWN);
2771 	}
2772 #endif /* (OEM_ANDROID) */
2773 
2774 	if (!data) {
2775 		WL_ERR(("data is not available\n"));
2776 		return BCME_BADARG;
2777 	}
2778 
2779 	if (len <= sizeof(struct bcm_nlmsg_hdr)) {
2780 		WL_ERR(("invalid len %d\n", len));
2781 		return BCME_BADARG;
2782 	}
2783 
2784 	WL_DBG(("entry: cmd = %d\n", nlioc->cmd));
2785 
2786 	if (nlioc->offset != sizeof(struct bcm_nlmsg_hdr)) {
2787 		WL_ERR(("invalid offset %d\n", nlioc->offset));
2788 		return BCME_BADARG;
2789 	}
2790 	len -= sizeof(struct bcm_nlmsg_hdr);
2791 	ret_len = nlioc->len;
2792 	if (ret_len > 0 || len > 0) {
2793 		if (len >= DHD_IOCTL_MAXLEN) {
2794 			WL_ERR(("oversize input buffer %d\n", len));
2795 			len = DHD_IOCTL_MAXLEN - 1;
2796 		}
2797 		if (ret_len >= DHD_IOCTL_MAXLEN) {
2798 			WL_ERR(("oversize return buffer %d\n", ret_len));
2799 			ret_len = DHD_IOCTL_MAXLEN - 1;
2800 		}
2801 
2802 		payload = max(ret_len, len) + 1;
2803 		buf = vzalloc(payload);
2804 		if (!buf) {
2805 			return -ENOMEM;
2806 		}
2807 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2808 		memcpy(buf, (void *)((char *)nlioc + nlioc->offset), len);
2809 		GCC_DIAGNOSTIC_POP();
2810 		*((char *)buf + len) = '\0';
2811 	}
2812 
2813 	ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf);
2814 	if (ret) {
2815 		WL_ERR(("dhd_cfgvendor returned error %d\n", ret));
2816 		vfree(buf);
2817 		return ret;
2818 	}
2819 	cur = buf;
2820 	while (ret_len > 0) {
2821 		msglen = ret_len > maxmsglen ? maxmsglen : ret_len;
2822 		ret_len -= msglen;
2823 		payload = msglen + sizeof(msglen);
2824 		reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
2825 		if (!reply) {
2826 			WL_ERR(("Failed to allocate reply msg\n"));
2827 			ret = -ENOMEM;
2828 			break;
2829 		}
2830 
2831 		if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
2832 			nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
2833 			kfree_skb(reply);
2834 			ret = -ENOBUFS;
2835 			break;
2836 		}
2837 
2838 		ret = cfg80211_vendor_cmd_reply(reply);
2839 		if (ret) {
2840 			WL_ERR(("testmode reply failed:%d\n", ret));
2841 			break;
2842 		}
2843 		cur = (void *)((char *)cur + msglen);
2844 	}
2845 
2846 	return ret;
2847 }
2848 
2849 struct net_device *
wl_cfgvendor_get_ndev(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const char * data,unsigned long int * out_addr)2850 wl_cfgvendor_get_ndev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
2851 	const char *data, unsigned long int *out_addr)
2852 {
2853 	char *pos, *pos1;
2854 	char ifname[IFNAMSIZ + 1] = {0};
2855 	struct net_info *iter, *next;
2856 	struct net_device *ndev = NULL;
2857 	ulong ifname_len;
2858 	*out_addr = (unsigned long int) data; /* point to command str by default */
2859 
2860 	/* check whether ifname=<ifname> is provided in the command */
2861 	pos = strstr(data, "ifname=");
2862 	if (pos) {
2863 		pos += strlen("ifname=");
2864 		pos1 = strstr(pos, " ");
2865 		if (!pos1) {
2866 			WL_ERR(("command format error \n"));
2867 			return NULL;
2868 		}
2869 
2870 		ifname_len = pos1 - pos;
2871 		if (memcpy_s(ifname, (sizeof(ifname) - 1), pos, ifname_len) != BCME_OK) {
2872 			WL_ERR(("Failed to copy data. len: %ld\n", ifname_len));
2873 			return NULL;
2874 		}
2875 		GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2876 		for_each_ndev(cfg, iter, next) {
2877 			if (iter->ndev) {
2878 				if (strncmp(iter->ndev->name, ifname,
2879 					strlen(iter->ndev->name)) == 0) {
2880 					/* matching ifname found */
2881 					WL_DBG(("matching interface (%s) found ndev:%p \n",
2882 						iter->ndev->name, iter->ndev));
2883 					*out_addr = (unsigned long int)(pos1 + 1);
2884 					/* Returns the command portion after ifname=<name> */
2885 					return iter->ndev;
2886 				}
2887 			}
2888 		}
2889 		GCC_DIAGNOSTIC_POP();
2890 		WL_ERR(("Couldn't find ifname:%s in the netinfo list \n",
2891 			ifname));
2892 		return NULL;
2893 	}
2894 
2895 	/* If ifname=<name> arg is not provided, use default ndev */
2896 	ndev = wdev->netdev ? wdev->netdev : bcmcfg_to_prmry_ndev(cfg);
2897 	WL_DBG(("Using default ndev (%s) \n", ndev->name));
2898 	return ndev;
2899 }
2900 
2901 #ifdef WL_SAE
wl_cfgvendor_map_supp_sae_pwe_to_fw(u32 sup_value,u32 * sae_pwe)2902 static int wl_cfgvendor_map_supp_sae_pwe_to_fw(u32 sup_value, u32 *sae_pwe)
2903 {
2904 	s32 ret = BCME_OK;
2905 	switch (sup_value) {
2906 		case SUPP_SAE_PWE_LOOP:
2907 			*sae_pwe = SAE_PWE_LOOP;
2908 			break;
2909 		case SUPP_SAE_PWE_H2E:
2910 			*sae_pwe = SAE_PWE_H2E;
2911 			break;
2912 		case SUPP_SAE_PWE_TRANS:
2913 			*sae_pwe = SAE_PWE_LOOP | SAE_PWE_H2E;
2914 			break;
2915 		default:
2916 			ret = BCME_BADARG;
2917 	}
2918 	return ret;
2919 }
2920 #endif /* WL_SAE */
2921 
2922 int
wl_cfgvendor_connect_params_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2923 wl_cfgvendor_connect_params_handler(struct wiphy *wiphy,
2924 	struct wireless_dev *wdev, const void  *data, int len)
2925 {
2926 	struct net_device *net = wdev->netdev;
2927 	int ret = BCME_OK;
2928 	int attr_type;
2929 	int rem = len;
2930 	const struct nlattr *iter;
2931 
2932 	BCM_REFERENCE(net);
2933 
2934 	nla_for_each_attr(iter, data, len, rem) {
2935 		attr_type = nla_type(iter);
2936 		WL_DBG(("attr type: (%u)\n", attr_type));
2937 
2938 		switch (attr_type) {
2939 #ifdef WL_SAE
2940 		case BRCM_ATTR_SAE_PWE: {
2941 			u32 sae_pwe = 0;
2942 			if (nla_len(iter) != sizeof(uint32)) {
2943 				WL_ERR(("Invalid value of sae_pwe\n"));
2944 				ret = -EINVAL;
2945 				break;
2946 			}
2947 			ret = wl_cfgvendor_map_supp_sae_pwe_to_fw(nla_get_u32(iter), &sae_pwe);
2948 			if (unlikely(ret)) {
2949 				WL_ERR(("Invalid sae_pwe\n"));
2950 				break;
2951 			}
2952 			ret = wl_cfg80211_set_wsec_info(net, &sae_pwe,
2953 				sizeof(sae_pwe), WL_WSEC_INFO_BSS_SAE_PWE);
2954 			if (unlikely(ret)) {
2955 				WL_ERR(("set wsec_info_sae_pwe failed \n"));
2956 			}
2957 			break;
2958 		}
2959 #endif /* WL_SAE */
2960 		/* Add new attributes here */
2961 		default:
2962 			WL_DBG(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
2963 		}
2964 	}
2965 
2966 	return ret;
2967 }
2968 
2969 int
wl_cfgvendor_start_ap_params_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2970 wl_cfgvendor_start_ap_params_handler(struct wiphy *wiphy,
2971 	struct wireless_dev *wdev, const void  *data, int len)
2972 {
2973 	struct net_device *net = wdev->netdev;
2974 	int ret = BCME_OK;
2975 	int attr_type;
2976 	int rem = len;
2977 	const struct nlattr *iter;
2978 
2979 	BCM_REFERENCE(net);
2980 
2981 	nla_for_each_attr(iter, data, len, rem) {
2982 		attr_type = nla_type(iter);
2983 		WL_DBG(("attr type: (%u)\n", attr_type));
2984 
2985 		switch (attr_type) {
2986 #ifdef WL_SAE
2987 		case BRCM_ATTR_SAE_PWE: {
2988 			u32 sae_pwe = 0;
2989 			if (nla_len(iter) != sizeof(uint32)) {
2990 				WL_ERR(("Invalid value of sae_pwe\n"));
2991 				ret = -EINVAL;
2992 				break;
2993 			}
2994 			ret = wl_cfgvendor_map_supp_sae_pwe_to_fw(nla_get_u32(iter), &sae_pwe);
2995 			if (unlikely(ret)) {
2996 				WL_ERR(("Invalid sae_pwe\n"));
2997 				break;
2998 			}
2999 			ret = wl_cfg80211_set_wsec_info(net, &sae_pwe,
3000 				sizeof(sae_pwe), WL_WSEC_INFO_BSS_SAE_PWE);
3001 			if (unlikely(ret)) {
3002 				WL_ERR(("set wsec_info_sae_pwe failed \n"));
3003 			}
3004 			break;
3005 		}
3006 #endif /* WL_SAE */
3007 		/* Add new attributes here */
3008 		default:
3009 			WL_DBG(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
3010 		}
3011 	}
3012 
3013 	return ret;
3014 }
3015 
3016 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
3017 static int
wl_cfgvendor_set_sae_password(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3018 wl_cfgvendor_set_sae_password(struct wiphy *wiphy,
3019 	struct wireless_dev *wdev, const void  *data, int len)
3020 {
3021 	int err = BCME_OK;
3022 	struct net_device *net = wdev->netdev;
3023 	struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3024 	wsec_pmk_t pmk;
3025 	s32 bssidx;
3026 
3027 /* This api not needed for wpa_supplicant based sae authentication */
3028 #ifdef WL_CLIENT_SAE
3029 	WL_INFORM_MEM(("Ignore for external sae auth\n"));
3030 	return BCME_OK;
3031 #endif /* WL_CLIENT_SAE */
3032 
3033 	/* clear the content of pmk structure before usage */
3034 	(void)memset_s(&pmk, sizeof(wsec_pmk_t), 0x0, sizeof(wsec_pmk_t));
3035 
3036 	if ((bssidx = wl_get_bssidx_by_wdev(cfg, net->ieee80211_ptr)) < 0) {
3037 		WL_ERR(("Find p2p index from wdev(%p) failed\n", net->ieee80211_ptr));
3038 		return BCME_ERROR;
3039 	}
3040 
3041 	if ((len < WSEC_MIN_PSK_LEN) || (len >= WSEC_MAX_PASSPHRASE_LEN)) {
3042 		WL_ERR(("Invalid passphrase length %d..should be >= 8 and < 256\n",
3043 			len));
3044 		err = BCME_BADLEN;
3045 		goto done;
3046 	}
3047 	/* Set AUTH to SAE */
3048 	err = wldev_iovar_setint_bsscfg(net, "wpa_auth", WPA3_AUTH_SAE_PSK, bssidx);
3049 	if (unlikely(err)) {
3050 		WL_ERR(("could not set wpa_auth (0x%x)\n", err));
3051 		goto done;
3052 	}
3053 	pmk.key_len = htod16(len);
3054 	bcopy((const u8*)data, pmk.key, len);
3055 	pmk.flags = htod16(WSEC_PASSPHRASE);
3056 
3057 	err = wldev_ioctl_set(net, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
3058 	if (err) {
3059 		WL_ERR(("\n failed to set pmk %d\n", err));
3060 		goto done;
3061 	} else {
3062 		WL_INFORM_MEM(("sae passphrase set successfully\n"));
3063 	}
3064 done:
3065 	return err;
3066 }
3067 #endif /* WL_SAE || WL_CLIENT_SAE */
3068 
3069 #ifdef BCM_PRIV_CMD_SUPPORT
3070 /* strlen("ifname=") + IFNAMESIZE + strlen(" ") + '\0' */
3071 #define ANDROID_PRIV_CMD_IF_PREFIX_LEN	(7 + IFNAMSIZ + 2)
3072 /* Max length for the reply buffer. For BRCM_ATTR_DRIVER_CMD, the reply
3073  * would be a formatted string and reply buf would be the size of the
3074  * string.
3075  */
3076 #define WL_DRIVER_PRIV_CMD_LEN 512
3077 static int
wl_cfgvendor_priv_bcm_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3078 wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy,
3079 	struct wireless_dev *wdev, const void  *data, int len)
3080 {
3081 	const struct nlattr *iter;
3082 	int err = 0;
3083 	int data_len = 0, cmd_len = 0, tmp = 0, type = 0;
3084 	struct net_device *ndev = wdev->netdev;
3085 	char *cmd = NULL;
3086 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3087 	int bytes_written;
3088 	struct net_device *net = NULL;
3089 	unsigned long int cmd_out = 0;
3090 
3091 #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
3092 	u32 cmd_buf_len = WL_DRIVER_PRIV_CMD_LEN;
3093 	char cmd_prefix[ANDROID_PRIV_CMD_IF_PREFIX_LEN + 1] = {0};
3094 	char *cmd_buf = NULL;
3095 	char *current_pos;
3096 	u32 cmd_offset;
3097 #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
3098 
3099 	WL_DBG(("%s: Enter \n", __func__));
3100 
3101 	/* hold wake lock */
3102 	net_os_wake_lock(ndev);
3103 
3104 	nla_for_each_attr(iter, data, len, tmp) {
3105 		type = nla_type(iter);
3106 		cmd = nla_data(iter);
3107 		cmd_len = nla_len(iter);
3108 
3109 		WL_DBG(("%s: type: %d cmd_len:%d cmd_ptr:%p \n", __func__, type, cmd_len, cmd));
3110 		if (!cmd || !cmd_len) {
3111 			WL_ERR(("Invalid cmd data \n"));
3112 			err = -EINVAL;
3113 			goto exit;
3114 		}
3115 
3116 #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
3117 		if (type == BRCM_ATTR_DRIVER_CMD) {
3118 			if ((cmd_len >= WL_DRIVER_PRIV_CMD_LEN) ||
3119 				(cmd_len < ANDROID_PRIV_CMD_IF_PREFIX_LEN)) {
3120 				WL_ERR(("Unexpected command length (%u)."
3121 					"Ignore the command\n", cmd_len));
3122 				err = -EINVAL;
3123 				goto exit;
3124 			}
3125 
3126 			/* check whether there is any ifname prefix provided */
3127 			if (memcpy_s(cmd_prefix, (sizeof(cmd_prefix) - 1),
3128 					cmd, ANDROID_PRIV_CMD_IF_PREFIX_LEN) != BCME_OK) {
3129 				WL_ERR(("memcpy failed for cmd buffer. len:%d\n", cmd_len));
3130 				err = -ENOMEM;
3131 				goto exit;
3132 			}
3133 
3134 			net = wl_cfgvendor_get_ndev(cfg, wdev, cmd_prefix, &cmd_out);
3135 			if (!cmd_out || !net) {
3136 				WL_ERR(("ndev not found\n"));
3137 				err = -ENODEV;
3138 				goto exit;
3139 			}
3140 
3141 			/* find offset of the command */
3142 			current_pos = (char *)cmd_out;
3143 			cmd_offset = current_pos - cmd_prefix;
3144 
3145 			if (!current_pos || (cmd_offset) > ANDROID_PRIV_CMD_IF_PREFIX_LEN) {
3146 				WL_ERR(("Invalid len cmd_offset: %u \n", cmd_offset));
3147 				err = -EINVAL;
3148 				goto exit;
3149 			}
3150 
3151 			/* Private command data in expected to be in str format. To ensure that
3152 			 * the data is null terminated, copy to a local buffer before use
3153 			 */
3154 			cmd_buf = (char *)MALLOCZ(cfg->osh, cmd_buf_len);
3155 			if (!cmd_buf) {
3156 				WL_ERR(("memory alloc failed for %u \n", cmd_buf_len));
3157 				err = -ENOMEM;
3158 				goto exit;
3159 			}
3160 
3161 			/* Point to the start of command */
3162 			if (memcpy_s(cmd_buf, (WL_DRIVER_PRIV_CMD_LEN - 1),
3163 				(const void *)(cmd + cmd_offset),
3164 				(cmd_len - cmd_offset - 1)) != BCME_OK) {
3165 				WL_ERR(("memcpy failed for cmd buffer. len:%d\n", cmd_len));
3166 				err = -ENOMEM;
3167 				goto exit;
3168 			}
3169 			cmd_buf[WL_DRIVER_PRIV_CMD_LEN - 1] = '\0';
3170 
3171 			WL_DBG(("vendor_command: %s len: %u \n", cmd_buf, cmd_buf_len));
3172 			bytes_written = wl_handle_private_cmd(net, cmd_buf, cmd_buf_len);
3173 			WL_DBG(("bytes_written: %d \n", bytes_written));
3174 			if (bytes_written == 0) {
3175 				snprintf(cmd_buf, cmd_buf_len, "%s", "OK");
3176 				data_len = sizeof("OK");
3177 			} else if (bytes_written > 0) {
3178 				if (bytes_written >= (cmd_buf_len - 1)) {
3179 					/* Not expected */
3180 					ASSERT(0);
3181 					err = -EINVAL;
3182 					goto exit;
3183 				}
3184 				data_len = bytes_written;
3185 			} else {
3186 				/* -ve return value. Propagate the error back */
3187 				err = bytes_written;
3188 				goto exit;
3189 			}
3190 			if ((data_len > 0) && (data_len < (cmd_buf_len - 1)) && cmd_buf) {
3191 				err =  wl_cfgvendor_send_cmd_reply(wiphy, cmd_buf, data_len);
3192 				if (unlikely(err)) {
3193 					WL_ERR(("Vendor Command reply failed ret:%d \n", err));
3194 				} else {
3195 					WL_DBG(("Vendor Command reply sent successfully!\n"));
3196 				}
3197 			} else {
3198 				/* No data to be sent back as reply */
3199 				WL_ERR(("Vendor_cmd: No reply expected. data_len:%u cmd_buf %p \n",
3200 					data_len, cmd_buf));
3201 			}
3202 			break;
3203 		}
3204 #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
3205 
3206 	}
3207 
3208 exit:
3209 
3210 #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
3211 	if (cmd_buf) {
3212 		MFREE(cfg->osh, cmd_buf, cmd_buf_len);
3213 	}
3214 #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
3215 
3216 	net_os_wake_unlock(ndev);
3217 	return err;
3218 }
3219 #endif /* BCM_PRIV_CMD_SUPPORT */
3220 
3221 #ifdef WL_NAN
3222 static const char *
nan_attr_to_str(u16 cmd)3223 nan_attr_to_str(u16 cmd)
3224 {
3225 	const char *id2str;
3226 
3227 	switch (cmd) {
3228 	C2S(NAN_ATTRIBUTE_HEADER);
3229 		break;
3230 	C2S(NAN_ATTRIBUTE_HANDLE);
3231 		break;
3232 	C2S(NAN_ATTRIBUTE_TRANSAC_ID);
3233 		break;
3234 	C2S(NAN_ATTRIBUTE_2G_SUPPORT);
3235 		break;
3236 	C2S(NAN_ATTRIBUTE_SDF_2G_SUPPORT);
3237 		break;
3238 	C2S(NAN_ATTRIBUTE_SDF_5G_SUPPORT);
3239 		break;
3240 	C2S(NAN_ATTRIBUTE_5G_SUPPORT);
3241 		break;
3242 	C2S(NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON);
3243 		break;
3244 	C2S(NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON);
3245 		break;
3246 	C2S(NAN_ATTRIBUTE_CLUSTER_LOW);
3247 		break;
3248 	C2S(NAN_ATTRIBUTE_CLUSTER_HIGH);
3249 		break;
3250 	C2S(NAN_ATTRIBUTE_SID_BEACON);
3251 		break;
3252 	C2S(NAN_ATTRIBUTE_RSSI_CLOSE);
3253 		break;
3254 	C2S(NAN_ATTRIBUTE_RSSI_MIDDLE);
3255 		break;
3256 	C2S(NAN_ATTRIBUTE_RSSI_PROXIMITY);
3257 		break;
3258 	C2S(NAN_ATTRIBUTE_RSSI_CLOSE_5G);
3259 		break;
3260 	C2S(NAN_ATTRIBUTE_RSSI_MIDDLE_5G);
3261 		break;
3262 	C2S(NAN_ATTRIBUTE_RSSI_PROXIMITY_5G);
3263 		break;
3264 	C2S(NAN_ATTRIBUTE_HOP_COUNT_LIMIT);
3265 		break;
3266 	C2S(NAN_ATTRIBUTE_RANDOM_TIME);
3267 		break;
3268 	C2S(NAN_ATTRIBUTE_MASTER_PREF);
3269 		break;
3270 	C2S(NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL);
3271 		break;
3272 	C2S(NAN_ATTRIBUTE_PUBLISH_ID);
3273 		break;
3274 	C2S(NAN_ATTRIBUTE_TTL);
3275 		break;
3276 	C2S(NAN_ATTRIBUTE_PERIOD);
3277 		break;
3278 	C2S(NAN_ATTRIBUTE_REPLIED_EVENT_FLAG);
3279 		break;
3280 	C2S(NAN_ATTRIBUTE_PUBLISH_TYPE);
3281 		break;
3282 	C2S(NAN_ATTRIBUTE_TX_TYPE);
3283 		break;
3284 	C2S(NAN_ATTRIBUTE_PUBLISH_COUNT);
3285 		break;
3286 	C2S(NAN_ATTRIBUTE_SERVICE_NAME_LEN);
3287 		break;
3288 	C2S(NAN_ATTRIBUTE_SERVICE_NAME);
3289 		break;
3290 	C2S(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN);
3291 		break;
3292 	C2S(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO);
3293 		break;
3294 	C2S(NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN);
3295 		break;
3296 	C2S(NAN_ATTRIBUTE_RX_MATCH_FILTER);
3297 		break;
3298 	C2S(NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN);
3299 		break;
3300 	C2S(NAN_ATTRIBUTE_TX_MATCH_FILTER);
3301 		break;
3302 	C2S(NAN_ATTRIBUTE_SUBSCRIBE_ID);
3303 		break;
3304 	C2S(NAN_ATTRIBUTE_SUBSCRIBE_TYPE);
3305 		break;
3306 	C2S(NAN_ATTRIBUTE_SERVICERESPONSEFILTER);
3307 		break;
3308 	C2S(NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE);
3309 		break;
3310 	C2S(NAN_ATTRIBUTE_USESERVICERESPONSEFILTER);
3311 		break;
3312 	C2S(NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION);
3313 		break;
3314 	C2S(NAN_ATTRIBUTE_SUBSCRIBE_MATCH);
3315 		break;
3316 	C2S(NAN_ATTRIBUTE_SUBSCRIBE_COUNT);
3317 		break;
3318 	C2S(NAN_ATTRIBUTE_MAC_ADDR);
3319 		break;
3320 	C2S(NAN_ATTRIBUTE_MAC_ADDR_LIST);
3321 		break;
3322 	C2S(NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES);
3323 		break;
3324 	C2S(NAN_ATTRIBUTE_PUBLISH_MATCH);
3325 		break;
3326 	C2S(NAN_ATTRIBUTE_ENABLE_STATUS);
3327 		break;
3328 	C2S(NAN_ATTRIBUTE_JOIN_STATUS);
3329 		break;
3330 	C2S(NAN_ATTRIBUTE_ROLE);
3331 		break;
3332 	C2S(NAN_ATTRIBUTE_MASTER_RANK);
3333 		break;
3334 	C2S(NAN_ATTRIBUTE_ANCHOR_MASTER_RANK);
3335 		break;
3336 	C2S(NAN_ATTRIBUTE_CNT_PEND_TXFRM);
3337 		break;
3338 	C2S(NAN_ATTRIBUTE_CNT_BCN_TX);
3339 		break;
3340 	C2S(NAN_ATTRIBUTE_CNT_BCN_RX);
3341 		break;
3342 	C2S(NAN_ATTRIBUTE_CNT_SVC_DISC_TX);
3343 		break;
3344 	C2S(NAN_ATTRIBUTE_CNT_SVC_DISC_RX);
3345 		break;
3346 	C2S(NAN_ATTRIBUTE_AMBTT);
3347 		break;
3348 	C2S(NAN_ATTRIBUTE_CLUSTER_ID);
3349 		break;
3350 	C2S(NAN_ATTRIBUTE_INST_ID);
3351 		break;
3352 	C2S(NAN_ATTRIBUTE_OUI);
3353 		break;
3354 	C2S(NAN_ATTRIBUTE_STATUS);
3355 		break;
3356 	C2S(NAN_ATTRIBUTE_DE_EVENT_TYPE);
3357 		break;
3358 	C2S(NAN_ATTRIBUTE_MERGE);
3359 		break;
3360 	C2S(NAN_ATTRIBUTE_IFACE);
3361 		break;
3362 	C2S(NAN_ATTRIBUTE_CHANNEL);
3363 		break;
3364 	C2S(NAN_ATTRIBUTE_24G_CHANNEL);
3365 		break;
3366 	C2S(NAN_ATTRIBUTE_5G_CHANNEL);
3367 		break;
3368 	C2S(NAN_ATTRIBUTE_PEER_ID);
3369 		break;
3370 	C2S(NAN_ATTRIBUTE_NDP_ID);
3371 		break;
3372 	C2S(NAN_ATTRIBUTE_SECURITY);
3373 		break;
3374 	C2S(NAN_ATTRIBUTE_QOS);
3375 		break;
3376 	C2S(NAN_ATTRIBUTE_RSP_CODE);
3377 		break;
3378 	C2S(NAN_ATTRIBUTE_INST_COUNT);
3379 		break;
3380 	C2S(NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR);
3381 		break;
3382 	C2S(NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR);
3383 		break;
3384 	C2S(NAN_ATTRIBUTE_IF_ADDR);
3385 		break;
3386 	C2S(NAN_ATTRIBUTE_WARMUP_TIME);
3387 		break;
3388 	C2S(NAN_ATTRIBUTE_RECV_IND_CFG);
3389 		break;
3390 	C2S(NAN_ATTRIBUTE_CONNMAP);
3391 		break;
3392 	C2S(NAN_ATTRIBUTE_DWELL_TIME);
3393 		break;
3394 	C2S(NAN_ATTRIBUTE_SCAN_PERIOD);
3395 		break;
3396 	C2S(NAN_ATTRIBUTE_RSSI_WINDOW_SIZE);
3397 		break;
3398 	C2S(NAN_ATTRIBUTE_CONF_CLUSTER_VAL);
3399 		break;
3400 	C2S(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE);
3401 		break;
3402 	C2S(NAN_ATTRIBUTE_KEY_TYPE);
3403 		break;
3404 	C2S(NAN_ATTRIBUTE_KEY_LEN);
3405 		break;
3406 	C2S(NAN_ATTRIBUTE_SCID);
3407 		break;
3408 	C2S(NAN_ATTRIBUTE_SCID_LEN);
3409 		break;
3410 	C2S(NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP);
3411 		break;
3412 	C2S(NAN_ATTRIBUTE_SDE_CONTROL_SECURITY);
3413 		break;
3414 	C2S(NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE);
3415 		break;
3416 	C2S(NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT);
3417 		break;
3418 	C2S(NAN_ATTRIBUTE_NO_CONFIG_AVAIL);
3419 		break;
3420 	C2S(NAN_ATTRIBUTE_2G_AWAKE_DW);
3421 		break;
3422 	C2S(NAN_ATTRIBUTE_5G_AWAKE_DW);
3423 		break;
3424 	C2S(NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG);
3425 		break;
3426 	C2S(NAN_ATTRIBUTE_KEY_DATA);
3427 		break;
3428 	C2S(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN);
3429 		break;
3430 	C2S(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO);
3431 		break;
3432 	C2S(NAN_ATTRIBUTE_REASON);
3433 		break;
3434 	C2S(NAN_ATTRIBUTE_DISC_IND_CFG);
3435 		break;
3436 	C2S(NAN_ATTRIBUTE_DWELL_TIME_5G);
3437 		break;
3438 	C2S(NAN_ATTRIBUTE_SCAN_PERIOD_5G);
3439 		break;
3440 	C2S(NAN_ATTRIBUTE_SVC_RESPONDER_POLICY);
3441 		break;
3442 	C2S(NAN_ATTRIBUTE_EVENT_MASK);
3443 		break;
3444 	C2S(NAN_ATTRIBUTE_SUB_SID_BEACON);
3445 		break;
3446 	C2S(NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL);
3447 		break;
3448 	C2S(NAN_ATTRIBUTE_CMD_RESP_DATA);
3449 		break;
3450 	C2S(NAN_ATTRIBUTE_CMD_USE_NDPE);
3451 		break;
3452 	C2S(NAN_ATTRIBUTE_ENABLE_MERGE);
3453 		break;
3454 	C2S(NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL);
3455 		break;
3456 	C2S(NAN_ATTRIBUTE_NSS);
3457 		break;
3458 	C2S(NAN_ATTRIBUTE_ENABLE_RANGING);
3459 		break;
3460 	C2S(NAN_ATTRIBUTE_DW_EARLY_TERM);
3461 		break;
3462 	default:
3463 		id2str = "NAN_ATTRIBUTE_UNKNOWN";
3464 	}
3465 
3466 	return id2str;
3467 }
3468 
3469 nan_hal_status_t nan_status_reasonstr_map[] = {
3470 	{NAN_STATUS_SUCCESS, "NAN status success"},
3471 	{NAN_STATUS_INTERNAL_FAILURE, "NAN Discovery engine failure"},
3472 	{NAN_STATUS_PROTOCOL_FAILURE, "protocol failure"},
3473 	{NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID, "invalid pub_sub ID"},
3474 	{NAN_STATUS_NO_RESOURCE_AVAILABLE, "No space available"},
3475 	{NAN_STATUS_INVALID_PARAM, "invalid param"},
3476 	{NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID, "invalid req inst id"},
3477 	{NAN_STATUS_INVALID_NDP_ID, "invalid ndp id"},
3478 	{NAN_STATUS_NAN_NOT_ALLOWED, "Nan not allowed"},
3479 	{NAN_STATUS_NO_OTA_ACK, "No OTA ack"},
3480 	{NAN_STATUS_ALREADY_ENABLED, "NAN is Already enabled"},
3481 	{NAN_STATUS_FOLLOWUP_QUEUE_FULL, "Follow-up queue full"},
3482 	{NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED, "unsupported concurrency"},
3483 };
3484 
3485 void
wl_cfgvendor_add_nan_reason_str(nan_status_type_t status,nan_hal_resp_t * nan_req_resp)3486 wl_cfgvendor_add_nan_reason_str(nan_status_type_t status, nan_hal_resp_t *nan_req_resp)
3487 {
3488 	int i = 0;
3489 	int num = (int)(sizeof(nan_status_reasonstr_map)/sizeof(nan_status_reasonstr_map[0]));
3490 	for (i = 0; i < num; i++) {
3491 		if (nan_status_reasonstr_map[i].status == status) {
3492 			strlcpy(nan_req_resp->nan_reason, nan_status_reasonstr_map[i].nan_reason,
3493 				sizeof(nan_status_reasonstr_map[i].nan_reason));
3494 			break;
3495 		}
3496 	}
3497 }
3498 
3499 nan_status_type_t
wl_cfgvendor_brcm_to_nanhal_status(int32 vendor_status)3500 wl_cfgvendor_brcm_to_nanhal_status(int32 vendor_status)
3501 {
3502 	nan_status_type_t hal_status;
3503 	switch (vendor_status) {
3504 		case BCME_OK:
3505 			hal_status = NAN_STATUS_SUCCESS;
3506 			break;
3507 		case BCME_BUSY:
3508 		case BCME_NOTREADY:
3509 			hal_status = NAN_STATUS_NAN_NOT_ALLOWED;
3510 			break;
3511 		case BCME_BADLEN:
3512 		case BCME_BADBAND:
3513 		case BCME_UNSUPPORTED:
3514 		case BCME_USAGE_ERROR:
3515 		case BCME_BADARG:
3516 		case BCME_NOTENABLED:
3517 			hal_status = NAN_STATUS_INVALID_PARAM;
3518 			break;
3519 		case BCME_NOMEM:
3520 		case BCME_NORESOURCE:
3521 		case WL_NAN_E_SVC_SUB_LIST_FULL:
3522 			hal_status = NAN_STATUS_NO_RESOURCE_AVAILABLE;
3523 			break;
3524 		case WL_NAN_E_SD_TX_LIST_FULL:
3525 			hal_status = NAN_STATUS_FOLLOWUP_QUEUE_FULL;
3526 			break;
3527 		case WL_NAN_E_BAD_INSTANCE:
3528 			hal_status = NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
3529 			break;
3530 		default:
3531 			WL_ERR(("%s Unknown vendor status, status = %d\n",
3532 					__func__, vendor_status));
3533 			/* Generic error */
3534 			hal_status = NAN_STATUS_INTERNAL_FAILURE;
3535 	}
3536 	return hal_status;
3537 }
3538 
3539 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)3540 wl_cfgvendor_nan_cmd_reply(struct wiphy *wiphy, int nan_cmd,
3541 	nan_hal_resp_t *nan_req_resp, int ret, int nan_cmd_status)
3542 {
3543 	int err;
3544 	int nan_reply;
3545 	nan_req_resp->subcmd = nan_cmd;
3546 	if (ret == BCME_OK) {
3547 		nan_reply = nan_cmd_status;
3548 	} else {
3549 		nan_reply = ret;
3550 	}
3551 	nan_req_resp->status = wl_cfgvendor_brcm_to_nanhal_status(nan_reply);
3552 	nan_req_resp->value = ret;
3553 	err = wl_cfgvendor_send_cmd_reply(wiphy, nan_req_resp,
3554 		sizeof(*nan_req_resp));
3555 	return err;
3556 }
3557 
3558 static void
wl_cfgvendor_free_disc_cmd_data(struct bcm_cfg80211 * cfg,nan_discover_cmd_data_t * cmd_data)3559 wl_cfgvendor_free_disc_cmd_data(struct bcm_cfg80211 *cfg,
3560 	nan_discover_cmd_data_t *cmd_data)
3561 {
3562 	if (!cmd_data) {
3563 		WL_ERR(("Cmd_data is null\n"));
3564 		return;
3565 	}
3566 	if (cmd_data->svc_info.data) {
3567 		MFREE(cfg->osh, cmd_data->svc_info.data, cmd_data->svc_info.dlen);
3568 	}
3569 	if (cmd_data->svc_hash.data) {
3570 		MFREE(cfg->osh, cmd_data->svc_hash.data, cmd_data->svc_hash.dlen);
3571 	}
3572 	if (cmd_data->rx_match.data) {
3573 		MFREE(cfg->osh, cmd_data->rx_match.data, cmd_data->rx_match.dlen);
3574 	}
3575 	if (cmd_data->tx_match.data) {
3576 		MFREE(cfg->osh, cmd_data->tx_match.data, cmd_data->tx_match.dlen);
3577 	}
3578 	if (cmd_data->mac_list.list) {
3579 		MFREE(cfg->osh, cmd_data->mac_list.list,
3580 			cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN);
3581 	}
3582 	if (cmd_data->key.data) {
3583 		MFREE(cfg->osh, cmd_data->key.data, NAN_MAX_PMK_LEN);
3584 	}
3585 	if (cmd_data->sde_svc_info.data) {
3586 		MFREE(cfg->osh, cmd_data->sde_svc_info.data, cmd_data->sde_svc_info.dlen);
3587 	}
3588 	MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
3589 }
3590 
3591 static void
wl_cfgvendor_free_dp_cmd_data(struct bcm_cfg80211 * cfg,nan_datapath_cmd_data_t * cmd_data)3592 wl_cfgvendor_free_dp_cmd_data(struct bcm_cfg80211 *cfg,
3593 	nan_datapath_cmd_data_t *cmd_data)
3594 {
3595 	if (!cmd_data) {
3596 		WL_ERR(("Cmd_data is null\n"));
3597 		return;
3598 	}
3599 	if (cmd_data->svc_hash.data) {
3600 		MFREE(cfg->osh, cmd_data->svc_hash.data, cmd_data->svc_hash.dlen);
3601 	}
3602 	if (cmd_data->svc_info.data) {
3603 		MFREE(cfg->osh, cmd_data->svc_info.data, cmd_data->svc_info.dlen);
3604 	}
3605 	if (cmd_data->key.data) {
3606 		MFREE(cfg->osh, cmd_data->key.data, NAN_MAX_PMK_LEN);
3607 	}
3608 	MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
3609 }
3610 
3611 #define WL_NAN_EVENT_MAX_BUF 256
3612 #ifdef WL_NAN_DISC_CACHE
3613 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)3614 wl_cfgvendor_nan_parse_dp_sec_info_args(struct wiphy *wiphy,
3615 	const void *buf, int len, nan_datapath_sec_info_cmd_data_t *cmd_data)
3616 {
3617 	int ret = BCME_OK;
3618 	int attr_type;
3619 	int rem = len;
3620 	const struct nlattr *iter;
3621 
3622 	NAN_DBG_ENTER();
3623 
3624 	nla_for_each_attr(iter, buf, len, rem) {
3625 		attr_type = nla_type(iter);
3626 		WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
3627 
3628 		switch (attr_type) {
3629 		case NAN_ATTRIBUTE_MAC_ADDR:
3630 			ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
3631 				(char*)nla_data(iter), nla_len(iter));
3632 			if (ret != BCME_OK) {
3633 				WL_ERR(("Failed to copy mac addr\n"));
3634 				return ret;
3635 			}
3636 			break;
3637 		case NAN_ATTRIBUTE_PUBLISH_ID:
3638 			cmd_data->pub_id = nla_get_u16(iter);
3639 			break;
3640 		case NAN_ATTRIBUTE_NDP_ID:
3641 			cmd_data->ndp_instance_id = nla_get_u32(iter);
3642 			break;
3643 		default:
3644 			WL_ERR(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
3645 			ret = BCME_BADARG;
3646 			break;
3647 		}
3648 	}
3649 	/* We need to call set_config_handler b/f calling start enable TBD */
3650 	NAN_DBG_EXIT();
3651 	return ret;
3652 }
3653 #endif /* WL_NAN_DISC_CACHE */
3654 
3655 int8 chanbuf[CHANSPEC_STR_LEN];
3656 static int
wl_cfgvendor_nan_parse_datapath_args(struct wiphy * wiphy,const void * buf,int len,nan_datapath_cmd_data_t * cmd_data)3657 wl_cfgvendor_nan_parse_datapath_args(struct wiphy *wiphy,
3658 	const void *buf, int len, nan_datapath_cmd_data_t *cmd_data)
3659 {
3660 	int ret = BCME_OK;
3661 	int attr_type;
3662 	int rem = len;
3663 	const struct nlattr *iter;
3664 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3665 	int chan;
3666 
3667 	NAN_DBG_ENTER();
3668 
3669 	nla_for_each_attr(iter, buf, len, rem) {
3670 		attr_type = nla_type(iter);
3671 		WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
3672 
3673 		switch (attr_type) {
3674 		case NAN_ATTRIBUTE_NDP_ID:
3675 			if (nla_len(iter) != sizeof(uint32)) {
3676 				ret = -EINVAL;
3677 				goto exit;
3678 			}
3679 			cmd_data->ndp_instance_id = nla_get_u32(iter);
3680 			break;
3681 		case NAN_ATTRIBUTE_IFACE:
3682 			if (nla_len(iter) >= sizeof(cmd_data->ndp_iface)) {
3683 				WL_ERR(("iface_name len wrong:%d\n", nla_len(iter)));
3684 				ret = -EINVAL;
3685 				goto exit;
3686 			}
3687 			strlcpy((char *)cmd_data->ndp_iface, (char *)nla_data(iter),
3688 				nla_len(iter));
3689 			break;
3690 		case NAN_ATTRIBUTE_SECURITY:
3691 			if (nla_len(iter) != sizeof(uint8)) {
3692 				ret = -EINVAL;
3693 				goto exit;
3694 			}
3695 			cmd_data->ndp_cfg.security_cfg = nla_get_u8(iter);
3696 			break;
3697 		case NAN_ATTRIBUTE_QOS:
3698 			if (nla_len(iter) != sizeof(uint8)) {
3699 				ret = -EINVAL;
3700 				goto exit;
3701 			}
3702 			cmd_data->ndp_cfg.qos_cfg = nla_get_u8(iter);
3703 			break;
3704 		case NAN_ATTRIBUTE_RSP_CODE:
3705 			if (nla_len(iter) != sizeof(uint8)) {
3706 				ret = -EINVAL;
3707 				goto exit;
3708 			}
3709 			cmd_data->rsp_code = nla_get_u8(iter);
3710 			break;
3711 		case NAN_ATTRIBUTE_INST_COUNT:
3712 			if (nla_len(iter) != sizeof(uint8)) {
3713 				ret = -EINVAL;
3714 				goto exit;
3715 			}
3716 			cmd_data->num_ndp_instances = nla_get_u8(iter);
3717 			break;
3718 		case NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR:
3719 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3720 				ret = -EINVAL;
3721 				goto exit;
3722 			}
3723 			ret = memcpy_s((char*)&cmd_data->peer_disc_mac_addr,
3724 				ETHER_ADDR_LEN,	(char*)nla_data(iter), nla_len(iter));
3725 			if (ret != BCME_OK) {
3726 				WL_ERR(("Failed to copy peer_disc_mac_addr\n"));
3727 				goto exit;
3728 			}
3729 			break;
3730 		case NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR:
3731 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3732 				ret = -EINVAL;
3733 				goto exit;
3734 			}
3735 			ret = memcpy_s((char*)&cmd_data->peer_ndi_mac_addr,
3736 				ETHER_ADDR_LEN,	(char*)nla_data(iter), nla_len(iter));
3737 			if (ret != BCME_OK) {
3738 				WL_ERR(("Failed to copy peer_ndi_mac_addr\n"));
3739 				goto exit;
3740 			}
3741 			break;
3742 		case NAN_ATTRIBUTE_MAC_ADDR:
3743 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3744 				ret = -EINVAL;
3745 				goto exit;
3746 			}
3747 			ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
3748 					(char*)nla_data(iter), nla_len(iter));
3749 			if (ret != BCME_OK) {
3750 				WL_ERR(("Failed to copy mac_addr\n"));
3751 				goto exit;
3752 			}
3753 			break;
3754 		case NAN_ATTRIBUTE_IF_ADDR:
3755 			if (nla_len(iter) != ETHER_ADDR_LEN) {
3756 				ret = -EINVAL;
3757 				goto exit;
3758 			}
3759 			ret = memcpy_s((char*)&cmd_data->if_addr, ETHER_ADDR_LEN,
3760 					(char*)nla_data(iter), nla_len(iter));
3761 			if (ret != BCME_OK) {
3762 				WL_ERR(("Failed to copy if_addr\n"));
3763 				goto exit;
3764 			}
3765 			break;
3766 		case NAN_ATTRIBUTE_ENTRY_CONTROL:
3767 			if (nla_len(iter) != sizeof(uint8)) {
3768 				ret = -EINVAL;
3769 				goto exit;
3770 			}
3771 			cmd_data->avail_params.duration = nla_get_u8(iter);
3772 			break;
3773 		case NAN_ATTRIBUTE_AVAIL_BIT_MAP:
3774 			if (nla_len(iter) != sizeof(uint32)) {
3775 				ret = -EINVAL;
3776 				goto exit;
3777 			}
3778 			cmd_data->avail_params.bmap = nla_get_u32(iter);
3779 			break;
3780 		case NAN_ATTRIBUTE_CHANNEL: {
3781 			if (nla_len(iter) != sizeof(uint32)) {
3782 				ret = -EINVAL;
3783 				goto exit;
3784 			}
3785 			/* take the default channel start_factor frequency */
3786 			chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
3787 			if (chan <= CH_MAX_2G_CHANNEL) {
3788 				cmd_data->avail_params.chanspec[0] =
3789 					wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
3790 			} else {
3791 				cmd_data->avail_params.chanspec[0] =
3792 					wf_channel2chspec(chan, WL_CHANSPEC_BW_80);
3793 			}
3794 			if (cmd_data->avail_params.chanspec[0] == 0) {
3795 				WL_ERR(("Channel is not valid \n"));
3796 				ret = -EINVAL;
3797 				goto exit;
3798 			}
3799 			WL_TRACE(("valid chanspec, chanspec = 0x%04x \n",
3800 				cmd_data->avail_params.chanspec[0]));
3801 			break;
3802 		}
3803 		case NAN_ATTRIBUTE_NO_CONFIG_AVAIL:
3804 			if (nla_len(iter) != sizeof(uint8)) {
3805 				ret = -EINVAL;
3806 				goto exit;
3807 			}
3808 			cmd_data->avail_params.no_config_avail = (bool)nla_get_u8(iter);
3809 			break;
3810 		case NAN_ATTRIBUTE_SERVICE_NAME_LEN: {
3811 			if (nla_len(iter) != sizeof(uint16)) {
3812 				ret = -EINVAL;
3813 				goto exit;
3814 			}
3815 			if (cmd_data->svc_hash.dlen) {
3816 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3817 				ret = -EINVAL;
3818 				goto exit;
3819 			}
3820 			cmd_data->svc_hash.dlen = nla_get_u16(iter);
3821 			if (cmd_data->svc_hash.dlen != WL_NAN_SVC_HASH_LEN) {
3822 				WL_ERR(("invalid svc_hash length = %u\n", cmd_data->svc_hash.dlen));
3823 				ret = -EINVAL;
3824 				goto exit;
3825 			}
3826 			break;
3827 		}
3828 		case NAN_ATTRIBUTE_SERVICE_NAME:
3829 			if ((!cmd_data->svc_hash.dlen) ||
3830 				(nla_len(iter) != cmd_data->svc_hash.dlen)) {
3831 				WL_ERR(("invalid svc_hash length = %d,%d\n",
3832 					cmd_data->svc_hash.dlen, nla_len(iter)));
3833 				ret = -EINVAL;
3834 				goto exit;
3835 			}
3836 			if (cmd_data->svc_hash.data) {
3837 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3838 				ret = -EINVAL;
3839 				goto exit;
3840 			}
3841 			cmd_data->svc_hash.data =
3842 				MALLOCZ(cfg->osh, cmd_data->svc_hash.dlen);
3843 			if (!cmd_data->svc_hash.data) {
3844 				WL_ERR(("failed to allocate svc_hash data, len=%d\n",
3845 					cmd_data->svc_hash.dlen));
3846 				ret = -ENOMEM;
3847 				goto exit;
3848 			}
3849 			ret = memcpy_s(cmd_data->svc_hash.data, cmd_data->svc_hash.dlen,
3850 					nla_data(iter), nla_len(iter));
3851 			if (ret != BCME_OK) {
3852 				WL_ERR(("Failed to copy svc hash data\n"));
3853 				goto exit;
3854 			}
3855 			break;
3856 		case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN:
3857 			if (nla_len(iter) != sizeof(uint16)) {
3858 				ret = -EINVAL;
3859 				goto exit;
3860 			}
3861 			if (cmd_data->svc_info.dlen) {
3862 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3863 				ret = -EINVAL;
3864 				goto exit;
3865 			}
3866 			cmd_data->svc_info.dlen = nla_get_u16(iter);
3867 			if (cmd_data->svc_info.dlen > MAX_APP_INFO_LEN) {
3868 				WL_ERR_RLMT(("Not allowed beyond :%d\n", MAX_APP_INFO_LEN));
3869 				ret = -EINVAL;
3870 				goto exit;
3871 			}
3872 			break;
3873 		case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO:
3874 			if ((!cmd_data->svc_info.dlen) ||
3875 				(nla_len(iter) != cmd_data->svc_info.dlen)) {
3876 				WL_ERR(("failed to allocate svc info by invalid len=%d,%d\n",
3877 					cmd_data->svc_info.dlen, nla_len(iter)));
3878 				ret = -EINVAL;
3879 				goto exit;
3880 			}
3881 			if (cmd_data->svc_info.data) {
3882 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3883 				ret = -EINVAL;
3884 				goto exit;
3885 			}
3886 			cmd_data->svc_info.data = MALLOCZ(cfg->osh, cmd_data->svc_info.dlen);
3887 			if (cmd_data->svc_info.data == NULL) {
3888 				WL_ERR(("failed to allocate svc info data, len=%d\n",
3889 					cmd_data->svc_info.dlen));
3890 				ret = -ENOMEM;
3891 				goto exit;
3892 			}
3893 			ret = memcpy_s(cmd_data->svc_info.data, cmd_data->svc_info.dlen,
3894 					nla_data(iter), nla_len(iter));
3895 			if (ret != BCME_OK) {
3896 				WL_ERR(("Failed to copy svc info\n"));
3897 				goto exit;
3898 			}
3899 			break;
3900 		case NAN_ATTRIBUTE_PUBLISH_ID:
3901 			if (nla_len(iter) != sizeof(uint32)) {
3902 				ret = -EINVAL;
3903 				goto exit;
3904 			}
3905 			cmd_data->pub_id = nla_get_u32(iter);
3906 			break;
3907 		case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
3908 			if (nla_len(iter) != sizeof(uint8)) {
3909 				ret = -EINVAL;
3910 				goto exit;
3911 			}
3912 			cmd_data->csid = nla_get_u8(iter);
3913 			WL_TRACE(("CSID = %u\n", cmd_data->csid));
3914 			break;
3915 		case NAN_ATTRIBUTE_KEY_TYPE:
3916 			if (nla_len(iter) != sizeof(uint8)) {
3917 				ret = -EINVAL;
3918 				goto exit;
3919 			}
3920 			cmd_data->key_type = nla_get_u8(iter);
3921 			WL_TRACE(("Key Type = %u\n", cmd_data->key_type));
3922 			break;
3923 		case NAN_ATTRIBUTE_KEY_LEN:
3924 			if (nla_len(iter) != sizeof(uint32)) {
3925 				ret = -EINVAL;
3926 				goto exit;
3927 			}
3928 			if (cmd_data->key.dlen) {
3929 				WL_ERR(("trying to overwrite:%d\n", attr_type));
3930 				ret = -EINVAL;
3931 				goto exit;
3932 			}
3933 			cmd_data->key.dlen = nla_get_u32(iter);
3934 			if ((!cmd_data->key.dlen) || (cmd_data->key.dlen > WL_NAN_NCS_SK_PMK_LEN)) {
3935 				WL_ERR(("invalid key length = %u\n", cmd_data->key.dlen));
3936 				ret = -EINVAL;
3937 				goto exit;
3938 			}
3939 			WL_TRACE(("valid key length = %u\n", cmd_data->key.dlen));
3940 			break;
3941 		case NAN_ATTRIBUTE_KEY_DATA:
3942 			if ((!cmd_data->key.dlen) ||
3943 				(nla_len(iter) != cmd_data->key.dlen)) {
3944 				WL_ERR(("failed to allocate key data by invalid len=%d,%d\n",
3945 					cmd_data->key.dlen, nla_len(iter)));
3946 				ret = -EINVAL;
3947 				goto exit;
3948 			}
3949 			if (cmd_data->key.data) {
3950 				WL_ERR(("trying to overwrite key data.\n"));
3951 				ret = -EINVAL;
3952 				goto exit;
3953 			}
3954 
3955 			cmd_data->key.data = MALLOCZ(cfg->osh, NAN_MAX_PMK_LEN);
3956 			if (cmd_data->key.data == NULL) {
3957 				WL_ERR(("failed to allocate key data, len=%d\n",
3958 					cmd_data->key.dlen));
3959 				ret = -ENOMEM;
3960 				goto exit;
3961 			}
3962 			ret = memcpy_s(cmd_data->key.data, NAN_MAX_PMK_LEN,
3963 					nla_data(iter), nla_len(iter));
3964 			if (ret != BCME_OK) {
3965 				WL_ERR(("Failed to key data\n"));
3966 				goto exit;
3967 			}
3968 			break;
3969 
3970 		default:
3971 			WL_ERR(("Unknown type, %d\n", attr_type));
3972 			ret = -EINVAL;
3973 			goto exit;
3974 		}
3975 	}
3976 exit:
3977 	/* We need to call set_config_handler b/f calling start enable TBD */
3978 	NAN_DBG_EXIT();
3979 	return ret;
3980 }
3981 
3982 static int
wl_cfgvendor_nan_parse_discover_args(struct wiphy * wiphy,const void * buf,int len,nan_discover_cmd_data_t * cmd_data)3983 wl_cfgvendor_nan_parse_discover_args(struct wiphy *wiphy,
3984 	const void *buf, int len, nan_discover_cmd_data_t *cmd_data)
3985 {
3986 	int ret = BCME_OK;
3987 	int attr_type;
3988 	int rem = len;
3989 	const struct nlattr *iter;
3990 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3991 	u8 val_u8;
3992 	u32 bit_flag;
3993 	u8 flag_match;
3994 
3995 	NAN_DBG_ENTER();
3996 
3997 	nla_for_each_attr(iter, buf, len, rem) {
3998 		attr_type = nla_type(iter);
3999 		WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
4000 
4001 		switch (attr_type) {
4002 		case NAN_ATTRIBUTE_TRANSAC_ID:
4003 			if (nla_len(iter) != sizeof(uint16)) {
4004 				ret = -EINVAL;
4005 				goto exit;
4006 			}
4007 			cmd_data->token = nla_get_u16(iter);
4008 			break;
4009 		case NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL:
4010 			break;
4011 
4012 		/* Nan Publish/Subscribe request Attributes */
4013 		case NAN_ATTRIBUTE_PUBLISH_ID:
4014 			if (nla_len(iter) != sizeof(uint16)) {
4015 				ret = -EINVAL;
4016 				goto exit;
4017 			}
4018 			cmd_data->pub_id = nla_get_u16(iter);
4019 			cmd_data->local_id = cmd_data->pub_id;
4020 			break;
4021 		case NAN_ATTRIBUTE_MAC_ADDR:
4022 			if (nla_len(iter) != ETHER_ADDR_LEN) {
4023 				ret = -EINVAL;
4024 				goto exit;
4025 			}
4026 			ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
4027 					(char*)nla_data(iter), nla_len(iter));
4028 			if (ret != BCME_OK) {
4029 				WL_ERR(("Failed to copy mac addr\n"));
4030 				return ret;
4031 			}
4032 			break;
4033 		case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN:
4034 			if (nla_len(iter) != sizeof(uint16)) {
4035 				ret = -EINVAL;
4036 				goto exit;
4037 			}
4038 			if (cmd_data->svc_info.dlen) {
4039 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4040 				ret = -EINVAL;
4041 				goto exit;
4042 			}
4043 			cmd_data->svc_info.dlen = nla_get_u16(iter);
4044 			if (cmd_data->svc_info.dlen > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
4045 				WL_ERR_RLMT(("Not allowed beyond :%d\n",
4046 					NAN_MAX_SERVICE_SPECIFIC_INFO_LEN));
4047 				ret = -EINVAL;
4048 				goto exit;
4049 			}
4050 			break;
4051 		case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO:
4052 			if ((!cmd_data->svc_info.dlen) ||
4053 				(nla_len(iter) != cmd_data->svc_info.dlen)) {
4054 				WL_ERR(("failed to allocate svc info by invalid len=%d,%d\n",
4055 					cmd_data->svc_info.dlen, nla_len(iter)));
4056 				ret = -EINVAL;
4057 				goto exit;
4058 			}
4059 			if (cmd_data->svc_info.data) {
4060 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4061 				ret = -EINVAL;
4062 				goto exit;
4063 			}
4064 
4065 			cmd_data->svc_info.data = MALLOCZ(cfg->osh, cmd_data->svc_info.dlen);
4066 			if (cmd_data->svc_info.data == NULL) {
4067 				WL_ERR(("failed to allocate svc info data, len=%d\n",
4068 					cmd_data->svc_info.dlen));
4069 				ret = -ENOMEM;
4070 				goto exit;
4071 			}
4072 			ret = memcpy_s(cmd_data->svc_info.data, cmd_data->svc_info.dlen,
4073 					nla_data(iter), nla_len(iter));
4074 			if (ret != BCME_OK) {
4075 				WL_ERR(("Failed to copy svc info\n"));
4076 				return ret;
4077 			}
4078 			break;
4079 		case NAN_ATTRIBUTE_SUBSCRIBE_ID:
4080 			if (nla_len(iter) != sizeof(uint16)) {
4081 				ret = -EINVAL;
4082 				goto exit;
4083 			}
4084 			cmd_data->sub_id = nla_get_u16(iter);
4085 			cmd_data->local_id = cmd_data->sub_id;
4086 			break;
4087 		case NAN_ATTRIBUTE_SUBSCRIBE_TYPE:
4088 			if (nla_len(iter) != sizeof(uint8)) {
4089 				ret = -EINVAL;
4090 				goto exit;
4091 			}
4092 			cmd_data->flags |= nla_get_u8(iter) ? WL_NAN_SUB_ACTIVE : 0;
4093 			break;
4094 		case NAN_ATTRIBUTE_PUBLISH_COUNT:
4095 			if (nla_len(iter) != sizeof(uint8)) {
4096 				ret = -EINVAL;
4097 				goto exit;
4098 			}
4099 			cmd_data->life_count = nla_get_u8(iter);
4100 			break;
4101 		case NAN_ATTRIBUTE_PUBLISH_TYPE: {
4102 			if (nla_len(iter) != sizeof(uint8)) {
4103 				ret = -EINVAL;
4104 				goto exit;
4105 			}
4106 			val_u8 = nla_get_u8(iter);
4107 			if (val_u8 == 0) {
4108 				cmd_data->flags |= WL_NAN_PUB_UNSOLICIT;
4109 			} else if (val_u8 == 1) {
4110 				cmd_data->flags |= WL_NAN_PUB_SOLICIT;
4111 			} else {
4112 				cmd_data->flags |= WL_NAN_PUB_BOTH;
4113 			}
4114 			break;
4115 		}
4116 		case NAN_ATTRIBUTE_PERIOD: {
4117 			if (nla_len(iter) != sizeof(uint16)) {
4118 				ret = -EINVAL;
4119 				goto exit;
4120 			}
4121 			if (nla_get_u16(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
4122 				WL_ERR(("Invalid/Out of bound value = %u\n", nla_get_u16(iter)));
4123 				ret = BCME_BADARG;
4124 				break;
4125 			}
4126 			if (nla_get_u16(iter)) {
4127 				cmd_data->period = 1 << (nla_get_u16(iter)-1);
4128 			}
4129 			break;
4130 		}
4131 		case NAN_ATTRIBUTE_REPLIED_EVENT_FLAG:
4132 			break;
4133 		case NAN_ATTRIBUTE_TTL:
4134 			if (nla_len(iter) != sizeof(uint16)) {
4135 				ret = -EINVAL;
4136 				goto exit;
4137 			}
4138 			cmd_data->ttl = nla_get_u16(iter);
4139 			break;
4140 		case NAN_ATTRIBUTE_SERVICE_NAME_LEN: {
4141 			if (nla_len(iter) != sizeof(uint16)) {
4142 				ret = -EINVAL;
4143 				goto exit;
4144 			}
4145 			if (cmd_data->svc_hash.dlen) {
4146 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4147 				ret = -EINVAL;
4148 				goto exit;
4149 			}
4150 
4151 			cmd_data->svc_hash.dlen = nla_get_u16(iter);
4152 			if (cmd_data->svc_hash.dlen != WL_NAN_SVC_HASH_LEN) {
4153 				WL_ERR(("invalid svc_hash length = %u\n", cmd_data->svc_hash.dlen));
4154 				ret = -EINVAL;
4155 				goto exit;
4156 			}
4157 			break;
4158 		}
4159 		case NAN_ATTRIBUTE_SERVICE_NAME:
4160 			if ((!cmd_data->svc_hash.dlen) ||
4161 				(nla_len(iter) != cmd_data->svc_hash.dlen)) {
4162 				WL_ERR(("invalid svc_hash length = %d,%d\n",
4163 					cmd_data->svc_hash.dlen, nla_len(iter)));
4164 				ret = -EINVAL;
4165 				goto exit;
4166 			}
4167 			if (cmd_data->svc_hash.data) {
4168 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4169 				ret = -EINVAL;
4170 				goto exit;
4171 			}
4172 
4173 			cmd_data->svc_hash.data =
4174 				MALLOCZ(cfg->osh, cmd_data->svc_hash.dlen);
4175 			if (!cmd_data->svc_hash.data) {
4176 				WL_ERR(("failed to allocate svc_hash data, len=%d\n",
4177 					cmd_data->svc_hash.dlen));
4178 				ret = -ENOMEM;
4179 				goto exit;
4180 			}
4181 			ret = memcpy_s(cmd_data->svc_hash.data, cmd_data->svc_hash.dlen,
4182 					nla_data(iter), nla_len(iter));
4183 			if (ret != BCME_OK) {
4184 				WL_ERR(("Failed to copy svc hash data\n"));
4185 				return ret;
4186 			}
4187 			break;
4188 		case NAN_ATTRIBUTE_PEER_ID:
4189 			if (nla_len(iter) != sizeof(uint32)) {
4190 				ret = -EINVAL;
4191 				goto exit;
4192 			}
4193 			cmd_data->remote_id = nla_get_u32(iter);
4194 			break;
4195 		case NAN_ATTRIBUTE_INST_ID:
4196 			if (nla_len(iter) != sizeof(uint16)) {
4197 				ret = -EINVAL;
4198 				goto exit;
4199 			}
4200 			cmd_data->local_id = nla_get_u16(iter);
4201 			break;
4202 		case NAN_ATTRIBUTE_SUBSCRIBE_COUNT:
4203 			if (nla_len(iter) != sizeof(uint8)) {
4204 				ret = -EINVAL;
4205 				goto exit;
4206 			}
4207 			cmd_data->life_count = nla_get_u8(iter);
4208 			break;
4209 		case NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION: {
4210 			if (nla_len(iter) != sizeof(uint8)) {
4211 				ret = -EINVAL;
4212 				goto exit;
4213 			}
4214 			bit_flag = (u32)nla_get_u8(iter);
4215 			cmd_data->flags |=
4216 				bit_flag ? WL_NAN_SUB_MATCH_IF_SVC_INFO : 0;
4217 			break;
4218 		}
4219 		case NAN_ATTRIBUTE_SUBSCRIBE_MATCH:
4220 		case NAN_ATTRIBUTE_PUBLISH_MATCH: {
4221 			if (nla_len(iter) != sizeof(uint8)) {
4222 				ret = -EINVAL;
4223 				goto exit;
4224 			}
4225 			flag_match = nla_get_u8(iter);
4226 
4227 			switch (flag_match) {
4228 			case NAN_MATCH_ALG_MATCH_CONTINUOUS:
4229 				/* Default fw behaviour, no need to set explicitly */
4230 				break;
4231 			case NAN_MATCH_ALG_MATCH_ONCE:
4232 				cmd_data->flags |= WL_NAN_MATCH_ONCE;
4233 				break;
4234 			case NAN_MATCH_ALG_MATCH_NEVER:
4235 				cmd_data->flags |= WL_NAN_MATCH_NEVER;
4236 				break;
4237 			default:
4238 				WL_ERR(("invalid nan match alg = %u\n", flag_match));
4239 				ret = -EINVAL;
4240 				goto exit;
4241 			}
4242 			break;
4243 		}
4244 		case NAN_ATTRIBUTE_SERVICERESPONSEFILTER:
4245 			if (nla_len(iter) != sizeof(uint8)) {
4246 				ret = -EINVAL;
4247 				goto exit;
4248 			}
4249 			cmd_data->srf_type = nla_get_u8(iter);
4250 			break;
4251 		case NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE:
4252 			if (nla_len(iter) != sizeof(uint8)) {
4253 				ret = -EINVAL;
4254 				goto exit;
4255 			}
4256 			cmd_data->srf_include = nla_get_u8(iter);
4257 			break;
4258 		case NAN_ATTRIBUTE_USESERVICERESPONSEFILTER:
4259 			if (nla_len(iter) != sizeof(uint8)) {
4260 				ret = -EINVAL;
4261 				goto exit;
4262 			}
4263 			cmd_data->use_srf = nla_get_u8(iter);
4264 			break;
4265 		case NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN:
4266 			if (nla_len(iter) != sizeof(uint16)) {
4267 				ret = -EINVAL;
4268 				goto exit;
4269 			}
4270 			if (cmd_data->rx_match.dlen) {
4271 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4272 				ret = -EINVAL;
4273 				goto exit;
4274 			}
4275 			cmd_data->rx_match.dlen = nla_get_u16(iter);
4276 			if (cmd_data->rx_match.dlen > MAX_MATCH_FILTER_LEN) {
4277 				ret = -EINVAL;
4278 				WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_MATCH_FILTER_LEN));
4279 				goto exit;
4280 			}
4281 			break;
4282 		case NAN_ATTRIBUTE_RX_MATCH_FILTER:
4283 			if ((!cmd_data->rx_match.dlen) ||
4284 			    (nla_len(iter) != cmd_data->rx_match.dlen)) {
4285 				WL_ERR(("RX match filter len wrong:%d,%d\n",
4286 					cmd_data->rx_match.dlen, nla_len(iter)));
4287 				ret = -EINVAL;
4288 				goto exit;
4289 			}
4290 			if (cmd_data->rx_match.data) {
4291 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4292 				ret = -EINVAL;
4293 				goto exit;
4294 			}
4295 			cmd_data->rx_match.data =
4296 				MALLOCZ(cfg->osh, cmd_data->rx_match.dlen);
4297 			if (cmd_data->rx_match.data == NULL) {
4298 				WL_ERR(("failed to allocate LEN=[%u]\n",
4299 					cmd_data->rx_match.dlen));
4300 				ret = -ENOMEM;
4301 				goto exit;
4302 			}
4303 			ret = memcpy_s(cmd_data->rx_match.data, cmd_data->rx_match.dlen,
4304 					nla_data(iter), nla_len(iter));
4305 			if (ret != BCME_OK) {
4306 				WL_ERR(("Failed to copy rx match data\n"));
4307 				return ret;
4308 			}
4309 			break;
4310 		case NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN:
4311 			if (nla_len(iter) != sizeof(uint16)) {
4312 				ret = -EINVAL;
4313 				goto exit;
4314 			}
4315 			if (cmd_data->tx_match.dlen) {
4316 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4317 				ret = -EINVAL;
4318 				goto exit;
4319 			}
4320 			cmd_data->tx_match.dlen = nla_get_u16(iter);
4321 			if (cmd_data->tx_match.dlen > MAX_MATCH_FILTER_LEN) {
4322 				ret = -EINVAL;
4323 				WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_MATCH_FILTER_LEN));
4324 				goto exit;
4325 			}
4326 			break;
4327 		case NAN_ATTRIBUTE_TX_MATCH_FILTER:
4328 			if ((!cmd_data->tx_match.dlen) ||
4329 			    (nla_len(iter) != cmd_data->tx_match.dlen)) {
4330 				WL_ERR(("TX match filter len wrong:%d,%d\n",
4331 					cmd_data->tx_match.dlen, nla_len(iter)));
4332 				ret = -EINVAL;
4333 				goto exit;
4334 			}
4335 			if (cmd_data->tx_match.data) {
4336 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4337 				ret = -EINVAL;
4338 				goto exit;
4339 			}
4340 			cmd_data->tx_match.data =
4341 				MALLOCZ(cfg->osh, cmd_data->tx_match.dlen);
4342 			if (cmd_data->tx_match.data == NULL) {
4343 				WL_ERR(("failed to allocate LEN=[%u]\n",
4344 					cmd_data->tx_match.dlen));
4345 				ret = -EINVAL;
4346 				goto exit;
4347 			}
4348 			ret = memcpy_s(cmd_data->tx_match.data, cmd_data->tx_match.dlen,
4349 					nla_data(iter), nla_len(iter));
4350 			if (ret != BCME_OK) {
4351 				WL_ERR(("Failed to copy tx match data\n"));
4352 				return ret;
4353 			}
4354 			break;
4355 		case NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES:
4356 			if (nla_len(iter) != sizeof(uint16)) {
4357 				ret = -EINVAL;
4358 				goto exit;
4359 			}
4360 			if (cmd_data->mac_list.num_mac_addr) {
4361 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4362 				ret = -EINVAL;
4363 				goto exit;
4364 			}
4365 			cmd_data->mac_list.num_mac_addr = nla_get_u16(iter);
4366 			if (cmd_data->mac_list.num_mac_addr >= NAN_SRF_MAX_MAC) {
4367 				WL_ERR(("trying to overflow num :%d\n",
4368 					cmd_data->mac_list.num_mac_addr));
4369 				cmd_data->mac_list.num_mac_addr = 0;
4370 				ret = -EINVAL;
4371 				goto exit;
4372 			}
4373 			break;
4374 		case NAN_ATTRIBUTE_MAC_ADDR_LIST:
4375 			if ((!cmd_data->mac_list.num_mac_addr) ||
4376 			    (nla_len(iter) != (cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN))) {
4377 				WL_ERR(("wrong mac list len:%d,%d\n",
4378 					cmd_data->mac_list.num_mac_addr, nla_len(iter)));
4379 				ret = -EINVAL;
4380 				goto exit;
4381 			}
4382 			if (cmd_data->mac_list.list) {
4383 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4384 				ret = -EINVAL;
4385 				goto exit;
4386 			}
4387 			cmd_data->mac_list.list =
4388 				MALLOCZ(cfg->osh, (cmd_data->mac_list.num_mac_addr
4389 						* ETHER_ADDR_LEN));
4390 			if (cmd_data->mac_list.list == NULL) {
4391 				WL_ERR(("failed to allocate LEN=[%u]\n",
4392 				(cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN)));
4393 				ret = -ENOMEM;
4394 				goto exit;
4395 			}
4396 			ret = memcpy_s(cmd_data->mac_list.list,
4397 				(cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN),
4398 				nla_data(iter), nla_len(iter));
4399 			if (ret != BCME_OK) {
4400 				WL_ERR(("Failed to copy list of mac addresses\n"));
4401 				return ret;
4402 			}
4403 			break;
4404 		case NAN_ATTRIBUTE_TX_TYPE:
4405 			if (nla_len(iter) != sizeof(uint8)) {
4406 				ret = -EINVAL;
4407 				goto exit;
4408 			}
4409 			val_u8 =  nla_get_u8(iter);
4410 			if (val_u8 == 0) {
4411 				cmd_data->flags |= WL_NAN_PUB_BCAST;
4412 				WL_TRACE(("NAN_ATTRIBUTE_TX_TYPE: flags=NAN_PUB_BCAST\n"));
4413 			}
4414 			break;
4415 		case NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP:
4416 			if (nla_len(iter) != sizeof(uint8)) {
4417 				ret = -EINVAL;
4418 				goto exit;
4419 			}
4420 			if (nla_get_u8(iter) == 1) {
4421 				cmd_data->sde_control_flag
4422 					|= NAN_SDE_CF_DP_REQUIRED;
4423 				break;
4424 			}
4425 			break;
4426 		case NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT:
4427 			if (nla_len(iter) != sizeof(uint8)) {
4428 				ret = -EINVAL;
4429 				goto exit;
4430 			}
4431 			cmd_data->sde_control_config = TRUE;
4432 			if (nla_get_u8(iter) == 1) {
4433 				cmd_data->sde_control_flag
4434 					|= NAN_SDE_CF_RANGING_REQUIRED;
4435 				break;
4436 			}
4437 			break;
4438 		case NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE:
4439 			if (nla_len(iter) != sizeof(uint8)) {
4440 				ret = -EINVAL;
4441 				goto exit;
4442 			}
4443 			if (nla_get_u8(iter) == 1) {
4444 				cmd_data->sde_control_flag
4445 					|= NAN_SDE_CF_MULTICAST_TYPE;
4446 				break;
4447 			}
4448 			break;
4449 		case NAN_ATTRIBUTE_SDE_CONTROL_SECURITY:
4450 			if (nla_len(iter) != sizeof(uint8)) {
4451 				ret = -EINVAL;
4452 				goto exit;
4453 			}
4454 			if (nla_get_u8(iter) == 1) {
4455 				cmd_data->sde_control_flag
4456 					|= NAN_SDE_CF_SECURITY_REQUIRED;
4457 				break;
4458 			}
4459 			break;
4460 		case NAN_ATTRIBUTE_RECV_IND_CFG:
4461 			if (nla_len(iter) != sizeof(uint8)) {
4462 				ret = -EINVAL;
4463 				goto exit;
4464 			}
4465 			cmd_data->recv_ind_flag = nla_get_u8(iter);
4466 			break;
4467 		case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
4468 			if (nla_len(iter) != sizeof(uint8)) {
4469 				ret = -EINVAL;
4470 				goto exit;
4471 			}
4472 			cmd_data->csid = nla_get_u8(iter);
4473 			WL_TRACE(("CSID = %u\n", cmd_data->csid));
4474 			break;
4475 		case NAN_ATTRIBUTE_KEY_TYPE:
4476 			if (nla_len(iter) != sizeof(uint8)) {
4477 				ret = -EINVAL;
4478 				goto exit;
4479 			}
4480 			cmd_data->key_type = nla_get_u8(iter);
4481 			WL_TRACE(("Key Type = %u\n", cmd_data->key_type));
4482 			break;
4483 		case NAN_ATTRIBUTE_KEY_LEN:
4484 			if (nla_len(iter) != sizeof(uint32)) {
4485 				ret = -EINVAL;
4486 				goto exit;
4487 			}
4488 			if (cmd_data->key.dlen) {
4489 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4490 				ret = -EINVAL;
4491 				goto exit;
4492 			}
4493 			cmd_data->key.dlen = nla_get_u32(iter);
4494 			if ((!cmd_data->key.dlen) || (cmd_data->key.dlen > WL_NAN_NCS_SK_PMK_LEN)) {
4495 				WL_ERR(("invalid key length = %u\n",
4496 					cmd_data->key.dlen));
4497 				break;
4498 			}
4499 			WL_TRACE(("valid key length = %u\n", cmd_data->key.dlen));
4500 			break;
4501 		case NAN_ATTRIBUTE_KEY_DATA:
4502 			if (!cmd_data->key.dlen ||
4503 			    (nla_len(iter) != cmd_data->key.dlen)) {
4504 				WL_ERR(("failed to allocate key data by invalid len=%d,%d\n",
4505 					cmd_data->key.dlen, nla_len(iter)));
4506 				ret = -EINVAL;
4507 				goto exit;
4508 			}
4509 			if (cmd_data->key.data) {
4510 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4511 				ret = -EINVAL;
4512 				goto exit;
4513 			}
4514 
4515 			cmd_data->key.data = MALLOCZ(cfg->osh, NAN_MAX_PMK_LEN);
4516 			if (cmd_data->key.data == NULL) {
4517 				WL_ERR(("failed to allocate key data, len=%d\n",
4518 					cmd_data->key.dlen));
4519 				ret = -ENOMEM;
4520 				goto exit;
4521 			}
4522 			ret = memcpy_s(cmd_data->key.data, NAN_MAX_PMK_LEN,
4523 					nla_data(iter), nla_len(iter));
4524 			if (ret != BCME_OK) {
4525 				WL_ERR(("Failed to key data\n"));
4526 				return ret;
4527 			}
4528 			break;
4529 		case NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG:
4530 			if (nla_len(iter) != sizeof(uint8)) {
4531 				ret = -EINVAL;
4532 				goto exit;
4533 			}
4534 			if (nla_get_u8(iter) == 1) {
4535 				cmd_data->flags |=
4536 					WL_NAN_RANGE_LIMITED;
4537 				break;
4538 			}
4539 			break;
4540 		case NAN_ATTRIBUTE_DISC_IND_CFG:
4541 			if (nla_len(iter) != sizeof(uint8)) {
4542 				ret = -EINVAL;
4543 				goto exit;
4544 			}
4545 			cmd_data->disc_ind_cfg = nla_get_u8(iter);
4546 			break;
4547 		case NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN:
4548 			if (nla_len(iter) != sizeof(uint16)) {
4549 				ret = -EINVAL;
4550 				goto exit;
4551 			}
4552 			if (cmd_data->sde_svc_info.dlen) {
4553 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4554 				ret = -EINVAL;
4555 				goto exit;
4556 			}
4557 			cmd_data->sde_svc_info.dlen = nla_get_u16(iter);
4558 			if (cmd_data->sde_svc_info.dlen > MAX_SDEA_SVC_INFO_LEN) {
4559 				ret = -EINVAL;
4560 				WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_SDEA_SVC_INFO_LEN));
4561 				goto exit;
4562 			}
4563 			break;
4564 		case NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO:
4565 			if ((!cmd_data->sde_svc_info.dlen) ||
4566 			    (nla_len(iter) != cmd_data->sde_svc_info.dlen)) {
4567 				WL_ERR(("wrong sdea info len:%d,%d\n",
4568 					cmd_data->sde_svc_info.dlen, nla_len(iter)));
4569 				ret = -EINVAL;
4570 				goto exit;
4571 			}
4572 			if (cmd_data->sde_svc_info.data) {
4573 				WL_ERR(("trying to overwrite:%d\n", attr_type));
4574 				ret = -EINVAL;
4575 				goto exit;
4576 			}
4577 			cmd_data->sde_svc_info.data = MALLOCZ(cfg->osh,
4578 				cmd_data->sde_svc_info.dlen);
4579 			if (cmd_data->sde_svc_info.data == NULL) {
4580 				WL_ERR(("failed to allocate svc info data, len=%d\n",
4581 					cmd_data->sde_svc_info.dlen));
4582 				ret = -ENOMEM;
4583 				goto exit;
4584 			}
4585 			ret = memcpy_s(cmd_data->sde_svc_info.data,
4586 					cmd_data->sde_svc_info.dlen,
4587 					nla_data(iter), nla_len(iter));
4588 			if (ret != BCME_OK) {
4589 				WL_ERR(("Failed to sdea info data\n"));
4590 				return ret;
4591 			}
4592 			break;
4593 		case NAN_ATTRIBUTE_SECURITY:
4594 			if (nla_len(iter) != sizeof(uint8)) {
4595 				ret = -EINVAL;
4596 				goto exit;
4597 			}
4598 			cmd_data->ndp_cfg.security_cfg = nla_get_u8(iter);
4599 			break;
4600 		case NAN_ATTRIBUTE_RANGING_INTERVAL:
4601 			if (nla_len(iter) != sizeof(uint32)) {
4602 				ret = -EINVAL;
4603 				goto exit;
4604 			}
4605 			cmd_data->ranging_intvl_msec = nla_get_u32(iter);
4606 			break;
4607 		case NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT:
4608 			if (nla_len(iter) != sizeof(uint32)) {
4609 				ret = -EINVAL;
4610 				goto exit;
4611 			}
4612 			cmd_data->ingress_limit = nla_get_u32(iter);
4613 			break;
4614 		case NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT:
4615 			if (nla_len(iter) != sizeof(uint32)) {
4616 				ret = -EINVAL;
4617 				goto exit;
4618 			}
4619 			cmd_data->egress_limit = nla_get_u32(iter);
4620 			break;
4621 		case NAN_ATTRIBUTE_RANGING_INDICATION:
4622 			if (nla_len(iter) != sizeof(uint32)) {
4623 				ret = -EINVAL;
4624 				goto exit;
4625 			}
4626 			cmd_data->ranging_indication = nla_get_u32(iter);
4627 			break;
4628 		/* Nan accept policy: Per service basis policy
4629 		 * Based on this policy(ALL/NONE), responder side
4630 		 * will send ACCEPT/REJECT
4631 		 */
4632 		case NAN_ATTRIBUTE_SVC_RESPONDER_POLICY:
4633 			if (nla_len(iter) != sizeof(uint8)) {
4634 				ret = -EINVAL;
4635 				goto exit;
4636 			}
4637 			cmd_data->service_responder_policy = nla_get_u8(iter);
4638 			break;
4639 		default:
4640 			WL_ERR(("Unknown type, %d\n", attr_type));
4641 			ret = -EINVAL;
4642 			goto exit;
4643 		}
4644 	}
4645 exit:
4646 	/* We need to call set_config_handler b/f calling start enable TBD */
4647 	NAN_DBG_EXIT();
4648 	return ret;
4649 }
4650 
4651 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)4652 wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf,
4653 	int len, nan_config_cmd_data_t *cmd_data, uint32 *nan_attr_mask)
4654 {
4655 	int ret = BCME_OK;
4656 	int attr_type;
4657 	int rem = len;
4658 	const struct nlattr *iter;
4659 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4660 	int chan;
4661 	u8 sid_beacon = 0, sub_sid_beacon = 0;
4662 
4663 	NAN_DBG_ENTER();
4664 
4665 	nla_for_each_attr(iter, buf, len, rem) {
4666 		attr_type = nla_type(iter);
4667 		WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
4668 
4669 		switch (attr_type) {
4670 		/* NAN Enable request attributes */
4671 		case NAN_ATTRIBUTE_2G_SUPPORT:{
4672 			if (nla_len(iter) != sizeof(uint8)) {
4673 				ret = -EINVAL;
4674 				goto exit;
4675 			}
4676 			cmd_data->support_2g = nla_get_u8(iter);
4677 			if (cmd_data->support_2g == 0) {
4678 				WL_ERR((" 2.4GHz support is not set \n"));
4679 				cmd_data->status = BCME_BADARG;
4680 				goto exit;
4681 			}
4682 			*nan_attr_mask |= NAN_ATTR_SUPPORT_2G_CONFIG;
4683 			break;
4684 		}
4685 		case NAN_ATTRIBUTE_5G_SUPPORT:{
4686 			if (nla_len(iter) != sizeof(uint8)) {
4687 				ret = -EINVAL;
4688 				goto exit;
4689 			}
4690 			cmd_data->support_5g = nla_get_u8(iter);
4691 			*nan_attr_mask |= NAN_ATTR_SUPPORT_5G_CONFIG;
4692 			break;
4693 		}
4694 		case NAN_ATTRIBUTE_CLUSTER_LOW: {
4695 			if (nla_len(iter) != sizeof(uint16)) {
4696 				ret = -EINVAL;
4697 				goto exit;
4698 			}
4699 			cmd_data->cluster_low = nla_get_u16(iter);
4700 			break;
4701 		}
4702 		case NAN_ATTRIBUTE_CLUSTER_HIGH: {
4703 			if (nla_len(iter) != sizeof(uint16)) {
4704 				ret = -EINVAL;
4705 				goto exit;
4706 			}
4707 			cmd_data->cluster_high = nla_get_u16(iter);
4708 			break;
4709 		}
4710 		case NAN_ATTRIBUTE_SID_BEACON: {
4711 			if (nla_len(iter) != sizeof(uint8)) {
4712 				ret = -EINVAL;
4713 				goto exit;
4714 			}
4715 			sid_beacon = nla_get_u8(iter);
4716 			cmd_data->sid_beacon.sid_enable = (sid_beacon & 0x01);
4717 			if (cmd_data->sid_beacon.sid_enable) {
4718 				cmd_data->sid_beacon.sid_count = (sid_beacon >> 1);
4719 				*nan_attr_mask |= NAN_ATTR_SID_BEACON_CONFIG;
4720 			} else {
4721 				WL_ERR((" sid beacon is not valid \n"));
4722 				cmd_data->status = BCME_BADARG;
4723 				goto exit;
4724 			}
4725 
4726 			break;
4727 		}
4728 		case NAN_ATTRIBUTE_SUB_SID_BEACON: {
4729 			if (nla_len(iter) != sizeof(uint8)) {
4730 				ret = -EINVAL;
4731 				goto exit;
4732 			}
4733 			sub_sid_beacon = nla_get_u8(iter);
4734 			cmd_data->sid_beacon.sub_sid_enable = (sub_sid_beacon & 0x01);
4735 			if (cmd_data->sid_beacon.sub_sid_enable) {
4736 				cmd_data->sid_beacon.sub_sid_count = (sub_sid_beacon >> 1);
4737 				*nan_attr_mask |= NAN_ATTR_SUB_SID_BEACON_CONFIG;
4738 			} else {
4739 				WL_ERR((" sub sid beacon is not valid \n"));
4740 				cmd_data->status = BCME_BADARG;
4741 				goto exit;
4742 			}
4743 			break;
4744 		}
4745 		case NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON:
4746 			if (nla_len(iter) != sizeof(uint8)) {
4747 				ret = -EINVAL;
4748 				goto exit;
4749 			}
4750 			cmd_data->beacon_2g_val = nla_get_u8(iter);
4751 			*nan_attr_mask |= NAN_ATTR_SYNC_DISC_2G_BEACON_CONFIG;
4752 			break;
4753 		case NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON:
4754 			if (nla_len(iter) != sizeof(uint8)) {
4755 				ret = -EINVAL;
4756 				goto exit;
4757 			}
4758 			cmd_data->beacon_5g_val = nla_get_u8(iter);
4759 			*nan_attr_mask |= NAN_ATTR_SYNC_DISC_5G_BEACON_CONFIG;
4760 			break;
4761 		case NAN_ATTRIBUTE_SDF_2G_SUPPORT:
4762 			if (nla_len(iter) != sizeof(uint8)) {
4763 				ret = -EINVAL;
4764 				goto exit;
4765 			}
4766 			cmd_data->sdf_2g_val = nla_get_u8(iter);
4767 			*nan_attr_mask |= NAN_ATTR_SDF_2G_SUPPORT_CONFIG;
4768 			break;
4769 		case NAN_ATTRIBUTE_SDF_5G_SUPPORT:
4770 			if (nla_len(iter) != sizeof(uint8)) {
4771 				ret = -EINVAL;
4772 				goto exit;
4773 			}
4774 			cmd_data->sdf_5g_val = nla_get_u8(iter);
4775 			*nan_attr_mask |= NAN_ATTR_SDF_5G_SUPPORT_CONFIG;
4776 			break;
4777 		case NAN_ATTRIBUTE_HOP_COUNT_LIMIT:
4778 			if (nla_len(iter) != sizeof(uint8)) {
4779 				ret = -EINVAL;
4780 				goto exit;
4781 			}
4782 			cmd_data->hop_count_limit = nla_get_u8(iter);
4783 			if (cmd_data->hop_count_limit == 0) {
4784 				WL_ERR((" hop count limit is not valid \n"));
4785 				cmd_data->status = BCME_BADARG;
4786 				goto exit;
4787 			}
4788 			*nan_attr_mask |= NAN_ATTR_HOP_COUNT_LIMIT_CONFIG;
4789 			break;
4790 		case NAN_ATTRIBUTE_RANDOM_TIME:
4791 			if (nla_len(iter) != sizeof(uint8)) {
4792 				ret = -EINVAL;
4793 				goto exit;
4794 			}
4795 			cmd_data->metrics.random_factor = nla_get_u8(iter);
4796 			*nan_attr_mask |= NAN_ATTR_RAND_FACTOR_CONFIG;
4797 			break;
4798 		case NAN_ATTRIBUTE_MASTER_PREF:
4799 			if (nla_len(iter) != sizeof(uint8)) {
4800 				ret = -EINVAL;
4801 				goto exit;
4802 			}
4803 			cmd_data->metrics.master_pref = nla_get_u8(iter);
4804 			break;
4805 		case NAN_ATTRIBUTE_OUI:
4806 			if (nla_len(iter) != sizeof(uint32)) {
4807 				ret = -EINVAL;
4808 				goto exit;
4809 			}
4810 			cmd_data->nan_oui = nla_get_u32(iter);
4811 			*nan_attr_mask |= NAN_ATTR_OUI_CONFIG;
4812 			WL_TRACE(("nan_oui=%d\n", cmd_data->nan_oui));
4813 			break;
4814 		case NAN_ATTRIBUTE_WARMUP_TIME:
4815 			if (nla_len(iter) != sizeof(uint16)) {
4816 				ret = -EINVAL;
4817 				goto exit;
4818 			}
4819 			cmd_data->warmup_time = nla_get_u16(iter);
4820 			break;
4821 		case NAN_ATTRIBUTE_AMBTT:
4822 		case NAN_ATTRIBUTE_MASTER_RANK:
4823 			WL_DBG(("Unhandled attribute, %d\n", attr_type));
4824 			break;
4825 		case NAN_ATTRIBUTE_CHANNEL: {
4826 			if (nla_len(iter) != sizeof(uint32)) {
4827 				ret = -EINVAL;
4828 				goto exit;
4829 			}
4830 			/* take the default channel start_factor frequency */
4831 			chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4832 			if (chan <= CH_MAX_2G_CHANNEL) {
4833 				cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4834 			} else {
4835 				cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_80);
4836 			}
4837 			if (cmd_data->chanspec[0] == 0) {
4838 				WL_ERR(("Channel is not valid \n"));
4839 				ret = -EINVAL;
4840 				goto exit;
4841 			}
4842 			WL_TRACE(("valid chanspec, chanspec = 0x%04x \n",
4843 				cmd_data->chanspec[0]));
4844 			break;
4845 		}
4846 		case NAN_ATTRIBUTE_24G_CHANNEL: {
4847 			if (nla_len(iter) != sizeof(uint32)) {
4848 				ret = -EINVAL;
4849 				goto exit;
4850 			}
4851 			/* take the default channel start_factor frequency */
4852 			chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4853 			/* 20MHz as BW */
4854 			cmd_data->chanspec[1] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4855 			if (cmd_data->chanspec[1] == 0) {
4856 				WL_ERR((" 2.4GHz Channel is not valid \n"));
4857 				ret = -EINVAL;
4858 				break;
4859 			}
4860 			*nan_attr_mask |= NAN_ATTR_2G_CHAN_CONFIG;
4861 			WL_TRACE(("valid 2.4GHz chanspec, chanspec = 0x%04x \n",
4862 				cmd_data->chanspec[1]));
4863 			break;
4864 		}
4865 		case NAN_ATTRIBUTE_5G_CHANNEL: {
4866 			if (nla_len(iter) != sizeof(uint32)) {
4867 				ret = -EINVAL;
4868 				goto exit;
4869 			}
4870 			/* take the default channel start_factor frequency */
4871 			chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4872 			/* 20MHz as BW */
4873 			cmd_data->chanspec[2] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4874 			if (cmd_data->chanspec[2] == 0) {
4875 				WL_ERR((" 5GHz Channel is not valid \n"));
4876 				ret = -EINVAL;
4877 				break;
4878 			}
4879 			*nan_attr_mask |= NAN_ATTR_5G_CHAN_CONFIG;
4880 			WL_TRACE(("valid 5GHz chanspec, chanspec = 0x%04x \n",
4881 				cmd_data->chanspec[2]));
4882 			break;
4883 		}
4884 		case NAN_ATTRIBUTE_CONF_CLUSTER_VAL:
4885 			if (nla_len(iter) != sizeof(uint8)) {
4886 				ret = -EINVAL;
4887 				goto exit;
4888 			}
4889 			cmd_data->config_cluster_val = nla_get_u8(iter);
4890 			*nan_attr_mask |= NAN_ATTR_CLUSTER_VAL_CONFIG;
4891 			break;
4892 		case NAN_ATTRIBUTE_DWELL_TIME:
4893 			if (nla_len(iter) != sizeof(uint8)) {
4894 				ret = -EINVAL;
4895 				goto exit;
4896 			}
4897 			cmd_data->dwell_time[0] = nla_get_u8(iter);
4898 			if (cmd_data->dwell_time[0] == 0) {
4899 				WL_ERR((" 2.4GHz dwell time is not valid \n"));
4900 				cmd_data->status = BCME_BADARG;
4901 				goto exit;
4902 			}
4903 			*nan_attr_mask |= NAN_ATTR_2G_DWELL_TIME_CONFIG;
4904 			break;
4905 		case NAN_ATTRIBUTE_SCAN_PERIOD:
4906 			if (nla_len(iter) != sizeof(uint16)) {
4907 				ret = -EINVAL;
4908 				goto exit;
4909 			}
4910 			cmd_data->scan_period[0] = nla_get_u16(iter);
4911 			if (cmd_data->scan_period[0] == 0) {
4912 				WL_ERR((" 2.4GHz scan period is not valid \n"));
4913 				cmd_data->status = BCME_BADARG;
4914 				goto exit;
4915 			}
4916 			*nan_attr_mask |= NAN_ATTR_2G_SCAN_PERIOD_CONFIG;
4917 			break;
4918 		case NAN_ATTRIBUTE_DWELL_TIME_5G:
4919 			if (nla_len(iter) != sizeof(uint8)) {
4920 				ret = -EINVAL;
4921 				goto exit;
4922 			}
4923 			cmd_data->dwell_time[1] = nla_get_u8(iter);
4924 			if (cmd_data->dwell_time[1] == 0) {
4925 				WL_ERR((" 5GHz dwell time is not valid \n"));
4926 				cmd_data->status = BCME_BADARG;
4927 				goto exit;
4928 			}
4929 			*nan_attr_mask |= NAN_ATTR_5G_DWELL_TIME_CONFIG;
4930 			break;
4931 		case NAN_ATTRIBUTE_SCAN_PERIOD_5G:
4932 			if (nla_len(iter) != sizeof(uint16)) {
4933 				ret = -EINVAL;
4934 				goto exit;
4935 			}
4936 			cmd_data->scan_period[1] = nla_get_u16(iter);
4937 			if (cmd_data->scan_period[1] == 0) {
4938 				WL_ERR((" 5GHz scan period is not valid \n"));
4939 				cmd_data->status = BCME_BADARG;
4940 				goto exit;
4941 			}
4942 			*nan_attr_mask |= NAN_ATTR_5G_SCAN_PERIOD_CONFIG;
4943 			break;
4944 		case NAN_ATTRIBUTE_AVAIL_BIT_MAP:
4945 			if (nla_len(iter) != sizeof(uint32)) {
4946 				ret = -EINVAL;
4947 				goto exit;
4948 			}
4949 			cmd_data->bmap = nla_get_u32(iter);
4950 			break;
4951 		case NAN_ATTRIBUTE_ENTRY_CONTROL:
4952 			if (nla_len(iter) != sizeof(uint8)) {
4953 				ret = -EINVAL;
4954 				goto exit;
4955 			}
4956 			cmd_data->avail_params.duration = nla_get_u8(iter);
4957 			break;
4958 		case NAN_ATTRIBUTE_RSSI_CLOSE:
4959 			if (nla_len(iter) != sizeof(uint8)) {
4960 				ret = -EINVAL;
4961 				goto exit;
4962 			}
4963 			cmd_data->rssi_attr.rssi_close_2dot4g_val = nla_get_s8(iter);
4964 			if (cmd_data->rssi_attr.rssi_close_2dot4g_val == 0) {
4965 				WL_ERR((" 2.4GHz rssi close is not valid \n"));
4966 				cmd_data->status = BCME_BADARG;
4967 				goto exit;
4968 			}
4969 			*nan_attr_mask |= NAN_ATTR_RSSI_CLOSE_CONFIG;
4970 			break;
4971 		case NAN_ATTRIBUTE_RSSI_MIDDLE:
4972 			if (nla_len(iter) != sizeof(uint8)) {
4973 				ret = -EINVAL;
4974 				goto exit;
4975 			}
4976 			cmd_data->rssi_attr.rssi_middle_2dot4g_val = nla_get_s8(iter);
4977 			if (cmd_data->rssi_attr.rssi_middle_2dot4g_val == 0) {
4978 				WL_ERR((" 2.4GHz rssi middle is not valid \n"));
4979 				cmd_data->status = BCME_BADARG;
4980 				goto exit;
4981 			}
4982 			*nan_attr_mask |= NAN_ATTR_RSSI_MIDDLE_2G_CONFIG;
4983 			break;
4984 		case NAN_ATTRIBUTE_RSSI_PROXIMITY:
4985 			if (nla_len(iter) != sizeof(uint8)) {
4986 				ret = -EINVAL;
4987 				goto exit;
4988 			}
4989 			cmd_data->rssi_attr.rssi_proximity_2dot4g_val = nla_get_s8(iter);
4990 			if (cmd_data->rssi_attr.rssi_proximity_2dot4g_val == 0) {
4991 				WL_ERR((" 2.4GHz rssi proximity is not valid \n"));
4992 				cmd_data->status = BCME_BADARG;
4993 				goto exit;
4994 			}
4995 			*nan_attr_mask |= NAN_ATTR_RSSI_PROXIMITY_2G_CONFIG;
4996 			break;
4997 		case NAN_ATTRIBUTE_RSSI_CLOSE_5G:
4998 			if (nla_len(iter) != sizeof(uint8)) {
4999 				ret = -EINVAL;
5000 				goto exit;
5001 			}
5002 			cmd_data->rssi_attr.rssi_close_5g_val = nla_get_s8(iter);
5003 			if (cmd_data->rssi_attr.rssi_close_5g_val == 0) {
5004 				WL_ERR((" 5GHz rssi close is not valid \n"));
5005 				cmd_data->status = BCME_BADARG;
5006 				goto exit;
5007 			}
5008 			*nan_attr_mask |= NAN_ATTR_RSSI_CLOSE_5G_CONFIG;
5009 			break;
5010 		case NAN_ATTRIBUTE_RSSI_MIDDLE_5G:
5011 			if (nla_len(iter) != sizeof(uint8)) {
5012 				ret = -EINVAL;
5013 				goto exit;
5014 			}
5015 			cmd_data->rssi_attr.rssi_middle_5g_val = nla_get_s8(iter);
5016 			if (cmd_data->rssi_attr.rssi_middle_5g_val == 0) {
5017 				WL_ERR((" 5Hz rssi middle is not valid \n"));
5018 				cmd_data->status = BCME_BADARG;
5019 				goto exit;
5020 			}
5021 			*nan_attr_mask |= NAN_ATTR_RSSI_MIDDLE_5G_CONFIG;
5022 			break;
5023 		case NAN_ATTRIBUTE_RSSI_PROXIMITY_5G:
5024 			if (nla_len(iter) != sizeof(uint8)) {
5025 				ret = -EINVAL;
5026 				goto exit;
5027 			}
5028 			cmd_data->rssi_attr.rssi_proximity_5g_val = nla_get_s8(iter);
5029 			if (cmd_data->rssi_attr.rssi_proximity_5g_val == 0) {
5030 				WL_ERR((" 5GHz rssi proximity is not valid \n"));
5031 				cmd_data->status = BCME_BADARG;
5032 				goto exit;
5033 			}
5034 			*nan_attr_mask |= NAN_ATTR_RSSI_PROXIMITY_5G_CONFIG;
5035 			break;
5036 		case NAN_ATTRIBUTE_RSSI_WINDOW_SIZE:
5037 			if (nla_len(iter) != sizeof(uint8)) {
5038 				ret = -EINVAL;
5039 				goto exit;
5040 			}
5041 			cmd_data->rssi_attr.rssi_window_size = nla_get_u8(iter);
5042 			if (cmd_data->rssi_attr.rssi_window_size == 0) {
5043 				WL_ERR((" rssi window size is not valid \n"));
5044 				cmd_data->status = BCME_BADARG;
5045 				goto exit;
5046 			}
5047 			*nan_attr_mask |= NAN_ATTR_RSSI_WINDOW_SIZE_CONFIG;
5048 			break;
5049 		case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
5050 			if (nla_len(iter) != sizeof(uint8)) {
5051 				ret = -EINVAL;
5052 				goto exit;
5053 			}
5054 			cmd_data->csid = nla_get_u8(iter);
5055 			WL_TRACE(("CSID = %u\n", cmd_data->csid));
5056 			break;
5057 		case NAN_ATTRIBUTE_SCID_LEN:
5058 			if (nla_len(iter) != sizeof(uint32)) {
5059 				ret = -EINVAL;
5060 				goto exit;
5061 			}
5062 			if (cmd_data->scid.dlen) {
5063 				WL_ERR(("trying to overwrite:%d\n", attr_type));
5064 				ret = -EINVAL;
5065 				goto exit;
5066 			}
5067 			cmd_data->scid.dlen = nla_get_u32(iter);
5068 			if (cmd_data->scid.dlen > MAX_SCID_LEN) {
5069 				ret = -EINVAL;
5070 				WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_SCID_LEN));
5071 				goto exit;
5072 			}
5073 			WL_TRACE(("valid scid length = %u\n", cmd_data->scid.dlen));
5074 			break;
5075 		case NAN_ATTRIBUTE_SCID:
5076 			if (!cmd_data->scid.dlen || (nla_len(iter) != cmd_data->scid.dlen)) {
5077 				WL_ERR(("wrong scid len:%d,%d\n", cmd_data->scid.dlen,
5078 					nla_len(iter)));
5079 				ret = -EINVAL;
5080 				goto exit;
5081 			}
5082 			if (cmd_data->scid.data) {
5083 				WL_ERR(("trying to overwrite:%d\n", attr_type));
5084 				ret = -EINVAL;
5085 				goto exit;
5086 			}
5087 
5088 			cmd_data->scid.data = MALLOCZ(cfg->osh, cmd_data->scid.dlen);
5089 			if (cmd_data->scid.data == NULL) {
5090 				WL_ERR(("failed to allocate scid, len=%d\n",
5091 					cmd_data->scid.dlen));
5092 				ret = -ENOMEM;
5093 				goto exit;
5094 			}
5095 			ret = memcpy_s(cmd_data->scid.data, cmd_data->scid.dlen,
5096 					nla_data(iter), nla_len(iter));
5097 			if (ret != BCME_OK) {
5098 				WL_ERR(("Failed to scid data\n"));
5099 				return ret;
5100 			}
5101 			break;
5102 		case NAN_ATTRIBUTE_2G_AWAKE_DW:
5103 			if (nla_len(iter) != sizeof(uint32)) {
5104 				ret = -EINVAL;
5105 				goto exit;
5106 			}
5107 			if (nla_get_u32(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
5108 				WL_ERR(("%s: Invalid/Out of bound value = %u\n",
5109 						__FUNCTION__, nla_get_u32(iter)));
5110 				ret = -EINVAL;
5111 				goto exit;
5112 			}
5113 			if (nla_get_u32(iter)) {
5114 				cmd_data->awake_dws.dw_interval_2g =
5115 					1 << (nla_get_u32(iter)-1);
5116 			}
5117 			*nan_attr_mask |= NAN_ATTR_2G_DW_CONFIG;
5118 			break;
5119 		case NAN_ATTRIBUTE_5G_AWAKE_DW:
5120 			if (nla_len(iter) != sizeof(uint32)) {
5121 				ret = -EINVAL;
5122 				goto exit;
5123 			}
5124 			if (nla_get_u32(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
5125 				WL_ERR(("%s: Invalid/Out of bound value = %u\n",
5126 						__FUNCTION__, nla_get_u32(iter)));
5127 				ret = BCME_BADARG;
5128 				break;
5129 			}
5130 			if (nla_get_u32(iter)) {
5131 				cmd_data->awake_dws.dw_interval_5g =
5132 					1 << (nla_get_u32(iter)-1);
5133 			}
5134 			*nan_attr_mask |= NAN_ATTR_5G_DW_CONFIG;
5135 			break;
5136 		case NAN_ATTRIBUTE_DISC_IND_CFG:
5137 			if (nla_len(iter) != sizeof(uint8)) {
5138 				ret = -EINVAL;
5139 				goto exit;
5140 			}
5141 			cmd_data->disc_ind_cfg = nla_get_u8(iter);
5142 			break;
5143 		case NAN_ATTRIBUTE_MAC_ADDR:
5144 			if (nla_len(iter) != ETHER_ADDR_LEN) {
5145 				ret = -EINVAL;
5146 				goto exit;
5147 			}
5148 			ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
5149 					(char*)nla_data(iter), nla_len(iter));
5150 			if (ret != BCME_OK) {
5151 				WL_ERR(("Failed to copy mac addr\n"));
5152 				return ret;
5153 			}
5154 			break;
5155 		case NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL:
5156 			if (nla_len(iter) != sizeof(uint32)) {
5157 				ret = -EINVAL;
5158 				goto exit;
5159 			}
5160 			/* run time nmi rand not supported as of now.
5161 			* Only during nan enable/iface-create rand mac is used
5162 			*/
5163 			cmd_data->nmi_rand_intvl = nla_get_u32(iter);
5164 			if (cmd_data->nmi_rand_intvl > 0) {
5165 				cfg->nancfg->mac_rand = true;
5166 			} else {
5167 				cfg->nancfg->mac_rand = false;
5168 			}
5169 			break;
5170 		case NAN_ATTRIBUTE_CMD_USE_NDPE:
5171 			if (nla_len(iter) != sizeof(uint32)) {
5172 				ret = -EINVAL;
5173 				goto exit;
5174 			}
5175 			cmd_data->use_ndpe_attr = nla_get_u32(iter);
5176 			break;
5177 		case NAN_ATTRIBUTE_ENABLE_MERGE:
5178 			if (nla_len(iter) != sizeof(uint8)) {
5179 				ret = -EINVAL;
5180 				goto exit;
5181 			}
5182 			cmd_data->enable_merge = nla_get_u8(iter);
5183 			break;
5184 		case NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL:
5185 			if (nla_len(iter) != sizeof(uint32)) {
5186 				ret = -EINVAL;
5187 				goto exit;
5188 			}
5189 			cmd_data->disc_bcn_interval = nla_get_u32(iter);
5190 			*nan_attr_mask |= NAN_ATTR_DISC_BEACON_INTERVAL;
5191 			break;
5192 		case NAN_ATTRIBUTE_NSS:
5193 			if (nla_len(iter) != sizeof(uint32)) {
5194 				ret = -EINVAL;
5195 				goto exit;
5196 			}
5197 			/* FW handles it internally,
5198 			* nothing to do as per the value rxed from framework, ignore.
5199 			*/
5200 			break;
5201 		case NAN_ATTRIBUTE_ENABLE_RANGING:
5202 			if (nla_len(iter) != sizeof(uint32)) {
5203 				ret = -EINVAL;
5204 				goto exit;
5205 			}
5206 			cfg->nancfg->ranging_enable = nla_get_u32(iter);
5207 			if (cfg->nancfg->ranging_enable == 0) {
5208 				WL_ERR((" ranging enable is not set \n"));
5209 				cmd_data->status = BCME_BADARG;
5210 				goto exit;
5211 			}
5212 			break;
5213 		case NAN_ATTRIBUTE_DW_EARLY_TERM:
5214 			if (nla_len(iter) != sizeof(uint32)) {
5215 				ret = -EINVAL;
5216 				goto exit;
5217 			}
5218 			cmd_data->dw_early_termination = nla_get_u32(iter);
5219 			break;
5220 		default:
5221 			WL_ERR(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
5222 			ret = -EINVAL;
5223 			goto exit;
5224 		}
5225 	}
5226 
5227 exit:
5228 	/* We need to call set_config_handler b/f calling start enable TBD */
5229 	NAN_DBG_EXIT();
5230 	if (ret) {
5231 		WL_ERR(("%s: Failed to parse attribute %d ret %d",
5232 			__FUNCTION__, attr_type, ret));
5233 	}
5234 	return ret;
5235 
5236 }
5237 
5238 static int
wl_cfgvendor_nan_dp_estb_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)5239 wl_cfgvendor_nan_dp_estb_event_data_filler(struct sk_buff *msg,
5240 	nan_event_data_t *event_data) {
5241 	int ret = BCME_OK;
5242 	ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
5243 	if (unlikely(ret)) {
5244 		WL_ERR(("Failed to put NDP ID, ret=%d\n", ret));
5245 		goto fail;
5246 	}
5247 	/*
5248 	 * NDI mac address of the peer
5249 	 * (required to derive target ipv6 address)
5250 	 */
5251 	ret = nla_put(msg, NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR, ETH_ALEN,
5252 			event_data->responder_ndi.octet);
5253 	if (unlikely(ret)) {
5254 		WL_ERR(("Failed to put resp ndi, ret=%d\n", ret));
5255 		goto fail;
5256 	}
5257 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_RSP_CODE, event_data->status);
5258 	if (unlikely(ret)) {
5259 		WL_ERR(("Failed to put response code, ret=%d\n", ret));
5260 		goto fail;
5261 	}
5262 	if (event_data->svc_info.dlen && event_data->svc_info.data) {
5263 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
5264 				event_data->svc_info.dlen);
5265 		if (unlikely(ret)) {
5266 			WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
5267 			goto fail;
5268 		}
5269 		ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
5270 				event_data->svc_info.dlen, event_data->svc_info.data);
5271 		if (unlikely(ret)) {
5272 			WL_ERR(("Failed to put svc info, ret=%d\n", ret));
5273 			goto fail;
5274 		}
5275 	}
5276 
5277 fail:
5278 	return ret;
5279 }
5280 static int
wl_cfgvendor_nan_dp_ind_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)5281 wl_cfgvendor_nan_dp_ind_event_data_filler(struct sk_buff *msg,
5282 		nan_event_data_t *event_data) {
5283 	int ret = BCME_OK;
5284 
5285 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID,
5286 			event_data->pub_id);
5287 	if (unlikely(ret)) {
5288 		WL_ERR(("Failed to put pub ID, ret=%d\n", ret));
5289 		goto fail;
5290 	}
5291 	ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
5292 	if (unlikely(ret)) {
5293 		WL_ERR(("Failed to put NDP ID, ret=%d\n", ret));
5294 		goto fail;
5295 	}
5296 	/* Discovery MAC addr of the peer/initiator */
5297 	ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETH_ALEN,
5298 			event_data->remote_nmi.octet);
5299 	if (unlikely(ret)) {
5300 		WL_ERR(("Failed to put remote NMI, ret=%d\n", ret));
5301 		goto fail;
5302 	}
5303 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_SECURITY, event_data->security);
5304 	if (unlikely(ret)) {
5305 		WL_ERR(("Failed to put security, ret=%d\n", ret));
5306 		goto fail;
5307 	}
5308 	if (event_data->svc_info.dlen && event_data->svc_info.data) {
5309 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
5310 				event_data->svc_info.dlen);
5311 		if (unlikely(ret)) {
5312 			WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
5313 			goto fail;
5314 		}
5315 		ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
5316 				event_data->svc_info.dlen, event_data->svc_info.data);
5317 		if (unlikely(ret)) {
5318 			WL_ERR(("Failed to put svc info, ret=%d\n", ret));
5319 			goto fail;
5320 		}
5321 	}
5322 
5323 fail:
5324 	return ret;
5325 }
5326 
5327 static int
wl_cfgvendor_nan_tx_followup_ind_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)5328 wl_cfgvendor_nan_tx_followup_ind_event_data_filler(struct sk_buff *msg,
5329 	nan_event_data_t *event_data) {
5330 	int ret = BCME_OK;
5331 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_TRANSAC_ID, event_data->token);
5332 	if (unlikely(ret)) {
5333 		WL_ERR(("Failed to put transaction id, ret=%d\n", ret));
5334 		goto fail;
5335 	}
5336 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->local_inst_id);
5337 	if (unlikely(ret)) {
5338 		WL_ERR(("Failed to put handle, ret=%d\n", ret));
5339 		goto fail;
5340 	}
5341 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
5342 	if (unlikely(ret)) {
5343 		WL_ERR(("Failed to put nan status, ret=%d\n", ret));
5344 		goto fail;
5345 	}
5346 	if (event_data->status == NAN_STATUS_SUCCESS) {
5347 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5348 				strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
5349 		if (unlikely(ret)) {
5350 			WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
5351 			goto fail;
5352 		}
5353 	} else {
5354 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5355 				strlen("NAN_STATUS_NO_OTA_ACK"), event_data->nan_reason);
5356 		if (unlikely(ret)) {
5357 			WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
5358 			goto fail;
5359 		}
5360 	}
5361 fail:
5362 	return ret;
5363 }
5364 
5365 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)5366 wl_cfgvendor_nan_svc_terminate_event_filler(struct sk_buff *msg,
5367 	struct bcm_cfg80211 *cfg, int event_id, nan_event_data_t *event_data) {
5368 	int ret = BCME_OK;
5369 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->local_inst_id);
5370 	if (unlikely(ret)) {
5371 		WL_ERR(("Failed to put handle, ret=%d\n", ret));
5372 		goto fail;
5373 	}
5374 
5375 	if (event_id == GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED) {
5376 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SUBSCRIBE_ID,
5377 				event_data->local_inst_id);
5378 		if (unlikely(ret)) {
5379 			WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
5380 			goto fail;
5381 		}
5382 	} else {
5383 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID,
5384 				event_data->local_inst_id);
5385 		if (unlikely(ret)) {
5386 			WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
5387 			goto fail;
5388 		}
5389 	}
5390 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
5391 	if (unlikely(ret)) {
5392 		WL_ERR(("Failed to put status, ret=%d\n", ret));
5393 		goto fail;
5394 	}
5395 	if (event_data->status == NAN_STATUS_SUCCESS) {
5396 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5397 				strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
5398 		if (unlikely(ret)) {
5399 			WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
5400 			goto fail;
5401 		}
5402 	} else {
5403 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5404 				strlen("NAN_STATUS_INTERNAL_FAILURE"), event_data->nan_reason);
5405 		if (unlikely(ret)) {
5406 			WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
5407 			goto fail;
5408 		}
5409 	}
5410 
5411 	ret = wl_cfgnan_remove_inst_id(cfg, event_data->local_inst_id);
5412 	if (ret) {
5413 		WL_ERR(("failed to free svc instance-id[%d], ret=%d, event_id = %d\n",
5414 				event_data->local_inst_id, ret, event_id));
5415 		goto fail;
5416 	}
5417 fail:
5418 	return ret;
5419 }
5420 
5421 static int
wl_cfgvendor_nan_opt_params_filler(struct sk_buff * msg,nan_event_data_t * event_data)5422 wl_cfgvendor_nan_opt_params_filler(struct sk_buff *msg,
5423 	nan_event_data_t *event_data) {
5424 	int ret = BCME_OK;
5425 	/* service specific info data */
5426 	if (event_data->svc_info.dlen && event_data->svc_info.data) {
5427 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
5428 				event_data->svc_info.dlen);
5429 		if (unlikely(ret)) {
5430 			WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
5431 			goto fail;
5432 		}
5433 		ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
5434 				event_data->svc_info.dlen, event_data->svc_info.data);
5435 		if (unlikely(ret)) {
5436 			WL_ERR(("Failed to put svc info, ret=%d\n", ret));
5437 			goto fail;
5438 		}
5439 		WL_TRACE(("svc info len = %d\n", event_data->svc_info.dlen));
5440 	}
5441 
5442 	/* sdea service specific info data */
5443 	if (event_data->sde_svc_info.dlen && event_data->sde_svc_info.data) {
5444 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
5445 				event_data->sde_svc_info.dlen);
5446 		if (unlikely(ret)) {
5447 			WL_ERR(("Failed to put sdea svc info len, ret=%d\n", ret));
5448 			goto fail;
5449 		}
5450 		ret = nla_put(msg, NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
5451 				event_data->sde_svc_info.dlen,
5452 				event_data->sde_svc_info.data);
5453 		if (unlikely(ret)) {
5454 			WL_ERR(("Failed to put sdea svc info, ret=%d\n", ret));
5455 			goto fail;
5456 		}
5457 		WL_TRACE(("sdea svc info len = %d\n", event_data->sde_svc_info.dlen));
5458 	}
5459 	/* service control discovery range limit */
5460 	/* TODO: */
5461 
5462 	/* service control binding bitmap */
5463 	/* TODO: */
5464 fail:
5465 	return ret;
5466 }
5467 
5468 static int
wl_cfgvendor_nan_tx_followup_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)5469 wl_cfgvendor_nan_tx_followup_event_filler(struct sk_buff *msg,
5470 		nan_event_data_t *event_data) {
5471 	int ret = BCME_OK;
5472 	/* In followup pkt, instance id and requestor instance id are configured
5473 	 * from the transmitter perspective. As the event is processed with the
5474 	 * role of receiver, the local handle should use requestor instance
5475 	 * id (peer_inst_id)
5476 	 */
5477 	WL_TRACE(("handle=%d\n", event_data->requestor_id));
5478 	WL_TRACE(("inst id (local id)=%d\n", event_data->local_inst_id));
5479 	WL_TRACE(("peer id (remote id)=%d\n", event_data->requestor_id));
5480 	WL_TRACE(("peer mac addr=" MACDBG "\n",
5481 			MAC2STRDBG(event_data->remote_nmi.octet)));
5482 	WL_TRACE(("peer rssi: %d\n", event_data->fup_rssi));
5483 	WL_TRACE(("attribute no: %d\n", event_data->attr_num));
5484 	WL_TRACE(("attribute len: %d\n", event_data->attr_list_len));
5485 
5486 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->requestor_id);
5487 	if (unlikely(ret)) {
5488 		WL_ERR(("Failed to put handle, ret=%d\n", ret));
5489 		goto fail;
5490 	}
5491 	ret = nla_put_u32(msg, NAN_ATTRIBUTE_INST_ID, event_data->local_inst_id);
5492 	if (unlikely(ret)) {
5493 		WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
5494 		goto fail;
5495 	}
5496 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_PEER_ID, event_data->requestor_id);
5497 	if (unlikely(ret)) {
5498 		WL_ERR(("Failed to put requestor inst id, ret=%d\n", ret));
5499 		goto fail;
5500 	}
5501 	ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETHER_ADDR_LEN,
5502 			event_data->remote_nmi.octet);
5503 	if (unlikely(ret)) {
5504 		WL_ERR(("Failed to put remote nmi, ret=%d\n", ret));
5505 		goto fail;
5506 	}
5507 	ret = nla_put_s8(msg, NAN_ATTRIBUTE_RSSI_PROXIMITY,
5508 			event_data->fup_rssi);
5509 	if (unlikely(ret)) {
5510 		WL_ERR(("Failed to put fup rssi, ret=%d\n", ret));
5511 		goto fail;
5512 	}
5513 fail:
5514 	return ret;
5515 }
5516 
5517 static int
wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)5518 wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff *msg,
5519 	nan_event_data_t *event_data) {
5520 	int ret = BCME_OK;
5521 	WL_TRACE(("handle (sub_id)=%d\n", event_data->sub_id));
5522 	WL_TRACE(("pub id=%d\n", event_data->pub_id));
5523 	WL_TRACE(("sub id=%d\n", event_data->sub_id));
5524 	WL_TRACE(("pub mac addr=" MACDBG "\n",
5525 			MAC2STRDBG(event_data->remote_nmi.octet)));
5526 	WL_TRACE(("attr no: %d\n", event_data->attr_num));
5527 	WL_TRACE(("attr len: %d\n", event_data->attr_list_len));
5528 
5529 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->sub_id);
5530 	if (unlikely(ret)) {
5531 		WL_ERR(("Failed to put handle, ret=%d\n", ret));
5532 		goto fail;
5533 	}
5534 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID, event_data->pub_id);
5535 	if (unlikely(ret)) {
5536 		WL_ERR(("Failed to put pub id, ret=%d\n", ret));
5537 		goto fail;
5538 	}
5539 	ret = nla_put_u16(msg, NAN_ATTRIBUTE_SUBSCRIBE_ID, event_data->sub_id);
5540 	if (unlikely(ret)) {
5541 		WL_ERR(("Failed to put Sub Id, ret=%d\n", ret));
5542 		goto fail;
5543 	}
5544 	ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETHER_ADDR_LEN,
5545 			event_data->remote_nmi.octet);
5546 	if (unlikely(ret)) {
5547 		WL_ERR(("Failed to put remote NMI, ret=%d\n", ret));
5548 		goto fail;
5549 	}
5550 	if (event_data->publish_rssi) {
5551 		event_data->publish_rssi = -event_data->publish_rssi;
5552 		ret = nla_put_u8(msg, NAN_ATTRIBUTE_RSSI_PROXIMITY,
5553 				event_data->publish_rssi);
5554 		if (unlikely(ret)) {
5555 			WL_ERR(("Failed to put publish rssi, ret=%d\n", ret));
5556 			goto fail;
5557 		}
5558 	}
5559 	if (event_data->ranging_result_present) {
5560 		ret = nla_put_u32(msg, NAN_ATTRIBUTE_RANGING_INDICATION,
5561 				event_data->ranging_ind);
5562 		if (unlikely(ret)) {
5563 			WL_ERR(("Failed to put ranging ind, ret=%d\n", ret));
5564 			goto fail;
5565 		}
5566 		ret = nla_put_u32(msg, NAN_ATTRIBUTE_RANGING_RESULT,
5567 				event_data->range_measurement_cm);
5568 		if (unlikely(ret)) {
5569 			WL_ERR(("Failed to put range measurement cm, ret=%d\n",
5570 					ret));
5571 			goto fail;
5572 		}
5573 	}
5574 	/*
5575 	 * handling optional service control, service response filter
5576 	 */
5577 	if (event_data->tx_match_filter.dlen && event_data->tx_match_filter.data) {
5578 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN,
5579 				event_data->tx_match_filter.dlen);
5580 		if (unlikely(ret)) {
5581 			WL_ERR(("Failed to put tx match filter len, ret=%d\n",
5582 					ret));
5583 			goto fail;
5584 		}
5585 		ret = nla_put(msg, NAN_ATTRIBUTE_TX_MATCH_FILTER,
5586 				event_data->tx_match_filter.dlen,
5587 				event_data->tx_match_filter.data);
5588 		if (unlikely(ret)) {
5589 			WL_ERR(("Failed to put tx match filter data, ret=%d\n",
5590 					ret));
5591 			goto fail;
5592 		}
5593 		WL_TRACE(("tx matching filter (%d):\n",
5594 				event_data->tx_match_filter.dlen));
5595 	}
5596 
5597 fail:
5598 	return ret;
5599 }
5600 
5601 static int
wl_cfgvendor_nan_de_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)5602 wl_cfgvendor_nan_de_event_filler(struct sk_buff *msg, nan_event_data_t *event_data)
5603 {
5604 	int ret = BCME_OK;
5605 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_ENABLE_STATUS, event_data->enabled);
5606 	if (unlikely(ret)) {
5607 		WL_ERR(("Failed to put event_data->enabled, ret=%d\n", ret));
5608 		goto fail;
5609 	}
5610 	ret = nla_put_u8(msg, NAN_ATTRIBUTE_DE_EVENT_TYPE,
5611 			event_data->nan_de_evt_type);
5612 	if (unlikely(ret)) {
5613 		WL_ERR(("Failed to put nan_de_evt_type, ret=%d\n", ret));
5614 		goto fail;
5615 	}
5616 	ret = nla_put(msg, NAN_ATTRIBUTE_CLUSTER_ID, ETH_ALEN,
5617 			event_data->clus_id.octet);
5618 	if (unlikely(ret)) {
5619 		WL_ERR(("Failed to put clust id, ret=%d\n", ret));
5620 		goto fail;
5621 	}
5622 	/* OOB tests requires local nmi */
5623 	ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETH_ALEN,
5624 			event_data->local_nmi.octet);
5625 	if (unlikely(ret)) {
5626 		WL_ERR(("Failed to put NMI, ret=%d\n", ret));
5627 		goto fail;
5628 	}
5629 fail:
5630 	return ret;
5631 }
5632 
5633 #ifdef RTT_SUPPORT
5634 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)5635 wl_cfgvendor_send_as_rtt_legacy_event(struct wiphy *wiphy, struct net_device *dev,
5636 	wl_nan_ev_rng_rpt_ind_t *range_res, uint32 status)
5637 {
5638 	s32 ret = BCME_OK;
5639 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5640 	rtt_report_t *report = NULL;
5641 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5642 	struct sk_buff *msg = NULL;
5643 	struct nlattr *rtt_nl_hdr;
5644 
5645 	NAN_DBG_ENTER();
5646 
5647 	report = MALLOCZ(cfg->osh, sizeof(*report));
5648 	if (!report) {
5649 		WL_ERR(("%s: memory allocation failed\n", __func__));
5650 		ret = BCME_NOMEM;
5651 		goto exit;
5652 	}
5653 	if (range_res) {
5654 		report->distance = range_res->dist_mm/10;
5655 		ret = memcpy_s(&report->addr, ETHER_ADDR_LEN,
5656 				&range_res->peer_m_addr, ETHER_ADDR_LEN);
5657 		if (ret != BCME_OK) {
5658 			WL_ERR(("Failed to copy peer_m_addr\n"));
5659 			goto exit;
5660 		}
5661 	}
5662 	report->status = (rtt_reason_t)status;
5663 	report->type   = RTT_TWO_WAY;
5664 
5665 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
5666 	LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
5667 	msg = cfg80211_vendor_event_alloc(wiphy, NULL, 100,
5668 			GOOGLE_RTT_COMPLETE_EVENT, kflags);
5669 #else
5670 	msg = cfg80211_vendor_event_alloc(wiphy, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags);
5671 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
5672 	/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
5673 	if (!msg) {
5674 		WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
5675 		ret = BCME_NOMEM;
5676 		goto exit;
5677 	}
5678 
5679 	ret = nla_put_u32(msg, RTT_ATTRIBUTE_RESULTS_COMPLETE, 1);
5680 	if (ret < 0) {
5681 		WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
5682 		goto exit;
5683 	}
5684 	rtt_nl_hdr = nla_nest_start(msg, RTT_ATTRIBUTE_RESULTS_PER_TARGET);
5685 	if (!rtt_nl_hdr) {
5686 		WL_ERR(("rtt_nl_hdr is NULL\n"));
5687 		ret = BCME_NOMEM;
5688 		goto exit;
5689 	}
5690 	ret = nla_put(msg, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &report->addr);
5691 	if (ret < 0) {
5692 		WL_ERR(("Failed to put RTT_ATTRIBUTE_TARGET_MAC\n"));
5693 		goto exit;
5694 	}
5695 	ret = nla_put_u32(msg, RTT_ATTRIBUTE_RESULT_CNT, 1);
5696 	if (ret < 0) {
5697 		WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_CNT\n"));
5698 		goto exit;
5699 	}
5700 	ret = nla_put(msg, RTT_ATTRIBUTE_RESULT,
5701 			sizeof(*report), report);
5702 	if (ret < 0) {
5703 		WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS\n"));
5704 		goto exit;
5705 	}
5706 	nla_nest_end(msg, rtt_nl_hdr);
5707 	cfg80211_vendor_event(msg, kflags);
5708 	if (report) {
5709 		MFREE(cfg->osh, report, sizeof(*report));
5710 	}
5711 
5712 	return ret;
5713 exit:
5714 	if (msg)
5715 		dev_kfree_skb_any(msg);
5716 	WL_ERR(("Failed to send event GOOGLE_RTT_COMPLETE_EVENT,"
5717 				" -- Free skb, ret = %d\n", ret));
5718 	if (report)
5719 		MFREE(cfg->osh, report, sizeof(*report));
5720 	NAN_DBG_EXIT();
5721 	return ret;
5722 }
5723 #endif /* RTT_SUPPORT */
5724 
5725 static int
wl_cfgvendor_send_nan_async_resp(struct wiphy * wiphy,struct wireless_dev * wdev,int event_id,u8 * nan_req_resp,u16 len)5726 wl_cfgvendor_send_nan_async_resp(struct wiphy *wiphy, struct wireless_dev *wdev,
5727 	int event_id, u8* nan_req_resp, u16 len)
5728 {
5729 	int ret = BCME_OK;
5730 	int buf_len = NAN_EVENT_BUFFER_SIZE_LARGE;
5731 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5732 
5733 	struct sk_buff *msg;
5734 
5735 	NAN_DBG_ENTER();
5736 
5737 	/* Allocate the skb for vendor event */
5738 	msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, wdev, buf_len,
5739 		event_id, kflags);
5740 	if (!msg) {
5741 		WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
5742 		return -ENOMEM;
5743 	}
5744 
5745 	ret = nla_put(msg, NAN_ATTRIBUTE_CMD_RESP_DATA,
5746 			len, (u8*)nan_req_resp);
5747 	if (unlikely(ret)) {
5748 		WL_ERR(("Failed to put resp data, ret=%d\n",
5749 				ret));
5750 		goto fail;
5751 	}
5752 	WL_DBG(("Event sent up to hal, event_id = %d, ret = %d\n",
5753 		event_id, ret));
5754 	cfg80211_vendor_event(msg, kflags);
5755 	NAN_DBG_EXIT();
5756 	return ret;
5757 
5758 fail:
5759 	dev_kfree_skb_any(msg);
5760 	WL_ERR(("Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n",
5761 		event_id, ret));
5762 	NAN_DBG_EXIT();
5763 	return ret;
5764 }
5765 
5766 int
wl_cfgvendor_nan_send_async_disable_resp(struct wireless_dev * wdev)5767 wl_cfgvendor_nan_send_async_disable_resp(struct wireless_dev *wdev)
5768 {
5769 	int ret = BCME_OK;
5770 	struct wiphy *wiphy = wdev->wiphy;
5771 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5772 	nan_hal_resp_t nan_req_resp;
5773 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5774 	nan_req_resp.status = NAN_STATUS_SUCCESS;
5775 	nan_req_resp.value = BCME_OK;
5776 	nan_req_resp.subcmd = NAN_WIFI_SUBCMD_DISABLE;
5777 	WL_INFORM_MEM(("Send NAN_ASYNC_RESPONSE_DISABLED\n"));
5778 	ret = wl_cfgvendor_send_nan_async_resp(wiphy, wdev,
5779 		NAN_ASYNC_RESPONSE_DISABLED, (u8*)&nan_req_resp, sizeof(nan_req_resp));
5780 	cfg->nancfg->notify_user = false;
5781 	return ret;
5782 }
5783 
5784 int
wl_cfgvendor_send_nan_event(struct wiphy * wiphy,struct net_device * dev,int event_id,nan_event_data_t * event_data)5785 wl_cfgvendor_send_nan_event(struct wiphy *wiphy, struct net_device *dev,
5786 	int event_id, nan_event_data_t *event_data)
5787 {
5788 	int ret = BCME_OK;
5789 	int buf_len = NAN_EVENT_BUFFER_SIZE_LARGE;
5790 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5791 
5792 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5793 	struct sk_buff *msg;
5794 
5795 	NAN_DBG_ENTER();
5796 
5797 	/* Allocate the skb for vendor event */
5798 	msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(dev), buf_len,
5799 		event_id, kflags);
5800 	if (!msg) {
5801 		WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
5802 		return -ENOMEM;
5803 	}
5804 
5805 	switch (event_id) {
5806 	case GOOGLE_NAN_EVENT_DE_EVENT: {
5807 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_DE_EVENT cluster id=" MACDBG "nmi= " MACDBG "\n",
5808 			MAC2STRDBG(event_data->clus_id.octet),
5809 			MAC2STRDBG(event_data->local_nmi.octet)));
5810 		ret = wl_cfgvendor_nan_de_event_filler(msg, event_data);
5811 		if (unlikely(ret)) {
5812 			WL_ERR(("Failed to fill de event data, ret=%d\n", ret));
5813 			goto fail;
5814 		}
5815 		break;
5816 	}
5817 	case GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH:
5818 	case GOOGLE_NAN_EVENT_FOLLOWUP: {
5819 		if (event_id == GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH) {
5820 			WL_DBG(("GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH\n"));
5821 			ret = wl_cfgvendor_nan_sub_match_event_filler(msg, event_data);
5822 			if (unlikely(ret)) {
5823 				WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5824 				goto fail;
5825 			}
5826 		} else if (event_id == GOOGLE_NAN_EVENT_FOLLOWUP) {
5827 			WL_DBG(("GOOGLE_NAN_EVENT_FOLLOWUP\n"));
5828 			ret = wl_cfgvendor_nan_tx_followup_event_filler(msg, event_data);
5829 			if (unlikely(ret)) {
5830 				WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5831 				goto fail;
5832 			}
5833 		}
5834 		ret = wl_cfgvendor_nan_opt_params_filler(msg, event_data);
5835 		if (unlikely(ret)) {
5836 			WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5837 			goto fail;
5838 		}
5839 		break;
5840 	}
5841 
5842 	case GOOGLE_NAN_EVENT_DISABLED: {
5843 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DISABLED\n"));
5844 		ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, 0);
5845 		if (unlikely(ret)) {
5846 			WL_ERR(("Failed to put handle, ret=%d\n", ret));
5847 			goto fail;
5848 		}
5849 		ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
5850 		if (unlikely(ret)) {
5851 			WL_ERR(("Failed to put status, ret=%d\n", ret));
5852 			goto fail;
5853 		}
5854 		ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5855 			strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
5856 		if (unlikely(ret)) {
5857 			WL_ERR(("Failed to put reason code, ret=%d\n", ret));
5858 			goto fail;
5859 		}
5860 		break;
5861 	}
5862 
5863 	case GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED:
5864 	case GOOGLE_NAN_EVENT_PUBLISH_TERMINATED: {
5865 		WL_DBG(("GOOGLE_NAN_SVC_TERMINATED, %d\n", event_id));
5866 		ret = wl_cfgvendor_nan_svc_terminate_event_filler(msg, cfg, event_id, event_data);
5867 		if (unlikely(ret)) {
5868 			WL_ERR(("Failed to fill svc terminate event data, ret=%d\n", ret));
5869 			goto fail;
5870 		}
5871 		break;
5872 	}
5873 
5874 	case GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND: {
5875 		WL_DBG(("GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND %d\n",
5876 			GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND));
5877 		ret = wl_cfgvendor_nan_tx_followup_ind_event_data_filler(msg, event_data);
5878 		if (unlikely(ret)) {
5879 			WL_ERR(("Failed to fill tx follow up ind event data, ret=%d\n", ret));
5880 			goto fail;
5881 		}
5882 
5883 		break;
5884 	}
5885 
5886 	case GOOGLE_NAN_EVENT_DATA_REQUEST: {
5887 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_REQUEST\n"));
5888 		ret = wl_cfgvendor_nan_dp_ind_event_data_filler(msg, event_data);
5889 		if (unlikely(ret)) {
5890 			WL_ERR(("Failed to fill dp ind event data, ret=%d\n", ret));
5891 			goto fail;
5892 		}
5893 		break;
5894 	}
5895 
5896 	case GOOGLE_NAN_EVENT_DATA_CONFIRMATION: {
5897 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_CONFIRMATION\n"));
5898 
5899 		ret = wl_cfgvendor_nan_dp_estb_event_data_filler(msg, event_data);
5900 		if (unlikely(ret)) {
5901 			WL_ERR(("Failed to fill dp estb event data, ret=%d\n", ret));
5902 			goto fail;
5903 		}
5904 		break;
5905 	}
5906 
5907 	case GOOGLE_NAN_EVENT_DATA_END: {
5908 		WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_END\n"));
5909 		ret = nla_put_u8(msg, NAN_ATTRIBUTE_INST_COUNT, 1);
5910 		if (unlikely(ret)) {
5911 			WL_ERR(("Failed to put inst count, ret=%d\n", ret));
5912 			goto fail;
5913 		}
5914 		ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
5915 		if (unlikely(ret)) {
5916 			WL_ERR(("Failed to put ndp id, ret=%d\n", ret));
5917 			goto fail;
5918 		}
5919 		break;
5920 	}
5921 
5922 	default:
5923 		goto fail;
5924 	}
5925 
5926 	cfg80211_vendor_event(msg, kflags);
5927 	NAN_DBG_EXIT();
5928 	return ret;
5929 
5930 fail:
5931 	dev_kfree_skb_any(msg);
5932 	WL_ERR(("Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n",
5933 			event_id, ret));
5934 	NAN_DBG_EXIT();
5935 	return ret;
5936 }
5937 
5938 static int
wl_cfgvendor_nan_req_subscribe(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5939 wl_cfgvendor_nan_req_subscribe(struct wiphy *wiphy,
5940 	struct wireless_dev *wdev, const void * data, int len)
5941 {
5942 	int ret = 0;
5943 	nan_discover_cmd_data_t *cmd_data = NULL;
5944 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5945 	nan_hal_resp_t nan_req_resp;
5946 
5947 	NAN_DBG_ENTER();
5948 	/* Blocking Subscribe if NAN is not enable */
5949 	if (!cfg->nancfg->nan_enable) {
5950 		WL_ERR(("nan is not enabled, subscribe blocked\n"));
5951 		ret = BCME_ERROR;
5952 		goto exit;
5953 	}
5954 	cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5955 	if (!cmd_data) {
5956 		WL_ERR(("%s: memory allocation failed\n", __func__));
5957 		ret = BCME_NOMEM;
5958 		goto exit;
5959 	}
5960 
5961 	bzero(&nan_req_resp, sizeof(nan_req_resp));
5962 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
5963 	if (ret) {
5964 		WL_ERR(("failed to parse nan disc vendor args, ret = %d\n", ret));
5965 		goto exit;
5966 	}
5967 
5968 	if (cmd_data->sub_id == 0) {
5969 		ret = wl_cfgnan_generate_inst_id(cfg, &cmd_data->sub_id);
5970 		if (ret) {
5971 			WL_ERR(("failed to generate instance-id for subscribe\n"));
5972 			goto exit;
5973 		}
5974 	} else {
5975 		cmd_data->svc_update = true;
5976 	}
5977 
5978 	ret = wl_cfgnan_subscribe_handler(wdev->netdev, cfg, cmd_data);
5979 	if (unlikely(ret) || unlikely(cmd_data->status)) {
5980 		WL_ERR(("failed to subscribe error[%d], status = [%d]\n",
5981 				ret, cmd_data->status));
5982 		wl_cfgnan_remove_inst_id(cfg, cmd_data->sub_id);
5983 		goto exit;
5984 	}
5985 
5986 	WL_DBG(("subscriber instance id=%d\n", cmd_data->sub_id));
5987 
5988 	if (cmd_data->status == WL_NAN_E_OK) {
5989 		nan_req_resp.instance_id = cmd_data->sub_id;
5990 	} else {
5991 		nan_req_resp.instance_id = 0;
5992 	}
5993 exit:
5994 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_REQUEST_SUBSCRIBE,
5995 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5996 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
5997 	NAN_DBG_EXIT();
5998 	return ret;
5999 }
6000 
6001 static int
wl_cfgvendor_nan_req_publish(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6002 wl_cfgvendor_nan_req_publish(struct wiphy *wiphy,
6003 	struct wireless_dev *wdev, const void * data, int len)
6004 {
6005 	int ret = 0;
6006 	nan_discover_cmd_data_t *cmd_data = NULL;
6007 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6008 	nan_hal_resp_t nan_req_resp;
6009 	NAN_DBG_ENTER();
6010 
6011 	/* Blocking Publish if NAN is not enable */
6012 	if (!cfg->nancfg->nan_enable) {
6013 		WL_ERR(("nan is not enabled publish blocked\n"));
6014 		ret = BCME_ERROR;
6015 		goto exit;
6016 	}
6017 	cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6018 	if (!cmd_data) {
6019 		WL_ERR(("%s: memory allocation failed\n", __func__));
6020 		ret = BCME_NOMEM;
6021 		goto exit;
6022 	}
6023 
6024 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6025 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
6026 	if (ret) {
6027 		WL_ERR(("failed to parse nan disc vendor args, ret = %d\n", ret));
6028 		goto exit;
6029 	}
6030 
6031 	if (cmd_data->pub_id == 0) {
6032 		ret = wl_cfgnan_generate_inst_id(cfg, &cmd_data->pub_id);
6033 		if (ret) {
6034 			WL_ERR(("failed to generate instance-id for publisher\n"));
6035 			goto exit;
6036 		}
6037 	} else {
6038 		cmd_data->svc_update = true;
6039 	}
6040 
6041 	ret = wl_cfgnan_publish_handler(wdev->netdev, cfg, cmd_data);
6042 	if (unlikely(ret) || unlikely(cmd_data->status)) {
6043 		WL_ERR(("failed to publish error[%d], status[%d]\n",
6044 				ret, cmd_data->status));
6045 		wl_cfgnan_remove_inst_id(cfg, cmd_data->pub_id);
6046 		goto exit;
6047 	}
6048 
6049 	WL_DBG(("publisher instance id=%d\n", cmd_data->pub_id));
6050 
6051 	if (cmd_data->status == WL_NAN_E_OK) {
6052 		nan_req_resp.instance_id = cmd_data->pub_id;
6053 	} else {
6054 		nan_req_resp.instance_id = 0;
6055 	}
6056 exit:
6057 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_REQUEST_PUBLISH,
6058 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6059 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
6060 	NAN_DBG_EXIT();
6061 	return ret;
6062 }
6063 
6064 static int
wl_cfgvendor_nan_start_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6065 wl_cfgvendor_nan_start_handler(struct wiphy *wiphy,
6066 	struct wireless_dev *wdev, const void  *data, int len)
6067 {
6068 	int ret = 0;
6069 	nan_config_cmd_data_t *cmd_data;
6070 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6071 	nan_hal_resp_t nan_req_resp;
6072 	uint32 nan_attr_mask = 0;
6073 
6074 	cmd_data = (nan_config_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6075 	if (!cmd_data) {
6076 		WL_ERR(("%s: memory allocation failed\n", __func__));
6077 		ret = BCME_NOMEM;
6078 		goto exit;
6079 	}
6080 	NAN_DBG_ENTER();
6081 
6082 	ret = wl_cfgnan_check_nan_disable_pending(cfg, false, true);
6083 	if (ret != BCME_OK) {
6084 		WL_ERR(("failed to disable nan, error[%d]\n", ret));
6085 		goto exit;
6086 	}
6087 
6088 	if (cfg->nancfg->nan_enable) {
6089 		WL_ERR(("nan is already enabled\n"));
6090 		ret = BCME_OK;
6091 		goto exit;
6092 	}
6093 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6094 
6095 	cmd_data->sid_beacon.sid_enable = NAN_SID_ENABLE_FLAG_INVALID; /* Setting to some default */
6096 	cmd_data->sid_beacon.sid_count = NAN_SID_BEACON_COUNT_INVALID; /* Setting to some default */
6097 
6098 	ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask);
6099 	if (ret) {
6100 		WL_ERR(("failed to parse nan vendor args, ret %d\n", ret));
6101 		goto exit;
6102 	}
6103 	if (cmd_data->status == BCME_BADARG) {
6104 		WL_ERR(("nan vendor args is invalid\n"));
6105 		goto exit;
6106 	}
6107 
6108 	ret = wl_cfgnan_start_handler(wdev->netdev, cfg, cmd_data, nan_attr_mask);
6109 	if (ret) {
6110 		WL_ERR(("failed to start nan error[%d]\n", ret));
6111 		goto exit;
6112 	}
6113 	/* Initializing Instance Id List */
6114 	bzero(cfg->nancfg->nan_inst_ctrl, NAN_ID_CTRL_SIZE * sizeof(nan_svc_inst_t));
6115 exit:
6116 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_ENABLE,
6117 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6118 	if (cmd_data) {
6119 		if (cmd_data->scid.data) {
6120 			MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen);
6121 			cmd_data->scid.dlen = 0;
6122 		}
6123 		MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
6124 	}
6125 	NAN_DBG_EXIT();
6126 	return ret;
6127 }
6128 
6129 static int
wl_cfgvendor_terminate_dp_rng_sessions(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,bool * ssn_exists)6130 wl_cfgvendor_terminate_dp_rng_sessions(struct bcm_cfg80211 *cfg,
6131 	struct wireless_dev *wdev, bool *ssn_exists)
6132 {
6133 	int ret = 0;
6134 	uint8 i = 0;
6135 	int status = BCME_ERROR;
6136 	wl_nancfg_t *nancfg = cfg->nancfg;
6137 	dhd_pub_t *dhdp;
6138 #ifdef RTT_SUPPORT
6139 	nan_ranging_inst_t *ranging_inst = NULL;
6140 #endif /* RTT_SUPPORT */
6141 
6142 	*ssn_exists = false;
6143 	dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6144 	/* Cleanup active Data Paths If any */
6145 	for (i = 0; i < NAN_MAX_NDP_PEER; i++) {
6146 		if (nancfg->ndp_id[i]) {
6147 			WL_DBG(("Found entry of ndp id = [%d], end dp associated to it\n",
6148 					nancfg->ndp_id[i]));
6149 			ret = wl_cfgnan_data_path_end_handler(wdev->netdev, cfg,
6150 					nancfg->ndp_id[i], &status);
6151 			if ((ret == BCME_OK) && cfg->nancfg->nan_enable &&
6152 				dhdp->up) {
6153 				*ssn_exists = true;
6154 			}
6155 		}
6156 	}
6157 
6158 #ifdef RTT_SUPPORT
6159 	/* Cancel ranging sessiosns */
6160 	for (i = 0; i < NAN_MAX_RANGING_INST; i++) {
6161 		ranging_inst = &nancfg->nan_ranging_info[i];
6162 		if (ranging_inst->in_use &&
6163 				(NAN_RANGING_IS_IN_PROG(ranging_inst->range_status))) {
6164 			ret = wl_cfgnan_cancel_ranging(bcmcfg_to_prmry_ndev(cfg), cfg,
6165 					&ranging_inst->range_id,
6166 					NAN_RNG_TERM_FLAG_NONE, &status);
6167 			if (unlikely(ret) || unlikely(status)) {
6168 				WL_ERR(("nan range cancel failed ret = %d status = %d\n",
6169 					ret, status));
6170 			} else {
6171 				*ssn_exists = true;
6172 			}
6173 		}
6174 	}
6175 #endif /* RTT_SUPPORT */
6176 	return ret;
6177 }
6178 
6179 static int
wl_cfgvendor_nan_stop_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6180 wl_cfgvendor_nan_stop_handler(struct wiphy *wiphy,
6181 	struct wireless_dev *wdev, const void * data, int len)
6182 {
6183 	int ret = BCME_OK;
6184 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6185 	bool ssn_exists = false;
6186 	uint32 delay_ms = 0;
6187 	wl_nancfg_t *nancfg = cfg->nancfg;
6188 
6189 	NAN_DBG_ENTER();
6190 	mutex_lock(&cfg->if_sync);
6191 
6192 	if (nancfg->nan_init_state == false) {
6193 		WL_INFORM_MEM(("nan is not initialized/nmi doesnt exists\n"));
6194 		goto exit;
6195 	}
6196 	if (nancfg->nan_enable == false) {
6197 		WL_INFORM_MEM(("nan is in disabled state\n"));
6198 	} else {
6199 		nancfg->notify_user = true;
6200 		wl_cfgvendor_terminate_dp_rng_sessions(cfg, wdev, &ssn_exists);
6201 		if (ssn_exists == true) {
6202 			/*
6203 			* Schedule nan disable with NAN_DISABLE_CMD_DELAY
6204 			* delay to make sure
6205 			* fw cleans any active Data paths and
6206 			* notifies the peer about the dp session terminations
6207 			*/
6208 			WL_INFORM_MEM(("Schedule Nan Disable Req with NAN_DISABLE_CMD_DELAY\n"));
6209 			delay_ms = NAN_DISABLE_CMD_DELAY;
6210 			DHD_NAN_WAKE_LOCK_TIMEOUT(cfg->pub, NAN_WAKELOCK_TIMEOUT);
6211 		} else {
6212 			delay_ms = 0;
6213 		}
6214 		schedule_delayed_work(&nancfg->nan_disable,
6215 			msecs_to_jiffies(delay_ms));
6216 	}
6217 exit:
6218 	mutex_unlock(&cfg->if_sync);
6219 	NAN_DBG_EXIT();
6220 	return ret;
6221 }
6222 
6223 static int
wl_cfgvendor_nan_config_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6224 wl_cfgvendor_nan_config_handler(struct wiphy *wiphy,
6225 	struct wireless_dev *wdev, const void  *data, int len)
6226 {
6227 	int ret = 0;
6228 	nan_config_cmd_data_t *cmd_data;
6229 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6230 	nan_hal_resp_t nan_req_resp;
6231 	uint32 nan_attr_mask = 0;
6232 
6233 	cmd_data = MALLOCZ(cfg->osh, sizeof(*cmd_data));
6234 	if (!cmd_data) {
6235 		WL_ERR(("%s: memory allocation failed\n", __func__));
6236 		ret = BCME_NOMEM;
6237 		goto exit;
6238 	}
6239 	NAN_DBG_ENTER();
6240 
6241 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6242 
6243 	cmd_data->avail_params.duration = NAN_BAND_INVALID;  /* Setting to some default */
6244 	cmd_data->sid_beacon.sid_enable = NAN_SID_ENABLE_FLAG_INVALID; /* Setting to some default */
6245 	cmd_data->sid_beacon.sid_count = NAN_SID_BEACON_COUNT_INVALID; /* Setting to some default */
6246 
6247 	ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask);
6248 	if (ret) {
6249 		WL_ERR(("failed to parse nan vendor args, ret = %d\n", ret));
6250 		goto exit;
6251 	}
6252 	if (cmd_data->status == BCME_BADARG) {
6253 		WL_ERR(("nan vendor args is invalid\n"));
6254 		goto exit;
6255 	}
6256 
6257 	ret = wl_cfgnan_config_handler(wdev->netdev, cfg, cmd_data, nan_attr_mask);
6258 	if (ret) {
6259 		WL_ERR(("failed in config request, nan error[%d]\n", ret));
6260 		goto exit;
6261 	}
6262 exit:
6263 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CONFIG,
6264 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6265 	if (cmd_data) {
6266 		if (cmd_data->scid.data) {
6267 			MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen);
6268 			cmd_data->scid.dlen = 0;
6269 		}
6270 		MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
6271 	}
6272 	NAN_DBG_EXIT();
6273 	return ret;
6274 }
6275 
6276 static int
wl_cfgvendor_nan_cancel_publish(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6277 wl_cfgvendor_nan_cancel_publish(struct wiphy *wiphy,
6278 	struct wireless_dev *wdev, const void * data, int len)
6279 {
6280 	int ret = 0;
6281 	nan_discover_cmd_data_t *cmd_data = NULL;
6282 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6283 	nan_hal_resp_t nan_req_resp;
6284 
6285 	/* Blocking Cancel_Publish if NAN is not enable */
6286 	if (!cfg->nancfg->nan_enable) {
6287 		WL_ERR(("nan is not enabled, cancel publish blocked\n"));
6288 		ret = BCME_ERROR;
6289 		goto exit;
6290 	}
6291 	cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6292 	if (!cmd_data) {
6293 		WL_ERR(("%s: memory allocation failed\n", __func__));
6294 		ret = BCME_NOMEM;
6295 		goto exit;
6296 	}
6297 	NAN_DBG_ENTER();
6298 
6299 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6300 
6301 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
6302 	if (ret) {
6303 		WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
6304 		goto exit;
6305 	}
6306 	nan_req_resp.instance_id = cmd_data->pub_id;
6307 	WL_INFORM_MEM(("[NAN] cancel publish instance_id=%d\n", cmd_data->pub_id));
6308 
6309 	ret = wl_cfgnan_cancel_pub_handler(wdev->netdev, cfg, cmd_data);
6310 	if (ret) {
6311 		WL_ERR(("failed to cancel publish nan instance-id[%d] error[%d]\n",
6312 			cmd_data->pub_id, ret));
6313 		goto exit;
6314 	}
6315 exit:
6316 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CANCEL_PUBLISH,
6317 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6318 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
6319 	NAN_DBG_EXIT();
6320 	return ret;
6321 }
6322 
6323 static int
wl_cfgvendor_nan_cancel_subscribe(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6324 wl_cfgvendor_nan_cancel_subscribe(struct wiphy *wiphy,
6325 	struct wireless_dev *wdev, const void * data, int len)
6326 {
6327 	int ret = 0;
6328 	nan_discover_cmd_data_t *cmd_data = NULL;
6329 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6330 	nan_hal_resp_t nan_req_resp;
6331 
6332 	/* Blocking Cancel_Subscribe if NAN is not enableb */
6333 	if (!cfg->nancfg->nan_enable) {
6334 		WL_ERR(("nan is not enabled, cancel subscribe blocked\n"));
6335 		ret = BCME_ERROR;
6336 		goto exit;
6337 	}
6338 	cmd_data = MALLOCZ(cfg->osh, sizeof(*cmd_data));
6339 	if (!cmd_data) {
6340 		WL_ERR(("%s: memory allocation failed\n", __func__));
6341 		ret = BCME_NOMEM;
6342 		goto exit;
6343 	}
6344 	NAN_DBG_ENTER();
6345 
6346 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6347 
6348 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
6349 	if (ret) {
6350 		WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
6351 		goto exit;
6352 	}
6353 	nan_req_resp.instance_id = cmd_data->sub_id;
6354 	WL_INFORM_MEM(("[NAN] cancel subscribe instance_id=%d\n", cmd_data->sub_id));
6355 
6356 	ret = wl_cfgnan_cancel_sub_handler(wdev->netdev, cfg, cmd_data);
6357 	if (ret) {
6358 		WL_ERR(("failed to cancel subscribe nan instance-id[%d] error[%d]\n",
6359 			cmd_data->sub_id, ret));
6360 		goto exit;
6361 	}
6362 exit:
6363 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CANCEL_SUBSCRIBE,
6364 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6365 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
6366 	NAN_DBG_EXIT();
6367 	return ret;
6368 }
6369 
6370 static int
wl_cfgvendor_nan_transmit(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6371 wl_cfgvendor_nan_transmit(struct wiphy *wiphy,
6372 	struct wireless_dev *wdev, const void * data, int len)
6373 {
6374 	int ret = 0;
6375 	nan_discover_cmd_data_t *cmd_data = NULL;
6376 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6377 	nan_hal_resp_t nan_req_resp;
6378 
6379 	/* Blocking Transmit if NAN is not enable */
6380 	if (!cfg->nancfg->nan_enable) {
6381 		WL_ERR(("nan is not enabled, transmit blocked\n"));
6382 		ret = BCME_ERROR;
6383 		goto exit;
6384 	}
6385 	cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6386 	if (!cmd_data) {
6387 		WL_ERR(("%s: memory allocation failed\n", __func__));
6388 		ret = BCME_NOMEM;
6389 		goto exit;
6390 	}
6391 	NAN_DBG_ENTER();
6392 
6393 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6394 
6395 	ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
6396 	if (ret) {
6397 		WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
6398 		goto exit;
6399 	}
6400 	nan_req_resp.instance_id = cmd_data->local_id;
6401 	ret = wl_cfgnan_transmit_handler(wdev->netdev, cfg, cmd_data);
6402 	if (ret) {
6403 		WL_ERR(("failed to transmit-followup nan error[%d]\n", ret));
6404 		goto exit;
6405 	}
6406 exit:
6407 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_TRANSMIT,
6408 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6409 	wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
6410 	NAN_DBG_EXIT();
6411 	return ret;
6412 }
6413 
6414 static int
wl_cfgvendor_nan_get_capablities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6415 wl_cfgvendor_nan_get_capablities(struct wiphy *wiphy,
6416 	struct wireless_dev *wdev, const void * data, int len)
6417 {
6418 	int ret = 0;
6419 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6420 	nan_hal_resp_t nan_req_resp;
6421 
6422 	NAN_DBG_ENTER();
6423 
6424 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6425 	ret = wl_cfgnan_get_capablities_handler(wdev->netdev, cfg, &nan_req_resp.capabilities);
6426 	if (ret) {
6427 		WL_ERR(("Could not get capabilities\n"));
6428 		ret = -EINVAL;
6429 		goto exit;
6430 	}
6431 exit:
6432 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_GET_CAPABILITIES,
6433 		&nan_req_resp, ret, BCME_OK);
6434 	NAN_DBG_EXIT();
6435 	return ret;
6436 }
6437 
6438 static int
wl_cfgvendor_nan_data_path_iface_create(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6439 wl_cfgvendor_nan_data_path_iface_create(struct wiphy *wiphy,
6440 	struct wireless_dev *wdev, const void * data, int len)
6441 {
6442 	int ret = 0;
6443 	nan_datapath_cmd_data_t *cmd_data = NULL;
6444 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6445 	nan_hal_resp_t nan_req_resp;
6446 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6447 
6448 	if (!cfg->nancfg->nan_init_state) {
6449 		WL_ERR(("%s: NAN is not inited or Device doesn't support NAN \n", __func__));
6450 		ret = -ENODEV;
6451 		goto exit;
6452 	}
6453 
6454 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6455 	if (!cmd_data) {
6456 		WL_ERR(("%s: memory allocation failed\n", __func__));
6457 		ret = BCME_NOMEM;
6458 		goto exit;
6459 	}
6460 	NAN_DBG_ENTER();
6461 
6462 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6463 
6464 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6465 	if (ret) {
6466 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6467 		goto exit;
6468 	}
6469 
6470 	if (cfg->nancfg->nan_enable) { /* new framework Impl, iface create called after nan enab */
6471 		ret = wl_cfgnan_data_path_iface_create_delete_handler(wdev->netdev,
6472 			cfg, cmd_data->ndp_iface,
6473 			NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE, dhdp->up);
6474 		if (ret != BCME_OK) {
6475 			WL_ERR(("failed to create iface, ret = %d\n", ret));
6476 			goto exit;
6477 		}
6478 	}
6479 exit:
6480 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE,
6481 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6482 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6483 	NAN_DBG_EXIT();
6484 	return ret;
6485 }
6486 
6487 static int
wl_cfgvendor_nan_data_path_iface_delete(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6488 wl_cfgvendor_nan_data_path_iface_delete(struct wiphy *wiphy,
6489 	struct wireless_dev *wdev, const void * data, int len)
6490 {
6491 	int ret = 0;
6492 	nan_datapath_cmd_data_t *cmd_data = NULL;
6493 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6494 	nan_hal_resp_t nan_req_resp;
6495 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6496 
6497 	if (cfg->nancfg->nan_init_state == false) {
6498 		WL_ERR(("%s: NAN is not inited or Device doesn't support NAN \n", __func__));
6499 		/* Deinit has taken care of cleaing the virtual iface */
6500 		ret = BCME_OK;
6501 		goto exit;
6502 	}
6503 
6504 	NAN_DBG_ENTER();
6505 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6506 	if (!cmd_data) {
6507 		WL_ERR(("%s: memory allocation failed\n", __func__));
6508 		ret = BCME_NOMEM;
6509 		goto exit;
6510 	}
6511 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6512 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6513 	if (ret) {
6514 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6515 		goto exit;
6516 	}
6517 
6518 	ret = wl_cfgnan_data_path_iface_create_delete_handler(wdev->netdev, cfg,
6519 		(char*)cmd_data->ndp_iface,
6520 		NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE, dhdp->up);
6521 	if (ret) {
6522 		WL_ERR(("failed to delete ndp iface [%d]\n", ret));
6523 		goto exit;
6524 	}
6525 exit:
6526 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE,
6527 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6528 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6529 	NAN_DBG_EXIT();
6530 	return ret;
6531 }
6532 
6533 static int
wl_cfgvendor_nan_data_path_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6534 wl_cfgvendor_nan_data_path_request(struct wiphy *wiphy,
6535 	struct wireless_dev *wdev, const void * data, int len)
6536 {
6537 	int ret = 0;
6538 	nan_datapath_cmd_data_t *cmd_data = NULL;
6539 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6540 	nan_hal_resp_t nan_req_resp;
6541 	uint8 ndp_instance_id = 0;
6542 
6543 	if (!cfg->nancfg->nan_enable) {
6544 		WL_ERR(("nan is not enabled, nan data path request blocked\n"));
6545 		ret = BCME_ERROR;
6546 		goto exit;
6547 	}
6548 
6549 	NAN_DBG_ENTER();
6550 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6551 	if (!cmd_data) {
6552 		WL_ERR(("%s: memory allocation failed\n", __func__));
6553 		ret = BCME_NOMEM;
6554 		goto exit;
6555 	}
6556 
6557 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6558 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6559 	if (ret) {
6560 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6561 		goto exit;
6562 	}
6563 
6564 	ret = wl_cfgnan_data_path_request_handler(wdev->netdev, cfg,
6565 			cmd_data, &ndp_instance_id);
6566 	if (ret) {
6567 		WL_ERR(("failed to request nan data path [%d]\n", ret));
6568 		goto exit;
6569 	}
6570 
6571 	if (cmd_data->status == BCME_OK) {
6572 		nan_req_resp.ndp_instance_id = cmd_data->ndp_instance_id;
6573 	} else {
6574 		nan_req_resp.ndp_instance_id = 0;
6575 	}
6576 exit:
6577 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_REQUEST,
6578 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6579 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6580 	NAN_DBG_EXIT();
6581 	return ret;
6582 }
6583 
6584 static int
wl_cfgvendor_nan_data_path_response(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6585 wl_cfgvendor_nan_data_path_response(struct wiphy *wiphy,
6586 	struct wireless_dev *wdev, const void * data, int len)
6587 {
6588 	int ret = 0;
6589 	nan_datapath_cmd_data_t *cmd_data = NULL;
6590 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6591 	nan_hal_resp_t nan_req_resp;
6592 
6593 	if (!cfg->nancfg->nan_enable) {
6594 		WL_ERR(("nan is not enabled, nan data path response blocked\n"));
6595 		ret = BCME_ERROR;
6596 		goto exit;
6597 	}
6598 	NAN_DBG_ENTER();
6599 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6600 	if (!cmd_data) {
6601 		WL_ERR(("%s: memory allocation failed\n", __func__));
6602 		ret = BCME_NOMEM;
6603 		goto exit;
6604 	}
6605 
6606 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6607 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6608 	if (ret) {
6609 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6610 		goto exit;
6611 	}
6612 	ret = wl_cfgnan_data_path_response_handler(wdev->netdev, cfg, cmd_data);
6613 	if (ret) {
6614 		WL_ERR(("failed to response nan data path [%d]\n", ret));
6615 		goto exit;
6616 	}
6617 exit:
6618 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_RESPONSE,
6619 		&nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6620 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6621 	NAN_DBG_EXIT();
6622 	return ret;
6623 }
6624 
6625 static int
wl_cfgvendor_nan_data_path_end(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6626 wl_cfgvendor_nan_data_path_end(struct wiphy *wiphy,
6627 	struct wireless_dev *wdev, const void * data, int len)
6628 {
6629 	int ret = 0;
6630 	nan_datapath_cmd_data_t *cmd_data = NULL;
6631 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6632 	nan_hal_resp_t nan_req_resp;
6633 	int status = BCME_ERROR;
6634 
6635 	NAN_DBG_ENTER();
6636 	if (!cfg->nancfg->nan_enable) {
6637 		WL_ERR(("nan is not enabled, nan data path end blocked\n"));
6638 		ret = BCME_OK;
6639 		goto exit;
6640 	}
6641 	cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6642 	if (!cmd_data) {
6643 		WL_ERR(("%s: memory allocation failed\n", __func__));
6644 		ret = BCME_NOMEM;
6645 		goto exit;
6646 	}
6647 
6648 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6649 	ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6650 	if (ret) {
6651 		WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6652 		goto exit;
6653 	}
6654 	ret = wl_cfgnan_data_path_end_handler(wdev->netdev, cfg,
6655 			cmd_data->ndp_instance_id, &status);
6656 	if (ret) {
6657 		WL_ERR(("failed to end nan data path [%d]\n", ret));
6658 		goto exit;
6659 	}
6660 exit:
6661 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_END,
6662 		&nan_req_resp, ret, cmd_data ? status : BCME_OK);
6663 	wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6664 	NAN_DBG_EXIT();
6665 	return ret;
6666 }
6667 
6668 #ifdef WL_NAN_DISC_CACHE
6669 static int
wl_cfgvendor_nan_data_path_sec_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6670 wl_cfgvendor_nan_data_path_sec_info(struct wiphy *wiphy,
6671 	struct wireless_dev *wdev, const void *data, int len)
6672 {
6673 	int ret = 0;
6674 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6675 	nan_hal_resp_t nan_req_resp;
6676 	nan_datapath_sec_info_cmd_data_t *cmd_data = NULL;
6677 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6678 
6679 	NAN_DBG_ENTER();
6680 	if (!cfg->nancfg->nan_enable) {
6681 		WL_ERR(("nan is not enabled\n"));
6682 		ret = BCME_UNSUPPORTED;
6683 		goto exit;
6684 	}
6685 	cmd_data = MALLOCZ(dhdp->osh, sizeof(*cmd_data));
6686 	if (!cmd_data) {
6687 		WL_ERR(("%s: memory allocation failed\n", __func__));
6688 		ret = BCME_NOMEM;
6689 		goto exit;
6690 	}
6691 
6692 	ret = wl_cfgvendor_nan_parse_dp_sec_info_args(wiphy, data, len, cmd_data);
6693 	if (ret) {
6694 		WL_ERR(("failed to parse sec info args\n"));
6695 		goto exit;
6696 	}
6697 
6698 	bzero(&nan_req_resp, sizeof(nan_req_resp));
6699 	ret = wl_cfgnan_sec_info_handler(cfg, cmd_data, &nan_req_resp);
6700 	if (ret) {
6701 		WL_ERR(("failed to retrieve svc hash/pub nmi error[%d]\n", ret));
6702 		goto exit;
6703 	}
6704 exit:
6705 	ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_SEC_INFO,
6706 		&nan_req_resp, ret, BCME_OK);
6707 	if (cmd_data) {
6708 		MFREE(dhdp->osh, cmd_data, sizeof(*cmd_data));
6709 	}
6710 	NAN_DBG_EXIT();
6711 	return ret;
6712 }
6713 #endif /* WL_NAN_DISC_CACHE */
6714 
6715 static int
wl_cfgvendor_nan_version_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6716 wl_cfgvendor_nan_version_info(struct wiphy *wiphy,
6717 	struct wireless_dev *wdev, const void *data, int len)
6718 {
6719 	int ret = BCME_OK;
6720 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6721 	uint32 version = NAN_HAL_VERSION_1;
6722 
6723 	BCM_REFERENCE(cfg);
6724 	WL_DBG(("Enter %s version %d\n", __FUNCTION__, version));
6725 	ret = wl_cfgvendor_send_cmd_reply(wiphy, &version, sizeof(version));
6726 	return ret;
6727 }
6728 
6729 static int
wl_cfgvendor_nan_enable_merge(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6730 wl_cfgvendor_nan_enable_merge(struct wiphy *wiphy,
6731 	struct wireless_dev *wdev, const void * data, int len)
6732 {
6733 	int ret = 0;
6734 	nan_config_cmd_data_t *cmd_data = NULL;
6735 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6736 	int status = BCME_OK;
6737 	uint32 nan_attr_mask = 0;
6738 
6739 	BCM_REFERENCE(nan_attr_mask);
6740 	NAN_DBG_ENTER();
6741 	cmd_data = (nan_config_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6742 	if (!cmd_data) {
6743 		WL_ERR(("%s: memory allocation failed\n", __func__));
6744 		ret = BCME_NOMEM;
6745 		goto exit;
6746 	}
6747 
6748 	ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask);
6749 	if (ret) {
6750 		WL_ERR((" Enable merge: failed to parse nan config vendor args, ret = %d\n", ret));
6751 		goto exit;
6752 	}
6753 	ret = wl_cfgnan_set_enable_merge(wdev->netdev, cfg, cmd_data->enable_merge, &status);
6754 	if (unlikely(ret) || unlikely(status)) {
6755 		WL_ERR(("Enable merge: failed to set config request  [%d]\n", ret));
6756 		/* As there is no cmd_reply, return status if error is in status else return ret */
6757 		if (status) {
6758 			ret = status;
6759 		}
6760 		goto exit;
6761 	}
6762 exit:
6763 	if (cmd_data) {
6764 		if (cmd_data->scid.data) {
6765 			MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen);
6766 			cmd_data->scid.dlen = 0;
6767 		}
6768 		MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
6769 	}
6770 	NAN_DBG_EXIT();
6771 	return ret;
6772 }
6773 #endif /* WL_NAN */
6774 
6775 #ifdef LINKSTAT_SUPPORT
6776 
6777 #define NUM_RATE 32
6778 #define NUM_PEER 1
6779 #define NUM_CHAN 11
6780 #define HEADER_SIZE sizeof(ver_len)
6781 
6782 #define NUM_PNO_SCANS 8
6783 #define NUM_CCA_SAMPLING_SECS 1
6784 
wl_cfgvendor_lstats_get_bcn_mbss(char * buf,uint32 * rxbeaconmbss)6785 static int wl_cfgvendor_lstats_get_bcn_mbss(char *buf, uint32 *rxbeaconmbss)
6786 {
6787 	wl_cnt_info_t *cbuf = (wl_cnt_info_t *)buf;
6788 	const void *cnt;
6789 
6790 	if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6791 			WL_CNT_XTLV_CNTV_LE10_UCODE, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6792 		*rxbeaconmbss = ((const wl_cnt_v_le10_mcst_t *)cnt)->rxbeaconmbss;
6793 	} else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6794 			WL_CNT_XTLV_LT40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6795 		*rxbeaconmbss = ((const wl_cnt_lt40mcst_v1_t *)cnt)->rxbeaconmbss;
6796 	} else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6797 			WL_CNT_XTLV_GE40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6798 		*rxbeaconmbss = ((const wl_cnt_ge40mcst_v1_t *)cnt)->rxbeaconmbss;
6799 	} else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6800 			WL_CNT_XTLV_GE80_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6801 		*rxbeaconmbss = ((const wl_cnt_ge80mcst_v1_t *)cnt)->rxbeaconmbss;
6802 	} else {
6803 		*rxbeaconmbss = 0;
6804 		return BCME_NOTFOUND;
6805 	}
6806 
6807 	return BCME_OK;
6808 }
6809 
fill_chanspec_to_channel_info(chanspec_t cur_chanspec,wifi_channel_info * channel,int * cur_band)6810 static void fill_chanspec_to_channel_info(chanspec_t cur_chanspec,
6811 	wifi_channel_info *channel, int *cur_band)
6812 {
6813 	int band;
6814 	channel->width = WIFI_CHAN_WIDTH_INVALID;
6815 
6816 	if (CHSPEC_IS20(cur_chanspec)) {
6817 		channel->width = WIFI_CHAN_WIDTH_20;
6818 	} else if (CHSPEC_IS40(cur_chanspec)) {
6819 		channel->width = WIFI_CHAN_WIDTH_40;
6820 	} else if (CHSPEC_IS80(cur_chanspec)) {
6821 		channel->width = WIFI_CHAN_WIDTH_80;
6822 	} else if (CHSPEC_IS160(cur_chanspec)) {
6823 		channel->width = WIFI_CHAN_WIDTH_160;
6824 	} else if (CHSPEC_IS8080(cur_chanspec)) {
6825 		channel->width = WIFI_CHAN_WIDTH_80P80;
6826 	}
6827 
6828 	band = *cur_band = CHSPEC_BAND(cur_chanspec);
6829 	channel->center_freq =
6830 		wl_channel_to_frequency(wf_chspec_primary20_chan(cur_chanspec),
6831 			band);
6832 
6833 	if (CHSPEC_IS160(cur_chanspec) || CHSPEC_IS8080(cur_chanspec)) {
6834 		channel->center_freq0 =
6835 			wl_channel_to_frequency(wf_chspec_primary80_channel(cur_chanspec),
6836 				band);
6837 		channel->center_freq1 =
6838 			wl_channel_to_frequency(wf_chspec_secondary80_channel(cur_chanspec),
6839 				band);
6840 	} else {
6841 		channel->center_freq0 =
6842 			wl_channel_to_frequency(CHSPEC_CHANNEL(cur_chanspec),
6843 				band);
6844 		channel->center_freq1 = 0;
6845 	}
6846 }
6847 
wl_cfgvendor_lstats_get_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6848 static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy,
6849 	struct wireless_dev *wdev, const void  *data, int len)
6850 {
6851 	static char iovar_buf[WLC_IOCTL_MAXLEN];
6852 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6853 	int err = 0, ret = 0, i;
6854 	wifi_radio_stat *radio;
6855 	wifi_radio_stat_h radio_h;
6856 	wifi_channel_stat *chan_stats = NULL;
6857 	uint chan_stats_size = 0;
6858 #ifdef CHAN_STATS_SUPPORT
6859 	wifi_channel_stat *p_chan_stats = NULL;
6860 	cca_congest_ext_channel_req_v2_t *per_chspec_stats = NULL;
6861 	uint per_chspec_stats_size = 0;
6862 	cca_congest_ext_channel_req_v3_t *all_chan_results;
6863 	cca_congest_ext_channel_req_v3_t *all_chan_req = NULL;
6864 	uint all_chan_req_size = sizeof(cca_congest_ext_channel_req_v3_t);
6865 #else
6866 	/* cca_get_stats_ext iovar for Wifi channel statics */
6867 	struct cca_congest_ext_channel_req_v2 *cca_v2_results;
6868 	struct cca_congest_ext_channel_req_v2 *cca_v2_req = NULL;
6869 	uint cca_v2_req_size = sizeof(cca_congest_ext_channel_req_v2_t);
6870 #endif /* CHAN_STATS_SUPPORT  */
6871 	const wl_cnt_wlc_t *wlc_cnt;
6872 	scb_val_t scbval;
6873 	char *output = NULL;
6874 	char *outdata = NULL;
6875 	wifi_rate_stat_v1 *p_wifi_rate_stat_v1 = NULL;
6876 	wifi_rate_stat *p_wifi_rate_stat = NULL;
6877 	uint total_len = 0;
6878 	uint32 rxbeaconmbss;
6879 	wlc_rev_info_t revinfo;
6880 	wl_if_stats_t *if_stats = NULL;
6881 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6882 	wl_pwrstats_query_t scan_query;
6883 	wl_pwrstats_t *pwrstats;
6884 	wl_pwr_scan_stats_t scan_stats;
6885 	int scan_time_len;
6886 	uint32 tot_pno_dur = 0;
6887 	wifi_channel_stat cur_channel_stat;
6888 	cca_congest_channel_req_t *cca_result;
6889 	cca_congest_channel_req_t cca_req;
6890 	uint32 cca_busy_time = 0;
6891 	int cur_chansp, cur_band;
6892 	chanspec_t cur_chanspec;
6893 
6894 	COMPAT_STRUCT_IFACE(wifi_iface_stat, iface);
6895 
6896 	WL_TRACE(("%s: Enter \n", __func__));
6897 	RETURN_EIO_IF_NOT_UP(cfg);
6898 
6899 	BCM_REFERENCE(if_stats);
6900 	BCM_REFERENCE(dhdp);
6901 	/* Get the device rev info */
6902 	bzero(&revinfo, sizeof(revinfo));
6903 	err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_REVINFO, &revinfo,
6904 			sizeof(revinfo));
6905 	if (err != BCME_OK) {
6906 		goto exit;
6907 	}
6908 
6909 	outdata = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
6910 	if (outdata == NULL) {
6911 		WL_ERR(("outdata alloc failed\n"));
6912 		return BCME_NOMEM;
6913 	}
6914 
6915 	bzero(&scbval, sizeof(scb_val_t));
6916 	bzero(outdata, WLC_IOCTL_MAXLEN);
6917 	output = outdata;
6918 
6919 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0,
6920 		iovar_buf, WLC_IOCTL_MAXLEN, NULL);
6921 	if (err != BCME_OK && err != BCME_UNSUPPORTED) {
6922 		WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wifi_radio_stat)));
6923 		goto exit;
6924 	}
6925 	radio = (wifi_radio_stat *)iovar_buf;
6926 
6927 	bzero(&radio_h, sizeof(wifi_radio_stat_h));
6928 	radio_h.on_time = radio->on_time;
6929 	radio_h.tx_time = radio->tx_time;
6930 	radio_h.rx_time = radio->rx_time;
6931 	radio_h.on_time_scan = radio->on_time_scan;
6932 	radio_h.on_time_nbd = radio->on_time_nbd;
6933 	radio_h.on_time_gscan = radio->on_time_gscan;
6934 	radio_h.on_time_roam_scan = radio->on_time_roam_scan;
6935 	radio_h.on_time_pno_scan = radio->on_time_pno_scan;
6936 	radio_h.on_time_hs20 = radio->on_time_hs20;
6937 	radio_h.num_channels = NUM_PEER;
6938 
6939 	scan_query.length = 1;
6940 	scan_query.type[0] = WL_PWRSTATS_TYPE_SCAN;
6941 
6942 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "pwrstats", &scan_query,
6943 		sizeof(scan_query), iovar_buf, WLC_IOCTL_MAXLEN, NULL);
6944 	if (err != BCME_OK && err != BCME_UNSUPPORTED) {
6945 		WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_pwrstats_t)));
6946 		goto exit;
6947 	}
6948 
6949 	pwrstats = (wl_pwrstats_t *) iovar_buf;
6950 
6951 	if (dtoh16(pwrstats->version) != WL_PWRSTATS_VERSION) {
6952 		WL_ERR(("PWRSTATS Version mismatch\n"));
6953 		err = BCME_ERROR;
6954 		goto exit;
6955 	}
6956 
6957 	scan_time_len = dtoh16(((uint16 *)pwrstats->data)[1]);
6958 
6959 	if (scan_time_len < sizeof(wl_pwr_scan_stats_t)) {
6960 		WL_ERR(("WL_PWRSTATS_TYPE_SCAN IOVAR info short len :  %d < %d\n",
6961 			scan_time_len, (int)sizeof(wl_pwr_scan_stats_t)));
6962 		err = BCME_ERROR;
6963 		goto exit;
6964 	}
6965 
6966 	(void) memcpy_s(&scan_stats, sizeof(wl_pwr_scan_stats_t), pwrstats->data, scan_time_len);
6967 
6968 	/* wl_pwr_scan_stats structure has the array of pno_scans.
6969 	 * scan_data_t pno_scans[8];
6970 	 * The number of array is 8 : For future PNO bucketing (BSSID, SSID, etc)
6971 	 * FW sets the number as harcoded.
6972 	 * If the hardcoded number (8) is changed,
6973 	 * the loop condition or NUM_PNO_SCANS has to be changed
6974 	 */
6975 
6976 	for (i = 0; i < NUM_PNO_SCANS; i++) {
6977 		tot_pno_dur += dtoh32(scan_stats.pno_scans[i].dur);
6978 	}
6979 
6980 	/*  Android Framework defines the total scan time in ms.
6981 	 *  But FW sends each scan time in us except for roam scan time.
6982 	 *  So we need to scale the times in ms.
6983 	 */
6984 
6985 	radio_h.on_time_scan = (uint32)((tot_pno_dur +
6986 		dtoh32(scan_stats.user_scans.dur) +
6987 		dtoh32(scan_stats.assoc_scans.dur) +
6988 		dtoh32(scan_stats.other_scans.dur)) / 1000);
6989 
6990 	radio_h.on_time_scan += dtoh32(scan_stats.roam_scans.dur);
6991 	radio_h.on_time_roam_scan = dtoh32(scan_stats.roam_scans.dur);
6992 	radio_h.on_time_pno_scan = (uint32)(tot_pno_dur / 1000);
6993 
6994 	WL_TRACE(("pwr_scan_stats : %u %u %u %u %u %u\n",
6995 		radio_h.on_time_scan,
6996 		dtoh32(scan_stats.user_scans.dur),
6997 		dtoh32(scan_stats.assoc_scans.dur),
6998 		dtoh32(scan_stats.roam_scans.dur),
6999 		tot_pno_dur,
7000 		dtoh32(scan_stats.other_scans.dur)));
7001 
7002 	err = wldev_iovar_getint(bcmcfg_to_prmry_ndev(cfg), "chanspec", (int*)&cur_chansp);
7003 	if (err != BCME_OK) {
7004 		WL_ERR(("error (%d) \n", err));
7005 		goto exit;
7006 	}
7007 
7008 	cur_chanspec = wl_chspec_driver_to_host(cur_chansp);
7009 
7010 	if (!wf_chspec_valid(cur_chanspec)) {
7011 		WL_ERR(("Invalid chanspec : %x\n", cur_chanspec));
7012 		err = BCME_ERROR;
7013 		goto exit;
7014 	}
7015 
7016 	fill_chanspec_to_channel_info(cur_chanspec, &cur_channel_stat.channel, &cur_band);
7017 	WL_TRACE(("chanspec : %x, BW : %d, Cur Band : %x, freq : %d, freq0 :%d, freq1 : %d\n",
7018 		cur_chanspec,
7019 		cur_channel_stat.channel.width,
7020 		cur_band,
7021 		cur_channel_stat.channel.center_freq,
7022 		cur_channel_stat.channel.center_freq0,
7023 		cur_channel_stat.channel.center_freq1));
7024 
7025 	chan_stats_size = sizeof(wifi_channel_stat);
7026 	chan_stats = &cur_channel_stat;
7027 
7028 #ifdef CHAN_STATS_SUPPORT
7029 	/* Option to get all channel statistics */
7030 	all_chan_req = (void *)MALLOCZ(cfg->osh, all_chan_req_size);
7031 	if (all_chan_req == NULL) {
7032 		err = BCME_NOMEM;
7033 		WL_ERR(("all_chan_req alloc failed\n"));
7034 		goto exit;
7035 	}
7036 	all_chan_req->num_of_entries = 0;
7037 	all_chan_req->ver = WL_CCA_EXT_REQ_VER_V3;
7038 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats_ext",
7039 		all_chan_req, all_chan_req_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7040 
7041 	if (err != BCME_OK && err != BCME_UNSUPPORTED) {
7042 		WL_ERR(("cca_get_stats_ext iovar err = %d\n", err));
7043 		goto exit;
7044 	}
7045 
7046 	all_chan_results = (cca_congest_ext_channel_req_v3_t *) iovar_buf;
7047 	if ((err == BCME_OK) &&
7048 			(dtoh16(all_chan_results->ver) == WL_CCA_EXT_REQ_VER_V3)) {
7049 		wifi_channel_stat *all_chan_stats = NULL;
7050 		int i = 0, num_channels;
7051 
7052 		num_channels = dtoh16(all_chan_results->num_of_entries);
7053 		radio_h.num_channels = num_channels;
7054 
7055 		chan_stats_size = sizeof(wifi_channel_stat) * num_channels;
7056 		chan_stats = (wifi_channel_stat*)MALLOCZ(cfg->osh, chan_stats_size);
7057 		p_chan_stats = chan_stats;
7058 		if (chan_stats == NULL) {
7059 			WL_ERR(("chan_stats alloc failed\n"));
7060 			goto exit;
7061 		}
7062 		bzero(chan_stats, chan_stats_size);
7063 		all_chan_stats = chan_stats;
7064 
7065 		per_chspec_stats_size =
7066 			sizeof(cca_congest_ext_channel_req_v2_t) * num_channels;
7067 		per_chspec_stats = (cca_congest_ext_channel_req_v2_t *)
7068 			MALLOCZ(cfg->osh, per_chspec_stats_size);
7069 		if (per_chspec_stats == NULL) {
7070 			WL_ERR(("per_chspec_stats alloc failed\n"));
7071 			goto exit;
7072 		}
7073 		(void) memcpy_s(per_chspec_stats, per_chspec_stats_size,
7074 			&all_chan_results->per_chan_stats, per_chspec_stats_size);
7075 
7076 		WL_TRACE(("** Per channel CCA entries ** \n"));
7077 
7078 		for (i = 0; i < num_channels; i++, all_chan_stats++) {
7079 			if (per_chspec_stats[i].num_secs != 1) {
7080 				WL_ERR(("Bogus num of seconds returned %d\n",
7081 					per_chspec_stats[i].num_secs));
7082 				goto exit;
7083 			}
7084 
7085 			fill_chanspec_to_channel_info(per_chspec_stats[i].chanspec,
7086 				&all_chan_stats->channel, &cur_band);
7087 
7088 			all_chan_stats->on_time =
7089 				per_chspec_stats[i].secs[0].radio_on_time;
7090 			all_chan_stats->cca_busy_time =
7091 				per_chspec_stats[i].secs[0].cca_busy_time;
7092 
7093 			WL_TRACE(("chanspec %x num_sec %d radio_on_time %d cca_busytime %d \n",
7094 				per_chspec_stats[i].chanspec, per_chspec_stats[i].num_secs,
7095 				per_chspec_stats[i].secs[0].radio_on_time,
7096 				per_chspec_stats[i].secs[0].cca_busy_time));
7097 		}
7098 	}
7099 #else
7100 	cca_v2_req = (void *)MALLOCZ(cfg->osh, cca_v2_req_size);
7101 	if (cca_v2_req == NULL) {
7102 		err = BCME_NOMEM;
7103 		WL_ERR(("cca_v2_req alloc failed\n"));
7104 		goto exit;
7105 	}
7106 	cca_v2_req->ver = WL_CCA_EXT_REQ_VER_V2;
7107 	cca_v2_req->chanspec =
7108 		wl_chspec_host_to_driver(wf_chspec_primary20_chspec(cur_chanspec));
7109 
7110 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats_ext", cca_v2_req,
7111 		cca_v2_req_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7112 
7113 	if (err != BCME_OK && err != BCME_UNSUPPORTED) {
7114 		WL_ERR(("cca_get_stats_ext iovar err = %d\n", err));
7115 		goto exit;
7116 	}
7117 
7118 	cca_v2_results = (struct cca_congest_ext_channel_req_v2 *) iovar_buf;
7119 
7120 	/* Check the verison for cca_get_stats_ext iovar */
7121 	if ((err == BCME_OK) &&
7122 			(dtoh16(cca_v2_results->ver) == WL_CCA_EXT_REQ_VER_V2)) {
7123 		/* the accumulated time for the current channel */
7124 		cur_channel_stat.on_time = dtoh32(cca_v2_results->secs[0].radio_on_time);
7125 		cur_channel_stat.cca_busy_time = dtoh32(cca_v2_results->secs[0].cca_busy_time);
7126 
7127 		WL_TRACE(("wifi chan statics - on_time : %u, cca_busy_time : %u\n",
7128 			cur_channel_stat.on_time, cur_channel_stat.cca_busy_time));
7129 	}
7130 #endif /* CHAN_STATS_SUPPORT  */
7131 	else {
7132 		/* To get fine-grained cca result,
7133 		* you can increase num_secs because num_secs is the time to get samples.
7134 		* Also if the time is increased,
7135 		* it is necessary to use a loop to add the times of cca_result->sec[].
7136 		* For simplicity, the sampling time is set to 1sec.
7137 		*/
7138 		WL_TRACE(("cca_get_stats_ext unsupported or version mismatch\n"));
7139 
7140 		cca_req.num_secs = NUM_CCA_SAMPLING_SECS;
7141 		cca_req.chanspec = wl_chspec_host_to_driver(cur_chanspec);
7142 
7143 		err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats", &cca_req,
7144 			sizeof(cca_req), iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7145 
7146 		if (err != BCME_OK && err != BCME_UNSUPPORTED) {
7147 			WL_ERR(("error (%d) - size = %zu\n",
7148 				err, sizeof(cca_congest_channel_req_t)));
7149 			goto exit;
7150 		}
7151 
7152 		cur_channel_stat.on_time = radio_h.on_time;
7153 
7154 		if (err == BCME_OK) {
7155 			cca_result = (cca_congest_channel_req_t *) iovar_buf;
7156 			cca_busy_time = dtoh32(cca_result->secs[0].congest_ibss) +
7157 				dtoh32(cca_result->secs[0].congest_obss) +
7158 				dtoh32(cca_result->secs[0].interference);
7159 
7160 			WL_TRACE(("wifi stats : %u, %u, %u, %u, %u\n", cur_channel_stat.on_time,
7161 				cca_busy_time,
7162 				dtoh32(cca_result->secs[0].congest_ibss),
7163 				dtoh32(cca_result->secs[0].congest_obss),
7164 				dtoh32(cca_result->secs[0].interference)));
7165 		} else {
7166 			WL_INFORM(("cca_get_stats is unsupported \n"));
7167 		}
7168 
7169 		/* If cca_get_stats is unsupported, cca_busy_time has zero value as initial value */
7170 		cur_channel_stat.cca_busy_time = cca_busy_time;
7171 	}
7172 
7173 	ret = memcpy_s(output, WLC_IOCTL_MAXLEN, &radio_h, sizeof(wifi_radio_stat_h));
7174 	if (ret) {
7175 		WL_ERR(("Failed to copy wifi_radio_stat_h: %d\n", ret));
7176 		goto exit;
7177 	}
7178 	output += sizeof(wifi_radio_stat_h);
7179 
7180 	ret = memcpy_s(output, (WLC_IOCTL_MAXLEN - sizeof(wifi_radio_stat_h)),
7181 		chan_stats, chan_stats_size);
7182 	if (ret) {
7183 		WL_ERR(("Failed to copy wifi_channel_stat: %d\n", ret));
7184 		goto exit;
7185 	}
7186 	output += chan_stats_size;
7187 
7188 	COMPAT_BZERO_IFACE(wifi_iface_stat, iface);
7189 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].ac, WIFI_AC_VO);
7190 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].ac, WIFI_AC_VI);
7191 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].ac, WIFI_AC_BE);
7192 	COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].ac, WIFI_AC_BK);
7193 
7194 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0,
7195 		iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7196 	if (unlikely(err)) {
7197 		WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_cnt_wlc_t)));
7198 		goto exit;
7199 	}
7200 
7201 	CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MAXLEN);
7202 	/* Translate traditional (ver <= 10) counters struct to new xtlv type struct */
7203 	/* traditional(ver<=10)counters will use WL_CNT_XTLV_CNTV_LE10_UCODE.
7204 	 * Other cases will use its xtlv type accroding to corerev
7205 	 */
7206 	err = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WLC_IOCTL_MAXLEN, revinfo.corerev);
7207 	if (err != BCME_OK) {
7208 		WL_ERR(("wl_cntbuf_to_xtlv_format ERR %d\n", err));
7209 		goto exit;
7210 	}
7211 
7212 	if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
7213 		WL_ERR(("wlc_cnt NULL!\n"));
7214 		err = BCME_ERROR;
7215 		goto exit;
7216 	}
7217 
7218 #ifndef DISABLE_IF_COUNTERS
7219 	if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(wl_if_stats_t));
7220 	if (!if_stats) {
7221 	    WL_ERR(("MALLOCZ failed\n"));
7222 	    err = BCME_NOMEM;
7223 	    goto exit;
7224 	}
7225 
7226 	if (FW_SUPPORTED(dhdp, ifst)) {
7227 		err = wl_cfg80211_ifstats_counters(bcmcfg_to_prmry_ndev(cfg), if_stats);
7228 	} else {
7229 		err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "if_counters",
7230 			NULL, 0, (char *)if_stats, sizeof(*if_stats), NULL);
7231 	}
7232 
7233 	if (!err) {
7234 		/* Populate from if_stats */
7235 		if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
7236 			WL_ERR(("incorrect version of wl_if_stats_t,"
7237 				" expected=%u got=%u\n", WL_IF_STATS_T_VERSION,
7238 				if_stats->version));
7239 			goto exit;
7240 		}
7241 		COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu, (uint32)if_stats->txframe);
7242 		COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu,
7243 			(uint32)(if_stats->rxframe - if_stats->rxmulti));
7244 		COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost, (uint32)if_stats->txfail);
7245 		COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, (uint32)if_stats->txretrans);
7246 	} else
7247 #endif /* !DISABLE_IF_COUNTERS */
7248 	{
7249 		COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu,
7250 			(wlc_cnt->txfrmsnt - wlc_cnt->txmulti));
7251 		COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu, wlc_cnt->rxframe);
7252 		COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost, wlc_cnt->txfail);
7253 		COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, wlc_cnt->txretrans);
7254 	}
7255 
7256 	err = wl_cfgvendor_lstats_get_bcn_mbss(iovar_buf, &rxbeaconmbss);
7257 	if (unlikely(err)) {
7258 		WL_ERR(("get_bcn_mbss error (%d)\n", err));
7259 		goto exit;
7260 	}
7261 
7262 	err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval);
7263 	if (unlikely(err)) {
7264 		WL_ERR(("get_rssi error (%d)\n", err));
7265 		goto exit;
7266 	}
7267 
7268 	COMPAT_ASSIGN_VALUE(iface, beacon_rx, rxbeaconmbss);
7269 	COMPAT_ASSIGN_VALUE(iface, rssi_mgmt, scbval.val);
7270 	COMPAT_ASSIGN_VALUE(iface, num_peers, NUM_PEER);
7271 	COMPAT_ASSIGN_VALUE(iface, peer_info->num_rate, NUM_RATE);
7272 
7273 	COMPAT_MEMCOPY_IFACE(output, total_len, wifi_iface_stat, iface, wifi_rate_stat);
7274 
7275 	err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0,
7276 		iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7277 	if (err != BCME_OK && err != BCME_UNSUPPORTED) {
7278 		WL_ERR(("error (%d) - size = %zu\n", err, NUM_RATE*sizeof(wifi_rate_stat)));
7279 		goto exit;
7280 	}
7281 	for (i = 0; i < NUM_RATE; i++) {
7282 		p_wifi_rate_stat =
7283 			(wifi_rate_stat *)(iovar_buf + i*sizeof(wifi_rate_stat));
7284 		p_wifi_rate_stat_v1 = (wifi_rate_stat_v1 *)output;
7285 		p_wifi_rate_stat_v1->rate.preamble = p_wifi_rate_stat->rate.preamble;
7286 		p_wifi_rate_stat_v1->rate.nss = p_wifi_rate_stat->rate.nss;
7287 		p_wifi_rate_stat_v1->rate.bw = p_wifi_rate_stat->rate.bw;
7288 		p_wifi_rate_stat_v1->rate.rateMcsIdx = p_wifi_rate_stat->rate.rateMcsIdx;
7289 		p_wifi_rate_stat_v1->rate.reserved = p_wifi_rate_stat->rate.reserved;
7290 		p_wifi_rate_stat_v1->rate.bitrate = p_wifi_rate_stat->rate.bitrate;
7291 		p_wifi_rate_stat_v1->tx_mpdu = p_wifi_rate_stat->tx_mpdu;
7292 		p_wifi_rate_stat_v1->rx_mpdu = p_wifi_rate_stat->rx_mpdu;
7293 		p_wifi_rate_stat_v1->mpdu_lost = p_wifi_rate_stat->mpdu_lost;
7294 		p_wifi_rate_stat_v1->retries = p_wifi_rate_stat->retries;
7295 		p_wifi_rate_stat_v1->retries_short = p_wifi_rate_stat->retries_short;
7296 		p_wifi_rate_stat_v1->retries_long = p_wifi_rate_stat->retries_long;
7297 		output = (char *) &(p_wifi_rate_stat_v1->retries_long);
7298 		output += sizeof(p_wifi_rate_stat_v1->retries_long);
7299 	}
7300 
7301 	total_len = sizeof(wifi_radio_stat_h) + chan_stats_size;
7302 	total_len = total_len - sizeof(wifi_peer_info) +
7303 		NUM_PEER * (sizeof(wifi_peer_info) - sizeof(wifi_rate_stat_v1) +
7304 			NUM_RATE * sizeof(wifi_rate_stat_v1));
7305 
7306 	if (total_len > WLC_IOCTL_MAXLEN) {
7307 		WL_ERR(("Error! total_len:%d is unexpected value\n", total_len));
7308 		err = BCME_BADLEN;
7309 		goto exit;
7310 	}
7311 	err =  wl_cfgvendor_send_cmd_reply(wiphy, outdata, total_len);
7312 
7313 	if (unlikely(err))
7314 		WL_ERR(("Vendor Command reply failed ret:%d \n", err));
7315 
7316 exit:
7317 #ifdef CHAN_STATS_SUPPORT
7318 	if (all_chan_req) {
7319 		MFREE(cfg->osh, all_chan_req, all_chan_req_size);
7320 	}
7321 #else
7322 	if (cca_v2_req) {
7323 		MFREE(cfg->osh, cca_v2_req, cca_v2_req_size);
7324 	}
7325 #endif /* CHAN_STATS_SUPPORT */
7326 	if (outdata) {
7327 		MFREE(cfg->osh, outdata, WLC_IOCTL_MAXLEN);
7328 	}
7329 	if (if_stats) {
7330 		MFREE(cfg->osh, if_stats, sizeof(wl_if_stats_t));
7331 	}
7332 #ifdef CHAN_STATS_SUPPORT
7333 	if (p_chan_stats) {
7334 		MFREE(cfg->osh, p_chan_stats, chan_stats_size);
7335 	}
7336 	if (per_chspec_stats) {
7337 		MFREE(cfg->osh, per_chspec_stats, per_chspec_stats_size);
7338 	}
7339 #endif /* CHAN_STATS_SUPPORT */
7340 	return err;
7341 }
7342 #endif /* LINKSTAT_SUPPORT */
7343 
7344 #ifdef DHD_LOG_DUMP
7345 static int
wl_cfgvendor_get_buf_data(const struct nlattr * iter,struct buf_data ** buf)7346 wl_cfgvendor_get_buf_data(const struct nlattr *iter, struct buf_data **buf)
7347 {
7348 	int ret = BCME_OK;
7349 
7350 	if (nla_len(iter) != sizeof(struct buf_data)) {
7351 		WL_ERR(("Invalid len : %d\n", nla_len(iter)));
7352 		ret = BCME_BADLEN;
7353 	}
7354 	(*buf) = (struct buf_data *)nla_data(iter);
7355 	if (!(*buf) || (((*buf)->len) <= 0) || !((*buf)->data_buf[0])) {
7356 		WL_ERR(("Invalid buffer\n"));
7357 		ret = BCME_ERROR;
7358 	}
7359 	return ret;
7360 }
7361 
7362 static int
wl_cfgvendor_dbg_file_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7363 wl_cfgvendor_dbg_file_dump(struct wiphy *wiphy,
7364 		struct wireless_dev *wdev, const void *data, int len)
7365 {
7366 	int ret = BCME_OK, rem, type = 0;
7367 	const struct nlattr *iter;
7368 	char *mem_buf = NULL;
7369 	struct sk_buff *skb = NULL;
7370 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7371 	struct buf_data *buf;
7372 	int pos = 0;
7373 
7374 	/* Alloc the SKB for vendor_event */
7375 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
7376 	if (!skb) {
7377 		WL_ERR(("skb allocation is failed\n"));
7378 		ret = BCME_NOMEM;
7379 		goto exit;
7380 	}
7381 	WL_ERR(("%s\n", __FUNCTION__));
7382 	nla_for_each_attr(iter, data, len, rem) {
7383 		type = nla_type(iter);
7384 		ret = wl_cfgvendor_get_buf_data(iter, &buf);
7385 		if (ret)
7386 			goto exit;
7387 		switch (type) {
7388 			case DUMP_BUF_ATTR_MEMDUMP:
7389 				ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf,
7390 					(uint32 *)(&(buf->len)));
7391 				if (ret) {
7392 					WL_ERR(("failed to get_socram_dump : %d\n", ret));
7393 					goto exit;
7394 				}
7395 				ret = dhd_export_debug_data(mem_buf, NULL, buf->data_buf[0],
7396 					(int)buf->len, &pos);
7397 				break;
7398 
7399 			case DUMP_BUF_ATTR_TIMESTAMP :
7400 				ret = dhd_print_time_str(buf->data_buf[0], NULL,
7401 					(uint32)buf->len, &pos);
7402 				break;
7403 #ifdef EWP_ECNTRS_LOGGING
7404 			case DUMP_BUF_ATTR_ECNTRS :
7405 				ret = dhd_print_ecntrs_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7406 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7407 				break;
7408 #endif /* EWP_ECNTRS_LOGGING */
7409 #ifdef DHD_STATUS_LOGGING
7410 			case DUMP_BUF_ATTR_STATUS_LOG :
7411 				ret = dhd_print_status_log_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7412 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7413 				break;
7414 #endif /* DHD_STATUS_LOGGING */
7415 #ifdef EWP_RTT_LOGGING
7416 			case DUMP_BUF_ATTR_RTT_LOG :
7417 				ret = dhd_print_rtt_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7418 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7419 				break;
7420 #endif /* EWP_RTT_LOGGING */
7421 			case DUMP_BUF_ATTR_DHD_DUMP :
7422 				ret = dhd_print_dump_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7423 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7424 				break;
7425 #if defined(BCMPCIE)
7426 			case DUMP_BUF_ATTR_EXT_TRAP :
7427 				ret = dhd_print_ext_trap_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7428 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7429 				break;
7430 #endif /* BCMPCIE */
7431 #if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT)
7432 			case DUMP_BUF_ATTR_HEALTH_CHK :
7433 				ret = dhd_print_health_chk_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7434 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7435 				break;
7436 #endif
7437 			case DUMP_BUF_ATTR_COOKIE :
7438 				ret = dhd_print_cookie_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7439 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7440 				break;
7441 #ifdef DHD_DUMP_PCIE_RINGS
7442 			case DUMP_BUF_ATTR_FLOWRING_DUMP :
7443 				ret = dhd_print_flowring_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7444 					buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7445 				break;
7446 #endif
7447 			case DUMP_BUF_ATTR_GENERAL_LOG :
7448 				ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
7449 					buf->data_buf[0], NULL, (uint32)buf->len,
7450 					DLD_BUF_TYPE_GENERAL, &pos);
7451 				break;
7452 
7453 			case DUMP_BUF_ATTR_PRESERVE_LOG :
7454 				ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
7455 					buf->data_buf[0], NULL, (uint32)buf->len,
7456 					DLD_BUF_TYPE_PRESERVE, &pos);
7457 				break;
7458 
7459 			case DUMP_BUF_ATTR_SPECIAL_LOG :
7460 				ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
7461 					buf->data_buf[0], NULL, (uint32)buf->len,
7462 					DLD_BUF_TYPE_SPECIAL, &pos);
7463 				break;
7464 #ifdef DHD_SSSR_DUMP
7465 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7466 			case DUMP_BUF_ATTR_SSSR_C0_D11_BEFORE :
7467 				ret = dhd_sssr_dump_d11_buf_before(bcmcfg_to_prmry_ndev(cfg),
7468 					buf->data_buf[0], (uint32)buf->len, 0);
7469 				break;
7470 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7471 
7472 			case DUMP_BUF_ATTR_SSSR_C0_D11_AFTER :
7473 				ret = dhd_sssr_dump_d11_buf_after(bcmcfg_to_prmry_ndev(cfg),
7474 					buf->data_buf[0], (uint32)buf->len, 0);
7475 				break;
7476 
7477 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7478 			case DUMP_BUF_ATTR_SSSR_C1_D11_BEFORE :
7479 				ret = dhd_sssr_dump_d11_buf_before(bcmcfg_to_prmry_ndev(cfg),
7480 					buf->data_buf[0], (uint32)buf->len, 1);
7481 				break;
7482 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7483 
7484 			case DUMP_BUF_ATTR_SSSR_C1_D11_AFTER :
7485 				ret = dhd_sssr_dump_d11_buf_after(bcmcfg_to_prmry_ndev(cfg),
7486 					buf->data_buf[0], (uint32)buf->len, 1);
7487 				break;
7488 
7489 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7490 			case DUMP_BUF_ATTR_SSSR_C2_D11_BEFORE :
7491 				ret = dhd_sssr_dump_d11_buf_before(bcmcfg_to_prmry_ndev(cfg),
7492 					buf->data_buf[0], (uint32)buf->len, 2);
7493 				break;
7494 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7495 
7496 			case DUMP_BUF_ATTR_SSSR_C2_D11_AFTER :
7497 				ret = dhd_sssr_dump_d11_buf_after(bcmcfg_to_prmry_ndev(cfg),
7498 					buf->data_buf[0], (uint32)buf->len, 2);
7499 				break;
7500 
7501 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7502 			case DUMP_BUF_ATTR_SSSR_DIG_BEFORE :
7503 				ret = dhd_sssr_dump_dig_buf_before(bcmcfg_to_prmry_ndev(cfg),
7504 					buf->data_buf[0], (uint32)buf->len);
7505 				break;
7506 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7507 
7508 			case DUMP_BUF_ATTR_SSSR_DIG_AFTER :
7509 				ret = dhd_sssr_dump_dig_buf_after(bcmcfg_to_prmry_ndev(cfg),
7510 					buf->data_buf[0], (uint32)buf->len);
7511 				break;
7512 #endif /* DHD_SSSR_DUMP */
7513 #ifdef DHD_PKT_LOGGING
7514 			case DUMP_BUF_ATTR_PKTLOG:
7515 				ret = dhd_os_get_pktlog_dump(bcmcfg_to_prmry_ndev(cfg),
7516 					buf->data_buf[0], (uint32)buf->len);
7517 				break;
7518 
7519 			case DUMP_BUF_ATTR_PKTLOG_DEBUG:
7520 				ret = dhd_os_get_pktlog_dump(bcmcfg_to_prmry_ndev(cfg),
7521 					buf->data_buf[0], (uint32)buf->len);
7522 				break;
7523 #endif /* DHD_PKT_LOGGING */
7524 #ifdef DNGL_AXI_ERROR_LOGGING
7525 			case DUMP_BUF_ATTR_AXI_ERROR:
7526 				ret = dhd_os_get_axi_error_dump(bcmcfg_to_prmry_ndev(cfg),
7527 					buf->data_buf[0], (uint32)buf->len);
7528 				break;
7529 #endif /* DNGL_AXI_ERROR_LOGGING */
7530 			default:
7531 				WL_ERR(("Unknown type: %d\n", type));
7532 				ret = BCME_ERROR;
7533 				goto exit;
7534 		}
7535 	}
7536 
7537 	if (ret)
7538 		goto exit;
7539 
7540 	ret = nla_put_u32(skb, type, (uint32)(ret));
7541 	if (ret < 0) {
7542 		WL_ERR(("Failed to put type, ret:%d\n", ret));
7543 		goto exit;
7544 	}
7545 	ret = cfg80211_vendor_cmd_reply(skb);
7546 	if (ret) {
7547 		WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
7548 	}
7549 	return ret;
7550 exit:
7551 	if (skb) {
7552 		/* Free skb memory */
7553 		kfree_skb(skb);
7554 	}
7555 	return ret;
7556 }
7557 #endif /* DHD_LOG_DUMP */
7558 
7559 #ifdef DEBUGABILITY
7560 #ifndef DEBUGABILITY_DISABLE_MEMDUMP
7561 static int
wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7562 wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
7563 		struct wireless_dev *wdev, const void  *data, int len)
7564 {
7565 	int ret = BCME_OK;
7566 	uint32 alloc_len;
7567 	struct sk_buff *skb = NULL;
7568 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7569 	dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7570 	u32 supported_features = 0;
7571 
7572 	WL_ERR(("wl_cfgvendor_dbg_trigger_mem_dump %d\n", __LINE__));
7573 
7574 	ret = dhd_os_dbg_get_feature(dhdp, &supported_features);
7575 	if (!(supported_features & DBG_MEMORY_DUMP_SUPPORTED)) {
7576 		WL_ERR(("not support DBG_MEMORY_DUMP_SUPPORTED\n"));
7577 		ret = -3; //WIFI_ERROR_NOT_SUPPORTED=-3
7578 		goto exit;
7579 	}
7580 
7581 	dhdp->memdump_type = DUMP_TYPE_CFG_VENDOR_TRIGGERED;
7582 	ret = dhd_os_socram_dump(bcmcfg_to_prmry_ndev(cfg), &alloc_len);
7583 	if (ret) {
7584 		WL_ERR(("failed to call dhd_os_socram_dump : %d\n", ret));
7585 		goto exit;
7586 	}
7587 	/* Alloc the SKB for vendor_event */
7588 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
7589 	if (!skb) {
7590 		WL_ERR(("skb allocation is failed\n"));
7591 		ret = BCME_NOMEM;
7592 		goto exit;
7593 	}
7594 	ret = nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, alloc_len);
7595 
7596 	if (unlikely(ret)) {
7597 		WL_ERR(("Failed to put fw dump length, ret=%d\n", ret));
7598 		goto exit;
7599 	}
7600 
7601 	ret = cfg80211_vendor_cmd_reply(skb);
7602 
7603 	if (ret) {
7604 		WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
7605 		goto exit;
7606 	}
7607 	return ret;
7608 exit:
7609 	/* Free skb memory */
7610 	if (skb) {
7611 		kfree_skb(skb);
7612 	}
7613 	return ret;
7614 }
7615 
7616 static int
wl_cfgvendor_dbg_get_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7617 wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
7618 		struct wireless_dev *wdev, const void *data, int len)
7619 {
7620 	int ret = BCME_OK, rem, type;
7621 	int buf_len = 0;
7622 	uintptr_t user_buf = (uintptr_t)NULL;
7623 	const struct nlattr *iter;
7624 	char *mem_buf = NULL;
7625 	struct sk_buff *skb = NULL;
7626 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7627 
7628 	nla_for_each_attr(iter, data, len, rem) {
7629 		type = nla_type(iter);
7630 		switch (type) {
7631 			case DEBUG_ATTRIBUTE_FW_DUMP_LEN:
7632 				/* Check if the iter is valid and
7633 				 * buffer length is not already initialized.
7634 				 */
7635 				if ((nla_len(iter) == sizeof(uint32)) &&
7636 						!buf_len) {
7637 					buf_len = nla_get_u32(iter);
7638 					if (buf_len <= 0) {
7639 						ret = BCME_ERROR;
7640 						goto exit;
7641 					}
7642 				} else {
7643 					ret = BCME_ERROR;
7644 					goto exit;
7645 				}
7646 				break;
7647 			case DEBUG_ATTRIBUTE_FW_DUMP_DATA:
7648 				if (nla_len(iter) != sizeof(uint64)) {
7649 					WL_ERR(("Invalid len\n"));
7650 					ret = BCME_ERROR;
7651 					goto exit;
7652 				}
7653 				user_buf = (uintptr_t)nla_get_u64(iter);
7654 				if (!user_buf) {
7655 					ret = BCME_ERROR;
7656 					goto exit;
7657 				}
7658 				break;
7659 			default:
7660 				WL_ERR(("Unknown type: %d\n", type));
7661 				ret = BCME_ERROR;
7662 				goto exit;
7663 		}
7664 	}
7665 	if (buf_len > 0 && user_buf) {
7666 #if 0
7667 		mem_buf = vmalloc(buf_len);
7668 		if (!mem_buf) {
7669 			WL_ERR(("failed to allocate mem_buf with size : %d\n", buf_len));
7670 			ret = BCME_NOMEM;
7671 			goto exit;
7672 		}
7673 #endif
7674 		ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf, &buf_len);
7675 		if (ret) {
7676 			WL_ERR(("failed to get_socram_dump : %d\n", ret));
7677 			goto free_mem;
7678 		}
7679 #ifdef CONFIG_COMPAT
7680 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
7681 		if (in_compat_syscall())
7682 #else
7683 		if (is_compat_task())
7684 #endif /* LINUX_VER >= 4.6 */
7685 		{
7686 			void * usr_ptr =  compat_ptr((uintptr_t) user_buf);
7687 			ret = copy_to_user(usr_ptr, mem_buf, buf_len);
7688 			if (ret) {
7689 				WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
7690 				goto free_mem;
7691 			}
7692 		}
7693 		else
7694 #endif /* CONFIG_COMPAT */
7695 		{
7696 			ret = copy_to_user((void*)user_buf, mem_buf, buf_len);
7697 			if (ret) {
7698 				WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
7699 				goto free_mem;
7700 			}
7701 		}
7702 		/* Alloc the SKB for vendor_event */
7703 		skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
7704 		if (!skb) {
7705 			WL_ERR(("skb allocation is failed\n"));
7706 			ret = BCME_NOMEM;
7707 			goto free_mem;
7708 		}
7709 		/* Indicate the memdump is succesfully copied */
7710 		ret = nla_put(skb, DEBUG_ATTRIBUTE_FW_DUMP_DATA, sizeof(ret), &ret);
7711 		if (ret < 0) {
7712 			WL_ERR(("Failed to put DEBUG_ATTRIBUTE_FW_DUMP_DATA, ret:%d\n", ret));
7713 			goto free_mem;
7714 		}
7715 
7716 		ret = cfg80211_vendor_cmd_reply(skb);
7717 
7718 		if (ret) {
7719 			WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
7720 		}
7721 		skb = NULL;
7722 	}
7723 
7724 free_mem:
7725 //	vfree(mem_buf);
7726 	/* Free skb memory */
7727 	if (skb) {
7728 		kfree_skb(skb);
7729 	}
7730 exit:
7731 	return ret;
7732 }
7733 #else
7734 static int
wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7735 wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
7736 	struct wireless_dev *wdev, const void  *data, int len)
7737 {
7738 	return WIFI_ERROR_NOT_SUPPORTED;
7739 }
7740 
7741 static int
wl_cfgvendor_dbg_get_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7742 wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
7743 	struct wireless_dev *wdev, const void *data, int len)
7744 {
7745 	return WIFI_ERROR_NOT_SUPPORTED;
7746 }
7747 #endif /* !DEBUGABILITY_DISABLE_MEMDUMP */
7748 
wl_cfgvendor_dbg_start_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7749 static int wl_cfgvendor_dbg_start_logging(struct wiphy *wiphy,
7750 	struct wireless_dev *wdev, const void  *data, int len)
7751 {
7752 	int ret = BCME_OK, rem, type;
7753 	char ring_name[DBGRING_NAME_MAX] = {0};
7754 	int log_level = 0, flags = 0, time_intval = 0, threshold = 0;
7755 	const struct nlattr *iter;
7756 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7757 	dhd_pub_t *dhd_pub = cfg->pub;
7758 	nla_for_each_attr(iter, data, len, rem) {
7759 		type = nla_type(iter);
7760 		switch (type) {
7761 			case DEBUG_ATTRIBUTE_RING_NAME:
7762 				strncpy(ring_name, nla_data(iter),
7763 					MIN(sizeof(ring_name) -1, nla_len(iter)));
7764 				break;
7765 			case DEBUG_ATTRIBUTE_LOG_LEVEL:
7766 				log_level = nla_get_u32(iter);
7767 				break;
7768 			case DEBUG_ATTRIBUTE_RING_FLAGS:
7769 				flags = nla_get_u32(iter);
7770 				break;
7771 			case DEBUG_ATTRIBUTE_LOG_TIME_INTVAL:
7772 				time_intval = nla_get_u32(iter);
7773 				break;
7774 			case DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE:
7775 				threshold = nla_get_u32(iter);
7776 				break;
7777 			default:
7778 				WL_ERR(("Unknown type: %d\n", type));
7779 				ret = BCME_BADADDR;
7780 				goto exit;
7781 		}
7782 	}
7783 
7784 	ret = dhd_os_start_logging(dhd_pub, ring_name, log_level, flags, time_intval, threshold);
7785 	if (ret < 0) {
7786 		WL_ERR(("start_logging is failed ret: %d\n", ret));
7787 	}
7788 exit:
7789 	return ret;
7790 }
7791 
wl_cfgvendor_dbg_reset_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7792 static int wl_cfgvendor_dbg_reset_logging(struct wiphy *wiphy,
7793 	struct wireless_dev *wdev, const void  *data, int len)
7794 {
7795 	int ret = BCME_OK;
7796 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7797 	dhd_pub_t *dhd_pub = cfg->pub;
7798 
7799 	ret = dhd_os_reset_logging(dhd_pub);
7800 	if (ret < 0) {
7801 		WL_ERR(("reset logging is failed ret: %d\n", ret));
7802 	}
7803 
7804 	return ret;
7805 }
7806 
wl_cfgvendor_dbg_get_ring_status(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7807 static int wl_cfgvendor_dbg_get_ring_status(struct wiphy *wiphy,
7808 	struct wireless_dev *wdev, const void  *data, int len)
7809 {
7810 	int ret = BCME_OK;
7811 	int ring_id, i;
7812 	int ring_cnt;
7813 	struct sk_buff *skb;
7814 	dhd_dbg_ring_status_t dbg_ring_status[DEBUG_RING_ID_MAX];
7815 	dhd_dbg_ring_status_t ring_status;
7816 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7817 	dhd_pub_t *dhd_pub = cfg->pub;
7818 	bzero(dbg_ring_status, DBG_RING_STATUS_SIZE * DEBUG_RING_ID_MAX);
7819 	ring_cnt = 0;
7820 	for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
7821 		ret = dhd_os_get_ring_status(dhd_pub, ring_id, &ring_status);
7822 		if (ret == BCME_NOTFOUND) {
7823 			WL_DBG(("The ring (%d) is not found \n", ring_id));
7824 		} else if (ret == BCME_OK) {
7825 			dbg_ring_status[ring_cnt++] = ring_status;
7826 		}
7827 	}
7828 	/* Alloc the SKB for vendor_event */
7829 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
7830 		nla_total_size(DBG_RING_STATUS_SIZE) * ring_cnt + nla_total_size(sizeof(ring_cnt)));
7831 	if (!skb) {
7832 		WL_ERR(("skb allocation is failed\n"));
7833 		ret = BCME_NOMEM;
7834 		goto exit;
7835 	}
7836 
7837 	/* Ignore return of nla_put_u32 and nla_put since the skb allocated
7838 	 * above has a requested size for all payload
7839 	 */
7840 	(void)nla_put_u32(skb, DEBUG_ATTRIBUTE_RING_NUM, ring_cnt);
7841 	for (i = 0; i < ring_cnt; i++) {
7842 		(void)nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, DBG_RING_STATUS_SIZE,
7843 				&dbg_ring_status[i]);
7844 	}
7845 	ret = cfg80211_vendor_cmd_reply(skb);
7846 
7847 	if (ret) {
7848 		WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
7849 	}
7850 exit:
7851 	return ret;
7852 }
7853 
wl_cfgvendor_dbg_get_ring_data(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7854 static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy,
7855 	struct wireless_dev *wdev, const void  *data, int len)
7856 {
7857 	int ret = BCME_OK, rem, type;
7858 	char ring_name[DBGRING_NAME_MAX] = {0};
7859 	const struct nlattr *iter;
7860 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7861 	dhd_pub_t *dhd_pub = cfg->pub;
7862 
7863 	nla_for_each_attr(iter, data, len, rem) {
7864 		type = nla_type(iter);
7865 		switch (type) {
7866 			case DEBUG_ATTRIBUTE_RING_NAME:
7867 				strlcpy(ring_name, nla_data(iter), sizeof(ring_name));
7868 				break;
7869 			default:
7870 				WL_ERR(("Unknown type: %d\n", type));
7871 				return ret;
7872 		}
7873 	}
7874 
7875 	ret = dhd_os_trigger_get_ring_data(dhd_pub, ring_name);
7876 	if (ret < 0) {
7877 		WL_ERR(("trigger_get_data failed ret:%d\n", ret));
7878 	}
7879 
7880 	return ret;
7881 }
7882 #endif /* DEBUGABILITY */
7883 
wl_cfgvendor_dbg_get_feature(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7884 static int wl_cfgvendor_dbg_get_feature(struct wiphy *wiphy,
7885 	struct wireless_dev *wdev, const void  *data, int len)
7886 {
7887 	int ret = BCME_OK;
7888 	u32 supported_features = 0;
7889 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7890 	dhd_pub_t *dhd_pub = cfg->pub;
7891 
7892 	ret = dhd_os_dbg_get_feature(dhd_pub, &supported_features);
7893 	if (ret < 0) {
7894 		WL_ERR(("dbg_get_feature failed ret:%d\n", ret));
7895 		goto exit;
7896 	}
7897 	ret = wl_cfgvendor_send_cmd_reply(wiphy, &supported_features,
7898 		sizeof(supported_features));
7899 exit:
7900 	return ret;
7901 }
7902 
7903 #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)7904 static void wl_cfgvendor_dbg_ring_send_evt(void *ctx,
7905 	const int ring_id, const void *data, const uint32 len,
7906 	const dhd_dbg_ring_status_t ring_status)
7907 {
7908 	struct net_device *ndev = ctx;
7909 	struct wiphy *wiphy;
7910 	gfp_t kflags;
7911 	struct sk_buff *skb;
7912 	struct nlmsghdr *nlh;
7913 	struct bcm_cfg80211 *cfg;
7914 	if (!ndev) {
7915 		WL_ERR(("ndev is NULL\n"));
7916 		return;
7917 	}
7918 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
7919 	wiphy = ndev->ieee80211_ptr->wiphy;
7920 	cfg = wiphy_priv(wiphy);
7921 
7922 	/* If wifi hal is not start, don't send event to wifi hal */
7923 	if (!cfg->hal_started) {
7924 		WL_ERR(("Hal is not started\n"));
7925 		return;
7926 	}
7927 	/* Alloc the SKB for vendor_event */
7928 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
7929 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
7930 	skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + CFG80211_VENDOR_EVT_SKB_SZ,
7931 			GOOGLE_DEBUG_RING_EVENT, kflags);
7932 #else
7933 	skb = cfg80211_vendor_event_alloc(wiphy, len + CFG80211_VENDOR_EVT_SKB_SZ,
7934 			GOOGLE_DEBUG_RING_EVENT, kflags);
7935 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
7936 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
7937 	if (!skb) {
7938 		WL_ERR(("skb alloc failed"));
7939 		return;
7940 	}
7941 	/* Set halpid for sending unicast event to wifi hal */
7942 	nlh = (struct nlmsghdr*)skb->data;
7943 	nlh->nlmsg_pid = cfg->halpid;
7944 	nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, sizeof(ring_status), &ring_status);
7945 	nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
7946 	cfg80211_vendor_event(skb, kflags);
7947 }
7948 #endif /* DEBUGABILITY */
7949 
7950 #ifdef DHD_LOG_DUMP
7951 #ifdef DHD_SSSR_DUMP
7952 #define DUMP_SSSR_DUMP_MAX_COUNT	8
wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff * skb,struct net_device * ndev)7953 static int wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff *skb,
7954 		struct net_device *ndev)
7955 {
7956 	int ret = BCME_OK;
7957 #ifdef DHD_SSSR_DUMP
7958 	uint32 arr_len[DUMP_SSSR_DUMP_MAX_COUNT];
7959 #endif /* DHD_SSSR_DUMP */
7960 	char memdump_path[MEMDUMP_PATH_LEN];
7961 	dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
7962 
7963 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7964 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
7965 		"sssr_dump_core_0_before_SR");
7966 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP, memdump_path);
7967 	if (unlikely(ret)) {
7968 		WL_ERR(("Failed to nla put sssr core 0 before dump path, ret=%d\n", ret));
7969 		goto exit;
7970 	}
7971 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7972 
7973 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
7974 		"sssr_dump_core_0_after_SR");
7975 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP, memdump_path);
7976 	if (unlikely(ret)) {
7977 		WL_ERR(("Failed to nla put sssr core 1 after dump path, ret=%d\n", ret));
7978 		goto exit;
7979 	}
7980 
7981 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7982 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
7983 		"sssr_dump_core_1_before_SR");
7984 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP, memdump_path);
7985 	if (unlikely(ret)) {
7986 		WL_ERR(("Failed to nla put sssr core 1 before dump path, ret=%d\n", ret));
7987 		goto exit;
7988 	}
7989 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7990 
7991 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
7992 		"sssr_dump_core_1_after_SR");
7993 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP, memdump_path);
7994 	if (unlikely(ret)) {
7995 		WL_ERR(("Failed to nla put sssr core 1 after dump path, ret=%d\n", ret));
7996 		goto exit;
7997 	}
7998 
7999 	if (dhdp->sssr_d11_outofreset[2]) {
8000 #ifdef DHD_SSSR_DUMP_BEFORE_SR
8001 		dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
8002 			"sssr_dump_core_2_before_SR");
8003 		ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP,
8004 			memdump_path);
8005 		if (unlikely(ret)) {
8006 			WL_ERR(("Failed to nla put sssr core 2 before dump path, ret=%d\n",
8007 				ret));
8008 			goto exit;
8009 		}
8010 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
8011 
8012 		dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
8013 			"sssr_dump_core_2_after_SR");
8014 		ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP,
8015 			memdump_path);
8016 		if (unlikely(ret)) {
8017 			WL_ERR(("Failed to nla put sssr core 2 after dump path, ret=%d\n",
8018 				ret));
8019 			goto exit;
8020 		}
8021 	}
8022 
8023 #ifdef DHD_SSSR_DUMP_BEFORE_SR
8024 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
8025 		"sssr_dump_dig_before_SR");
8026 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP, memdump_path);
8027 	if (unlikely(ret)) {
8028 		WL_ERR(("Failed to nla put sssr dig before dump path, ret=%d\n", ret));
8029 		goto exit;
8030 	}
8031 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
8032 
8033 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
8034 		"sssr_dump_dig_after_SR");
8035 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP, memdump_path);
8036 	if (unlikely(ret)) {
8037 		WL_ERR(("Failed to nla put sssr dig after dump path, ret=%d\n", ret));
8038 		goto exit;
8039 	}
8040 
8041 #ifdef DHD_SSSR_DUMP
8042 	memset(arr_len, 0, sizeof(arr_len));
8043 	dhd_nla_put_sssr_dump_len(ndev, arr_len);
8044 #ifdef DHD_SSSR_DUMP_BEFORE_SR
8045 	ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C0_D11_BEFORE, arr_len[0]);
8046 	ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C1_D11_BEFORE, arr_len[2]);
8047 	ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C2_D11_BEFORE, arr_len[4]);
8048 	ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_DIG_BEFORE, arr_len[6]);
8049 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
8050 	ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C0_D11_AFTER, arr_len[1]);
8051 	ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C1_D11_AFTER, arr_len[3]);
8052 	ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C2_D11_AFTER, arr_len[5]);
8053 	ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_DIG_AFTER, arr_len[7]);
8054 	if (unlikely(ret)) {
8055 		WL_ERR(("Failed to nla put sssr dump len, ret=%d\n", ret));
8056 		goto exit;
8057 	}
8058 #endif /* DHD_SSSR_DUMP */
8059 
8060 exit:
8061 	return ret;
8062 }
8063 #else
wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff * skb,struct net_device * ndev)8064 static int wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff *skb,
8065 		struct net_device *ndev)
8066 {
8067 	return BCME_OK;
8068 }
8069 #endif /* DHD_SSSR_DUMP */
8070 
wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff * skb,struct net_device * ndev)8071 static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb,
8072 		struct net_device *ndev)
8073 {
8074 	int ret = BCME_OK;
8075 	uint32 len = 0;
8076 	char dump_path[128];
8077 
8078 	ret = dhd_get_debug_dump_file_name(ndev, NULL, dump_path, sizeof(dump_path));
8079 	if (ret < 0) {
8080 		WL_ERR(("%s: Failed to get debug dump filename\n", __FUNCTION__));
8081 		goto exit;
8082 	}
8083 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_DEBUG_DUMP, dump_path);
8084 	if (unlikely(ret)) {
8085 		WL_ERR(("Failed to nla put debug dump path, ret=%d\n", ret));
8086 		goto exit;
8087 	}
8088 	WL_ERR(("debug_dump path = %s%s\n", dump_path, FILE_NAME_HAL_TAG));
8089 	wl_print_verinfo(wl_get_cfg(ndev));
8090 
8091 	len = dhd_get_time_str_len();
8092 	if (len) {
8093 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_TIMESTAMP, len);
8094 		if (unlikely(ret)) {
8095 			WL_ERR(("Failed to nla put time stamp length, ret=%d\n", ret));
8096 			goto exit;
8097 		}
8098 	}
8099 
8100 	len = dhd_get_dld_len(DLD_BUF_TYPE_GENERAL);
8101 	if (len) {
8102 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_GENERAL_LOG, len);
8103 		if (unlikely(ret)) {
8104 			WL_ERR(("Failed to nla put general log length, ret=%d\n", ret));
8105 			goto exit;
8106 		}
8107 	}
8108 #ifdef EWP_ECNTRS_LOGGING
8109 	len = dhd_get_ecntrs_len(ndev, NULL);
8110 	if (len) {
8111 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_ECNTRS, len);
8112 		if (unlikely(ret)) {
8113 			WL_ERR(("Failed to nla put ecntrs length, ret=%d\n", ret));
8114 			goto exit;
8115 		}
8116 	}
8117 #endif /* EWP_ECNTRS_LOGGING */
8118 	len = dhd_get_dld_len(DLD_BUF_TYPE_SPECIAL);
8119 	if (len) {
8120 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_SPECIAL_LOG, len);
8121 		if (unlikely(ret)) {
8122 			WL_ERR(("Failed to nla put special log length, ret=%d\n", ret));
8123 			goto exit;
8124 		}
8125 	}
8126 	len = dhd_get_dhd_dump_len(ndev, NULL);
8127 	if (len) {
8128 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_DHD_DUMP, len);
8129 		if (unlikely(ret)) {
8130 			WL_ERR(("Failed to nla put dhd dump length, ret=%d\n", ret));
8131 			goto exit;
8132 		}
8133 	}
8134 
8135 #if defined(BCMPCIE)
8136 	len = dhd_get_ext_trap_len(ndev, NULL);
8137 	if (len) {
8138 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_EXT_TRAP, len);
8139 		if (unlikely(ret)) {
8140 			WL_ERR(("Failed to nla put ext trap length, ret=%d\n", ret));
8141 			goto exit;
8142 		}
8143 	}
8144 #endif /* BCMPCIE */
8145 
8146 #if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT)
8147 	len = dhd_get_health_chk_len(ndev, NULL);
8148 	if (len) {
8149 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_HEALTH_CHK, len);
8150 		if (unlikely(ret)) {
8151 			WL_ERR(("Failed to nla put health check length, ret=%d\n", ret));
8152 			goto exit;
8153 		}
8154 	}
8155 #endif
8156 
8157 	len = dhd_get_dld_len(DLD_BUF_TYPE_PRESERVE);
8158 	if (len) {
8159 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_PRESERVE_LOG, len);
8160 		if (unlikely(ret)) {
8161 			WL_ERR(("Failed to nla put preserve log length, ret=%d\n", ret));
8162 			goto exit;
8163 		}
8164 	}
8165 
8166 	len = dhd_get_cookie_log_len(ndev, NULL);
8167 	if (len) {
8168 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_COOKIE, len);
8169 		if (unlikely(ret)) {
8170 			WL_ERR(("Failed to nla put cookie length, ret=%d\n", ret));
8171 			goto exit;
8172 		}
8173 	}
8174 #ifdef DHD_DUMP_PCIE_RINGS
8175 	len = dhd_get_flowring_len(ndev, NULL);
8176 	if (len) {
8177 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_FLOWRING_DUMP, len);
8178 		if (unlikely(ret)) {
8179 			WL_ERR(("Failed to nla put flowring dump length, ret=%d\n", ret));
8180 			goto exit;
8181 		}
8182 	}
8183 #endif
8184 #ifdef DHD_STATUS_LOGGING
8185 	len = dhd_get_status_log_len(ndev, NULL);
8186 	if (len) {
8187 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_STATUS_LOG, len);
8188 		if (unlikely(ret)) {
8189 			WL_ERR(("Failed to nla put status log length, ret=%d\n", ret));
8190 			goto exit;
8191 		}
8192 	}
8193 #endif /* DHD_STATUS_LOGGING */
8194 #ifdef EWP_RTT_LOGGING
8195 	len = dhd_get_rtt_len(ndev, NULL);
8196 	if (len) {
8197 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_RTT_LOG, len);
8198 		if (unlikely(ret)) {
8199 			WL_ERR(("Failed to nla put rtt log length, ret=%d\n", ret));
8200 			goto exit;
8201 		}
8202 	}
8203 #endif /* EWP_RTT_LOGGING */
8204 exit:
8205 	return ret;
8206 }
8207 #ifdef DNGL_AXI_ERROR_LOGGING
wl_cfgvendor_nla_put_axi_error_data(struct sk_buff * skb,struct net_device * ndev)8208 static void wl_cfgvendor_nla_put_axi_error_data(struct sk_buff *skb,
8209 		struct net_device *ndev)
8210 {
8211 	int ret = 0;
8212 	char axierrordump_path[MEMDUMP_PATH_LEN];
8213 	int dumpsize = dhd_os_get_axi_error_dump_size(ndev);
8214 	if (dumpsize <= 0) {
8215 		WL_ERR(("Failed to calcuate axi error dump len\n"));
8216 		return;
8217 	}
8218 	dhd_os_get_axi_error_filename(ndev, axierrordump_path, MEMDUMP_PATH_LEN);
8219 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_AXI_ERROR_DUMP, axierrordump_path);
8220 	if (ret) {
8221 		WL_ERR(("Failed to put filename\n"));
8222 		return;
8223 	}
8224 	ret = nla_put_u32(skb, DUMP_LEN_ATTR_AXI_ERROR, dumpsize);
8225 	if (ret) {
8226 		WL_ERR(("Failed to put filesize\n"));
8227 		return;
8228 	}
8229 }
8230 #endif /* DNGL_AXI_ERROR_LOGGING */
8231 #ifdef DHD_PKT_LOGGING
wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff * skb,struct net_device * ndev,bool pktlogdbg)8232 static int wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff *skb,
8233 		struct net_device *ndev, bool pktlogdbg)
8234 {
8235 	int ret = BCME_OK;
8236 	char pktlogdump_path[MEMDUMP_PATH_LEN];
8237 	uint32 pktlog_dumpsize = dhd_os_get_pktlog_dump_size(ndev);
8238 	if (pktlog_dumpsize == 0) {
8239 		WL_ERR(("Failed to calcuate pktlog len\n"));
8240 		return BCME_ERROR;
8241 	}
8242 
8243 	dhd_os_get_pktlogdump_filename(ndev, pktlogdump_path, MEMDUMP_PATH_LEN);
8244 
8245 	if (pktlogdbg) {
8246 		ret = nla_put_string(skb, DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP, pktlogdump_path);
8247 		if (ret) {
8248 			WL_ERR(("Failed to put filename\n"));
8249 			return ret;
8250 		}
8251 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_PKTLOG_DEBUG, pktlog_dumpsize);
8252 		if (ret) {
8253 			WL_ERR(("Failed to put filesize\n"));
8254 			return ret;
8255 		}
8256 	} else {
8257 		ret = nla_put_string(skb, DUMP_FILENAME_ATTR_PKTLOG_DUMP, pktlogdump_path);
8258 		if (ret) {
8259 			WL_ERR(("Failed to put filename\n"));
8260 			return ret;
8261 		}
8262 		ret = nla_put_u32(skb, DUMP_LEN_ATTR_PKTLOG, pktlog_dumpsize);
8263 		if (ret) {
8264 			WL_ERR(("Failed to put filesize\n"));
8265 			return ret;
8266 		}
8267 	}
8268 	return ret;
8269 }
8270 #endif /* DHD_PKT_LOGGING */
8271 
wl_cfgvendor_nla_put_memdump_data(struct sk_buff * skb,struct net_device * ndev,const uint32 fw_len)8272 static int wl_cfgvendor_nla_put_memdump_data(struct sk_buff *skb,
8273 		struct net_device *ndev, const uint32 fw_len)
8274 {
8275 	char memdump_path[MEMDUMP_PATH_LEN];
8276 	int ret = BCME_OK;
8277 
8278 	dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN, "mem_dump");
8279 	ret = nla_put_string(skb, DUMP_FILENAME_ATTR_MEM_DUMP, memdump_path);
8280 	if (unlikely(ret)) {
8281 		WL_ERR(("Failed to nla put mem dump path, ret=%d\n", ret));
8282 		goto exit;
8283 	}
8284 	ret = nla_put_u32(skb, DUMP_LEN_ATTR_MEMDUMP, fw_len);
8285 	if (unlikely(ret)) {
8286 		WL_ERR(("Failed to nla put mem dump length, ret=%d\n", ret));
8287 		goto exit;
8288 	}
8289 
8290 exit:
8291 	return ret;
8292 }
8293 
wl_cfgvendor_nla_put_dump_data(dhd_pub_t * dhd_pub,struct sk_buff * skb,struct net_device * ndev,const uint32 fw_len)8294 static int wl_cfgvendor_nla_put_dump_data(dhd_pub_t *dhd_pub, struct sk_buff *skb,
8295 		struct net_device *ndev, const uint32 fw_len)
8296 {
8297 	int ret = BCME_OK;
8298 
8299 #ifdef DNGL_AXI_ERROR_LOGGING
8300 	if (dhd_pub->smmu_fault_occurred) {
8301 		wl_cfgvendor_nla_put_axi_error_data(skb, ndev);
8302 	}
8303 #endif /* DNGL_AXI_ERROR_LOGGING */
8304 	if (dhd_pub->memdump_enabled || (dhd_pub->memdump_type == DUMP_TYPE_BY_SYSDUMP)) {
8305 		if (((ret = wl_cfgvendor_nla_put_debug_dump_data(skb, ndev)) < 0) ||
8306 			((ret = wl_cfgvendor_nla_put_memdump_data(skb, ndev, fw_len)) < 0) ||
8307 			((ret = wl_cfgvendor_nla_put_sssr_dump_data(skb, ndev)) < 0)) {
8308 			goto done;
8309 		}
8310 #ifdef DHD_PKT_LOGGING
8311 		if ((ret = wl_cfgvendor_nla_put_pktlogdump_data(skb, ndev, FALSE)) < 0) {
8312 			goto done;
8313 		}
8314 #endif /* DHD_PKT_LOGGING */
8315 	}
8316 done:
8317 	return ret;
8318 }
8319 
wl_cfgvendor_dbg_send_file_dump_evt(void * ctx,const void * data,const uint32 len,const uint32 fw_len)8320 static void wl_cfgvendor_dbg_send_file_dump_evt(void *ctx, const void *data,
8321 	const uint32 len, const uint32 fw_len)
8322 {
8323 	struct net_device *ndev = ctx;
8324 	struct wiphy *wiphy;
8325 	gfp_t kflags;
8326 	struct sk_buff *skb = NULL;
8327 	struct bcm_cfg80211 *cfg;
8328 	dhd_pub_t *dhd_pub;
8329 	int ret = BCME_OK;
8330 
8331 	if (!ndev) {
8332 		WL_ERR(("ndev is NULL\n"));
8333 		return;
8334 	}
8335 
8336 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
8337 	wiphy = ndev->ieee80211_ptr->wiphy;
8338 	/* Alloc the SKB for vendor_event */
8339 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
8340 		LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
8341 	skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + CFG80211_VENDOR_EVT_SKB_SZ,
8342 			GOOGLE_FILE_DUMP_EVENT, kflags);
8343 #else
8344 	skb = cfg80211_vendor_event_alloc(wiphy, len + CFG80211_VENDOR_EVT_SKB_SZ,
8345 			GOOGLE_FILE_DUMP_EVENT, kflags);
8346 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
8347 		/* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
8348 	if (!skb) {
8349 		WL_ERR(("skb alloc failed"));
8350 		return;
8351 	}
8352 
8353 	cfg = wiphy_priv(wiphy);
8354 	dhd_pub = cfg->pub;
8355 
8356 #ifdef DHD_PKT_LOGGING
8357 	if (dhd_pub->pktlog_debug) {
8358 		if ((ret = wl_cfgvendor_nla_put_pktlogdump_data(skb, ndev, TRUE)) < 0) {
8359 			WL_ERR(("nla put failed\n"));
8360 			goto done;
8361 		}
8362 		dhd_pub->pktlog_debug = FALSE;
8363 	} else
8364 #endif /* DHD_PKT_LOGGING */
8365 	{
8366 		if ((ret = wl_cfgvendor_nla_put_dump_data(dhd_pub, skb, ndev, fw_len)) < 0) {
8367 			WL_ERR(("nla put failed\n"));
8368 			goto done;
8369 		}
8370 	}
8371 	/* TODO : Similar to above function add for debug_dump, sssr_dump, and pktlog also. */
8372 	cfg80211_vendor_event(skb, kflags);
8373 	return;
8374 done:
8375 	if (skb) {
8376 		dev_kfree_skb_any(skb);
8377 	}
8378 }
8379 #endif /* DHD_LOG_DUMP */
8380 
wl_cfgvendor_dbg_get_version(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8381 static int wl_cfgvendor_dbg_get_version(struct wiphy *wiphy,
8382 	struct wireless_dev *wdev, const void *data, int len)
8383 {
8384 	int ret = BCME_OK, rem, type;
8385 	int buf_len = 1024;
8386 	bool dhd_ver = FALSE;
8387 	char *buf_ptr, *ver, *p;
8388 	const struct nlattr *iter;
8389 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8390 
8391 	buf_ptr = (char *)MALLOCZ(cfg->osh, buf_len);
8392 	if (!buf_ptr) {
8393 		WL_ERR(("failed to allocate the buffer for version n"));
8394 		ret = BCME_NOMEM;
8395 		goto exit;
8396 	}
8397 	nla_for_each_attr(iter, data, len, rem) {
8398 		type = nla_type(iter);
8399 		switch (type) {
8400 			case DEBUG_ATTRIBUTE_GET_DRIVER:
8401 				dhd_ver = TRUE;
8402 				break;
8403 			case DEBUG_ATTRIBUTE_GET_FW:
8404 				dhd_ver = FALSE;
8405 				break;
8406 			default:
8407 				WL_ERR(("Unknown type: %d\n", type));
8408 				ret = BCME_ERROR;
8409 				goto exit;
8410 		}
8411 	}
8412 	ret = dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg), dhd_ver, &buf_ptr, buf_len);
8413 	if (ret < 0) {
8414 		WL_ERR(("failed to get the version %d\n", ret));
8415 		goto exit;
8416 	}
8417 	ver = strstr(buf_ptr, "version ");
8418 	if (!ver) {
8419 		WL_ERR(("failed to locate the version\n"));
8420 		goto exit;
8421 	}
8422 	ver += strlen("version ");
8423 	/* Adjust version format to fit in android sys property */
8424 	for (p = ver; (*p != ' ') && (*p != '\n') && (*p != 0); p++) {
8425 		;
8426 	}
8427 	ret = wl_cfgvendor_send_cmd_reply(wiphy, ver, p - ver);
8428 exit:
8429 	MFREE(cfg->osh, buf_ptr, buf_len);
8430 	return ret;
8431 }
8432 
8433 #ifdef DBG_PKT_MON
wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8434 static int wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy *wiphy,
8435 	struct wireless_dev *wdev, const void *data, int len)
8436 {
8437 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8438 	dhd_pub_t *dhd_pub = cfg->pub;
8439 	int ret;
8440 
8441 	ret = dhd_os_dbg_attach_pkt_monitor(dhd_pub);
8442 	if (unlikely(ret)) {
8443 		WL_ERR(("failed to start pkt fate monitoring, ret=%d", ret));
8444 	}
8445 
8446 	return ret;
8447 }
8448 
8449 typedef int (*dbg_mon_get_pkts_t) (dhd_pub_t *dhdp, void __user *user_buf,
8450 	uint16 req_count, uint16 *resp_count);
8451 
__wl_cfgvendor_dbg_get_pkt_fates(struct wiphy * wiphy,const void * data,int len,dbg_mon_get_pkts_t dbg_mon_get_pkts)8452 static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy *wiphy,
8453 	const void *data, int len, dbg_mon_get_pkts_t dbg_mon_get_pkts)
8454 {
8455 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8456 	dhd_pub_t *dhd_pub = cfg->pub;
8457 	struct sk_buff *skb = NULL;
8458 	const struct nlattr *iter;
8459 	void __user *user_buf = NULL;
8460 	uint16 req_count = 0, resp_count = 0;
8461 	int ret, tmp, type, mem_needed;
8462 
8463 	nla_for_each_attr(iter, data, len, tmp) {
8464 		type = nla_type(iter);
8465 		switch (type) {
8466 			case DEBUG_ATTRIBUTE_PKT_FATE_NUM:
8467 				req_count = nla_get_u32(iter);
8468 				break;
8469 			case DEBUG_ATTRIBUTE_PKT_FATE_DATA:
8470 				user_buf = (void __user *)(unsigned long) nla_get_u64(iter);
8471 				break;
8472 			default:
8473 				WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
8474 				ret = -EINVAL;
8475 				goto exit;
8476 		}
8477 	}
8478 
8479 	if (!req_count || !user_buf) {
8480 		WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n",
8481 			__FUNCTION__, user_buf, req_count));
8482 		ret = -EINVAL;
8483 		goto exit;
8484 	}
8485 
8486 	ret = dbg_mon_get_pkts(dhd_pub, user_buf, req_count, &resp_count);
8487 	if (unlikely(ret)) {
8488 		WL_ERR(("failed to get packets, ret:%d \n", ret));
8489 		goto exit;
8490 	}
8491 
8492 	mem_needed = VENDOR_REPLY_OVERHEAD + ATTRIBUTE_U32_LEN;
8493 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
8494 	if (unlikely(!skb)) {
8495 		WL_ERR(("skb alloc failed"));
8496 		ret = -ENOMEM;
8497 		goto exit;
8498 	}
8499 
8500 	ret = nla_put_u32(skb, DEBUG_ATTRIBUTE_PKT_FATE_NUM, resp_count);
8501 	if (ret < 0) {
8502 		WL_ERR(("Failed to put DEBUG_ATTRIBUTE_PKT_FATE_NUM, ret:%d\n", ret));
8503 		goto exit;
8504 	}
8505 
8506 	ret = cfg80211_vendor_cmd_reply(skb);
8507 	if (unlikely(ret)) {
8508 		WL_ERR(("vendor Command reply failed ret:%d \n", ret));
8509 	}
8510 	return ret;
8511 
8512 exit:
8513 	/* Free skb memory */
8514 	if (skb) {
8515 		kfree_skb(skb);
8516 	}
8517 	return ret;
8518 }
8519 
wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8520 static int wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy *wiphy,
8521 	struct wireless_dev *wdev, const void  *data, int len)
8522 {
8523 	int ret;
8524 
8525 	ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
8526 			dhd_os_dbg_monitor_get_tx_pkts);
8527 	if (unlikely(ret)) {
8528 		WL_ERR(("failed to get tx packets, ret:%d \n", ret));
8529 	}
8530 
8531 	return ret;
8532 }
8533 
wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8534 static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy *wiphy,
8535 	struct wireless_dev *wdev, const void  *data, int len)
8536 {
8537 	int ret;
8538 
8539 	ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
8540 			dhd_os_dbg_monitor_get_rx_pkts);
8541 	if (unlikely(ret)) {
8542 		WL_ERR(("failed to get rx packets, ret:%d \n", ret));
8543 	}
8544 
8545 	return ret;
8546 }
8547 #endif /* DBG_PKT_MON */
8548 
8549 #ifdef KEEP_ALIVE
8550 /* max size of IP packet for keep alive */
8551 #define MKEEP_ALIVE_IP_PKT_MAX 256
8552 
wl_cfgvendor_start_mkeep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8553 static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
8554 	const void *data, int len)
8555 {
8556 	int ret = BCME_OK, rem, type;
8557 	uint8 mkeep_alive_id = 0;
8558 	uint8 *ip_pkt = NULL;
8559 	uint16 ip_pkt_len = 0;
8560 	uint16 ether_type = ETHERTYPE_IP;
8561 	uint8 src_mac[ETHER_ADDR_LEN];
8562 	uint8 dst_mac[ETHER_ADDR_LEN];
8563 	uint32 period_msec = 0;
8564 	const struct nlattr *iter;
8565 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8566 
8567 	nla_for_each_attr(iter, data, len, rem) {
8568 		type = nla_type(iter);
8569 		switch (type) {
8570 			case MKEEP_ALIVE_ATTRIBUTE_ID:
8571 				mkeep_alive_id = nla_get_u8(iter);
8572 				break;
8573 			case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
8574 				ip_pkt_len = nla_get_u16(iter);
8575 				if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
8576 					ret = BCME_BADARG;
8577 					goto exit;
8578 				}
8579 				break;
8580 			case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
8581 				if (ip_pkt) {
8582 					ret = BCME_BADARG;
8583 					WL_ERR(("ip_pkt already allocated\n"));
8584 					goto exit;
8585 				}
8586 				if (!ip_pkt_len) {
8587 					ret = BCME_BADARG;
8588 					WL_ERR(("ip packet length is 0\n"));
8589 					goto exit;
8590 				}
8591 				ip_pkt = (u8 *)MALLOCZ(cfg->osh, ip_pkt_len);
8592 				if (ip_pkt == NULL) {
8593 					ret = BCME_NOMEM;
8594 					WL_ERR(("Failed to allocate mem for ip packet\n"));
8595 					goto exit;
8596 				}
8597 				memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len);
8598 				break;
8599 			case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
8600 				memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN);
8601 				break;
8602 			case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
8603 				memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN);
8604 				break;
8605 			case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
8606 				period_msec = nla_get_u32(iter);
8607 				break;
8608 			case MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE:
8609 				ether_type = nla_get_u16(iter);
8610 				if (!((ether_type == ETHERTYPE_IP) ||
8611 						(ether_type == ETHERTYPE_IPV6))) {
8612 					WL_ERR(("Invalid ether type, %2x\n", ether_type));
8613 					ret = BCME_BADARG;
8614 					goto exit;
8615 				}
8616 				break;
8617 			default:
8618 				WL_ERR(("Unknown type: %d\n", type));
8619 				ret = BCME_BADARG;
8620 				goto exit;
8621 		}
8622 	}
8623 
8624 	if (ip_pkt == NULL) {
8625 		ret = BCME_BADARG;
8626 		WL_ERR(("ip packet is NULL\n"));
8627 		goto exit;
8628 	}
8629 
8630 	ret = wl_cfg80211_start_mkeep_alive(cfg, mkeep_alive_id,
8631 		ether_type, ip_pkt, ip_pkt_len, src_mac, dst_mac, period_msec);
8632 	if (ret < 0) {
8633 		WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret));
8634 	}
8635 
8636 exit:
8637 	if (ip_pkt) {
8638 		MFREE(cfg->osh, ip_pkt, ip_pkt_len);
8639 	}
8640 
8641 	return ret;
8642 }
8643 
wl_cfgvendor_stop_mkeep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8644 static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
8645 	const void *data, int len)
8646 {
8647 	int ret = BCME_OK, rem, type;
8648 	uint8 mkeep_alive_id = 0;
8649 	const struct nlattr *iter;
8650 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8651 
8652 	nla_for_each_attr(iter, data, len, rem) {
8653 		type = nla_type(iter);
8654 		switch (type) {
8655 			case MKEEP_ALIVE_ATTRIBUTE_ID:
8656 				mkeep_alive_id = nla_get_u8(iter);
8657 				break;
8658 			default:
8659 				WL_ERR(("Unknown type: %d\n", type));
8660 				ret = BCME_BADARG;
8661 				break;
8662 		}
8663 	}
8664 
8665 	ret = wl_cfg80211_stop_mkeep_alive(cfg, mkeep_alive_id);
8666 	if (ret < 0) {
8667 		WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret));
8668 	}
8669 
8670 	return ret;
8671 }
8672 #endif /* KEEP_ALIVE */
8673 
8674 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
8675 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
8676 const struct nla_policy apf_atrribute_policy[APF_ATTRIBUTE_MAX] = {
8677 	[APF_ATTRIBUTE_VERSION] = { .type = NLA_U32 },
8678 	[APF_ATTRIBUTE_MAX_LEN] = { .type = NLA_U32 },
8679 	[APF_ATTRIBUTE_PROGRAM] = { .type = NLA_BINARY },
8680 	[APF_ATTRIBUTE_PROGRAM_LEN] = { .type = NLA_U32 },
8681 };
8682 #endif /* LINUX_VERSION >= 5.3 */
8683 
8684 static int
wl_cfgvendor_apf_get_capabilities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8685 wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy,
8686 	struct wireless_dev *wdev, const void *data, int len)
8687 {
8688 	struct net_device *ndev = wdev_to_ndev(wdev);
8689 	struct sk_buff *skb = NULL;
8690 	int ret, ver, max_len, mem_needed;
8691 
8692 	/* APF version */
8693 	ver = 0;
8694 	ret = dhd_dev_apf_get_version(ndev, &ver);
8695 	if (unlikely(ret)) {
8696 		WL_ERR(("APF get version failed, ret=%d\n", ret));
8697 		return ret;
8698 	}
8699 
8700 	/* APF memory size limit */
8701 	max_len = 0;
8702 	ret = dhd_dev_apf_get_max_len(ndev, &max_len);
8703 	if (unlikely(ret)) {
8704 		WL_ERR(("APF get maximum length failed, ret=%d\n", ret));
8705 		return ret;
8706 	}
8707 
8708 	mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
8709 
8710 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
8711 	if (unlikely(!skb)) {
8712 		WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
8713 		return -ENOMEM;
8714 	}
8715 
8716 	ret = nla_put_u32(skb, APF_ATTRIBUTE_VERSION, ver);
8717 	if (ret < 0) {
8718 		WL_ERR(("Failed to put APF_ATTRIBUTE_VERSION, ret:%d\n", ret));
8719 		goto exit;
8720 	}
8721 	ret = nla_put_u32(skb, APF_ATTRIBUTE_MAX_LEN, max_len);
8722 	if (ret < 0) {
8723 		WL_ERR(("Failed to put APF_ATTRIBUTE_MAX_LEN, ret:%d\n", ret));
8724 		goto exit;
8725 	}
8726 
8727 	ret = cfg80211_vendor_cmd_reply(skb);
8728 	if (unlikely(ret)) {
8729 		WL_ERR(("vendor command reply failed, ret=%d\n", ret));
8730 	}
8731 	return ret;
8732 exit:
8733 	/* Free skb memory */
8734 	kfree_skb(skb);
8735 	return ret;
8736 }
8737 
8738 static int
wl_cfgvendor_apf_set_filter(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8739 wl_cfgvendor_apf_set_filter(struct wiphy *wiphy,
8740 	struct wireless_dev *wdev, const void  *data, int len)
8741 {
8742 	struct net_device *ndev = wdev_to_ndev(wdev);
8743 	const struct nlattr *iter;
8744 	u8 *program = NULL;
8745 	u32 program_len = 0;
8746 	int ret, tmp, type;
8747 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8748 
8749 	if (len <= 0) {
8750 		WL_ERR(("Invalid len: %d\n", len));
8751 		ret = -EINVAL;
8752 		goto exit;
8753 	}
8754 	nla_for_each_attr(iter, data, len, tmp) {
8755 		type = nla_type(iter);
8756 		switch (type) {
8757 			case APF_ATTRIBUTE_PROGRAM_LEN:
8758 				/* check if the iter value is valid and program_len
8759 				 * is not already initialized.
8760 				 */
8761 				if (nla_len(iter) == sizeof(uint32) && !program_len) {
8762 					program_len = nla_get_u32(iter);
8763 				} else {
8764 					ret = -EINVAL;
8765 					goto exit;
8766 				}
8767 
8768 				if (program_len > WL_APF_PROGRAM_MAX_SIZE) {
8769 					WL_ERR(("program len is more than expected len\n"));
8770 					ret = -EINVAL;
8771 					goto exit;
8772 				}
8773 
8774 				if (unlikely(!program_len)) {
8775 					WL_ERR(("zero program length\n"));
8776 					ret = -EINVAL;
8777 					goto exit;
8778 				}
8779 				break;
8780 			case APF_ATTRIBUTE_PROGRAM:
8781 				if (unlikely(program)) {
8782 					WL_ERR(("program already allocated\n"));
8783 					ret = -EINVAL;
8784 					goto exit;
8785 				}
8786 				if (unlikely(!program_len)) {
8787 					WL_ERR(("program len is not set\n"));
8788 					ret = -EINVAL;
8789 					goto exit;
8790 				}
8791 				if (nla_len(iter) != program_len) {
8792 					WL_ERR(("program_len is not same\n"));
8793 					ret = -EINVAL;
8794 					goto exit;
8795 				}
8796 				program = MALLOCZ(cfg->osh, program_len);
8797 				if (unlikely(!program)) {
8798 					WL_ERR(("%s: can't allocate %d bytes\n",
8799 					      __FUNCTION__, program_len));
8800 					ret = -ENOMEM;
8801 					goto exit;
8802 				}
8803 				memcpy(program, (u8*)nla_data(iter), program_len);
8804 				break;
8805 			default:
8806 				WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
8807 				ret = -EINVAL;
8808 				goto exit;
8809 		}
8810 	}
8811 
8812 	ret = dhd_dev_apf_add_filter(ndev, program, program_len);
8813 
8814 exit:
8815 	if (program) {
8816 		MFREE(cfg->osh, program, program_len);
8817 	}
8818 	return ret;
8819 }
8820 #endif /* PKT_FILTER_SUPPORT && APF */
8821 
8822 #ifdef NDO_CONFIG_SUPPORT
wl_cfgvendor_configure_nd_offload(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8823 static int wl_cfgvendor_configure_nd_offload(struct wiphy *wiphy,
8824 	struct wireless_dev *wdev, const void  *data, int len)
8825 {
8826 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8827 	const struct nlattr *iter;
8828 	int ret = BCME_OK, rem, type;
8829 	u8 enable = 0;
8830 
8831 	nla_for_each_attr(iter, data, len, rem) {
8832 		type = nla_type(iter);
8833 		switch (type) {
8834 			case ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE:
8835 				enable = nla_get_u8(iter);
8836 				break;
8837 			default:
8838 				WL_ERR(("Unknown type: %d\n", type));
8839 				ret = BCME_BADARG;
8840 				goto exit;
8841 		}
8842 	}
8843 
8844 	ret = dhd_dev_ndo_cfg(bcmcfg_to_prmry_ndev(cfg), enable);
8845 	if (ret < 0) {
8846 		WL_ERR(("dhd_dev_ndo_cfg() failed: %d\n", ret));
8847 	}
8848 
8849 exit:
8850 	return ret;
8851 }
8852 #endif /* NDO_CONFIG_SUPPORT */
8853 
8854 #if !defined(BCMSUP_4WAY_HANDSHAKE) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
wl_cfgvendor_set_pmk(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8855 static int wl_cfgvendor_set_pmk(struct wiphy *wiphy,
8856 	struct wireless_dev *wdev, const void *data, int len)
8857 {
8858 	int ret = 0;
8859 	wsec_pmk_t pmk;
8860 	const struct nlattr *iter;
8861 	int rem, type;
8862 	struct net_device *ndev = wdev_to_ndev(wdev);
8863 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8864 	struct wl_security *sec;
8865 
8866 	bzero(&pmk, sizeof(pmk));
8867 	nla_for_each_attr(iter, data, len, rem) {
8868 		type = nla_type(iter);
8869 		switch (type) {
8870 			case BRCM_ATTR_DRIVER_KEY_PMK:
8871 				pmk.flags = 0;
8872 				pmk.key_len = htod16(nla_len(iter));
8873 				ret = memcpy_s(pmk.key, sizeof(pmk.key),
8874 					(uint8 *)nla_data(iter), nla_len(iter));
8875 				if (ret) {
8876 					WL_ERR(("Failed to copy pmk: %d\n", ret));
8877 					ret = -EINVAL;
8878 					goto exit;
8879 				}
8880 				break;
8881 			default:
8882 				WL_ERR(("Unknown type: %d\n", type));
8883 				ret = BCME_BADARG;
8884 				goto exit;
8885 		}
8886 	}
8887 
8888 	sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
8889 	if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
8890 		(sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
8891 		ret = wldev_iovar_setbuf(ndev, "okc_info_pmk", pmk.key, pmk.key_len, cfg->ioctl_buf,
8892 			WLC_IOCTL_SMLEN,  &cfg->ioctl_buf_sync);
8893 		if (ret) {
8894 			/* could fail in case that 'okc' is not supported */
8895 			WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
8896 		}
8897 	}
8898 
8899 	ret = wldev_ioctl_set(ndev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
8900 	WL_INFORM_MEM(("IOVAR set_pmk ret:%d", ret));
8901 exit:
8902 	return ret;
8903 }
8904 #endif /* !BCMSUP_4WAY_HANDSHAKE || LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
8905 
wl_cfgvendor_get_driver_feature(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8906 static int wl_cfgvendor_get_driver_feature(struct wiphy *wiphy,
8907 	struct wireless_dev *wdev, const void  *data, int len)
8908 {
8909 	int ret = BCME_OK;
8910 	u8 supported[(BRCM_WLAN_VENDOR_FEATURES_MAX / 8) + 1] = {0};
8911 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8912 	dhd_pub_t *dhd_pub = cfg->pub;
8913 	struct sk_buff *skb;
8914 	int32 mem_needed;
8915 
8916 	mem_needed = VENDOR_REPLY_OVERHEAD + NLA_HDRLEN + sizeof(supported);
8917 
8918 	BCM_REFERENCE(dhd_pub);
8919 
8920 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
8921 	if (FW_SUPPORTED(dhd_pub, idsup)) {
8922 		ret = wl_features_set(supported, sizeof(supported),
8923 				BRCM_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD);
8924 	}
8925 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
8926 
8927 	/* Alloc the SKB for vendor_event */
8928 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
8929 	if (unlikely(!skb)) {
8930 		WL_ERR(("skb alloc failed"));
8931 		ret = BCME_NOMEM;
8932 		goto exit;
8933 	}
8934 
8935 	ret = nla_put(skb, BRCM_ATTR_DRIVER_FEATURE_FLAGS, sizeof(supported), supported);
8936 	if (ret) {
8937 		kfree_skb(skb);
8938 		goto exit;
8939 	}
8940 	ret = cfg80211_vendor_cmd_reply(skb);
8941 exit:
8942 	return ret;
8943 }
8944 
8945 #ifdef WL_P2P_RAND
8946 static int
wl_cfgvendor_set_p2p_rand_mac(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8947 wl_cfgvendor_set_p2p_rand_mac(struct wiphy *wiphy,
8948 		struct wireless_dev *wdev, const void  *data, int len)
8949 {
8950 	int err = 0;
8951 	struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8952 	int type;
8953 	WL_DBG(("%s, wdev->iftype = %d\n", __FUNCTION__, wdev->iftype));
8954 	WL_INFORM_MEM(("randomized p2p_dev_addr - "MACDBG"\n", MAC2STRDBG(nla_data(data))));
8955 
8956 	BCM_REFERENCE(cfg);
8957 
8958 	type = nla_type(data);
8959 
8960 	if (type == BRCM_ATTR_DRIVER_RAND_MAC) {
8961 		if (nla_len(data) != ETHER_ADDR_LEN) {
8962 			WL_ERR(("nla_len not matched.\n"));
8963 			err = -EINVAL;
8964 			goto exit;
8965 		}
8966 
8967 		if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE) {
8968 			WL_ERR(("wrong interface type , wdev->iftype=%d\n", wdev->iftype));
8969 			err = -EINVAL;
8970 			goto exit;
8971 		}
8972 		(void)memcpy_s(wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE), ETHER_ADDR_LEN,
8973 				nla_data(data), ETHER_ADDR_LEN);
8974 		(void)memcpy_s(wdev->address, ETHER_ADDR_LEN, nla_data(data), ETHER_ADDR_LEN);
8975 
8976 		err = wl_cfgp2p_disable_discovery(cfg);
8977 		if (unlikely(err < 0)) {
8978 			WL_ERR(("P2P disable discovery failed, ret=%d\n", err));
8979 			goto exit;
8980 		}
8981 
8982 		err = wl_cfgp2p_set_firm_p2p(cfg);
8983 		if (unlikely(err < 0)) {
8984 			WL_ERR(("Set P2P address in firmware failed, ret=%d\n", err));
8985 			goto exit;
8986 		}
8987 
8988 		err = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0);
8989 		if (unlikely(err < 0)) {
8990 			WL_ERR(("P2P enable discovery failed, ret=%d\n", err));
8991 			goto exit;
8992 		}
8993 	} else {
8994 		WL_ERR(("unexpected attrib type:%d\n", type));
8995 		err = -EINVAL;
8996 	}
8997 exit:
8998 	return err;
8999 }
9000 #endif /* WL_P2P_RAND */
9001 
9002 #ifdef WL_SAR_TX_POWER
9003 static int
wl_cfgvendor_tx_power_scenario(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9004 wl_cfgvendor_tx_power_scenario(struct wiphy *wiphy,
9005 	struct wireless_dev *wdev, const void  *data, int len)
9006 {
9007 	int err = BCME_ERROR, rem, type;
9008 	struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev));
9009 	const struct nlattr *iter;
9010 	wifi_power_scenario sar_tx_power_val = WIFI_POWER_SCENARIO_INVALID;
9011 	wl_sar_modes_t wifi_tx_power_mode = 0;
9012 
9013 	nla_for_each_attr(iter, data, len, rem) {
9014 		type = nla_type(iter);
9015 		if (type == ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO) {
9016 			sar_tx_power_val = nla_get_s8(iter);
9017 		} else {
9018 			WL_ERR(("Unknown attr type: %d\n", type));
9019 			err = -EINVAL;
9020 			goto exit;
9021 		}
9022 	}
9023 	/* If sar tx power is already configured, no need to set it again */
9024 	if (cfg->wifi_tx_power_mode == sar_tx_power_val) {
9025 		WL_INFORM_MEM(("%s, tx_power_mode %d is already set\n",
9026 			__FUNCTION__, sar_tx_power_val));
9027 		err = BCME_OK;
9028 		goto exit;
9029 	}
9030 
9031 	/* Map Android TX power modes to Brcm power mode */
9032 	switch (sar_tx_power_val) {
9033 		case WIFI_POWER_SCENARIO_VOICE_CALL:
9034 		case WIFI_POWER_SCENARIO_DEFAULT:
9035 			wifi_tx_power_mode = HEAD_SAR_BACKOFF_ENABLE;
9036 			break;
9037 		case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF:
9038 			wifi_tx_power_mode = GRIP_SAR_BACKOFF_DISABLE;
9039 			break;
9040 		case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF:
9041 			wifi_tx_power_mode = GRIP_SAR_BACKOFF_ENABLE;
9042 			break;
9043 		case WIFI_POWER_SCENARIO_ON_BODY_BT:
9044 			wifi_tx_power_mode = NR_mmWave_SAR_BACKOFF_ENABLE;
9045 			break;
9046 		case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON:
9047 			wifi_tx_power_mode = NR_Sub6_SAR_BACKOFF_DISABLE;
9048 			break;
9049 		case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON:
9050 			wifi_tx_power_mode = NR_Sub6_SAR_BACKOFF_ENABLE;
9051 			break;
9052 		default:
9053 			WL_ERR(("invalid wifi tx power scenario = %d\n",
9054 				sar_tx_power_val));
9055 			err = -EINVAL;
9056 			goto exit;
9057 	}
9058 
9059 	WL_DBG(("%s, tx_power_mode %d\n", __FUNCTION__, wifi_tx_power_mode));
9060 	err = wldev_iovar_setint(wdev_to_ndev(wdev), "sar_enable", wifi_tx_power_mode);
9061 	if (unlikely(err)) {
9062 		WL_ERR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
9063 		goto exit;
9064 	}
9065 	/* Cache the tx power mode sent by the hal */
9066 	cfg->wifi_tx_power_mode = sar_tx_power_val;
9067 exit:
9068 	return err;
9069 }
9070 #endif /* WL_SAR_TX_POWER */
9071 
9072 #if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
9073 static int
wl_cfgvendor_twt_setup(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9074 wl_cfgvendor_twt_setup(struct wiphy *wiphy,
9075 	struct wireless_dev *wdev, const void  *data, int len)
9076 {
9077 	wl_twt_config_t val;
9078 	s32 bw;
9079 	s32 type, rem_attr;
9080 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
9081 	u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
9082 	const struct nlattr *iter;
9083 	uint8 *rem = mybuf;
9084 	uint16 rem_len = sizeof(mybuf);
9085 
9086 	bzero(&val, sizeof(val));
9087 	val.version = WL_TWT_SETUP_VER;
9088 	val.length = sizeof(val.version) + sizeof(val.length);
9089 
9090 	/* Default values, Override Below */
9091 	val.desc.flow_flags = 0;
9092 	val.desc.wake_time_h = 0xFFFFFFFF;
9093 	val.desc.wake_time_l = 0xFFFFFFFF;
9094 	val.desc.wake_int_min = 0xFFFFFFFF;
9095 	val.desc.wake_int_max = 0xFFFFFFFF;
9096 	val.desc.wake_dur_min = 0xFFFFFFFF;
9097 	val.desc.wake_dur_max = 0xFFFFFFFF;
9098 	val.desc.avg_pkt_num  = 0xFFFFFFFF;
9099 	val.desc.avg_pkt_size = 0xFFFFFFFF;
9100 
9101 	nla_for_each_attr(iter, data, len, rem_attr) {
9102 		type = nla_type(iter);
9103 		switch (type) {
9104 			case ANDR_TWT_ATTR_CONFIG_ID:
9105 				/* Config ID */
9106 				val.desc.configID = nla_get_u8(iter);
9107 				break;
9108 			case ANDR_TWT_ATTR_NEGOTIATION_TYPE:
9109 				/* negotiation_type */
9110 				val.desc.negotiation_type  = nla_get_u8(iter);
9111 				break;
9112 			case ANDR_TWT_ATTR_TRIGGER_TYPE:
9113 				/* Trigger Type */
9114 				if (nla_get_u8(iter) == 1) {
9115 					val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER;
9116 				}
9117 				break;
9118 			case ANDR_TWT_ATTR_WAKE_DURATION:
9119 				/* Wake Duration */
9120 				val.desc.wake_dur = nla_get_u32(iter);
9121 				break;
9122 			case ANDR_TWT_ATTR_WAKE_INTERVAL:
9123 				/* Wake interval */
9124 				val.desc.wake_int = nla_get_u32(iter);
9125 				break;
9126 			case ANDR_TWT_ATTR_WAKETIME_OFFSET:
9127 				/* Wake Time parameter */
9128 				val.desc.wake_time_h = 0;
9129 				val.desc.wake_time_l = nla_get_u32(iter);
9130 				break;
9131 			case ANDR_TWT_ATTR_WAKE_INTERVAL_MIN:
9132 				/* Minimum allowed Wake interval */
9133 				val.desc.wake_int_min = nla_get_u32(iter);
9134 				break;
9135 			case ANDR_TWT_ATTR_WAKE_INTERVAL_MAX:
9136 				/* Max Allowed Wake interval */
9137 				val.desc.wake_int_max = nla_get_u32(iter);
9138 				break;
9139 			case ANDR_TWT_ATTR_WAKE_DURATION_MIN:
9140 				/* Minimum allowed Wake duration */
9141 				val.desc.wake_dur_min = nla_get_u32(iter);
9142 				break;
9143 			case ANDR_TWT_ATTR_WAKE_DURATION_MAX:
9144 				/* Maximum allowed Wake duration */
9145 				val.desc.wake_dur_max = nla_get_u32(iter);
9146 				break;
9147 			case ANDR_TWT_ATTR_AVG_PKT_NUM:
9148 				/* Average number of packets */
9149 				val.desc.avg_pkt_num  = nla_get_u32(iter);
9150 				break;
9151 			case ANDR_TWT_ATTR_AVG_PKT_SIZE:
9152 				/* Average packets size */
9153 				val.desc.avg_pkt_size = nla_get_u32(iter);
9154 				break;
9155 			default:
9156 				WL_ERR(("Invalid setup attribute type %d\n", type));
9157 				break;
9158 		}
9159 	}
9160 
9161 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG,
9162 			sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
9163 	if (bw != BCME_OK) {
9164 		goto exit;
9165 	}
9166 
9167 	bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
9168 		mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
9169 	if (bw < 0) {
9170 		WL_ERR(("twt config set failed. ret:%d\n", bw));
9171 	} else {
9172 		WL_INFORM(("twt config setup succeeded, config ID %d "
9173 			"Negotiation type %d flow flags %d\n", val.desc.configID,
9174 			val.desc.negotiation_type, val.desc.flow_flags));
9175 	}
9176 
9177 exit:
9178 	return bw;
9179 }
9180 
9181 static int
wl_cfgvendor_twt_teardown(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9182 wl_cfgvendor_twt_teardown(struct wiphy *wiphy,
9183 	struct wireless_dev *wdev, const void  *data, int len)
9184 {
9185 	wl_twt_teardown_t val;
9186 	s32 bw;
9187 	s32 type, rem_attr;
9188 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
9189 	u8 res_buf[WLC_IOCTL_SMLEN] = {0};
9190 	const struct nlattr *iter;
9191 	uint8 *rem = mybuf;
9192 	uint16 rem_len = sizeof(mybuf);
9193 
9194 	bzero(&val, sizeof(val));
9195 	val.version = WL_TWT_TEARDOWN_VER;
9196 	val.length = sizeof(val.version) + sizeof(val.length);
9197 
9198 	/* Default values, Override Below */
9199 	val.teardesc.flow_id = 0xFF;
9200 	val.teardesc.bid = 0xFF;
9201 
9202 	nla_for_each_attr(iter, data, len, rem_attr) {
9203 		type = nla_type(iter);
9204 		switch (type) {
9205 			case ANDR_TWT_ATTR_CONFIG_ID:
9206 				/* Config ID */
9207 				val.configID = nla_get_u8(iter);
9208 				break;
9209 			case ANDR_TWT_ATTR_NEGOTIATION_TYPE:
9210 				/* negotiation_type */
9211 				val.teardesc.negotiation_type  = nla_get_u8(iter);
9212 				break;
9213 			case ANDR_TWT_ATTR_ALL_TWT:
9214 				/* all twt */
9215 				val.teardesc.alltwt = nla_get_u8(iter);
9216 				break;
9217 			default:
9218 				WL_ERR(("Invalid teardown attribute type %d\n", type));
9219 			break;
9220 		}
9221 	}
9222 
9223 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
9224 		sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
9225 	if (bw != BCME_OK) {
9226 		goto exit;
9227 	}
9228 
9229 	bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
9230 		mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
9231 	if (bw < 0) {
9232 		WL_ERR(("twt teardown failed. ret:%d\n", bw));
9233 	} else {
9234 		WL_INFORM(("twt teardown succeeded, config ID %d "
9235 			"Negotiation type %d alltwt %d\n", val.configID,
9236 			val.teardesc.negotiation_type, val.teardesc.alltwt));
9237 	}
9238 
9239 exit:
9240 	return bw;
9241 }
9242 
9243 static int
wl_cfgvendor_twt_info_frame(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9244 wl_cfgvendor_twt_info_frame(struct wiphy *wiphy,
9245 	struct wireless_dev *wdev, const void  *data, int len)
9246 {
9247 	wl_twt_info_t val;
9248 	int bw;
9249 	s32 type, rem_attr;
9250 	const struct nlattr *iter;
9251 	u8 mybuf[WLC_IOCTL_SMLEN] = {0};
9252 	u8 res_buf[WLC_IOCTL_SMLEN] = {0};
9253 	uint8 *rem = mybuf;
9254 	uint16 rem_len = sizeof(mybuf);
9255 	uint32 val32 = 0;
9256 
9257 	bzero(&val, sizeof(val));
9258 	val.version = WL_TWT_INFO_VER;
9259 	val.length = sizeof(val.version) + sizeof(val.length);
9260 
9261 	/* Default values, Override Below */
9262 	val.infodesc.flow_id = 0xFF;
9263 	val.desc.next_twt_h = 0xFFFFFFFF;
9264 	val.desc.next_twt_l = 0xFFFFFFFF;
9265 
9266 	nla_for_each_attr(iter, data, len, rem_attr) {
9267 		type = nla_type(iter);
9268 		if (type == ANDR_TWT_ATTR_CONFIG_ID) {
9269 			/* Config ID */
9270 			val.configID = nla_get_u8(iter);
9271 		} else if (type == ANDR_TWT_ATTR_RESUME_TIME) {
9272 			/* Resume offset */
9273 			val32 = nla_get_u32(iter);
9274 			if (!((val32 == 0) || (val32 == -1))) {
9275 				val.infodesc.next_twt_h = 0;
9276 				val.infodesc.next_twt_l = val32;
9277 				val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME;
9278 			}
9279 		} else if (type == ANDR_TWT_ATTR_ALL_TWT) {
9280 			/* all twt */
9281 			val32 = (uint32)nla_get_u8(iter);
9282 			if (val32) {
9283 				val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT;
9284 			}
9285 		} else {
9286 			WL_ERR(("Invalid info frame attribute type %d\n", type));
9287 		}
9288 	}
9289 
9290 	bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO,
9291 		sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
9292 	if (bw != BCME_OK) {
9293 		goto exit;
9294 	}
9295 
9296 	bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
9297 		mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
9298 	if (bw < 0) {
9299 		WL_ERR(("twt info frame failed. ret:%d\n", bw));
9300 	} else {
9301 		WL_INFORM(("twt info frame succeeded, config ID %d\n", val.configID));
9302 	}
9303 
9304 exit:
9305 	return bw;
9306 }
9307 
9308 static int
wl_cfgvendor_twt_stats_update_v2(struct wiphy * wiphy,wl_twt_stats_v2_t * stats)9309 wl_cfgvendor_twt_stats_update_v2(struct wiphy *wiphy, wl_twt_stats_v2_t *stats)
9310 {
9311 	u32 i;
9312 	wl_twt_peer_stats_v2_t *peer_stats;
9313 	struct sk_buff *skb;
9314 	int32 mem_needed;
9315 	int ret = BCME_OK;
9316 
9317 	mem_needed = BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN;
9318 
9319 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
9320 	if (unlikely(!skb)) {
9321 		WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
9322 		ret = -ENOMEM;
9323 		goto fail;
9324 	}
9325 
9326 	ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_PEER_STATS, stats->num_stats);
9327 	if (ret < 0) {
9328 		WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_PEER_STATS, ret:%d\n", ret));
9329 		goto fail;
9330 	}
9331 
9332 	for (i = 0; i < stats->num_stats; i++) {
9333 		peer_stats = &stats->peer_stats_list[i];
9334 
9335 		WL_INFORM_MEM(("%u %u %u %u %u",
9336 			peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg,
9337 			peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg));
9338 		ret = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, peer_stats->configID);
9339 		if (ret < 0) {
9340 			WL_ERR(("Failed to put ANDR_TWT_ATTR_CONFIG_ID, ret:%d\n", ret));
9341 			goto fail;
9342 		}
9343 		ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_TX, peer_stats->tx_pkts_avg);
9344 		if (ret < 0) {
9345 			WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_TX, ret:%d\n", ret));
9346 			goto fail;
9347 		}
9348 		ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, peer_stats->tx_pkt_sz_avg);
9349 		if (ret < 0) {
9350 			WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, ret:%d\n", ret));
9351 			goto fail;
9352 		}
9353 		ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_RX, peer_stats->rx_pkts_avg);
9354 		if (ret < 0) {
9355 			WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_RX, ret:%d\n", ret));
9356 			goto fail;
9357 		}
9358 		ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, peer_stats->rx_pkt_sz_avg);
9359 		if (ret < 0) {
9360 			WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, ret:%d\n", ret));
9361 			goto fail;
9362 		}
9363 		ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_EOSP_DUR, peer_stats->eosp_dur_avg);
9364 		if (ret < 0) {
9365 			WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_EOSP_DUR, ret:%d\n", ret));
9366 			goto fail;
9367 		}
9368 		ret = nla_put_u32(skb, ANDR_TWT_ATTR_EOSP_CNT, peer_stats->eosp_count);
9369 		if (ret < 0) {
9370 			WL_ERR(("Failed to put ANDR_TWT_ATTR_EOSP_CNT, ret:%d\n", ret));
9371 			goto fail;
9372 		}
9373 		ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_SP, peer_stats->sp_seq);
9374 		if (ret < 0) {
9375 			WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_SP, ret:%d\n", ret));
9376 			goto fail;
9377 		}
9378 	}
9379 
9380 	ret = cfg80211_vendor_cmd_reply(skb);
9381 	if (unlikely(ret)) {
9382 		WL_ERR(("vendor command reply failed, ret=%d\n", ret));
9383 	}
9384 	return ret;
9385 
9386 fail:
9387 	/* Free skb for failure cases */
9388 	if (skb) {
9389 		kfree_skb(skb);
9390 	}
9391 	return ret;
9392 }
9393 
9394 static int
wl_cfgvendor_twt_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len,bool clear_stats)9395 wl_cfgvendor_twt_stats(struct wiphy *wiphy,
9396 	struct wireless_dev *wdev, const void  *data, int len, bool clear_stats)
9397 {
9398 	wl_twt_stats_cmd_v1_t query;
9399 	wl_twt_stats_v2_t stats_v2;
9400 	s32 type, rem_attr;
9401 	const struct nlattr *iter;
9402 	int ret = BCME_OK;
9403 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
9404 	uint8 *pxtlv = NULL;
9405 	uint8 *iovresp = NULL;
9406 	uint16 buflen = 0, bufstart = 0;
9407 	struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev));
9408 
9409 	bzero(&query, sizeof(query));
9410 	query.version = WL_TWT_STATS_CMD_VERSION_1;
9411 	query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer);
9412 
9413 	/* Default values, Override Below */
9414 	query.num_bid = 0xFF;
9415 	query.num_fid = 0xFF;
9416 
9417 	if (clear_stats) {
9418 		query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET;
9419 	}
9420 	nla_for_each_attr(iter, data, len, rem_attr) {
9421 		type = nla_type(iter);
9422 		if (type == ANDR_TWT_ATTR_CONFIG_ID) {
9423 			/* Config ID */
9424 			query.configID = nla_get_u8(iter);
9425 		} else {
9426 			WL_ERR(("Invalid TWT stats attribute type %d\n", type));
9427 		}
9428 	}
9429 
9430 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
9431 	if (iovresp == NULL) {
9432 		WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
9433 		goto exit;
9434 	}
9435 
9436 	buflen = bufstart = WLC_IOCTL_SMLEN;
9437 	pxtlv = (uint8 *)iovbuf;
9438 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS,
9439 			sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32);
9440 	if (ret != BCME_OK) {
9441 		WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
9442 		goto exit;
9443 	}
9444 
9445 	if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen,
9446 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
9447 		WL_ERR(("twt status failed with err=%d \n", ret));
9448 		goto exit;
9449 	}
9450 
9451 	(void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2));
9452 
9453 	if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) {
9454 		if (!clear_stats) {
9455 			WL_ERR(("stats query ver %d, \n", dtoh16(stats_v2.version)));
9456 			ret = wl_cfgvendor_twt_stats_update_v2(wiphy, (wl_twt_stats_v2_t*)iovresp);
9457 		}
9458 	} else {
9459 		ret = BCME_UNSUPPORTED;
9460 		WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version)));
9461 		goto exit;
9462 	}
9463 
9464 exit:
9465 	if (iovresp) {
9466 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
9467 	}
9468 
9469 	return ret;
9470 }
9471 
9472 static int
wl_cfgvendor_twt_get_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9473 wl_cfgvendor_twt_get_stats(struct wiphy *wiphy,
9474 	struct wireless_dev *wdev, const void  *data, int len)
9475 {
9476 	return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, false);
9477 }
9478 
9479 static int
wl_cfgvendor_twt_clear_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9480 wl_cfgvendor_twt_clear_stats(struct wiphy *wiphy,
9481 	struct wireless_dev *wdev, const void  *data, int len)
9482 {
9483 	return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, true);
9484 }
9485 
9486 static int
wl_cfgvendor_twt_update_cap(struct wiphy * wiphy,wl_twt_cap_t * result)9487 wl_cfgvendor_twt_update_cap(struct wiphy *wiphy, wl_twt_cap_t *result)
9488 {
9489 	struct sk_buff *skb;
9490 	int32 mem_needed;
9491 	int ret = BCME_OK;
9492 
9493 	WL_INFORM_MEM(("TWT Capabilites Device,Peer 0x%04x 0x%04x\n",
9494 		result->device_cap, result->peer_cap));
9495 
9496 	mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
9497 
9498 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
9499 	if (unlikely(!skb)) {
9500 		WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
9501 		ret = -ENOMEM;
9502 		goto fail;
9503 	}
9504 
9505 	ret = nla_put_u32(skb, ANDR_TWT_ATTR_DEVICE_CAP, result->device_cap);
9506 	if (ret < 0) {
9507 		WL_ERR(("Failed to put ANDR_TWT_ATTR_DEVICE_CAP, ret:%d\n", ret));
9508 		goto fail;
9509 	}
9510 	ret = nla_put_u32(skb, ANDR_TWT_ATTR_PEER_CAP, result->peer_cap);
9511 	if (ret < 0) {
9512 		WL_ERR(("Failed to put ANDR_TWT_ATTR_PEER_CAP, ret:%d\n", ret));
9513 		goto fail;
9514 	}
9515 
9516 	ret = cfg80211_vendor_cmd_reply(skb);
9517 	if (unlikely(ret)) {
9518 		WL_ERR(("vendor command reply failed, ret=%d\n", ret));
9519 	}
9520 	return ret;
9521 
9522 fail:
9523 	/* Free skb for failure cases */
9524 	if (skb) {
9525 		kfree_skb(skb);
9526 	}
9527 	return ret;
9528 }
9529 
9530 static int
wl_cfgvendor_twt_cap(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9531 wl_cfgvendor_twt_cap(struct wiphy *wiphy,
9532 	struct wireless_dev *wdev, const void  *data, int len)
9533 {
9534 	int ret = BCME_OK;
9535 	char iovbuf[WLC_IOCTL_SMLEN] = {0, };
9536 	uint8 *pxtlv = NULL;
9537 	uint8 *iovresp = NULL;
9538 	wl_twt_cap_cmd_t cmd_cap;
9539 	wl_twt_cap_t result;
9540 
9541 	uint16 buflen = 0, bufstart = 0;
9542 	struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev));
9543 
9544 	bzero(&cmd_cap, sizeof(cmd_cap));
9545 
9546 	cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
9547 	cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
9548 
9549 	iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
9550 	if (iovresp == NULL) {
9551 		WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
9552 		goto exit;
9553 	}
9554 
9555 	buflen = bufstart = WLC_IOCTL_SMLEN;
9556 	pxtlv = (uint8 *)iovbuf;
9557 
9558 	ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
9559 			sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
9560 	if (ret != BCME_OK) {
9561 		WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
9562 		goto exit;
9563 	}
9564 
9565 	if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen,
9566 		iovresp, WLC_IOCTL_MEDLEN, NULL))) {
9567 		WL_ERR(("Getting twt status failed with err=%d \n", ret));
9568 		goto exit;
9569 	}
9570 
9571 	(void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
9572 
9573 	if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
9574 		WL_ERR(("capability ver %d, \n", dtoh16(result.version)));
9575 		ret = wl_cfgvendor_twt_update_cap(wiphy, &result);
9576 		return ret;
9577 	} else {
9578 		ret = BCME_UNSUPPORTED;
9579 		WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
9580 		goto exit;
9581 	}
9582 
9583 exit:
9584 	if (iovresp) {
9585 		MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
9586 	}
9587 
9588 	return ret;
9589 }
9590 
9591 static int
wl_cfgvendor_twt_update_setup_response(struct sk_buff * skb,void * event_data)9592 wl_cfgvendor_twt_update_setup_response(struct sk_buff *skb, void *event_data)
9593 {
9594 	s32 err = BCME_OK;
9595 	const wl_twt_setup_cplt_t *setup_cplt = (wl_twt_setup_cplt_t *)event_data;
9596 	const wl_twt_sdesc_t *sdesc = (const wl_twt_sdesc_t *)&setup_cplt[1];
9597 
9598 	WL_DBG(("TWT_SETUP: status %d, reason %d, configID %d, setup_cmd %d, flow_flags 0x%x,"
9599 		" flow_id %d, channel %d, negotiation_type %d, wake_time_h %u, wake_time_l %u,"
9600 		" wake_dur %u, wake_int %u\n",
9601 		(int)setup_cplt->status, (int)setup_cplt->reason_code, (int)setup_cplt->configID,
9602 		(int)sdesc->setup_cmd, sdesc->flow_flags, (int)sdesc->flow_id, (int)sdesc->channel,
9603 		(int)sdesc->negotiation_type, sdesc->wake_time_h, sdesc->wake_time_l,
9604 		sdesc->wake_dur, sdesc->wake_int));
9605 
9606 	err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_SETUP);
9607 	if (unlikely(err)) {
9608 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
9609 		goto fail;
9610 	}
9611 	err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, setup_cplt->configID);
9612 	if (unlikely(err)) {
9613 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n"));
9614 		goto fail;
9615 	}
9616 	err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, setup_cplt->reason_code);
9617 	if (unlikely(err)) {
9618 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n"));
9619 		goto fail;
9620 	}
9621 	err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(setup_cplt->status));
9622 	if (unlikely(err)) {
9623 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n"));
9624 		goto fail;
9625 	}
9626 	err = nla_put_u8(skb, ANDR_TWT_ATTR_NEGOTIATION_TYPE, sdesc->negotiation_type);
9627 	if (unlikely(err)) {
9628 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NEGOTIATION_TYPE failed\n"));
9629 		goto fail;
9630 	}
9631 	err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_DURATION, sdesc->wake_dur);
9632 	if (unlikely(err)) {
9633 		WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_DURATION failed\n"));
9634 		goto fail;
9635 	}
9636 	err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_INTERVAL, sdesc->wake_int);
9637 	if (unlikely(err)) {
9638 		WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_INTERVAL failed\n"));
9639 		goto fail;
9640 	}
9641 	err = nla_put_u8(skb, ANDR_TWT_ATTR_TRIGGER_TYPE,
9642 		!!(sdesc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER));
9643 	if (unlikely(err)) {
9644 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_TRIGGER_TYPE failed\n"));
9645 		goto fail;
9646 	}
9647 
9648 fail:
9649 	return err;
9650 }
9651 
9652 static int
wl_cfgvendor_twt_update_teardown_response(struct sk_buff * skb,void * event_data)9653 wl_cfgvendor_twt_update_teardown_response(struct sk_buff *skb, void *event_data)
9654 {
9655 	s32 err = BCME_OK;
9656 	const wl_twt_teardown_cplt_t *td_cplt = (wl_twt_teardown_cplt_t *)event_data;
9657 	const wl_twt_teardesc_t *teardesc = (const wl_twt_teardesc_t *)&td_cplt[1];
9658 
9659 	WL_DBG(("TWT_TEARDOWN: status %d, reason %d, configID %d, flow_id %d, negotiation_type %d,"
9660 		" bid %d, alltwt %d\n", (int)td_cplt->status, (int)td_cplt->reason_code,
9661 		(int)td_cplt->configID, (int)teardesc->flow_id, (int)teardesc->negotiation_type,
9662 		(int)teardesc->bid, (int)teardesc->alltwt));
9663 
9664 	err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_TEARDOWN);
9665 	if (unlikely(err)) {
9666 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
9667 		goto fail;
9668 	}
9669 	err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, td_cplt->reason_code);
9670 	if (unlikely(err)) {
9671 		WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_REASON_CODE failed\n"));
9672 		goto fail;
9673 	}
9674 	err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(td_cplt->status));
9675 	if (unlikely(err)) {
9676 		WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_STATUS failed\n"));
9677 		goto fail;
9678 	}
9679 	err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, td_cplt->configID);
9680 	if (unlikely(err)) {
9681 		WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_CONFIG_ID failed\n"));
9682 		goto fail;
9683 	}
9684 	err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT, teardesc->alltwt);
9685 	if (unlikely(err)) {
9686 		WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_ALL_TWT failed\n"));
9687 		goto fail;
9688 	}
9689 
9690 fail:
9691 	return err;
9692 }
9693 
9694 static int
wl_cfgvendor_twt_update_infoframe_response(struct sk_buff * skb,void * event_data)9695 wl_cfgvendor_twt_update_infoframe_response(struct sk_buff *skb, void *event_data)
9696 {
9697 	s32 err = BCME_OK;
9698 	const wl_twt_info_cplt_t *info_cplt = (wl_twt_info_cplt_t *)event_data;
9699 	const wl_twt_infodesc_t *infodesc = (const wl_twt_infodesc_t *)&info_cplt[1];
9700 
9701 	WL_DBG(("TWT_INFOFRM: status %d, reason %d, configID %d, flow_flags 0x%x, flow_id %d,"
9702 		" next_twt_h %u, next_twt_l %u\n", (int)info_cplt->status,
9703 		(int)info_cplt->reason_code, (int)info_cplt->configID, infodesc->flow_flags,
9704 		(int)infodesc->flow_id, infodesc->next_twt_h, infodesc->next_twt_l));
9705 
9706 	err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_INFO_FRM);
9707 	if (unlikely(err)) {
9708 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
9709 		goto fail;
9710 	}
9711 	err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, info_cplt->reason_code);
9712 	if (unlikely(err)) {
9713 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n"));
9714 		goto fail;
9715 	}
9716 	err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(info_cplt->status));
9717 	if (unlikely(err)) {
9718 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n"));
9719 		goto fail;
9720 	}
9721 	err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, info_cplt->configID);
9722 	if (unlikely(err)) {
9723 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n"));
9724 		goto fail;
9725 	}
9726 	err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT,
9727 			!!(infodesc->flow_flags & WL_TWT_INFO_FLAG_ALL_TWT));
9728 	if (unlikely(err)) {
9729 		WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n"));
9730 		goto fail;
9731 	}
9732 	err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_RESUMED,
9733 			!!(infodesc->flow_flags & WL_TWT_INFO_FLAG_RESUME));
9734 	if (unlikely(err)) {
9735 		WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n"));
9736 		goto fail;
9737 	}
9738 
9739 fail:
9740 	return err;
9741 }
9742 
9743 static int
wl_cfgvendor_twt_update_notify_response(struct sk_buff * skb,void * event_data)9744 wl_cfgvendor_twt_update_notify_response(struct sk_buff *skb, void *event_data)
9745 {
9746 	s32 err = BCME_OK;
9747 	const wl_twt_notify_t *notif_cplt = (wl_twt_notify_t *)event_data;
9748 
9749 	WL_DBG(("TWT_NOTIFY: notification %d\n", (int)notif_cplt->notification));
9750 
9751 	err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_NOTIFY);
9752 	if (unlikely(err)) {
9753 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
9754 		goto fail;
9755 	}
9756 
9757 	err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_NOTIFICATION, notif_cplt->notification);
9758 	if (unlikely(err)) {
9759 		WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NOTIFICATION failed\n"));
9760 		goto fail;
9761 	}
9762 
9763 fail:
9764 	return err;
9765 }
9766 
9767 s32
wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)9768 wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 *cfg,
9769 		bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
9770 {
9771 	struct sk_buff *skb = NULL;
9772 	gfp_t kflags;
9773 	struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
9774 	int err = BCME_OK;
9775 	struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
9776 	const wl_twt_event_t *twt_event = (wl_twt_event_t *)data;
9777 
9778 	kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
9779 	skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
9780 		BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_TWT, kflags);
9781 	if (!skb) {
9782 		WL_ERR(("skb alloc failed"));
9783 		err = BCME_NOMEM;
9784 		goto fail;
9785 	}
9786 
9787 	switch (twt_event->event_type) {
9788 		case WL_TWT_EVENT_SETUP:
9789 			err = wl_cfgvendor_twt_update_setup_response(skb,
9790 					(void*)twt_event->event_info);
9791 			break;
9792 		case WL_TWT_EVENT_TEARDOWN:
9793 			err = wl_cfgvendor_twt_update_teardown_response(skb,
9794 					(void*)twt_event->event_info);
9795 			break;
9796 		case WL_TWT_EVENT_INFOFRM:
9797 			err = wl_cfgvendor_twt_update_infoframe_response(skb,
9798 					(void*)twt_event->event_info);
9799 			break;
9800 		case WL_TWT_EVENT_NOTIFY:
9801 			err = wl_cfgvendor_twt_update_notify_response(skb,
9802 					(void*)twt_event->event_info);
9803 			break;
9804 		default:
9805 			WL_ERR(("Invalid TWT sub event type %d", twt_event->event_type));
9806 			err = BCME_UNSUPPORTED;
9807 			break;
9808 	}
9809 
9810 	if (err) {
9811 		goto fail;
9812 	}
9813 
9814 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9815 	cfg80211_vendor_event(skb, kflags);
9816 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9817 	WL_ERR(("Successfully sent TWT vendor event type %d\n", twt_event->event_type));
9818 	return BCME_OK;
9819 
9820 fail:
9821 	/* Free skb for failure cases */
9822 	if (skb) {
9823 		kfree_skb(skb);
9824 	}
9825 
9826 	return err;
9827 }
9828 #endif /* !WL_TWT && WL_TWT_HAL_IF */
9829 
9830 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
9831 const struct nla_policy andr_wifi_attr_policy[ANDR_WIFI_ATTRIBUTE_MAX] = {
9832 	[ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET] = { .type = NLA_U32 },
9833 	[ANDR_WIFI_ATTRIBUTE_FEATURE_SET] = { .type = NLA_U32 },
9834 	[ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI] = { .type = NLA_NUL_STRING, .len = 3 },
9835 	[ANDR_WIFI_ATTRIBUTE_NODFS_SET] = { .type = NLA_U32 },
9836 	[ANDR_WIFI_ATTRIBUTE_COUNTRY] = { .type = NLA_NUL_STRING, .len = 3 },
9837 	[ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE] = { .type = NLA_U8 },
9838 	[ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE] = { .type = NLA_U32 },
9839 	[ANDR_WIFI_ATTRIBUTE_LATENCY_MODE] = { .type = NLA_U32, .len = sizeof(uint32) },
9840 	[ANDR_WIFI_ATTRIBUTE_RANDOM_MAC] = { .type = NLA_U32 },
9841 	[ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO] = { .type = NLA_S8 },
9842 	[ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION] = { .type = NLA_S8 },
9843 	[ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW] = { .type = NLA_U32 },
9844 	[ANDR_WIFI_ATTRIBUTE_VOIP_MODE] = { .type = NLA_U32, .len = sizeof(uint32) },
9845 	[ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER] = { .type = NLA_U32, .len = sizeof(uint32) },
9846 };
9847 
9848 const struct nla_policy dump_buf_policy[DUMP_BUF_ATTR_MAX] = {
9849 	[DUMP_BUF_ATTR_MEMDUMP] = { .type = NLA_BINARY },
9850 	[DUMP_BUF_ATTR_SSSR_C0_D11_BEFORE] = { .type = NLA_BINARY },
9851 	[DUMP_BUF_ATTR_SSSR_C0_D11_AFTER] = { .type = NLA_BINARY },
9852 	[DUMP_BUF_ATTR_SSSR_C1_D11_BEFORE] = { .type = NLA_BINARY },
9853 	[DUMP_BUF_ATTR_SSSR_C1_D11_AFTER] = { .type = NLA_BINARY },
9854 	[DUMP_BUF_ATTR_SSSR_C2_D11_BEFORE] = { .type = NLA_BINARY },
9855 	[DUMP_BUF_ATTR_SSSR_C2_D11_AFTER] = { .type = NLA_BINARY },
9856 	[DUMP_BUF_ATTR_SSSR_DIG_BEFORE] = { .type = NLA_BINARY },
9857 	[DUMP_BUF_ATTR_SSSR_DIG_AFTER] = { .type = NLA_BINARY },
9858 	[DUMP_BUF_ATTR_TIMESTAMP] = { .type = NLA_BINARY },
9859 	[DUMP_BUF_ATTR_GENERAL_LOG] = { .type = NLA_BINARY },
9860 	[DUMP_BUF_ATTR_ECNTRS] = { .type = NLA_BINARY },
9861 	[DUMP_BUF_ATTR_SPECIAL_LOG] = { .type = NLA_BINARY },
9862 	[DUMP_BUF_ATTR_DHD_DUMP] = { .type = NLA_BINARY },
9863 	[DUMP_BUF_ATTR_EXT_TRAP] = { .type = NLA_BINARY },
9864 	[DUMP_BUF_ATTR_HEALTH_CHK] = { .type = NLA_BINARY },
9865 	[DUMP_BUF_ATTR_PRESERVE_LOG] = { .type = NLA_BINARY },
9866 	[DUMP_BUF_ATTR_COOKIE] = { .type = NLA_BINARY },
9867 	[DUMP_BUF_ATTR_FLOWRING_DUMP] = { .type = NLA_BINARY },
9868 	[DUMP_BUF_ATTR_PKTLOG] = { .type = NLA_BINARY },
9869 	[DUMP_BUF_ATTR_PKTLOG_DEBUG] = { .type = NLA_BINARY },
9870 	[DUMP_BUF_ATTR_STATUS_LOG] = { .type = NLA_BINARY },
9871 	[DUMP_BUF_ATTR_AXI_ERROR] = { .type = NLA_BINARY },
9872 	[DUMP_BUF_ATTR_RTT_LOG] = { .type = NLA_BINARY },
9873 	[DUMP_BUF_ATTR_SDTC_ETB_DUMP] = { .type = NLA_BINARY },
9874 	[DUMP_BUF_ATTR_PKTID_MAP_LOG] = { .type = NLA_BINARY },
9875 	[DUMP_BUF_ATTR_PKTID_UNMAP_LOG] = { .type = NLA_BINARY },
9876 };
9877 
9878 const struct nla_policy brcm_drv_attr_policy[BRCM_ATTR_DRIVER_MAX] = {
9879 	[BRCM_ATTR_DRIVER_CMD] = { .type = NLA_NUL_STRING },
9880 	[BRCM_ATTR_DRIVER_KEY_PMK] = { .type = NLA_BINARY, .len = WSEC_MAX_PASSPHRASE_LEN },
9881 	[BRCM_ATTR_DRIVER_FEATURE_FLAGS] = { .type = NLA_BINARY, .len =
9882 	((BRCM_WLAN_VENDOR_FEATURES_MAX / 8) + 1) },
9883 	[BRCM_ATTR_DRIVER_RAND_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9884 	[BRCM_ATTR_SAE_PWE] = { .type = NLA_U32 },
9885 };
9886 
9887 #ifdef RTT_SUPPORT
9888 const struct nla_policy rtt_attr_policy[RTT_ATTRIBUTE_MAX] = {
9889 	[RTT_ATTRIBUTE_TARGET_CNT] = { .type = NLA_U8 },
9890 	[RTT_ATTRIBUTE_TARGET_INFO] = { .type = NLA_NESTED },
9891 	[RTT_ATTRIBUTE_TARGET_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9892 	[RTT_ATTRIBUTE_TARGET_TYPE] = { .type = NLA_U8 },
9893 	[RTT_ATTRIBUTE_TARGET_PEER] = { .type = NLA_U8 },
9894 	[RTT_ATTRIBUTE_TARGET_CHAN] = { .type = NLA_BINARY },
9895 	[RTT_ATTRIBUTE_TARGET_PERIOD] = { .type = NLA_U32 },
9896 	[RTT_ATTRIBUTE_TARGET_NUM_BURST] = { .type = NLA_U32 },
9897 	[RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST] = { .type = NLA_U32 },
9898 	[RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM] = { .type = NLA_U32 },
9899 	[RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR] = { .type = NLA_U32 },
9900 	[RTT_ATTRIBUTE_TARGET_LCI] = { .type = NLA_U8 },
9901 	[RTT_ATTRIBUTE_TARGET_LCR] = { .type = NLA_U8 },
9902 	[RTT_ATTRIBUTE_TARGET_BURST_DURATION] = { .type = NLA_U32 },
9903 	[RTT_ATTRIBUTE_TARGET_PREAMBLE] = { .type = NLA_U8 },
9904 	[RTT_ATTRIBUTE_TARGET_BW] = { .type = NLA_U8 },
9905 	[RTT_ATTRIBUTE_RESULTS_COMPLETE] = { .type = NLA_U32 },
9906 	[RTT_ATTRIBUTE_RESULTS_PER_TARGET] = { .type = NLA_NESTED },
9907 	[RTT_ATTRIBUTE_RESULT_CNT] = { .type = NLA_U32 },
9908 	[RTT_ATTRIBUTE_RESULT] = { .type = NLA_BINARY, .len = sizeof(rtt_result_t) },
9909 	[RTT_ATTRIBUTE_RESULT_DETAIL] = { .type = NLA_BINARY,
9910 	.len = sizeof(struct rtt_result_detail) },
9911 };
9912 #endif /* RTT_SUPPORT */
9913 
9914 #ifdef KEEP_ALIVE
9915 const struct nla_policy mkeep_alive_attr_policy[MKEEP_ALIVE_ATTRIBUTE_MAX] = {
9916 	[MKEEP_ALIVE_ATTRIBUTE_ID] = { .type = NLA_U8 },
9917 	[MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = { .type = NLA_BINARY, .len = MKEEP_ALIVE_IP_PKT_MAX },
9918 	[MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = { .type = NLA_U16 },
9919 	[MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9920 	[MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9921 	[MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = { .type = NLA_U32 },
9922 	[MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE] = { .type = NLA_U16 }
9923 };
9924 #endif /* KEEP_ALIVE */
9925 #ifdef WL_NAN
9926 const struct nla_policy nan_attr_policy[NAN_ATTRIBUTE_MAX] = {
9927 	[NAN_ATTRIBUTE_2G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
9928 	[NAN_ATTRIBUTE_5G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
9929 	[NAN_ATTRIBUTE_CLUSTER_LOW] = { .type = NLA_U16, .len = sizeof(uint16) },
9930 	[NAN_ATTRIBUTE_CLUSTER_HIGH] = { .type = NLA_U16, .len = sizeof(uint16) },
9931 	[NAN_ATTRIBUTE_SID_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
9932 	[NAN_ATTRIBUTE_SUB_SID_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
9933 	[NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
9934 	[NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
9935 	[NAN_ATTRIBUTE_SDF_2G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
9936 	[NAN_ATTRIBUTE_SDF_5G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
9937 	[NAN_ATTRIBUTE_HOP_COUNT_LIMIT] = { .type = NLA_U8, .len = sizeof(uint8) },
9938 	[NAN_ATTRIBUTE_RANDOM_TIME] = { .type = NLA_U8, .len = sizeof(uint8) },
9939 	[NAN_ATTRIBUTE_MASTER_PREF] = { .type = NLA_U8, .len = sizeof(uint8) },
9940 	[NAN_ATTRIBUTE_OUI] = { .type = NLA_U32, .len = sizeof(uint32) },
9941 	[NAN_ATTRIBUTE_WARMUP_TIME] = { .type = NLA_U16, .len = sizeof(uint16) },
9942 	[NAN_ATTRIBUTE_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
9943 	[NAN_ATTRIBUTE_24G_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
9944 	[NAN_ATTRIBUTE_5G_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
9945 	[NAN_ATTRIBUTE_CONF_CLUSTER_VAL] = { .type = NLA_U8, .len = sizeof(uint8) },
9946 	[NAN_ATTRIBUTE_DWELL_TIME] = { .type = NLA_U8, .len = sizeof(uint8) },
9947 	[NAN_ATTRIBUTE_SCAN_PERIOD] = { .type = NLA_U16, .len = sizeof(uint16) },
9948 	[NAN_ATTRIBUTE_DWELL_TIME_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
9949 	[NAN_ATTRIBUTE_SCAN_PERIOD_5G] = { .type = NLA_U16, .len = sizeof(uint16) },
9950 	[NAN_ATTRIBUTE_AVAIL_BIT_MAP] = { .type = NLA_U32, .len = sizeof(uint32) },
9951 	[NAN_ATTRIBUTE_ENTRY_CONTROL] = { .type = NLA_U8, .len = sizeof(uint8) },
9952 	[NAN_ATTRIBUTE_RSSI_CLOSE] = { .type = NLA_U8, .len = sizeof(uint8) },
9953 	[NAN_ATTRIBUTE_RSSI_MIDDLE] = { .type = NLA_U8, .len = sizeof(uint8) },
9954 	[NAN_ATTRIBUTE_RSSI_PROXIMITY] = { .type = NLA_U8, .len = sizeof(uint8) },
9955 	[NAN_ATTRIBUTE_RSSI_CLOSE_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
9956 	[NAN_ATTRIBUTE_RSSI_MIDDLE_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
9957 	[NAN_ATTRIBUTE_RSSI_PROXIMITY_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
9958 	[NAN_ATTRIBUTE_RSSI_WINDOW_SIZE] = { .type = NLA_U8, .len = sizeof(uint8) },
9959 	[NAN_ATTRIBUTE_CIPHER_SUITE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
9960 	[NAN_ATTRIBUTE_SCID_LEN] = { .type = NLA_U32, .len = sizeof(uint32) },
9961 	[NAN_ATTRIBUTE_SCID] = { .type = NLA_BINARY, .len = MAX_SCID_LEN },
9962 	[NAN_ATTRIBUTE_2G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) },
9963 	[NAN_ATTRIBUTE_5G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) },
9964 	[NAN_ATTRIBUTE_DISC_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) },
9965 	[NAN_ATTRIBUTE_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9966 	[NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
9967 	[NAN_ATTRIBUTE_CMD_USE_NDPE] = { .type = NLA_U32, .len = sizeof(uint32) },
9968 	[NAN_ATTRIBUTE_ENABLE_MERGE] = { .type = NLA_U8, .len = sizeof(uint8) },
9969 	[NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
9970 	[NAN_ATTRIBUTE_NSS] = { .type = NLA_U32, .len = sizeof(uint32) },
9971 	[NAN_ATTRIBUTE_ENABLE_RANGING] = { .type = NLA_U32, .len = sizeof(uint32) },
9972 	[NAN_ATTRIBUTE_DW_EARLY_TERM] = { .type = NLA_U32, .len = sizeof(uint32) },
9973 	[NAN_ATTRIBUTE_TRANSAC_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
9974 	[NAN_ATTRIBUTE_PUBLISH_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
9975 	[NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
9976 	[NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO] = { .type = NLA_BINARY, .len =
9977 	NAN_MAX_SERVICE_SPECIFIC_INFO_LEN },
9978 	[NAN_ATTRIBUTE_SUBSCRIBE_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
9979 	[NAN_ATTRIBUTE_SUBSCRIBE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
9980 	[NAN_ATTRIBUTE_PUBLISH_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
9981 	[NAN_ATTRIBUTE_PUBLISH_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
9982 	[NAN_ATTRIBUTE_PERIOD] = { .type = NLA_U16, .len = sizeof(uint16) },
9983 	[NAN_ATTRIBUTE_TTL] = { .type = NLA_U16, .len = sizeof(uint16) },
9984 	[NAN_ATTRIBUTE_SERVICE_NAME_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
9985 	[NAN_ATTRIBUTE_SERVICE_NAME] = { .type = NLA_BINARY, .len = WL_NAN_SVC_HASH_LEN },
9986 	[NAN_ATTRIBUTE_PEER_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
9987 	[NAN_ATTRIBUTE_INST_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
9988 	[NAN_ATTRIBUTE_SUBSCRIBE_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
9989 	[NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION] = { .type = NLA_U8, .len = sizeof(uint8) },
9990 	[NAN_ATTRIBUTE_SUBSCRIBE_MATCH] = { .type = NLA_U8, .len = sizeof(uint8) },
9991 	[NAN_ATTRIBUTE_PUBLISH_MATCH] = { .type = NLA_U8, .len = sizeof(uint8) },
9992 	[NAN_ATTRIBUTE_SERVICERESPONSEFILTER] = { .type = NLA_U8, .len = sizeof(uint8) },
9993 	[NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE] = { .type = NLA_U8, .len = sizeof(uint8) },
9994 	[NAN_ATTRIBUTE_USESERVICERESPONSEFILTER] = { .type = NLA_U8, .len = sizeof(uint8) },
9995 	[NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
9996 	[NAN_ATTRIBUTE_RX_MATCH_FILTER] = { .type = NLA_BINARY, .len = MAX_MATCH_FILTER_LEN },
9997 	[NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
9998 	[NAN_ATTRIBUTE_TX_MATCH_FILTER] = { .type = NLA_BINARY, .len = MAX_MATCH_FILTER_LEN },
9999 	[NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES] = { .type = NLA_U16, .len = sizeof(uint16) },
10000 	[NAN_ATTRIBUTE_MAC_ADDR_LIST] = { .type = NLA_BINARY, .len =
10001 	(NAN_SRF_MAX_MAC*ETHER_ADDR_LEN) },
10002 	[NAN_ATTRIBUTE_TX_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
10003 	[NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP] = { .type = NLA_U8, .len = sizeof(uint8) },
10004 	[NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
10005 	[NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
10006 	[NAN_ATTRIBUTE_SDE_CONTROL_SECURITY] = { .type = NLA_U8, .len = sizeof(uint8) },
10007 	[NAN_ATTRIBUTE_RECV_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) },
10008 	[NAN_ATTRIBUTE_KEY_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
10009 	[NAN_ATTRIBUTE_KEY_LEN] = { .type = NLA_U32, .len = sizeof(uint32) },
10010 	[NAN_ATTRIBUTE_KEY_DATA] = { .type = NLA_BINARY, .len = NAN_MAX_PMK_LEN },
10011 	[NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG] = { .type = NLA_U8, .len = sizeof(uint8) },
10012 	[NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN] = { .type = NLA_U16, .len =
10013 	sizeof(uint16) },
10014 	[NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO] = { .type = NLA_BINARY, .len =
10015 	MAX_SDEA_SVC_INFO_LEN },
10016 	[NAN_ATTRIBUTE_SECURITY] = { .type = NLA_U8, .len = sizeof(uint8) },
10017 	[NAN_ATTRIBUTE_RANGING_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
10018 	[NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT] = { .type = NLA_U32, .len = sizeof(uint32) },
10019 	[NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT] = { .type = NLA_U32, .len = sizeof(uint32) },
10020 	[NAN_ATTRIBUTE_RANGING_INDICATION] = { .type = NLA_U32, .len = sizeof(uint32) },
10021 	[NAN_ATTRIBUTE_SVC_RESPONDER_POLICY] = { .type = NLA_U8, .len = sizeof(uint8) },
10022 	[NAN_ATTRIBUTE_NDP_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
10023 	[NAN_ATTRIBUTE_IFACE] = { .type = NLA_BINARY, .len = IFNAMSIZ+1 },
10024 	[NAN_ATTRIBUTE_QOS] = { .type = NLA_U8, .len = sizeof(uint8) },
10025 	[NAN_ATTRIBUTE_RSP_CODE] = { .type = NLA_U8, .len = sizeof(uint8) },
10026 	[NAN_ATTRIBUTE_INST_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
10027 	[NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
10028 	[NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
10029 	[NAN_ATTRIBUTE_IF_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
10030 	[NAN_ATTRIBUTE_NO_CONFIG_AVAIL] = { .type = NLA_U8, .len = sizeof(uint8) },
10031 	[NAN_ATTRIBUTE_CHANNEL_INFO] = { .type = NLA_BINARY, .len =
10032 	sizeof(nan_channel_info_t) * NAN_MAX_CHANNEL_INFO_SUPPORTED },
10033 	[NAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32, .len = sizeof(uint32) },
10034 	[NAN_ATTRIBUTE_INSTANT_MODE_ENABLE] = { .type = NLA_U32, .len = sizeof(uint32) },
10035 	[NAN_ATTRIBUTE_INSTANT_COMM_CHAN] = { .type = NLA_U32, .len = sizeof(uint32) },
10036 };
10037 #endif /* WL_NAN */
10038 
10039 const struct nla_policy gscan_attr_policy[GSCAN_ATTRIBUTE_MAX] = {
10040 	[GSCAN_ATTRIBUTE_BAND] = { .type = NLA_U32 },
10041 	[GSCAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32 },
10042 	[GSCAN_ATTRIBUTE_CHANNEL_LIST] = { .type = NLA_BINARY },
10043 	[GSCAN_ATTRIBUTE_WHITELIST_SSID] = { .type = NLA_BINARY, .len = IEEE80211_MAX_SSID_LEN },
10044 	[GSCAN_ATTRIBUTE_NUM_WL_SSID] = { .type = NLA_U32 },
10045 	[GSCAN_ATTRIBUTE_WL_SSID_LEN] = { .type = NLA_U32 },
10046 	[GSCAN_ATTRIBUTE_WL_SSID_FLUSH] = { .type = NLA_U32 },
10047 	[GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM] = { .type = NLA_NESTED },
10048 	/* length is sizeof(wl_ssid_whitelist_t) * MAX_SSID_WHITELIST_NUM */
10049 	[GSCAN_ATTRIBUTE_NUM_BSSID] = { .type = NLA_U32 },
10050 	[GSCAN_ATTRIBUTE_BSSID_PREF_LIST] = { .type = NLA_NESTED },
10051 	/* length is sizeof(wl_bssid_pref_list_t) * MAX_BSSID_PREF_LIST_NUM */
10052 	[GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH] = { .type = NLA_U32 },
10053 	[GSCAN_ATTRIBUTE_BSSID_PREF] = { .type = NLA_BINARY, .len = ETH_ALEN },
10054 	[GSCAN_ATTRIBUTE_RSSI_MODIFIER] = { .type = NLA_U32 },
10055 	[GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH] = { .type = NLA_U32 },
10056 	[GSCAN_ATTRIBUTE_BLACKLIST_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
10057 	[GSCAN_ATTRIBUTE_ROAM_STATE_SET] = { .type = NLA_U32 },
10058 };
10059 
10060 #ifdef DHD_WAKE_STATUS
10061 const struct nla_policy wake_stat_attr_policy[WAKE_STAT_ATTRIBUTE_MAX] = {
10062 	[WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT] = { .type = NLA_U32 },
10063 #ifdef CUSTOM_WAKE_REASON_STATS
10064 	[WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE] = { .type = NLA_BINARY,
10065 	.len = (MAX_WAKE_REASON_STATS * sizeof(int))},
10066 #else
10067 	[WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE] = { .type = NLA_BINARY,
10068 	.len = (WLC_E_LAST * sizeof(uint))},
10069 #endif /* CUSTOM_WAKE_REASON_STATS */
10070 	[WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT] = { .type = NLA_U32 },
10071 	[WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED] = { .type = NLA_U32 },
10072 	[WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW] = { .type = NLA_U32 },
10073 	[WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE] = { .type = NLA_U32 },
10074 	[WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT] = { .type = NLA_U32 },
10075 	[WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED] = { .type = NLA_U32 },
10076 	[WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE] = { .type = NLA_U32 },
10077 	[WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT] = { .type = NLA_U32 },
10078 	[WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT] = { .type = NLA_U32 },
10079 	[WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT] = { .type = NLA_U32 },
10080 	[WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT] = { .type = NLA_U32 },
10081 	[WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT] = { .type = NLA_U32 },
10082 	[WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA] = { .type = NLA_U32 },
10083 	[WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA] = { .type = NLA_U32 },
10084 	[WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS] = { .type = NLA_U32 },
10085 	[WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
10086 	[WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
10087 	[WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
10088 };
10089 #endif /* DHD_WAKE_STATUS */
10090 
10091 #ifdef RSSI_MONITOR_SUPPORT
10092 const struct nla_policy rssi_monitor_attr_policy[RSSI_MONITOR_ATTRIBUTE_MAX] = {
10093 	[RSSI_MONITOR_ATTRIBUTE_MAX_RSSI] = { .type = NLA_U32 },
10094 	[RSSI_MONITOR_ATTRIBUTE_MIN_RSSI] = { .type = NLA_U32 },
10095 	[RSSI_MONITOR_ATTRIBUTE_START] = { .type = NLA_U32 }
10096 };
10097 #endif /* RSSI_MONITOR_SUPPORT */
10098 
10099 
10100 const struct nla_policy hal_start_attr_policy[SET_HAL_START_ATTRIBUTE_MAX] = {
10101 	[0] = { .strict_start_type = 0 },
10102 	[SET_HAL_START_ATTRIBUTE_DEINIT] = { .type = NLA_UNSPEC },
10103 	[SET_HAL_START_ATTRIBUTE_PRE_INIT] = { .type = NLA_NUL_STRING },
10104 	[SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID] = { .type = NLA_U32 },
10105 };
10106 
10107 const struct nla_policy andr_dbg_policy[DEBUG_ATTRIBUTE_MAX] = {
10108 	[DEBUG_ATTRIBUTE_GET_DRIVER] = { .type = NLA_BINARY },
10109 	[DEBUG_ATTRIBUTE_GET_FW] = { .type = NLA_BINARY },
10110 	[DEBUG_ATTRIBUTE_RING_ID] = { .type = NLA_U32 },
10111 	[DEBUG_ATTRIBUTE_RING_NAME] = { .type = NLA_NUL_STRING },
10112 	[DEBUG_ATTRIBUTE_RING_FLAGS] = { .type = NLA_U32 },
10113 	[DEBUG_ATTRIBUTE_LOG_LEVEL] = { .type = NLA_U32 },
10114 	[DEBUG_ATTRIBUTE_LOG_TIME_INTVAL] = { .type = NLA_U32 },
10115 	[DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE] = { .type = NLA_U32 },
10116 	[DEBUG_ATTRIBUTE_FW_DUMP_LEN] = { .type = NLA_U32 },
10117 	[DEBUG_ATTRIBUTE_FW_DUMP_DATA] = { .type = NLA_U64 },
10118 	[DEBUG_ATTRIBUTE_FW_ERR_CODE] = { .type = NLA_U32 },
10119 	[DEBUG_ATTRIBUTE_RING_DATA] = { .type = NLA_BINARY },
10120 	[DEBUG_ATTRIBUTE_RING_STATUS] = { .type = NLA_BINARY },
10121 	[DEBUG_ATTRIBUTE_RING_NUM] = { .type = NLA_U32 },
10122 	[DEBUG_ATTRIBUTE_DRIVER_DUMP_LEN] = { .type = NLA_U32 },
10123 	[DEBUG_ATTRIBUTE_DRIVER_DUMP_DATA] = { .type = NLA_BINARY },
10124 	[DEBUG_ATTRIBUTE_PKT_FATE_NUM] = { .type = NLA_U32 },
10125 	[DEBUG_ATTRIBUTE_PKT_FATE_DATA] = { .type = NLA_U64 },
10126 	[DEBUG_ATTRIBUTE_HANG_REASON] = { .type = NLA_BINARY },
10127 };
10128 
10129 #if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
10130 const struct nla_policy andr_twt_attr_policy[ANDR_TWT_ATTR_MAX] = {
10131 	[ANDR_TWT_ATTR_NONE] = { .strict_start_type = 0 },
10132 	[ANDR_TWT_ATTR_CONFIG_ID] = { .type = NLA_U8 },
10133 	[ANDR_TWT_ATTR_NEGOTIATION_TYPE] = { .type = NLA_U8 },
10134 	[ANDR_TWT_ATTR_TRIGGER_TYPE] = { .type = NLA_U8 },
10135 	[ANDR_TWT_ATTR_WAKE_DURATION] = { .type = NLA_U32 },
10136 	[ANDR_TWT_ATTR_WAKE_INTERVAL] = { .type = NLA_U32 },
10137 	[ANDR_TWT_ATTR_WAKE_INTERVAL_MIN] = { .type = NLA_U32 },
10138 	[ANDR_TWT_ATTR_WAKE_INTERVAL_MAX] = { .type = NLA_U32 },
10139 	[ANDR_TWT_ATTR_WAKE_DURATION_MIN] = { .type = NLA_U32 },
10140 	[ANDR_TWT_ATTR_WAKE_DURATION_MAX] = { .type = NLA_U32 },
10141 	[ANDR_TWT_ATTR_AVG_PKT_SIZE] = { .type = NLA_U32 },
10142 	[ANDR_TWT_ATTR_AVG_PKT_NUM] = { .type = NLA_U32 },
10143 	[ANDR_TWT_ATTR_WAKETIME_OFFSET] = { .type = NLA_U32 },
10144 	[ANDR_TWT_ATTR_ALL_TWT] = { .type = NLA_U8 },
10145 	[ANDR_TWT_ATTR_RESUME_TIME] = { .type = NLA_U32 },
10146 	[ANDR_TWT_ATTR_AVG_EOSP_DUR] = { .type = NLA_U32 },
10147 	[ANDR_TWT_ATTR_EOSP_CNT] = { .type = NLA_U32 },
10148 	[ANDR_TWT_ATTR_NUM_SP] = { .type = NLA_U32 },
10149 	[ANDR_TWT_ATTR_DEVICE_CAP] = { .type = NLA_U32 },
10150 	[ANDR_TWT_ATTR_PEER_CAP] = { .type = NLA_U32 },
10151 	[ANDR_TWT_ATTR_STATUS] = { .type = NLA_U8 },
10152 	[ANDR_TWT_ATTR_REASON_CODE] = { .type = NLA_U8 },
10153 	[ANDR_TWT_ATTR_TWT_RESUMED] = { .type = NLA_U8 },
10154 	[ANDR_TWT_ATTR_TWT_NOTIFICATION] = { .type = NLA_U8 },
10155 	[ANDR_TWT_ATTR_SUB_EVENT] = { .type = NLA_U8 },
10156 	[ANDR_TWT_ATTR_NUM_PEER_STATS] = { .type = NLA_U8 },
10157 	[ANDR_TWT_ATTR_AVG_PKT_NUM_TX] = { .type = NLA_U32 },
10158 	[ANDR_TWT_ATTR_AVG_PKT_SIZE_TX] = { .type = NLA_U32 },
10159 	[ANDR_TWT_ATTR_AVG_PKT_NUM_RX] = { .type = NLA_U32 },
10160 	[ANDR_TWT_ATTR_AVG_PKT_SIZE_RX] = { .type = NLA_U32 },
10161 };
10162 #endif /* !WL_TWT && WL_TWT_HAL_IF */
10163 
10164 #endif /* LINUX_VERSION >= 5.3 */
10165 
10166 static struct wiphy_vendor_command wl_vendor_cmds [] = {
10167 	{
10168 		{
10169 			.vendor_id = OUI_BRCM,
10170 			.subcmd = BRCM_VENDOR_SCMD_PRIV_STR
10171 		},
10172 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10173 		.doit = wl_cfgvendor_priv_string_handler,
10174 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10175 		.policy = brcm_drv_attr_policy,
10176 		.maxattr = BRCM_ATTR_DRIVER_MAX
10177 #endif /* LINUX_VERSION >= 5.3 */
10178 	},
10179 #ifdef BCM_PRIV_CMD_SUPPORT
10180 	{
10181 		{
10182 			.vendor_id = OUI_BRCM,
10183 			.subcmd = BRCM_VENDOR_SCMD_BCM_STR
10184 		},
10185 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10186 		.doit = wl_cfgvendor_priv_bcm_handler,
10187 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10188 		.policy = brcm_drv_attr_policy,
10189 		.maxattr = BRCM_ATTR_DRIVER_MAX
10190 #endif /* LINUX_VERSION >= 5.3 */
10191 	},
10192 #endif /* BCM_PRIV_CMD_SUPPORT */
10193 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10194 	{
10195 		{
10196 			.vendor_id = OUI_BRCM,
10197 			.subcmd = BRCM_VENDOR_SCMD_BCM_PSK
10198 		},
10199 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10200 		.doit = wl_cfgvendor_set_sae_password
10201 	},
10202 #endif /* WL_SAE || WL_CLIENT_SAE */
10203 	{
10204 		{
10205 			.vendor_id = OUI_BRCM,
10206 			.subcmd = BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS
10207 		},
10208 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10209 		.doit = wl_cfgvendor_connect_params_handler,
10210 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10211 		.policy = brcm_drv_attr_policy,
10212 		.maxattr = BRCM_ATTR_DRIVER_MAX
10213 #endif /* LINUX_VERSION >= 5.3 */
10214 	},
10215 	{
10216 		{
10217 			.vendor_id = OUI_BRCM,
10218 			.subcmd = BRCM_VENDOR_SCMD_SET_START_AP_PARAMS
10219 		},
10220 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10221 		.doit = wl_cfgvendor_start_ap_params_handler,
10222 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10223 		.policy = brcm_drv_attr_policy,
10224 		.maxattr = BRCM_ATTR_DRIVER_MAX
10225 #endif /* LINUX_VERSION >= 5.3 */
10226 	},
10227 #ifdef GSCAN_SUPPORT
10228 	{
10229 		{
10230 			.vendor_id = OUI_GOOGLE,
10231 			.subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
10232 		},
10233 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10234 		.doit = wl_cfgvendor_gscan_get_capabilities
10235 	},
10236 	{
10237 		{
10238 			.vendor_id = OUI_GOOGLE,
10239 			.subcmd = GSCAN_SUBCMD_SET_CONFIG
10240 		},
10241 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10242 		.doit = wl_cfgvendor_set_scan_cfg
10243 	},
10244 	{
10245 		{
10246 			.vendor_id = OUI_GOOGLE,
10247 			.subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
10248 		},
10249 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10250 		.doit = wl_cfgvendor_set_batch_scan_cfg
10251 	},
10252 	{
10253 		{
10254 			.vendor_id = OUI_GOOGLE,
10255 			.subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
10256 		},
10257 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10258 		.doit = wl_cfgvendor_initiate_gscan
10259 	},
10260 	{
10261 		{
10262 			.vendor_id = OUI_GOOGLE,
10263 			.subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
10264 		},
10265 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10266 		.doit = wl_cfgvendor_enable_full_scan_result
10267 	},
10268 	{
10269 		{
10270 			.vendor_id = OUI_GOOGLE,
10271 			.subcmd = GSCAN_SUBCMD_SET_HOTLIST
10272 		},
10273 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10274 		.doit = wl_cfgvendor_hotlist_cfg
10275 	},
10276 	{
10277 		{
10278 			.vendor_id = OUI_GOOGLE,
10279 			.subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
10280 		},
10281 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10282 		.doit = wl_cfgvendor_gscan_get_batch_results
10283 	},
10284 #endif /* GSCAN_SUPPORT */
10285 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
10286 	{
10287 		{
10288 			.vendor_id = OUI_GOOGLE,
10289 			.subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
10290 		},
10291 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10292 		.doit = wl_cfgvendor_gscan_get_channel_list,
10293 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10294 		.policy = gscan_attr_policy,
10295 		.maxattr = GSCAN_ATTRIBUTE_MAX
10296 #endif /* LINUX_VERSION >= 5.3 */
10297 	},
10298 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
10299 #ifdef RTT_SUPPORT
10300 	{
10301 		{
10302 			.vendor_id = OUI_GOOGLE,
10303 			.subcmd = RTT_SUBCMD_SET_CONFIG
10304 		},
10305 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10306 		.doit = wl_cfgvendor_rtt_set_config,
10307 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10308 		.policy = rtt_attr_policy,
10309 		.maxattr = RTT_ATTRIBUTE_MAX
10310 #endif /* LINUX_VERSION >= 5.3 */
10311 	},
10312 	{
10313 		{
10314 			.vendor_id = OUI_GOOGLE,
10315 			.subcmd = RTT_SUBCMD_CANCEL_CONFIG
10316 		},
10317 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10318 		.doit = wl_cfgvendor_rtt_cancel_config,
10319 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10320 		.policy = rtt_attr_policy,
10321 		.maxattr = RTT_ATTRIBUTE_MAX
10322 #endif /* LINUX_VERSION >= 5.3 */
10323 	},
10324 	{
10325 		{
10326 			.vendor_id = OUI_GOOGLE,
10327 			.subcmd = RTT_SUBCMD_GETCAPABILITY
10328 		},
10329 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10330 		.doit = wl_cfgvendor_rtt_get_capability,
10331 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10332 		.policy = rtt_attr_policy,
10333 		.maxattr = RTT_ATTRIBUTE_MAX
10334 #endif /* LINUX_VERSION >= 5.3 */
10335 	},
10336 	{
10337 		{
10338 			.vendor_id = OUI_GOOGLE,
10339 			.subcmd = RTT_SUBCMD_GETAVAILCHANNEL
10340 		},
10341 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10342 		.doit = wl_cfgvendor_rtt_get_responder_info,
10343 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10344 		.policy = rtt_attr_policy,
10345 		.maxattr = RTT_ATTRIBUTE_MAX
10346 #endif /* LINUX_VERSION >= 5.3 */
10347 	},
10348 	{
10349 		{
10350 			.vendor_id = OUI_GOOGLE,
10351 			.subcmd = RTT_SUBCMD_SET_RESPONDER
10352 		},
10353 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10354 		.doit = wl_cfgvendor_rtt_set_responder,
10355 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10356 		.policy = rtt_attr_policy,
10357 		.maxattr = RTT_ATTRIBUTE_MAX
10358 #endif /* LINUX_VERSION >= 5.3 */
10359 	},
10360 	{
10361 		{
10362 			.vendor_id = OUI_GOOGLE,
10363 			.subcmd = RTT_SUBCMD_CANCEL_RESPONDER
10364 		},
10365 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10366 		.doit = wl_cfgvendor_rtt_cancel_responder,
10367 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10368 		.policy = rtt_attr_policy,
10369 		.maxattr = RTT_ATTRIBUTE_MAX
10370 #endif /* LINUX_VERSION >= 5.3 */
10371 	},
10372 #endif /* RTT_SUPPORT */
10373 	{
10374 		{
10375 			.vendor_id = OUI_GOOGLE,
10376 			.subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
10377 		},
10378 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10379 		.doit = wl_cfgvendor_get_feature_set,
10380 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10381 		.policy = andr_wifi_attr_policy,
10382 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10383 #endif /* LINUX_VERSION >= 5.3 */
10384 	},
10385 	{
10386 		{
10387 			.vendor_id = OUI_GOOGLE,
10388 			.subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
10389 		},
10390 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10391 		.doit = wl_cfgvendor_get_feature_set_matrix,
10392 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10393 		.policy = andr_wifi_attr_policy,
10394 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10395 #endif /* LINUX_VERSION >= 5.3 */
10396 	},
10397 	{
10398 		{
10399 			.vendor_id = OUI_GOOGLE,
10400 			.subcmd = ANDR_WIFI_RANDOM_MAC_OUI
10401 		},
10402 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10403 		.doit = wl_cfgvendor_set_rand_mac_oui,
10404 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10405 		.policy = andr_wifi_attr_policy,
10406 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10407 #endif /* LINUX_VERSION >= 5.3 */
10408 	},
10409 #ifdef CUSTOM_FORCE_NODFS_FLAG
10410 	{
10411 		{
10412 			.vendor_id = OUI_GOOGLE,
10413 			.subcmd = ANDR_WIFI_NODFS_CHANNELS
10414 		},
10415 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10416 		.doit = wl_cfgvendor_set_nodfs_flag,
10417 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10418 		.policy = andr_wifi_attr_policy,
10419 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10420 #endif /* LINUX_VERSION >= 5.3 */
10421 	},
10422 #endif /* CUSTOM_FORCE_NODFS_FLAG */
10423 	{
10424 		{
10425 			.vendor_id = OUI_GOOGLE,
10426 			.subcmd = ANDR_WIFI_SET_COUNTRY
10427 		},
10428 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10429 		.doit = wl_cfgvendor_set_country,
10430 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10431 		.policy = andr_wifi_attr_policy,
10432 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10433 #endif /* LINUX_VERSION >= 5.3 */
10434 	},
10435 #ifdef LINKSTAT_SUPPORT
10436 	{
10437 		{
10438 			.vendor_id = OUI_GOOGLE,
10439 			.subcmd = LSTATS_SUBCMD_GET_INFO
10440 		},
10441 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10442 		.doit = wl_cfgvendor_lstats_get_info
10443 	},
10444 #endif /* LINKSTAT_SUPPORT */
10445 
10446 #ifdef GSCAN_SUPPORT
10447 	{
10448 		{
10449 			.vendor_id = OUI_GOOGLE,
10450 			.subcmd = GSCAN_SUBCMD_SET_EPNO_SSID
10451 		},
10452 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10453 		.doit = wl_cfgvendor_epno_cfg
10454 
10455 	},
10456 	{
10457 		{
10458 			.vendor_id = OUI_GOOGLE,
10459 			.subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
10460 		},
10461 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10462 		.doit = wl_cfgvendor_set_lazy_roam_cfg
10463 
10464 	},
10465 	{
10466 		{
10467 			.vendor_id = OUI_GOOGLE,
10468 			.subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM
10469 		},
10470 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10471 		.doit = wl_cfgvendor_enable_lazy_roam
10472 
10473 	},
10474 	{
10475 		{
10476 			.vendor_id = OUI_GOOGLE,
10477 			.subcmd = WIFI_SUBCMD_SET_BSSID_PREF
10478 		},
10479 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10480 		.doit = wl_cfgvendor_set_bssid_pref
10481 
10482 	},
10483 #endif /* GSCAN_SUPPORT */
10484 #if defined(GSCAN_SUPPORT) || defined(ROAMEXP_SUPPORT)
10485 	{
10486 		{
10487 			.vendor_id = OUI_GOOGLE,
10488 			.subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST
10489 		},
10490 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10491 		.doit = wl_cfgvendor_set_ssid_whitelist,
10492 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10493 		.policy = gscan_attr_policy,
10494 		.maxattr = GSCAN_ATTRIBUTE_MAX
10495 #endif /* LINUX_VERSION >= 5.3 */
10496 
10497 	},
10498 	{
10499 		{
10500 			.vendor_id = OUI_GOOGLE,
10501 			.subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST
10502 		},
10503 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10504 		.doit = wl_cfgvendor_set_bssid_blacklist,
10505 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10506 		.policy = gscan_attr_policy,
10507 		.maxattr = GSCAN_ATTRIBUTE_MAX
10508 #endif /* LINUX_VERSION >= 5.3 */
10509 	},
10510 #endif /* GSCAN_SUPPORT || ROAMEXP_SUPPORT */
10511 #ifdef ROAMEXP_SUPPORT
10512 	{
10513 		{
10514 			.vendor_id = OUI_GOOGLE,
10515 			.subcmd = WIFI_SUBCMD_FW_ROAM_POLICY
10516 		},
10517 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10518 		.doit = wl_cfgvendor_set_fw_roaming_state,
10519 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10520 		.policy = gscan_attr_policy,
10521 		.maxattr = GSCAN_ATTRIBUTE_MAX
10522 #endif /* LINUX_VERSION >= 5.3 */
10523 	},
10524 	{
10525 		{
10526 			.vendor_id = OUI_GOOGLE,
10527 			.subcmd = WIFI_SUBCMD_ROAM_CAPABILITY
10528 		},
10529 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10530 		.doit = wl_cfgvendor_fw_roam_get_capability
10531 	},
10532 #endif /* ROAMEXP_SUPPORT */
10533 	{
10534 		{
10535 			.vendor_id = OUI_GOOGLE,
10536 			.subcmd = DEBUG_GET_VER
10537 		},
10538 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10539 		.doit = wl_cfgvendor_dbg_get_version,
10540 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10541 		.policy = andr_dbg_policy,
10542 		.maxattr = DEBUG_ATTRIBUTE_MAX
10543 #endif /* LINUX_VERSION >= 5.3 */
10544 	},
10545 #ifdef DHD_LOG_DUMP
10546 	{
10547 		{
10548 			.vendor_id = OUI_GOOGLE,
10549 			.subcmd = DEBUG_GET_FILE_DUMP_BUF
10550 		},
10551 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10552 		.doit = wl_cfgvendor_dbg_file_dump,
10553 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10554 		.policy = dump_buf_policy,
10555 		.maxattr = DUMP_BUF_ATTR_MAX
10556 #endif /* LINUX_VERSION >= 5.3 */
10557 	},
10558 #endif /* DHD_LOG_DUMP */
10559 
10560 #ifdef DEBUGABILITY
10561 	{
10562 		{
10563 			.vendor_id = OUI_GOOGLE,
10564 			.subcmd = DEBUG_TRIGGER_MEM_DUMP
10565 		},
10566 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10567 		.doit = wl_cfgvendor_dbg_trigger_mem_dump
10568 	},
10569 	{
10570 		{
10571 			.vendor_id = OUI_GOOGLE,
10572 			.subcmd = DEBUG_GET_MEM_DUMP
10573 		},
10574 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10575 		.doit = wl_cfgvendor_dbg_get_mem_dump,
10576 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10577 		.policy = andr_dbg_policy,
10578 		.maxattr = DEBUG_ATTRIBUTE_MAX
10579 #endif /* LINUX_VERSION >= 5.3 */
10580 	},
10581 	{
10582 		{
10583 			.vendor_id = OUI_GOOGLE,
10584 			.subcmd = DEBUG_START_LOGGING
10585 		},
10586 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10587 		.doit = wl_cfgvendor_dbg_start_logging,
10588 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10589 		.policy = andr_dbg_policy,
10590 		.maxattr = DEBUG_ATTRIBUTE_MAX
10591 #endif /* LINUX_VERSION >= 5.3 */
10592 	},
10593 	{
10594 		{
10595 			.vendor_id = OUI_GOOGLE,
10596 			.subcmd = DEBUG_RESET_LOGGING
10597 		},
10598 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10599 		.doit = wl_cfgvendor_dbg_reset_logging
10600 	},
10601 	{
10602 		{
10603 			.vendor_id = OUI_GOOGLE,
10604 			.subcmd = DEBUG_GET_RING_STATUS
10605 		},
10606 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10607 		.doit = wl_cfgvendor_dbg_get_ring_status,
10608 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10609 		.policy = andr_dbg_policy,
10610 		.maxattr = DEBUG_ATTRIBUTE_MAX
10611 #endif /* LINUX_VERSION >= 5.3 */
10612 	},
10613 	{
10614 		{
10615 			.vendor_id = OUI_GOOGLE,
10616 			.subcmd = DEBUG_GET_RING_DATA
10617 		},
10618 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10619 		.doit = wl_cfgvendor_dbg_get_ring_data,
10620 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10621 		.policy = andr_dbg_policy,
10622 		.maxattr = DEBUG_ATTRIBUTE_MAX
10623 #endif /* LINUX_VERSION >= 5.3 */
10624 	},
10625 #endif /* DEBUGABILITY */
10626 	{
10627 		{
10628 			.vendor_id = OUI_GOOGLE,
10629 			.subcmd = DEBUG_GET_FEATURE
10630 		},
10631 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10632 		.doit = wl_cfgvendor_dbg_get_feature
10633 	},
10634 #ifdef DBG_PKT_MON
10635 	{
10636 		{
10637 			.vendor_id = OUI_GOOGLE,
10638 			.subcmd = DEBUG_START_PKT_FATE_MONITORING
10639 		},
10640 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10641 		.doit = wl_cfgvendor_dbg_start_pkt_fate_monitoring
10642 	},
10643 	{
10644 		{
10645 			.vendor_id = OUI_GOOGLE,
10646 			.subcmd = DEBUG_GET_TX_PKT_FATES
10647 		},
10648 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10649 		.doit = wl_cfgvendor_dbg_get_tx_pkt_fates,
10650 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10651 		.policy = andr_dbg_policy,
10652 		.maxattr = DEBUG_ATTRIBUTE_MAX
10653 #endif /* LINUX_VERSION >= 5.3 */
10654 	},
10655 	{
10656 		{
10657 			.vendor_id = OUI_GOOGLE,
10658 			.subcmd = DEBUG_GET_RX_PKT_FATES
10659 		},
10660 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10661 		.doit = wl_cfgvendor_dbg_get_rx_pkt_fates,
10662 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10663 		.policy = andr_dbg_policy,
10664 		.maxattr = DEBUG_ATTRIBUTE_MAX
10665 #endif /* LINUX_VERSION >= 5.3 */
10666 	},
10667 #endif /* DBG_PKT_MON */
10668 #ifdef KEEP_ALIVE
10669 	{
10670 		{
10671 			.vendor_id = OUI_GOOGLE,
10672 			.subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
10673 		},
10674 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10675 		.doit = wl_cfgvendor_start_mkeep_alive,
10676 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10677 		.policy = mkeep_alive_attr_policy,
10678 		.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
10679 #endif /* LINUX_VERSION >= 5.3 */
10680 	},
10681 	{
10682 		{
10683 			.vendor_id = OUI_GOOGLE,
10684 			.subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
10685 		},
10686 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10687 		.doit = wl_cfgvendor_stop_mkeep_alive,
10688 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10689 		.policy = mkeep_alive_attr_policy,
10690 		.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
10691 #endif /* LINUX_VERSION >= 5.3 */
10692 	},
10693 #endif /* KEEP_ALIVE */
10694 #ifdef WL_NAN
10695 	{
10696 		{
10697 			.vendor_id = OUI_GOOGLE,
10698 			.subcmd = NAN_WIFI_SUBCMD_ENABLE
10699 		},
10700 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10701 		.doit = wl_cfgvendor_nan_start_handler,
10702 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10703 		.policy = nan_attr_policy,
10704 		.maxattr = NAN_ATTRIBUTE_MAX
10705 #endif /* LINUX_VERSION >= 5.3 */
10706 	},
10707 	{
10708 		{
10709 			.vendor_id = OUI_GOOGLE,
10710 			.subcmd = NAN_WIFI_SUBCMD_DISABLE
10711 		},
10712 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10713 		.doit = wl_cfgvendor_nan_stop_handler,
10714 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10715 		.policy = nan_attr_policy,
10716 		.maxattr = NAN_ATTRIBUTE_MAX
10717 #endif /* LINUX_VERSION >= 5.3 */
10718 	},
10719 	{
10720 		{
10721 			.vendor_id = OUI_GOOGLE,
10722 			.subcmd = NAN_WIFI_SUBCMD_CONFIG
10723 		},
10724 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10725 		.doit = wl_cfgvendor_nan_config_handler,
10726 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10727 		.policy = nan_attr_policy,
10728 		.maxattr = NAN_ATTRIBUTE_MAX
10729 #endif /* LINUX_VERSION >= 5.3 */
10730 	},
10731 	{
10732 		{
10733 			.vendor_id = OUI_GOOGLE,
10734 			.subcmd = NAN_WIFI_SUBCMD_REQUEST_PUBLISH
10735 		},
10736 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10737 		.doit = wl_cfgvendor_nan_req_publish,
10738 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10739 		.policy = nan_attr_policy,
10740 		.maxattr = NAN_ATTRIBUTE_MAX
10741 #endif /* LINUX_VERSION >= 5.3 */
10742 	},
10743 	{
10744 		{
10745 			.vendor_id = OUI_GOOGLE,
10746 			.subcmd = NAN_WIFI_SUBCMD_REQUEST_SUBSCRIBE
10747 		},
10748 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10749 		.doit = wl_cfgvendor_nan_req_subscribe,
10750 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10751 		.policy = nan_attr_policy,
10752 		.maxattr = NAN_ATTRIBUTE_MAX
10753 #endif /* LINUX_VERSION >= 5.3 */
10754 	},
10755 	{
10756 		{
10757 			.vendor_id = OUI_GOOGLE,
10758 			.subcmd = NAN_WIFI_SUBCMD_CANCEL_PUBLISH
10759 		},
10760 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10761 		.doit = wl_cfgvendor_nan_cancel_publish,
10762 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10763 		.policy = nan_attr_policy,
10764 		.maxattr = NAN_ATTRIBUTE_MAX
10765 #endif /* LINUX_VERSION >= 5.3 */
10766 	},
10767 	{
10768 		{
10769 			.vendor_id = OUI_GOOGLE,
10770 			.subcmd = NAN_WIFI_SUBCMD_CANCEL_SUBSCRIBE
10771 		},
10772 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10773 		.doit = wl_cfgvendor_nan_cancel_subscribe,
10774 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10775 		.policy = nan_attr_policy,
10776 		.maxattr = NAN_ATTRIBUTE_MAX
10777 #endif /* LINUX_VERSION >= 5.3 */
10778 	},
10779 	{
10780 		{
10781 			.vendor_id = OUI_GOOGLE,
10782 			.subcmd = NAN_WIFI_SUBCMD_TRANSMIT
10783 		},
10784 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10785 		.doit = wl_cfgvendor_nan_transmit,
10786 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10787 		.policy = nan_attr_policy,
10788 		.maxattr = NAN_ATTRIBUTE_MAX
10789 #endif /* LINUX_VERSION >= 5.3 */
10790 	},
10791 	{
10792 		{
10793 			.vendor_id = OUI_GOOGLE,
10794 			.subcmd = NAN_WIFI_SUBCMD_GET_CAPABILITIES
10795 		},
10796 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10797 		.doit = wl_cfgvendor_nan_get_capablities
10798 	},
10799 
10800 	{
10801 		{
10802 			.vendor_id = OUI_GOOGLE,
10803 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE
10804 		},
10805 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10806 		.doit = wl_cfgvendor_nan_data_path_iface_create,
10807 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10808 		.policy = nan_attr_policy,
10809 		.maxattr = NAN_ATTRIBUTE_MAX
10810 #endif /* LINUX_VERSION >= 5.3 */
10811 	},
10812 	{
10813 		{
10814 			.vendor_id = OUI_GOOGLE,
10815 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE
10816 		},
10817 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10818 		.doit = wl_cfgvendor_nan_data_path_iface_delete,
10819 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10820 		.policy = nan_attr_policy,
10821 		.maxattr = NAN_ATTRIBUTE_MAX
10822 #endif /* LINUX_VERSION >= 5.3 */
10823 	},
10824 	{
10825 		{
10826 			.vendor_id = OUI_GOOGLE,
10827 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_REQUEST
10828 		},
10829 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10830 		.doit = wl_cfgvendor_nan_data_path_request,
10831 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10832 		.policy = nan_attr_policy,
10833 		.maxattr = NAN_ATTRIBUTE_MAX
10834 #endif /* LINUX_VERSION >= 5.3 */
10835 	},
10836 	{
10837 		{
10838 			.vendor_id = OUI_GOOGLE,
10839 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_RESPONSE
10840 		},
10841 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10842 		.doit = wl_cfgvendor_nan_data_path_response,
10843 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10844 		.policy = nan_attr_policy,
10845 		.maxattr = NAN_ATTRIBUTE_MAX
10846 #endif /* LINUX_VERSION >= 5.3 */
10847 	},
10848 	{
10849 		{
10850 			.vendor_id = OUI_GOOGLE,
10851 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_END
10852 		},
10853 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10854 		.doit = wl_cfgvendor_nan_data_path_end,
10855 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10856 		.policy = nan_attr_policy,
10857 		.maxattr = NAN_ATTRIBUTE_MAX
10858 #endif /* LINUX_VERSION >= 5.3 */
10859 	},
10860 #ifdef WL_NAN_DISC_CACHE
10861 	{
10862 		{
10863 			.vendor_id = OUI_GOOGLE,
10864 			.subcmd = NAN_WIFI_SUBCMD_DATA_PATH_SEC_INFO
10865 		},
10866 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10867 		.doit = wl_cfgvendor_nan_data_path_sec_info,
10868 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10869 		.policy = nan_attr_policy,
10870 		.maxattr = NAN_ATTRIBUTE_MAX
10871 #endif /* LINUX_VERSION >= 5.3 */
10872 	},
10873 #endif /* WL_NAN_DISC_CACHE */
10874 	{
10875 		{
10876 			.vendor_id = OUI_GOOGLE,
10877 			.subcmd = NAN_WIFI_SUBCMD_VERSION_INFO
10878 		},
10879 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10880 		.doit = wl_cfgvendor_nan_version_info
10881 	},
10882 	{
10883 		{
10884 			.vendor_id = OUI_GOOGLE,
10885 			.subcmd = NAN_WIFI_SUBCMD_ENABLE_MERGE
10886 		},
10887 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10888 		.doit = wl_cfgvendor_nan_enable_merge,
10889 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10890 		.policy = nan_attr_policy,
10891 		.maxattr = NAN_ATTRIBUTE_MAX
10892 #endif /* LINUX_VERSION >= 5.3 */
10893 	},
10894 #endif /* WL_NAN */
10895 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
10896 	{
10897 		{
10898 			.vendor_id = OUI_GOOGLE,
10899 			.subcmd = APF_SUBCMD_GET_CAPABILITIES
10900 		},
10901 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10902 		.doit = wl_cfgvendor_apf_get_capabilities,
10903 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10904 		.policy = apf_atrribute_policy,
10905 		.maxattr = APF_ATTRIBUTE_MAX
10906 #endif /* LINUX_VERSION >= 5.3 */
10907 	},
10908 
10909 	{
10910 		{
10911 			.vendor_id = OUI_GOOGLE,
10912 			.subcmd = APF_SUBCMD_SET_FILTER
10913 		},
10914 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10915 		.doit = wl_cfgvendor_apf_set_filter,
10916 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10917 		.policy = apf_atrribute_policy,
10918 		.maxattr = APF_ATTRIBUTE_MAX
10919 #endif /* LINUX_VERSION >= 5.3 */
10920 	},
10921 #endif /* PKT_FILTER_SUPPORT && APF */
10922 #ifdef NDO_CONFIG_SUPPORT
10923 	{
10924 		{
10925 			.vendor_id = OUI_GOOGLE,
10926 			.subcmd = WIFI_SUBCMD_CONFIG_ND_OFFLOAD
10927 		},
10928 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10929 		.doit = wl_cfgvendor_configure_nd_offload,
10930 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10931 		.policy = andr_wifi_attr_policy,
10932 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10933 #endif /* LINUX_VERSION >= 5.3 */
10934 	},
10935 #endif /* NDO_CONFIG_SUPPORT */
10936 #ifdef RSSI_MONITOR_SUPPORT
10937 	{
10938 		{
10939 			.vendor_id = OUI_GOOGLE,
10940 			.subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR
10941 		},
10942 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10943 		.doit = wl_cfgvendor_set_rssi_monitor,
10944 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10945 		.policy = rssi_monitor_attr_policy,
10946 		.maxattr = RSSI_MONITOR_ATTRIBUTE_MAX
10947 #endif /* LINUX_VERSION >= 5.3 */
10948 	},
10949 #endif /* RSSI_MONITOR_SUPPORT */
10950 #ifdef DHD_WAKE_STATUS
10951 	{
10952 		{
10953 			.vendor_id = OUI_GOOGLE,
10954 			.subcmd = DEBUG_GET_WAKE_REASON_STATS
10955 		},
10956 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10957 		.doit = wl_cfgvendor_get_wake_reason_stats,
10958 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10959 		.policy = wake_stat_attr_policy,
10960 		.maxattr = WAKE_STAT_ATTRIBUTE_MAX
10961 #endif /* LINUX_VERSION >= 5.3 */
10962 	},
10963 #endif /* DHD_WAKE_STATUS */
10964 #ifdef DHDTCPACK_SUPPRESS
10965 	{
10966 		{
10967 			.vendor_id = OUI_GOOGLE,
10968 			.subcmd = WIFI_SUBCMD_CONFIG_TCPACK_SUP
10969 		},
10970 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10971 		.doit = wl_cfgvendor_set_tcpack_sup_mode,
10972 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10973 		.policy = andr_wifi_attr_policy,
10974 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10975 #endif /* LINUX_VERSION >= 5.3 */
10976 	},
10977 #endif /* DHDTCPACK_SUPPRESS */
10978 #if !defined(BCMSUP_4WAY_HANDSHAKE) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
10979 	{
10980 		{
10981 			.vendor_id = OUI_BRCM,
10982 			.subcmd = BRCM_VENDOR_SCMD_SET_PMK
10983 		},
10984 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10985 		.doit = wl_cfgvendor_set_pmk,
10986 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10987 		.policy = brcm_drv_attr_policy,
10988 		.maxattr = BRCM_ATTR_DRIVER_MAX
10989 #endif /* LINUX_VERSION >= 5.3 */
10990 	},
10991 #endif /* !BCMSUP_4WAY_HANDSHAKE || LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
10992 	{
10993 		{
10994 			.vendor_id = OUI_BRCM,
10995 			.subcmd = BRCM_VENDOR_SCMD_GET_FEATURES
10996 		},
10997 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10998 		.doit = wl_cfgvendor_get_driver_feature,
10999 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11000 		.policy = brcm_drv_attr_policy,
11001 		.maxattr = BRCM_ATTR_DRIVER_MAX
11002 #endif /* LINUX_VERSION >= 5.3 */
11003 	},
11004 #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT)
11005 	{
11006 		{
11007 			.vendor_id = OUI_GOOGLE,
11008 			.subcmd = DEBUG_FILE_DUMP_DONE_IND
11009 		},
11010 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11011 		.doit = wl_cfgvendor_notify_dump_completion
11012 	},
11013 #endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */
11014 #if defined(WL_CFG80211)
11015 	{
11016 		{
11017 			.vendor_id = OUI_GOOGLE,
11018 			.subcmd = DEBUG_SET_HAL_START
11019 		},
11020 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11021 		.doit = wl_cfgvendor_set_hal_started,
11022 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11023 		.policy = hal_start_attr_policy,
11024 		.maxattr = SET_HAL_START_ATTRIBUTE_MAX
11025 #endif /* LINUX_VERSION >= 5.3 */
11026 	},
11027 	{
11028 		{
11029 			.vendor_id = OUI_GOOGLE,
11030 			.subcmd = DEBUG_SET_HAL_STOP
11031 		},
11032 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11033 		.doit = wl_cfgvendor_stop_hal
11034 	},
11035 	{
11036 		{
11037 			.vendor_id = OUI_GOOGLE,
11038 			.subcmd = DEBUG_SET_HAL_PID
11039 		},
11040 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11041 		.doit = wl_cfgvendor_set_hal_pid,
11042 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11043 		.policy = hal_start_attr_policy,
11044 		.maxattr = SET_HAL_START_ATTRIBUTE_MAX
11045 #endif /* LINUX_VERSION >= 5.3 */
11046 	},
11047 #endif /* WL_CFG80211 */
11048 #ifdef WL_LATENCY_MODE
11049 	{
11050 		{
11051 			.vendor_id = OUI_GOOGLE,
11052 			.subcmd = WIFI_SUBCMD_SET_LATENCY_MODE
11053 		},
11054 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11055 		.doit = wl_cfgvendor_set_latency_mode,
11056 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11057 		.policy = andr_wifi_attr_policy,
11058 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
11059 #endif /* LINUX_VERSION >= 5.3 */
11060 	},
11061 #endif /* WL_LATENCY_MODE */
11062 #ifdef WL_P2P_RAND
11063 	{
11064 		{
11065 			.vendor_id = OUI_BRCM,
11066 			.subcmd = BRCM_VENDOR_SCMD_SET_MAC
11067 		},
11068 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV,
11069 		.doit = wl_cfgvendor_set_p2p_rand_mac,
11070 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11071 		.policy = brcm_drv_attr_policy,
11072 		.maxattr = BRCM_ATTR_DRIVER_MAX
11073 #endif /* LINUX_VERSION >= 5.3 */
11074 	},
11075 #endif /* WL_P2P_RAND */
11076 #ifdef WL_SAR_TX_POWER
11077 	{
11078 		{
11079 			.vendor_id = OUI_GOOGLE,
11080 			.subcmd = WIFI_SUBCMD_TX_POWER_SCENARIO
11081 		},
11082 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV,
11083 		.doit = wl_cfgvendor_tx_power_scenario,
11084 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11085 		.policy = andr_wifi_attr_policy,
11086 		.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
11087 #endif /* LINUX_VERSION >= 5.3 */
11088 	}
11089 #endif /* WL_SAR_TX_POWER */
11090 #if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
11091 	{
11092 		{
11093 			.vendor_id = OUI_GOOGLE,
11094 			.subcmd = ANDR_TWT_SUBCMD_SETUP
11095 		},
11096 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11097 		.doit = wl_cfgvendor_twt_setup,
11098 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11099 		.policy = andr_twt_attr_policy,
11100 		.maxattr = ANDR_TWT_ATTR_MAX
11101 #endif /* LINUX_VERSION >= 5.3 */
11102 	},
11103 	{
11104 		{
11105 			.vendor_id = OUI_GOOGLE,
11106 			.subcmd = ANDR_TWT_SUBCMD_TEARDOWN
11107 		},
11108 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11109 		.doit = wl_cfgvendor_twt_teardown,
11110 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11111 		.policy = andr_twt_attr_policy,
11112 		.maxattr = ANDR_TWT_ATTR_MAX
11113 #endif /* LINUX_VERSION >= 5.3 */
11114 	},
11115 	{
11116 		{
11117 			.vendor_id = OUI_GOOGLE,
11118 			.subcmd = ANDR_TWT_SUBCMD_INFO_FRAME
11119 		},
11120 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11121 		.doit = wl_cfgvendor_twt_info_frame,
11122 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11123 		.policy = andr_twt_attr_policy,
11124 		.maxattr = ANDR_TWT_ATTR_MAX
11125 #endif /* LINUX_VERSION >= 5.3 */
11126 	},
11127 	{
11128 		{
11129 			.vendor_id = OUI_GOOGLE,
11130 			.subcmd = ANDR_TWT_SUBCMD_GET_CAP
11131 		},
11132 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11133 		.doit = wl_cfgvendor_twt_cap,
11134 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11135 		.policy = andr_twt_attr_policy,
11136 		.maxattr = ANDR_TWT_ATTR_MAX
11137 #endif /* LINUX_VERSION >= 5.3 */
11138 	},
11139 	{
11140 		{
11141 			.vendor_id = OUI_GOOGLE,
11142 			.subcmd = ANDR_TWT_SUBCMD_GET_STATS
11143 		},
11144 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11145 		.doit = wl_cfgvendor_twt_get_stats,
11146 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11147 		.policy = andr_twt_attr_policy,
11148 		.maxattr = ANDR_TWT_ATTR_MAX
11149 #endif /* LINUX_VERSION >= 5.3 */
11150 	},
11151 	{
11152 		{
11153 			.vendor_id = OUI_GOOGLE,
11154 			.subcmd = ANDR_TWT_SUBCMD_CLR_STATS
11155 		},
11156 		.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11157 		.doit = wl_cfgvendor_twt_clear_stats,
11158 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11159 		.policy = andr_twt_attr_policy,
11160 		.maxattr = ANDR_TWT_ATTR_MAX
11161 #endif /* LINUX_VERSION >= 5.3 */
11162 	},
11163 #endif /* !WL_TWT && WL_TWT_HAL_IF */
11164 
11165 };
11166 
11167 static const struct  nl80211_vendor_cmd_info wl_vendor_events [] = {
11168 		{ OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
11169 		{ OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
11170 		{ OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
11171 		{ OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
11172 		{ OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
11173 		{ OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
11174 		{ OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
11175 		{ OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
11176 		{ OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT },
11177 		{ OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
11178 		{ OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
11179 		{ OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
11180 		{ OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
11181 		{ OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
11182 		{ OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT },
11183 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_ENABLED},
11184 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DISABLED},
11185 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH},
11186 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_REPLIED},
11187 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_PUBLISH_TERMINATED},
11188 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED},
11189 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DE_EVENT},
11190 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_FOLLOWUP},
11191 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND},
11192 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_REQUEST},
11193 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_CONFIRMATION},
11194 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_END},
11195 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_BEACON},
11196 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_SDF},
11197 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_TCA},
11198 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH},
11199 		{ OUI_GOOGLE, GOOGLE_NAN_EVENT_UNKNOWN},
11200 		{ OUI_GOOGLE, GOOGLE_ROAM_EVENT_START},
11201 		{ OUI_BRCM, BRCM_VENDOR_EVENT_HANGED},
11202 		{ OUI_BRCM, BRCM_VENDOR_EVENT_SAE_KEY},
11203 		{ OUI_BRCM, BRCM_VENDOR_EVENT_BEACON_RECV},
11204 		{ OUI_BRCM, BRCM_VENDOR_EVENT_PORT_AUTHORIZED},
11205 		{ OUI_GOOGLE, GOOGLE_FILE_DUMP_EVENT },
11206 		{ OUI_BRCM, BRCM_VENDOR_EVENT_CU},
11207 		{ OUI_BRCM, BRCM_VENDOR_EVENT_WIPS},
11208 		{ OUI_GOOGLE, NAN_ASYNC_RESPONSE_DISABLED},
11209 		{ OUI_BRCM, BRCM_VENDOR_EVENT_RCC_INFO},
11210 		{OUI_BRCM, BRCM_VENDOR_EVENT_TWT}
11211 };
11212 
11213 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11214 static void
wl_cfgvendor_apply_cmd_policy(struct wiphy * wiphy)11215 wl_cfgvendor_apply_cmd_policy(struct wiphy *wiphy)
11216 {
11217 	int i;
11218 	u32 n_cmds = wiphy->n_vendor_commands;
11219 
11220 	WL_INFORM(("Apply CMD_RAW_DATA policy\n"));
11221 	for (i = 0; i < n_cmds; i++) {
11222 		if (wl_vendor_cmds[i].policy == NULL) {
11223 			wl_vendor_cmds[i].policy = VENDOR_CMD_RAW_DATA;
11224 		}
11225 	}
11226 }
11227 #endif /* LINUX VER >= 5.3 */
11228 
wl_cfgvendor_attach(struct wiphy * wiphy,dhd_pub_t * dhd)11229 int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd)
11230 {
11231 
11232 	WL_INFORM_MEM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
11233 		NL80211_CMD_VENDOR));
11234 
11235 	wiphy->vendor_commands	= wl_vendor_cmds;
11236 	wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
11237 
11238 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11239 	wl_cfgvendor_apply_cmd_policy(wiphy);
11240 #endif /* LINUX VER >= 5.3 */
11241 
11242 	wiphy->vendor_events	= wl_vendor_events;
11243 	wiphy->n_vendor_events	= ARRAY_SIZE(wl_vendor_events);
11244 
11245 #ifdef DEBUGABILITY
11246 	dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
11247 	dhd_os_dbg_register_callback(DHD_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
11248 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
11249 	dhd_os_dbg_register_callback(DRIVER_LOG_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
11250 	dhd_os_dbg_register_callback(ROAM_STATS_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
11251 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
11252 #endif /* DEBUGABILITY */
11253 #ifdef DHD_LOG_DUMP
11254 	dhd_os_dbg_register_urgent_notifier(dhd, wl_cfgvendor_dbg_send_file_dump_evt);
11255 #endif /* DHD_LOG_DUMP */
11256 
11257 	return 0;
11258 }
11259 
wl_cfgvendor_detach(struct wiphy * wiphy)11260 int wl_cfgvendor_detach(struct wiphy *wiphy)
11261 {
11262 	WL_INFORM_MEM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
11263 
11264 	wiphy->vendor_commands  = NULL;
11265 	wiphy->vendor_events    = NULL;
11266 	wiphy->n_vendor_commands = 0;
11267 	wiphy->n_vendor_events  = 0;
11268 
11269 	return 0;
11270 }
11271 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
11272 
11273 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
11274 void
wl_cfgvendor_send_hang_event(struct net_device * dev,u16 reason,char * string,int hang_info_cnt)11275 wl_cfgvendor_send_hang_event(struct net_device *dev, u16 reason, char *string, int hang_info_cnt)
11276 {
11277 	struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11278 	struct wiphy *wiphy;
11279 	char *hang_info;
11280 	int len = 0;
11281 	int bytes_written;
11282 	uint32 dummy_data = 0;
11283 	int reason_hang_info = 0;
11284 	int cnt = 0;
11285 	dhd_pub_t *dhd;
11286 	int hang_reason_mismatch = FALSE;
11287 
11288 	if (!cfg || !cfg->wdev) {
11289 		WL_ERR(("cfg=%p wdev=%p\n", cfg, (cfg ? cfg->wdev : NULL)));
11290 		return;
11291 	}
11292 
11293 	wiphy = cfg->wdev->wiphy;
11294 
11295 	if (!wiphy) {
11296 		WL_ERR(("wiphy is NULL\n"));
11297 		return;
11298 	}
11299 
11300 	hang_info = MALLOCZ(cfg->osh, VENDOR_SEND_HANG_EXT_INFO_LEN);
11301 	if (hang_info == NULL) {
11302 		WL_ERR(("alloc hang_info failed\n"));
11303 		return;
11304 	}
11305 
11306 	dhd = (dhd_pub_t *)(cfg->pub);
11307 
11308 #ifdef WL_BCNRECV
11309 	/* check fakeapscan in progress then stop scan */
11310 	if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
11311 		wl_android_bcnrecv_stop(dev, WL_BCNRECV_HANG);
11312 	}
11313 #endif /* WL_BCNRECV */
11314 	sscanf(string, "%d", &reason_hang_info);
11315 	bytes_written = 0;
11316 	len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
11317 	if (strlen(string) == 0 || (reason_hang_info != reason)) {
11318 		WL_ERR(("hang reason mismatch: string len %d reason_hang_info %d\n",
11319 			(int)strlen(string), reason_hang_info));
11320 		hang_reason_mismatch = TRUE;
11321 		if (dhd) {
11322 			get_debug_dump_time(dhd->debug_dump_time_hang_str);
11323 			copy_debug_dump_time(dhd->debug_dump_time_str,
11324 					dhd->debug_dump_time_hang_str);
11325 		}
11326 		/* Fill bigdata key with */
11327 		bytes_written += scnprintf(&hang_info[bytes_written], len,
11328 				"%d %d %s %08x %08x %08x %08x %08x %08x %08x",
11329 				reason, VENDOR_SEND_HANG_EXT_INFO_VER,
11330 				dhd->debug_dump_time_hang_str,
11331 				0, 0, 0, 0, 0, 0, 0);
11332 		if (dhd) {
11333 			clear_debug_dump_time(dhd->debug_dump_time_hang_str);
11334 		}
11335 	} else {
11336 		bytes_written += scnprintf(&hang_info[bytes_written], len, "%s", string);
11337 	}
11338 
11339 	WL_ERR(("hang reason: %d info cnt: %d\n", reason, hang_info_cnt));
11340 
11341 	if (hang_reason_mismatch == FALSE) {
11342 		cnt = hang_info_cnt;
11343 	} else {
11344 		cnt = HANG_FIELD_MISMATCH_CNT;
11345 	}
11346 
11347 	while (cnt < HANG_FIELD_CNT_MAX) {
11348 		len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
11349 		if (len <= 0) {
11350 			break;
11351 		}
11352 		bytes_written += scnprintf(&hang_info[bytes_written], len,
11353 				"%c%08x", HANG_RAW_DEL, dummy_data);
11354 		cnt++;
11355 	}
11356 
11357 	WL_ERR(("hang info cnt: %d len: %d\n", cnt, (int)strlen(hang_info)));
11358 	WL_ERR(("hang info data: %s\n", hang_info));
11359 
11360 	wl_cfgvendor_send_async_event(wiphy,
11361 			bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_HANGED,
11362 			hang_info, (int)strlen(hang_info));
11363 
11364 	memset(string, 0, VENDOR_SEND_HANG_EXT_INFO_LEN);
11365 
11366 	if (hang_info) {
11367 		MFREE(cfg->osh, hang_info, VENDOR_SEND_HANG_EXT_INFO_LEN);
11368 	}
11369 
11370 #ifdef DHD_LOG_DUMP
11371 	dhd_logdump_cookie_save(dhd, dhd->debug_dump_time_hang_str, "HANG");
11372 #endif /*  DHD_LOG_DUMP */
11373 
11374 	if (dhd) {
11375 		clear_debug_dump_time(dhd->debug_dump_time_str);
11376 	}
11377 }
11378 
11379 void
wl_cfgvendor_simple_hang_event(struct net_device * dev,u16 reason)11380 wl_cfgvendor_simple_hang_event(struct net_device *dev, u16 reason)
11381 {
11382 	struct bcm_cfg80211 *cfg;
11383 	struct wiphy *wiphy;
11384 	struct sk_buff *msg;
11385 	gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
11386 	int hang_event_len = 0;
11387 #ifdef DHD_COREDUMP
11388 	dhd_pub_t *dhd;
11389 #endif
11390 	WL_ERR(("0x%x\n", reason));
11391 
11392 	cfg = wl_cfg80211_get_bcmcfg();
11393 	if (!cfg || !cfg->wdev) {
11394 		WL_ERR(("fw dump evt invalid arg\n"));
11395 		return;
11396 	}
11397 
11398 	wiphy = bcmcfg_to_wiphy(cfg);
11399 	if (!wiphy) {
11400 		WL_ERR(("wiphy is NULL\n"));
11401 		return;
11402 	}
11403 
11404 #ifdef DHD_COREDUMP
11405 	hang_event_len = DHD_MEMDUMP_LONGSTR_LEN;
11406 #endif
11407 
11408 	/* Allocate the skb for vendor event */
11409 	msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(dev),
11410 			hang_event_len, BRCM_VENDOR_EVENT_HANGED, kflags);
11411 	if (!msg) {
11412 		WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
11413 		return;
11414 	}
11415 
11416 #ifdef DHD_COREDUMP
11417 	dhd = (dhd_pub_t *)(cfg->pub);
11418 
11419 	WL_ERR(("hang reason: %s\n", dhd->memdump_str));
11420 	nla_put(msg, DEBUG_ATTRIBUTE_HANG_REASON, DHD_MEMDUMP_LONGSTR_LEN, dhd->memdump_str);
11421 #endif
11422 
11423 	cfg80211_vendor_event(msg, kflags);
11424 	return;
11425 }
11426 
11427 void
wl_copy_hang_info_if_falure(struct net_device * dev,u16 reason,s32 ret)11428 wl_copy_hang_info_if_falure(struct net_device *dev, u16 reason, s32 ret)
11429 {
11430 	struct bcm_cfg80211 *cfg = NULL;
11431 	dhd_pub_t *dhd;
11432 	s32 err = 0;
11433 	char ioctl_buf[WLC_IOCTL_SMLEN];
11434 	memuse_info_t mu;
11435 	int bytes_written = 0;
11436 	int remain_len = 0;
11437 
11438 	if (!dev) {
11439 		WL_ERR(("dev is null"));
11440 		return;
11441 
11442 	}
11443 
11444 	cfg = wl_get_cfg(dev);
11445 	if (!cfg) {
11446 		WL_ERR(("dev=%p cfg=%p\n", dev, cfg));
11447 		return;
11448 	}
11449 
11450 	dhd = (dhd_pub_t *)(cfg->pub);
11451 
11452 	if (!dhd || !dhd->hang_info) {
11453 		WL_ERR(("%s dhd=%p hang_info=%p\n", __FUNCTION__,
11454 			dhd, (dhd ? dhd->hang_info : NULL)));
11455 		return;
11456 	}
11457 
11458 	err = wldev_iovar_getbuf_bsscfg(dev, "memuse",
11459 			NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
11460 	if (unlikely(err)) {
11461 		WL_ERR(("error (%d)\n", err));
11462 		return;
11463 	}
11464 
11465 	memcpy(&mu, ioctl_buf, sizeof(memuse_info_t));
11466 
11467 	if (mu.len >= sizeof(memuse_info_t)) {
11468 		WL_ERR(("Heap Total: %d(%dK)\n", mu.arena_size, KB(mu.arena_size)));
11469 		WL_ERR(("Free: %d(%dK), LWM: %d(%dK)\n",
11470 			mu.arena_free, KB(mu.arena_free),
11471 			mu.free_lwm, KB(mu.free_lwm)));
11472 		WL_ERR(("In use: %d(%dK), HWM: %d(%dK)\n",
11473 			mu.inuse_size, KB(mu.inuse_size),
11474 			mu.inuse_hwm, KB(mu.inuse_hwm)));
11475 		WL_ERR(("Malloc failure count: %d\n", mu.mf_count));
11476 	}
11477 
11478 	memset(dhd->hang_info, 0, VENDOR_SEND_HANG_EXT_INFO_LEN);
11479 	remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
11480 
11481 	get_debug_dump_time(dhd->debug_dump_time_hang_str);
11482 	copy_debug_dump_time(dhd->debug_dump_time_str, dhd->debug_dump_time_hang_str);
11483 
11484 	bytes_written += scnprintf(&dhd->hang_info[bytes_written], remain_len,
11485 			"%d %d %s %d %d %d %d %d %08x %08x",
11486 			reason, VENDOR_SEND_HANG_EXT_INFO_VER,
11487 			dhd->debug_dump_time_hang_str,
11488 			ret, mu.arena_size, mu.arena_free, mu.inuse_size, mu.mf_count, 0, 0);
11489 
11490 	dhd->hang_info_cnt = HANG_FIELD_IF_FAILURE_CNT;
11491 
11492 	clear_debug_dump_time(dhd->debug_dump_time_hang_str);
11493 
11494 	return;
11495 }
11496 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
11497