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