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