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, ¶ms, 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