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