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