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