1 /*
2 * Linux cfg80211 Vendor Extension Code
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Dual:>>
22 */
23
24 /*
25 * New vendor interface additon to nl80211/cfg80211 to allow vendors
26 * to implement proprietary features over the cfg80211 stack.
27 */
28
29 #include <typedefs.h>
30 #include <linuxver.h>
31 #include <osl.h>
32 #include <linux/kernel.h>
33 #include <linux/vmalloc.h>
34
35 #include <bcmutils.h>
36 #include <bcmwifi_channels.h>
37 #include <bcmendian.h>
38 #include <ethernet.h>
39 #include <802.11.h>
40 #include <linux/if_arp.h>
41 #include <asm/uaccess.h>
42
43 #if defined(BCMDONGLEHOST)
44 #include <dngl_stats.h>
45 #include "wifi_stats.h"
46 #include <dhd.h>
47 #include <dhd_debug.h>
48 #include <dhdioctl.h>
49 #include <wlioctl.h>
50 #include <wlioctl_utils.h>
51 #include <dhd_cfg80211.h>
52 #ifdef DHD_PKT_LOGGING
53 #include <dhd_pktlog.h>
54 #endif /* DHD_PKT_LOGGING */
55 #ifdef PNO_SUPPORT
56 #include <dhd_pno.h>
57 #endif /* PNO_SUPPORT */
58 #ifdef RTT_SUPPORT
59 #include <dhd_rtt.h>
60 #endif /* RTT_SUPPORT */
61 #endif /* defined(BCMDONGLEHOST) */
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 #include <wl_cfgscan.h>
80 #ifdef WL_NAN
81 #include <wl_cfgnan.h>
82 #endif /* WL_NAN */
83
84 #ifdef OEM_ANDROID
85 #include <wl_android.h>
86 #endif /* OEM_ANDROID */
87
88 #include <wl_cfgvendor.h>
89 #ifdef PROP_TXSTATUS
90 #include <dhd_wlfc.h>
91 #endif
92 #include <brcm_nl80211.h>
93
94 char*
wl_get_kernel_timestamp(void)95 wl_get_kernel_timestamp(void)
96 {
97 static char buf[32];
98 u64 ts_nsec;
99 unsigned long rem_nsec;
100
101 ts_nsec = local_clock();
102 rem_nsec = DIV_AND_MOD_U64_BY_U32(ts_nsec, NSEC_PER_SEC);
103 snprintf(buf, sizeof(buf), "%5lu.%06lu",
104 (unsigned long)ts_nsec, rem_nsec / NSEC_PER_USEC);
105
106 return buf;
107 }
108
109 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
110 #if defined(WL_SUPP_EVENT)
111 int
wl_cfgvendor_send_supp_eventstring(const char * func_name,const char * fmt,...)112 wl_cfgvendor_send_supp_eventstring(const char *func_name, const char *fmt, ...)
113 {
114 char buf[SUPP_LOG_LEN] = {0};
115 struct bcm_cfg80211 *cfg;
116 struct wiphy *wiphy;
117 va_list args;
118 int len;
119 int prefix_len;
120 int rem_len;
121
122 cfg = wl_cfg80211_get_bcmcfg();
123 if (!cfg || !cfg->wdev) {
124 WL_DBG(("supp evt invalid arg\n"));
125 return BCME_OK;
126 }
127
128 wiphy = cfg->wdev->wiphy;
129 prefix_len = snprintf(buf, SUPP_LOG_LEN, "[DHD]<%s> %s: ",
130 wl_get_kernel_timestamp(), __func__);
131 /* Remaining buffer len */
132 rem_len = SUPP_LOG_LEN - (prefix_len + 1);
133 /* Print the arg list on to the remaining part of the buffer */
134 va_start(args, fmt);
135 len = vsnprintf((buf + prefix_len), rem_len, fmt, args);
136 va_end(args);
137 if (len < 0) {
138 return -EINVAL;
139 }
140
141 if (len > rem_len) {
142 /* If return length is greater than buffer len,
143 * then its truncated buffer case.
144 */
145 len = rem_len;
146 }
147
148 /* Ensure the buffer is null terminated */
149 len += prefix_len;
150 buf[len] = '\0';
151 len++;
152
153 return wl_cfgvendor_send_async_event(wiphy,
154 bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_PRIV_STR, buf, len);
155 }
156
157 int
wl_cfgvendor_notify_supp_event_str(const char * evt_name,const char * fmt,...)158 wl_cfgvendor_notify_supp_event_str(const char *evt_name, const char *fmt, ...)
159 {
160 char buf[SUPP_LOG_LEN] = {0};
161 struct bcm_cfg80211 *cfg;
162 struct wiphy *wiphy;
163 va_list args;
164 int len;
165 int prefix_len;
166 int rem_len;
167
168 cfg = wl_cfg80211_get_bcmcfg();
169 if (!cfg || !cfg->wdev) {
170 WL_DBG(("supp evt invalid arg\n"));
171 return BCME_OK;
172 }
173 wiphy = cfg->wdev->wiphy;
174 prefix_len = snprintf(buf, SUPP_LOG_LEN, "%s ", evt_name);
175 /* Remaining buffer len */
176 rem_len = SUPP_LOG_LEN - (prefix_len + 1);
177 /* Print the arg list on to the remaining part of the buffer */
178 va_start(args, fmt);
179 len = vsnprintf((buf + prefix_len), rem_len, fmt, args);
180 va_end(args);
181 if (len < 0) {
182 return -EINVAL;
183 }
184
185 if (len > rem_len) {
186 /* If return length is greater than buffer len,
187 * then its truncated buffer case.
188 */
189 len = rem_len;
190 }
191
192 /* Ensure the buffer is null terminated */
193 len += prefix_len;
194 buf[len] = '\0';
195 len++;
196
197 return wl_cfgvendor_send_async_event(wiphy,
198 bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_PRIV_STR, buf, len);
199 }
200 #endif /* WL_SUPP_EVENT */
201
202 /*
203 * This API is to be used for asynchronous vendor events. This
204 * shouldn't be used in response to a vendor command from its
205 * do_it handler context (instead wl_cfgvendor_send_cmd_reply should
206 * be used).
207 */
wl_cfgvendor_send_async_event(struct wiphy * wiphy,struct net_device * dev,int event_id,const void * data,int len)208 int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
209 struct net_device *dev, int event_id, const void *data, int len)
210 {
211 gfp_t kflags;
212 struct sk_buff *skb;
213
214 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
215
216 /* Alloc the SKB for vendor_event */
217 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
218 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
219 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev), len, event_id, kflags);
220 #else
221 skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
222 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
223 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
224 if (!skb) {
225 WL_ERR(("skb alloc failed"));
226 return -ENOMEM;
227 }
228
229 /* Push the data to the skb */
230 nla_put_nohdr(skb, len, data);
231
232 cfg80211_vendor_event(skb, kflags);
233
234 return 0;
235 }
236
237 static int
wl_cfgvendor_send_cmd_reply(struct wiphy * wiphy,const void * data,int len)238 wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
239 const void *data, int len)
240 {
241 struct sk_buff *skb;
242 int err;
243
244 /* Alloc the SKB for vendor_event */
245 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
246 if (unlikely(!skb)) {
247 WL_ERR(("skb alloc failed"));
248 err = -ENOMEM;
249 goto exit;
250 }
251
252 /* Push the data to the skb */
253 nla_put_nohdr(skb, len, data);
254 err = cfg80211_vendor_cmd_reply(skb);
255 exit:
256 WL_DBG(("status %d\n", err));
257 return err;
258 }
259
260 static int
wl_cfgvendor_get_feature_set(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)261 wl_cfgvendor_get_feature_set(struct wiphy *wiphy,
262 struct wireless_dev *wdev, const void *data, int len)
263 {
264 int err = 0;
265 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
266 int reply;
267
268 reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg));
269
270 err = wl_cfgvendor_send_cmd_reply(wiphy, &reply, sizeof(int));
271 if (unlikely(err))
272 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
273
274 return err;
275 }
276
277 static int
wl_cfgvendor_get_feature_set_matrix(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)278 wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
279 struct wireless_dev *wdev, const void *data, int len)
280 {
281 int err = 0;
282 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
283 struct sk_buff *skb;
284 int reply;
285 int mem_needed, i;
286
287 mem_needed = VENDOR_REPLY_OVERHEAD +
288 (ATTRIBUTE_U32_LEN * MAX_FEATURE_SET_CONCURRRENT_GROUPS) + 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,
308 reply);
309 if (unlikely(err)) {
310 kfree_skb(skb);
311 goto exit;
312 }
313 }
314 }
315
316 err = cfg80211_vendor_cmd_reply(skb);
317
318 if (unlikely(err)) {
319 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
320 }
321 exit:
322 return err;
323 }
324
325 static int
wl_cfgvendor_set_rand_mac_oui(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)326 wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy,
327 struct wireless_dev *wdev, const void *data, int len)
328 {
329 int err = -EINVAL;
330 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
331 int type;
332
333 if (!data) {
334 WL_ERR(("data is not available\n"));
335 goto exit;
336 }
337
338 if (len <= 0) {
339 WL_ERR(("invalid len %d\n", len));
340 goto exit;
341 }
342
343 type = nla_type(data);
344
345 if (type == ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI) {
346 if (nla_len(data) != DOT11_OUI_LEN) {
347 WL_ERR(("nla_len not matched.\n"));
348 goto exit;
349 }
350 err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), nla_data(data));
351
352 if (unlikely(err))
353 WL_ERR(("Bad OUI, could not set:%d \n", err));
354 }
355 exit:
356 return err;
357 }
358 #ifdef CUSTOM_FORCE_NODFS_FLAG
359 static int
wl_cfgvendor_set_nodfs_flag(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)360 wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy,
361 struct wireless_dev *wdev, const void *data, int len)
362 {
363 int err = -EINVAL;
364 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
365 int type;
366 u32 nodfs;
367
368 if (!data) {
369 WL_ERR(("data is not available\n"));
370 return -EINVAL;
371 }
372
373 if (len <= 0) {
374 WL_ERR(("invalid len %d\n", len));
375 return -EINVAL;
376 }
377
378 type = nla_type(data);
379 if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) {
380 nodfs = nla_get_u32(data);
381 err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs);
382 }
383
384 return err;
385 }
386 #endif /* CUSTOM_FORCE_NODFS_FLAG */
387
388 static int
wl_cfgvendor_set_country(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)389 wl_cfgvendor_set_country(struct wiphy *wiphy,
390 struct wireless_dev *wdev, const void *data, int len)
391 {
392 int err = BCME_ERROR, rem, type;
393 char country_code[WLC_CNTRY_BUF_SZ] = {0};
394 const struct nlattr *iter;
395 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
396 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
397
398 nla_for_each_attr(iter, data, len, rem) {
399 type = nla_type(iter);
400 switch (type) {
401 case ANDR_WIFI_ATTRIBUTE_COUNTRY:
402 err = memcpy_s(country_code, WLC_CNTRY_BUF_SZ,
403 nla_data(iter), nla_len(iter));
404 if (err) {
405 WL_ERR(("Failed to copy country code: %d\n", err));
406 return err;
407 }
408 break;
409 default:
410 WL_ERR(("Unknown type: %d\n", type));
411 return err;
412 }
413 }
414 /* country code is unique for dongle..hence using primary interface. */
415 err = wl_cfg80211_set_country_code(primary_ndev, country_code, true, true, 0);
416 if (err < 0) {
417 WL_ERR(("Set country failed ret:%d\n", err));
418 }
419
420 return err;
421 }
422
423 #ifdef GSCAN_SUPPORT
424 int
wl_cfgvendor_send_hotlist_event(struct wiphy * wiphy,struct net_device * dev,void * data,int len,wl_vendor_event_t event)425 wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
426 struct net_device *dev, void *data, int len, wl_vendor_event_t event)
427 {
428 gfp_t kflags;
429 const void *ptr;
430 struct sk_buff *skb;
431 int malloc_len, total, iter_cnt_to_send, cnt;
432 gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
433
434 total = len/sizeof(wifi_gscan_result_t);
435 while (total > 0) {
436 malloc_len = (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) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
448 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
449 skb = cfg80211_vendor_event_alloc(wiphy, ndev_to_wdev(dev),
450 malloc_len, event, kflags);
451 #else
452 skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags);
453 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
454 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
455 if (!skb) {
456 WL_ERR(("skb alloc failed"));
457 return -ENOMEM;
458 }
459
460 while (cache && iter_cnt_to_send) {
461 ptr = (const void *) &cache->results[cache->tot_consumed];
462
463 if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) {
464 cnt = iter_cnt_to_send;
465 } else {
466 cnt = (cache->tot_count - cache->tot_consumed);
467 }
468
469 iter_cnt_to_send -= cnt;
470 cache->tot_consumed += cnt;
471 /* Push the data to the skb */
472 #ifdef ANDROID13_KERNEL515_BKPORT
473 nla_put_nohdr(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
474 #else
475 nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
476 #endif
477 if (cache->tot_consumed == cache->tot_count) {
478 cache = cache->next;
479 }
480
481 }
482
483 cfg80211_vendor_event(skb, kflags);
484 }
485
486 return 0;
487 }
488
489 static int
wl_cfgvendor_gscan_get_capabilities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)490 wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
491 struct wireless_dev *wdev, const void *data, int len)
492 {
493 int err = 0;
494 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
495 dhd_pno_gscan_capabilities_t *reply = NULL;
496 uint32 reply_len = 0;
497
498 reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
499 DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
500 if (!reply) {
501 WL_ERR(("Could not get capabilities\n"));
502 err = -EINVAL;
503 return err;
504 }
505
506 err = wl_cfgvendor_send_cmd_reply(wiphy, reply, reply_len);
507 if (unlikely(err)) {
508 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
509 }
510
511 MFREE(cfg->osh, reply, reply_len);
512 return err;
513 }
514
515 static int
wl_cfgvendor_gscan_get_batch_results(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)516 wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
517 struct wireless_dev *wdev, const void *data, int len)
518 {
519 int err = 0;
520 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
521 gscan_results_cache_t *results, *iter;
522 uint32 reply_len, is_done = 1;
523 int32 mem_needed, num_results_iter;
524 wifi_gscan_result_t *ptr;
525 uint16 num_scan_ids, num_results;
526 struct sk_buff *skb;
527 struct nlattr *scan_hdr, *complete_flag;
528
529 err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
530 if (err != BCME_OK)
531 return -EBUSY;
532
533 err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
534 if (err != BCME_OK) {
535 WL_ERR(("Can't obtain lock to access batch results %d\n", err));
536 return -EBUSY;
537 }
538 results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
539 DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
540
541 if (!results) {
542 WL_ERR(("No results to send %d\n", err));
543 err = wl_cfgvendor_send_cmd_reply(wiphy, results, 0);
544
545 if (unlikely(err))
546 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
547 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
548 return err;
549 }
550 num_scan_ids = reply_len & 0xFFFF;
551 num_results = (reply_len & 0xFFFF0000) >> 16;
552 mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
553 (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
554 VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
555
556 if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
557 mem_needed = (int32)NLMSG_DEFAULT_SIZE;
558 }
559
560 WL_TRACE(("is_done %d mem_needed %d max_mem %d\n", is_done, mem_needed,
561 (int)NLMSG_DEFAULT_SIZE));
562 /* Alloc the SKB for vendor_event */
563 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
564 if (unlikely(!skb)) {
565 WL_ERR(("skb alloc failed"));
566 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
567 return -ENOMEM;
568 }
569 iter = results;
570 complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,
571 sizeof(is_done));
572
573 if (unlikely(!complete_flag)) {
574 WL_ERR(("complete_flag could not be reserved"));
575 kfree_skb(skb);
576 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
577 return -ENOMEM;
578 }
579 mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
580
581 while (iter) {
582 num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN);
583 num_results_iter /= (int32)sizeof(wifi_gscan_result_t);
584 if (num_results_iter <= 0 ||
585 ((iter->tot_count - iter->tot_consumed) > num_results_iter)) {
586 break;
587 }
588 scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
589 /* no more room? we are done then (for now) */
590 if (scan_hdr == NULL) {
591 is_done = 0;
592 break;
593 }
594 err = nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
595 if (unlikely(err)) {
596 goto fail;
597 }
598 err = nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
599 if (unlikely(err)) {
600 goto fail;
601 }
602 err = nla_put_u32(skb, GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK, iter->scan_ch_bucket);
603 if (unlikely(err)) {
604 goto fail;
605 }
606 num_results_iter = iter->tot_count - iter->tot_consumed;
607
608 err = nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
609 if (unlikely(err)) {
610 goto fail;
611 }
612 if (num_results_iter) {
613 ptr = &iter->results[iter->tot_consumed];
614 err = nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
615 num_results_iter * sizeof(wifi_gscan_result_t), ptr);
616 if (unlikely(err)) {
617 goto fail;
618 }
619 iter->tot_consumed += num_results_iter;
620 }
621 nla_nest_end(skb, scan_hdr);
622 mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
623 (num_results_iter * sizeof(wifi_gscan_result_t));
624 iter = iter->next;
625 }
626 /* Cleans up consumed results and returns TRUE if all results are consumed */
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
639 static int
wl_cfgvendor_initiate_gscan(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)640 wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
641 struct wireless_dev *wdev, 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 type = nla_type(iter);
652 if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
653 run = nla_get_u32(iter);
654 else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
655 flush = nla_get_u32(iter);
656 }
657
658 if (run != 0xFF) {
659 err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
660
661 if (unlikely(err)) {
662 WL_ERR(("Could not run gscan:%d \n", err));
663 }
664 return err;
665 } else {
666 return -EINVAL;
667 }
668
669 }
670
671 static int
wl_cfgvendor_enable_full_scan_result(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)672 wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
673 struct wireless_dev *wdev, 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
692 if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
693 real_time = nla_get_u32(data);
694
695 err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
696
697 if (unlikely(err)) {
698 WL_ERR(("Could not run gscan:%d \n", err));
699 }
700
701 } else {
702 err = -EINVAL;
703 }
704
705 return err;
706 }
707
708 static int
wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr * prev,gscan_scan_params_t * scan_param,int num)709 wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev,
710 gscan_scan_params_t *scan_param, int num)
711 {
712 struct dhd_pno_gscan_channel_bucket *ch_bucket;
713 int k = 0;
714 int type, err = 0, rem;
715 const struct nlattr *cur, *next;
716
717 nla_for_each_nested(cur, prev, rem) {
718 type = nla_type(cur);
719 ch_bucket = scan_param->channel_bucket;
720 switch (type) {
721 case GSCAN_ATTRIBUTE_BUCKET_ID:
722 break;
723 case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
724 if (nla_len(cur) != sizeof(uint32)) {
725 err = -EINVAL;
726 goto exit;
727 }
728
729 ch_bucket[num].bucket_freq_multiple =
730 nla_get_u32(cur) / MSEC_PER_SEC;
731 break;
732 case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
733 if (nla_len(cur) != sizeof(uint32)) {
734 err = -EINVAL;
735 goto exit;
736 }
737 ch_bucket[num].num_channels = nla_get_u32(cur);
738 if (ch_bucket[num].num_channels >
739 GSCAN_MAX_CHANNELS_IN_BUCKET) {
740 WL_ERR(("channel range:%d,bucket:%d\n",
741 ch_bucket[num].num_channels,
742 num));
743 err = -EINVAL;
744 goto exit;
745 }
746 break;
747 case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
748 nla_for_each_nested(next, cur, rem) {
749 if (k >= GSCAN_MAX_CHANNELS_IN_BUCKET)
750 break;
751 if (nla_len(next) != sizeof(uint32)) {
752 err = -EINVAL;
753 goto exit;
754 }
755 ch_bucket[num].chan_list[k] = nla_get_u32(next);
756 k++;
757 }
758 break;
759 case GSCAN_ATTRIBUTE_BUCKETS_BAND:
760 if (nla_len(cur) != sizeof(uint32)) {
761 err = -EINVAL;
762 goto exit;
763 }
764 ch_bucket[num].band = (uint16)nla_get_u32(cur);
765 break;
766 case GSCAN_ATTRIBUTE_REPORT_EVENTS:
767 if (nla_len(cur) != sizeof(uint32)) {
768 err = -EINVAL;
769 goto exit;
770 }
771 ch_bucket[num].report_flag = (uint8)nla_get_u32(cur);
772 break;
773 case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT:
774 if (nla_len(cur) != sizeof(uint32)) {
775 err = -EINVAL;
776 goto exit;
777 }
778 ch_bucket[num].repeat = (uint16)nla_get_u32(cur);
779 break;
780 case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD:
781 if (nla_len(cur) != sizeof(uint32)) {
782 err = -EINVAL;
783 goto exit;
784 }
785 ch_bucket[num].bucket_max_multiple =
786 nla_get_u32(cur) / MSEC_PER_SEC;
787 break;
788 default:
789 WL_ERR(("unknown attr type:%d\n", type));
790 err = -EINVAL;
791 goto exit;
792 }
793 }
794
795 exit:
796 return err;
797 }
798
799 static int
wl_cfgvendor_set_scan_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)800 wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, struct wireless_dev *wdev,
801 const void *data, int len)
802 {
803 int err = 0;
804 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
805 gscan_scan_params_t *scan_param;
806 int j = 0;
807 int type, tmp;
808 const struct nlattr *iter;
809
810 scan_param = (gscan_scan_params_t *)MALLOCZ(cfg->osh,
811 sizeof(gscan_scan_params_t));
812 if (!scan_param) {
813 WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
814 err = -EINVAL;
815 return err;
816
817 }
818
819 scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
820 nla_for_each_attr(iter, data, len, tmp) {
821 type = nla_type(iter);
822
823 if (j >= GSCAN_MAX_CH_BUCKETS) {
824 break;
825 }
826
827 switch (type) {
828 case GSCAN_ATTRIBUTE_BASE_PERIOD:
829 if (nla_len(iter) != sizeof(uint32)) {
830 err = -EINVAL;
831 goto exit;
832 }
833 scan_param->scan_fr = nla_get_u32(iter) / MSEC_PER_SEC;
834 break;
835 case GSCAN_ATTRIBUTE_NUM_BUCKETS:
836 if (nla_len(iter) != sizeof(uint32)) {
837 err = -EINVAL;
838 goto exit;
839 }
840 scan_param->nchannel_buckets = nla_get_u32(iter);
841 if (scan_param->nchannel_buckets >=
842 GSCAN_MAX_CH_BUCKETS) {
843 WL_ERR(("ncha_buck out of range %d\n",
844 scan_param->nchannel_buckets));
845 err = -EINVAL;
846 goto exit;
847 }
848 break;
849 case GSCAN_ATTRIBUTE_CH_BUCKET_1:
850 case GSCAN_ATTRIBUTE_CH_BUCKET_2:
851 case GSCAN_ATTRIBUTE_CH_BUCKET_3:
852 case GSCAN_ATTRIBUTE_CH_BUCKET_4:
853 case GSCAN_ATTRIBUTE_CH_BUCKET_5:
854 case GSCAN_ATTRIBUTE_CH_BUCKET_6:
855 case GSCAN_ATTRIBUTE_CH_BUCKET_7:
856 err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j);
857 if (err < 0) {
858 WL_ERR(("set_scan_cfg_buck error:%d\n", err));
859 goto exit;
860 }
861 j++;
862 break;
863 default:
864 WL_ERR(("Unknown type %d\n", type));
865 err = -EINVAL;
866 goto exit;
867 }
868 }
869
870 err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
871 DHD_PNO_SCAN_CFG_ID, scan_param, FALSE);
872
873 if (err < 0) {
874 WL_ERR(("Could not set GSCAN scan cfg\n"));
875 err = -EINVAL;
876 }
877
878 exit:
879 MFREE(cfg->osh, scan_param, sizeof(gscan_scan_params_t));
880 return err;
881
882 }
883
884 static int
wl_cfgvendor_hotlist_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)885 wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
886 struct wireless_dev *wdev, const void *data, int len)
887 {
888 int err = 0;
889 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
890 gscan_hotlist_scan_params_t *hotlist_params;
891 int tmp, tmp1, tmp2, type, j = 0, dummy;
892 const struct nlattr *outer, *inner = NULL, *iter;
893 bool flush = FALSE;
894 struct bssid_t *pbssid;
895
896 BCM_REFERENCE(dummy);
897
898 if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) {
899 WL_ERR(("buffer length :%d wrong - bail out.\n", len));
900 return -EINVAL;
901 }
902
903 hotlist_params = (gscan_hotlist_scan_params_t *)MALLOCZ(cfg->osh,
904 sizeof(*hotlist_params)
905 + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)));
906
907 if (!hotlist_params) {
908 WL_ERR(("Cannot Malloc memory.\n"));
909 return -ENOMEM;
910 }
911
912 hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
913
914 nla_for_each_attr(iter, data, len, tmp2) {
915 type = nla_type(iter);
916 switch (type) {
917 case GSCAN_ATTRIBUTE_HOTLIST_BSSID_COUNT:
918 if (nla_len(iter) != sizeof(uint32)) {
919 WL_DBG(("type:%d length:%d not matching.\n",
920 type, nla_len(iter)));
921 err = -EINVAL;
922 goto exit;
923 }
924 hotlist_params->nbssid = (uint16)nla_get_u32(iter);
925 if ((hotlist_params->nbssid == 0) ||
926 (hotlist_params->nbssid > PFN_SWC_MAX_NUM_APS)) {
927 WL_ERR(("nbssid:%d exceed limit.\n",
928 hotlist_params->nbssid));
929 err = -EINVAL;
930 goto exit;
931 }
932 break;
933 case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
934 if (hotlist_params->nbssid == 0) {
935 WL_ERR(("nbssid not retrieved.\n"));
936 err = -EINVAL;
937 goto exit;
938 }
939 pbssid = hotlist_params->bssid;
940 nla_for_each_nested(outer, iter, tmp) {
941 if (j >= hotlist_params->nbssid)
942 break;
943 nla_for_each_nested(inner, outer, tmp1) {
944 type = nla_type(inner);
945
946 switch (type) {
947 case GSCAN_ATTRIBUTE_BSSID:
948 if (nla_len(inner) != sizeof(pbssid[j].macaddr)) {
949 WL_ERR(("type:%d length:%d not matching.\n",
950 type, nla_len(inner)));
951 err = -EINVAL;
952 goto exit;
953 }
954 memcpy(
955 &(pbssid[j].macaddr),
956 nla_data(inner),
957 sizeof(pbssid[j].macaddr));
958 break;
959 case GSCAN_ATTRIBUTE_RSSI_LOW:
960 if (nla_len(inner) != sizeof(uint8)) {
961 WL_ERR(("type:%d length:%d not matching.\n",
962 type, nla_len(inner)));
963 err = -EINVAL;
964 goto exit;
965 }
966 pbssid[j].rssi_reporting_threshold =
967 (int8)nla_get_u8(inner);
968 break;
969 case GSCAN_ATTRIBUTE_RSSI_HIGH:
970 if (nla_len(inner) != sizeof(uint8)) {
971 WL_ERR(("type:%d length:%d not matching.\n",
972 type, nla_len(inner)));
973 err = -EINVAL;
974 goto exit;
975 }
976 dummy = (int8)nla_get_u8(inner);
977 WL_DBG(("dummy %d\n", dummy));
978 break;
979 default:
980 WL_ERR(("ATTR unknown %d\n", type));
981 err = -EINVAL;
982 goto exit;
983 }
984 }
985 j++;
986 }
987 if (j != hotlist_params->nbssid) {
988 WL_ERR(("bssid_cnt:%d != nbssid:%d.\n", j,
989 hotlist_params->nbssid));
990 err = -EINVAL;
991 goto exit;
992 }
993 break;
994 case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
995 if (nla_len(iter) != sizeof(uint8)) {
996 WL_ERR(("type:%d length:%d not matching.\n",
997 type, nla_len(iter)));
998 err = -EINVAL;
999 goto exit;
1000 }
1001 flush = nla_get_u8(iter);
1002 break;
1003 case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
1004 if (nla_len(iter) != sizeof(uint32)) {
1005 WL_ERR(("type:%d length:%d not matching.\n",
1006 type, nla_len(iter)));
1007 err = -EINVAL;
1008 goto exit;
1009 }
1010 hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter);
1011 break;
1012 default:
1013 WL_ERR(("Unknown type %d\n", type));
1014 err = -EINVAL;
1015 goto exit;
1016 }
1017
1018 }
1019
1020 if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1021 DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
1022 WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err));
1023 err = -EINVAL;
1024 goto exit;
1025 }
1026 exit:
1027 MFREE(cfg->osh, hotlist_params, sizeof(*hotlist_params)
1028 + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)));
1029 return err;
1030 }
1031
wl_cfgvendor_epno_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1032 static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy,
1033 struct wireless_dev *wdev, const void *data, int len)
1034 {
1035 int err = 0;
1036 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1037 dhd_pno_ssid_t *ssid_elem = NULL;
1038 int tmp, tmp1, tmp2, type = 0, num = 0;
1039 const struct nlattr *outer, *inner, *iter;
1040 uint8 flush = FALSE, i = 0;
1041 wl_ssid_ext_params_t params;
1042
1043 nla_for_each_attr(iter, data, len, tmp2) {
1044 type = nla_type(iter);
1045 switch (type) {
1046 case GSCAN_ATTRIBUTE_EPNO_SSID_LIST:
1047 nla_for_each_nested(outer, iter, tmp) {
1048 ssid_elem = (dhd_pno_ssid_t *)
1049 dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
1050 DHD_PNO_GET_NEW_EPNO_SSID_ELEM,
1051 NULL, &num);
1052 if (!ssid_elem) {
1053 WL_ERR(("Failed to get SSID LIST buffer\n"));
1054 err = -ENOMEM;
1055 goto exit;
1056 }
1057 i++;
1058 nla_for_each_nested(inner, outer, tmp1) {
1059 type = nla_type(inner);
1060
1061 switch (type) {
1062 case GSCAN_ATTRIBUTE_EPNO_SSID:
1063 memcpy(ssid_elem->SSID,
1064 nla_data(inner),
1065 DOT11_MAX_SSID_LEN);
1066 break;
1067 case GSCAN_ATTRIBUTE_EPNO_SSID_LEN:
1068 ssid_elem->SSID_len =
1069 nla_get_u32(inner);
1070 if (ssid_elem->SSID_len >
1071 DOT11_MAX_SSID_LEN) {
1072 WL_ERR(("SSID too"
1073 "long %d\n",
1074 ssid_elem->SSID_len));
1075 err = -EINVAL;
1076 MFREE(cfg->osh, ssid_elem,
1077 num);
1078 goto exit;
1079 }
1080 break;
1081 case GSCAN_ATTRIBUTE_EPNO_FLAGS:
1082 ssid_elem->flags =
1083 nla_get_u32(inner);
1084 ssid_elem->hidden =
1085 ((ssid_elem->flags &
1086 DHD_EPNO_HIDDEN_SSID) != 0);
1087 break;
1088 case GSCAN_ATTRIBUTE_EPNO_AUTH:
1089 ssid_elem->wpa_auth =
1090 nla_get_u32(inner);
1091 break;
1092 }
1093 }
1094 if (!ssid_elem->SSID_len) {
1095 WL_ERR(("Broadcast SSID is illegal for ePNO\n"));
1096 err = -EINVAL;
1097 MFREE(cfg->osh, ssid_elem, num);
1098 goto exit;
1099 }
1100 dhd_pno_translate_epno_fw_flags(&ssid_elem->flags);
1101 dhd_pno_set_epno_auth_flag(&ssid_elem->wpa_auth);
1102 MFREE(cfg->osh, ssid_elem, num);
1103 }
1104 break;
1105 case GSCAN_ATTRIBUTE_EPNO_SSID_NUM:
1106 num = nla_get_u8(iter);
1107 break;
1108 case GSCAN_ATTRIBUTE_EPNO_FLUSH:
1109 flush = (bool)nla_get_u32(iter);
1110 /* Flush attribute is expected before any ssid attribute */
1111 if (i && flush) {
1112 WL_ERR(("Bad attributes\n"));
1113 err = -EINVAL;
1114 goto exit;
1115 }
1116 /* Need to flush driver and FW cfg */
1117 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1118 DHD_PNO_EPNO_CFG_ID, NULL, flush);
1119 dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
1120 break;
1121 case GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR:
1122 params.min5G_rssi = nla_get_s8(iter);
1123 break;
1124 case GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR:
1125 params.min2G_rssi = nla_get_s8(iter);
1126 break;
1127 case GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX:
1128 params.init_score_max = nla_get_s16(iter);
1129 break;
1130 case GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS:
1131 params.cur_bssid_bonus = nla_get_s16(iter);
1132 break;
1133 case GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS:
1134 params.same_ssid_bonus = nla_get_s16(iter);
1135 break;
1136 case GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS:
1137 params.secure_bonus = nla_get_s16(iter);
1138 break;
1139 case GSCAN_ATTRIBUTE_EPNO_5G_BONUS:
1140 params.band_5g_bonus = nla_get_s16(iter);
1141 break;
1142 default:
1143 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1144 err = -EINVAL;
1145 goto exit;
1146 }
1147 }
1148 if (i != num) {
1149 WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__,
1150 num, i));
1151 err = -EINVAL;
1152 }
1153 exit:
1154 /* Flush all configs if error condition */
1155 if (err < 0) {
1156 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1157 DHD_PNO_EPNO_CFG_ID, NULL, TRUE);
1158 dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
1159 } else if (type != GSCAN_ATTRIBUTE_EPNO_FLUSH) {
1160 /* If the last attribute was FLUSH, nothing else to do */
1161 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1162 DHD_PNO_EPNO_PARAMS_ID, ¶ms, FALSE);
1163 err = dhd_dev_set_epno(bcmcfg_to_prmry_ndev(cfg));
1164 }
1165 return err;
1166 }
1167
1168 static int
wl_cfgvendor_set_batch_scan_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1169 wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
1170 struct wireless_dev *wdev, const void *data, int len)
1171 {
1172 int err = 0, tmp, type;
1173 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1174 gscan_batch_params_t batch_param;
1175 const struct nlattr *iter;
1176
1177 batch_param.mscan = batch_param.bestn = 0;
1178 batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
1179
1180 nla_for_each_attr(iter, data, len, tmp) {
1181 type = nla_type(iter);
1182
1183 switch (type) {
1184 case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
1185 batch_param.bestn = nla_get_u32(iter);
1186 break;
1187 case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
1188 batch_param.mscan = nla_get_u32(iter);
1189 break;
1190 case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
1191 batch_param.buffer_threshold = nla_get_u32(iter);
1192 break;
1193 default:
1194 WL_ERR(("Unknown type %d\n", type));
1195 break;
1196 }
1197 }
1198
1199 if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
1200 DHD_PNO_BATCH_SCAN_CFG_ID, &batch_param, FALSE) < 0) {
1201 WL_ERR(("Could not set batch cfg\n"));
1202 err = -EINVAL;
1203 return err;
1204 }
1205
1206 return err;
1207 }
1208
1209 #endif /* GSCAN_SUPPORT */
1210 #if defined (GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
1211 static int
wl_cfgvendor_gscan_get_channel_list(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1212 wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
1213 struct wireless_dev *wdev, const void *data, int len)
1214 {
1215 int err = 0, type, band;
1216 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1217 uint32 *reply = NULL;
1218 uint32 reply_len = 0, num_channels, mem_needed;
1219 struct sk_buff *skb;
1220 dhd_pub_t *dhdp;
1221 struct net_device *ndev = wdev->netdev;
1222
1223 if (!ndev) {
1224 WL_ERR(("ndev null\n"));
1225 return -EINVAL;
1226 }
1227
1228 dhdp = wl_cfg80211_get_dhdp(ndev);
1229 if (!dhdp) {
1230 WL_ERR(("dhdp null\n"));
1231 return -EINVAL;
1232 }
1233
1234 if (!data) {
1235 WL_ERR(("data is not available\n"));
1236 return -EINVAL;
1237 }
1238
1239 if (len <= 0) {
1240 WL_ERR(("invalid len %d\n", len));
1241 return -EINVAL;
1242 }
1243
1244 type = nla_type(data);
1245 if (type == GSCAN_ATTRIBUTE_BAND) {
1246 band = nla_get_u32(data);
1247 } else {
1248 return -EINVAL;
1249 }
1250
1251 reply = MALLOCZ(cfg->osh, CHANINFO_LIST_BUF_SIZE);
1252 if (reply == NULL) {
1253 WL_ERR(("failed to allocate chanspec buffer\n"));
1254 return -ENOMEM;
1255 }
1256 err = wl_cfgscan_get_band_freq_list(cfg, band, reply, &num_channels);
1257 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
1258 WL_ERR(("%s: failed to get valid channel list\n",
1259 __FUNCTION__));
1260 err = -EINVAL;
1261 goto exit;
1262 } else if (err == BCME_OK) {
1263 reply_len = (num_channels * sizeof(uint32));
1264 } else if (err == BCME_UNSUPPORTED) {
1265 reply = dhd_pno_get_gscan(dhdp,
1266 DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
1267 if (!reply) {
1268 WL_ERR(("Could not get channel list\n"));
1269 err = -EINVAL;
1270 return err;
1271 }
1272 num_channels = reply_len/sizeof(uint32);
1273 }
1274 mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
1275
1276 /* Alloc the SKB for vendor_event */
1277 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1278 if (unlikely(!skb)) {
1279 WL_ERR(("skb alloc failed"));
1280 err = -ENOMEM;
1281 goto exit;
1282 }
1283
1284 nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
1285 nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
1286
1287 err = cfg80211_vendor_cmd_reply(skb);
1288
1289 if (unlikely(err)) {
1290 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1291 }
1292 exit:
1293 MFREE(cfg->osh, reply, CHANINFO_LIST_BUF_SIZE);
1294 return err;
1295 }
1296 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
1297
1298 #ifdef RSSI_MONITOR_SUPPORT
wl_cfgvendor_set_rssi_monitor(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1299 static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy,
1300 struct wireless_dev *wdev, const void *data, int len)
1301 {
1302 int err = 0, tmp, type, start = 0;
1303 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1304 int8 max_rssi = 0, min_rssi = 0;
1305 const struct nlattr *iter;
1306
1307 if (!wl_get_drv_status(cfg, CONNECTED, wdev_to_ndev(wdev))) {
1308 WL_ERR(("Sta is not connected to an AP, rssi monitoring is not allowed\n"));
1309 return -EINVAL;
1310 }
1311
1312 nla_for_each_attr(iter, data, len, tmp) {
1313 type = nla_type(iter);
1314 switch (type) {
1315 case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI:
1316 max_rssi = (int8) nla_get_u32(iter);
1317 break;
1318 case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI:
1319 min_rssi = (int8) nla_get_u32(iter);
1320 break;
1321 case RSSI_MONITOR_ATTRIBUTE_START:
1322 start = nla_get_u32(iter);
1323 }
1324 }
1325
1326 if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
1327 start, max_rssi, min_rssi) < 0) {
1328 WL_ERR(("Could not set rssi monitor cfg\n"));
1329 err = -EINVAL;
1330 }
1331 return err;
1332 }
1333 #endif /* RSSI_MONITOR_SUPPORT */
1334
1335 #ifdef DHD_WAKE_STATUS
1336 static int
wl_cfgvendor_get_wake_reason_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1337 wl_cfgvendor_get_wake_reason_stats(struct wiphy *wiphy,
1338 struct wireless_dev *wdev, const void *data, int len)
1339 {
1340 struct net_device *ndev = wdev_to_ndev(wdev);
1341 wake_counts_t *pwake_count_info;
1342 int ret, mem_needed;
1343 #if defined(DHD_DEBUG) && defined(DHD_WAKE_EVENT_STATUS)
1344 int flowid;
1345 #endif /* DHD_DEBUG && DHD_WAKE_EVENT_STATUS */
1346 struct sk_buff *skb = NULL;
1347 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
1348
1349 WL_DBG(("Recv get wake status info cmd.\n"));
1350
1351 pwake_count_info = dhd_get_wakecount(dhdp);
1352 mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 20) +
1353 (WLC_E_LAST * sizeof(uint));
1354
1355 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1356 if (unlikely(!skb)) {
1357 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
1358 ret = -ENOMEM;
1359 goto exit;
1360 }
1361 #ifdef DHD_WAKE_EVENT_STATUS
1362 WL_ERR(("pwake_count_info->rcwake %d\n", pwake_count_info->rcwake));
1363 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, pwake_count_info->rcwake);
1364 if (unlikely(ret)) {
1365 WL_ERR(("Failed to put Total count of CMD event, ret=%d\n", ret));
1366 goto exit;
1367 }
1368 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED, WLC_E_LAST);
1369 if (unlikely(ret)) {
1370 WL_ERR(("Failed to put Max count of event used, ret=%d\n", ret));
1371 goto exit;
1372 }
1373 ret = nla_put(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE, (WLC_E_LAST * sizeof(uint)),
1374 pwake_count_info->rc_event);
1375 if (unlikely(ret)) {
1376 WL_ERR(("Failed to put Event wake data, ret=%d\n", ret));
1377 goto exit;
1378 }
1379 #ifdef DHD_DEBUG
1380 for (flowid = 0; flowid < WLC_E_LAST; flowid++) {
1381 if (pwake_count_info->rc_event[flowid] != 0) {
1382 WL_ERR((" %s = %u\n", bcmevent_get_name(flowid),
1383 pwake_count_info->rc_event[flowid]));
1384 }
1385 }
1386 #endif /* DHD_DEBUG */
1387 #endif /* DHD_WAKE_EVENT_STATUS */
1388 #ifdef DHD_WAKE_RX_STATUS
1389 WL_ERR(("pwake_count_info->rxwake %d\n", pwake_count_info->rxwake));
1390 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE, pwake_count_info->rxwake);
1391 if (unlikely(ret)) {
1392 WL_ERR(("Failed to put Total Wake due RX data, ret=%d\n", ret));
1393 goto exit;
1394 }
1395 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT, pwake_count_info->rx_ucast);
1396 if (unlikely(ret)) {
1397 WL_ERR(("Failed to put Total wake due to RX unicast, ret=%d\n", ret));
1398 goto exit;
1399 }
1400 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT, pwake_count_info->rx_mcast);
1401 if (unlikely(ret)) {
1402 WL_ERR(("Failed to put Total wake due RX multicast, ret=%d\n", ret));
1403 goto exit;
1404 }
1405 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT, pwake_count_info->rx_bcast);
1406 if (unlikely(ret)) {
1407 WL_ERR(("Failed to put Total wake due to RX broadcast, ret=%d\n", ret));
1408 goto exit;
1409 }
1410 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT, pwake_count_info->rx_arp);
1411 if (unlikely(ret)) {
1412 WL_ERR(("Failed to put Total wake due to ICMP pkt, ret=%d\n", ret));
1413 goto exit;
1414 }
1415 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT, pwake_count_info->rx_icmpv6);
1416 if (unlikely(ret)) {
1417 WL_ERR(("Failed to put Total wake due ICMPV6 pkt, ret=%d\n", ret));
1418 goto exit;
1419 }
1420 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA, pwake_count_info->rx_icmpv6_ra);
1421 if (unlikely(ret)) {
1422 WL_ERR(("Failed to put Total wake due to ICMPV6_RA, ret=%d\n", ret));
1423 goto exit;
1424 }
1425 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA, pwake_count_info->rx_icmpv6_na);
1426 if (unlikely(ret)) {
1427 WL_ERR(("Failed to put Total wake due to ICMPV6_NA, ret=%d\n", ret));
1428 goto exit;
1429 }
1430 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS, pwake_count_info->rx_icmpv6_ns);
1431 if (unlikely(ret)) {
1432 WL_ERR(("Failed to put Total wake due to ICMPV6_NS, ret=%d\n", ret));
1433 goto exit;
1434 }
1435 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
1436 pwake_count_info->rx_multi_ipv4);
1437 if (unlikely(ret)) {
1438 WL_ERR(("Failed to put Total wake due to RX IPV4 MULTICAST, ret=%d\n", ret));
1439 goto exit;
1440 }
1441 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
1442 pwake_count_info->rx_multi_ipv6);
1443 if (unlikely(ret)) {
1444 WL_ERR(("Failed to put Total wake due to RX IPV6 MULTICAST, ret=%d\n", ret));
1445 goto exit;
1446 }
1447 ret = nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT,
1448 pwake_count_info->rx_multi_other);
1449 if (unlikely(ret)) {
1450 WL_ERR(("Failed to put Total wake due to Other RX Multicast, ret=%d\n", ret));
1451 goto exit;
1452 }
1453 #endif /* #ifdef DHD_WAKE_RX_STATUS */
1454 ret = cfg80211_vendor_cmd_reply(skb);
1455 if (unlikely(ret)) {
1456 WL_ERR(("Vendor cmd reply for -get wake status failed:%d \n", ret));
1457 }
1458 /* On cfg80211_vendor_cmd_reply() skb is consumed and freed in case of success or failure */
1459 return ret;
1460
1461 exit:
1462 /* Free skb memory */
1463 if (skb) {
1464 kfree_skb(skb);
1465 }
1466 return ret;
1467 }
1468 #endif /* DHD_WAKE_STATUS */
1469
1470 #ifdef DHDTCPACK_SUPPRESS
1471 static int
wl_cfgvendor_set_tcpack_sup_mode(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1472 wl_cfgvendor_set_tcpack_sup_mode(struct wiphy *wiphy,
1473 struct wireless_dev *wdev, const void *data, int len)
1474 {
1475 int err = BCME_OK, type;
1476 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1477 struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1478 uint8 enable = 0;
1479
1480 if (!data) {
1481 WL_ERR(("data is not available\n"));
1482 err = BCME_BADARG;
1483 goto exit;
1484 }
1485
1486 if (len <= 0) {
1487 WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
1488 err = BCME_BADARG;
1489 goto exit;
1490 }
1491
1492 type = nla_type(data);
1493 if (type == ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE) {
1494 enable = (uint8) nla_get_u32(data);
1495 err = dhd_dev_set_tcpack_sup_mode_cfg(ndev, enable);
1496 if (unlikely(err)) {
1497 WL_ERR(("Could not set TCP Ack Suppress mode cfg: %d\n", err));
1498 }
1499 } else {
1500 err = BCME_BADARG;
1501 }
1502
1503 exit:
1504 return err;
1505 }
1506 #endif /* DHDTCPACK_SUPPRESS */
1507
1508 #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT)
1509 static int
wl_cfgvendor_notify_dump_completion(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1510 wl_cfgvendor_notify_dump_completion(struct wiphy *wiphy,
1511 struct wireless_dev *wdev, const void *data, int len)
1512 {
1513 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1514 dhd_pub_t *dhd_pub = cfg->pub;
1515 unsigned long flags = 0;
1516
1517 WL_INFORM(("%s, [DUMP] received file dump notification from HAL\n", __FUNCTION__));
1518
1519 DHD_GENERAL_LOCK(dhd_pub, flags);
1520 /* call wmb() to synchronize with the previous memory operations */
1521 OSL_SMP_WMB();
1522 DHD_BUS_BUSY_CLEAR_IN_HALDUMP(dhd_pub);
1523 /* Call another wmb() to make sure wait_for_dump_completion value
1524 * gets updated before waking up waiting context.
1525 */
1526 OSL_SMP_WMB();
1527 dhd_os_busbusy_wake(dhd_pub);
1528 DHD_GENERAL_UNLOCK(dhd_pub, flags);
1529
1530 return BCME_OK;
1531 }
1532 #endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */
1533
1534 #if defined(WL_CFG80211)
1535 static int
wl_cfgvendor_set_hal_pid(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1536 wl_cfgvendor_set_hal_pid(struct wiphy *wiphy,
1537 struct wireless_dev *wdev, const void *data, int len)
1538 {
1539 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1540 int ret = BCME_OK;
1541 uint32 type;
1542 if (!data) {
1543 WL_DBG(("%s,data is not available\n", __FUNCTION__));
1544 } else {
1545 if (len > 0) {
1546 type = nla_type(data);
1547 if (type == SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID) {
1548 if (nla_len(data)) {
1549 WL_DBG(("HAL PID = %u\n", nla_get_u32(data)));
1550 cfg->halpid = nla_get_u32(data);
1551 }
1552 }
1553 } else {
1554 WL_ERR(("invalid len %d\n", len));
1555 ret = BCME_ERROR;
1556 }
1557 }
1558 return ret;
1559 }
1560
1561 static int
wl_cfgvendor_set_hal_started(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1562 wl_cfgvendor_set_hal_started(struct wiphy *wiphy,
1563 struct wireless_dev *wdev, const void *data, int len)
1564 {
1565 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1566 #ifdef WL_STA_ASSOC_RAND
1567 struct ether_addr primary_mac;
1568 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
1569 #endif /* WL_STA_ASSOC_RAND */
1570 int ret = BCME_OK;
1571 #if defined(WIFI_TURNON_USE_HALINIT)
1572 struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1573 uint32 type;
1574
1575 if (!data) {
1576 WL_DBG(("%s,data is not available\n", __FUNCTION__));
1577 } else {
1578 if (len > 0) {
1579 type = nla_type(data);
1580 WL_INFORM(("%s,type: %xh\n", __FUNCTION__, type));
1581 if (type == SET_HAL_START_ATTRIBUTE_PRE_INIT) {
1582 if (nla_len(data)) {
1583 WL_INFORM(("%s, HAL version: %s\n", __FUNCTION__,
1584 (char*)nla_data(data)));
1585 }
1586 WL_INFORM(("%s, dhd_open start\n", __FUNCTION__));
1587 ret = dhd_open(ndev);
1588 if (ret != BCME_OK) {
1589 WL_INFORM(("%s, dhd_open failed\n", __FUNCTION__));
1590 return ret;
1591 } else {
1592 WL_INFORM(("%s, dhd_open succeeded\n", __FUNCTION__));
1593 }
1594 return ret;
1595 }
1596 } else {
1597 WL_ERR(("invalid len %d\n", len));
1598 }
1599 }
1600 #endif /* WIFI_TURNON_USE_HALINIT */
1601 RETURN_EIO_IF_NOT_UP(cfg);
1602 WL_INFORM(("%s,[DUMP] HAL STARTED\n", __FUNCTION__));
1603
1604 cfg->hal_started = true;
1605 #ifdef WL_STA_ASSOC_RAND
1606 /* If mac randomization is enabled and primary macaddress is not
1607 * randomized, randomize it from HAL init context
1608 */
1609 get_primary_mac(cfg, &primary_mac);
1610 if ((!ETHER_IS_LOCALADDR(&primary_mac)) &&
1611 (!wl_get_drv_status(cfg, CONNECTED, wdev_to_ndev(wdev)))) {
1612 WL_DBG_MEM(("%s, Local admin bit not set, randomize"
1613 "STA MAC address \n", __FUNCTION__));
1614 if ((ret = dhd_update_rand_mac_addr(dhd)) < 0) {
1615 WL_ERR(("%s: failed to set macaddress, ret = %d\n", __FUNCTION__, ret));
1616 return ret;
1617 }
1618 }
1619 #endif /* WL_STA_ASSOC_RAND */
1620 return ret;
1621 }
1622
1623 static int
wl_cfgvendor_stop_hal(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1624 wl_cfgvendor_stop_hal(struct wiphy *wiphy,
1625 struct wireless_dev *wdev, const void *data, int len)
1626 {
1627 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1628 WL_INFORM(("%s,[DUMP] HAL STOPPED\n", __FUNCTION__));
1629
1630 cfg->hal_started = false;
1631 return BCME_OK;
1632 }
1633 #endif /* WL_CFG80211 */
1634
1635 #ifdef WL_LATENCY_MODE
1636 static int
wl_cfgvendor_set_latency_mode(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1637 wl_cfgvendor_set_latency_mode(struct wiphy *wiphy,
1638 struct wireless_dev *wdev, const void *data, int len)
1639 {
1640 int err = BCME_OK, rem, type;
1641 u32 latency_mode;
1642 const struct nlattr *iter;
1643 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
1644 bool enable;
1645 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
1646 #ifdef WL_AUTO_QOS
1647 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
1648 #endif /* WL_AUTO_QOS */
1649
1650 nla_for_each_attr(iter, data, len, rem) {
1651 type = nla_type(iter);
1652 switch (type) {
1653 case ANDR_WIFI_ATTRIBUTE_LATENCY_MODE:
1654 latency_mode = nla_get_u32(iter);
1655 WL_DBG(("%s,Setting latency mode %u\n", __FUNCTION__,
1656 latency_mode));
1657 #ifdef WL_AUTO_QOS
1658 /* Enable/Disable qos monitoring */
1659 dhd_wl_sock_qos_set_status(dhdp, latency_mode);
1660 #endif /* WL_AUTO_QOS */
1661 #ifdef SUPPORT_LATENCY_CRITICAL_DATA
1662 enable = latency_mode ? true : false;
1663 err = wldev_iovar_setint(wdev->netdev,
1664 "latency_critical_data", enable);
1665 if (err != BCME_OK) {
1666 WL_ERR(("failed to set latency_critical_data "
1667 "enable %d, error = %d\n", enable, err));
1668 /* Proceed with other optimizations possible */
1669 err = BCME_OK;
1670 }
1671 #endif /* SUPPORT_LATENCY_CRITICAL_DATA */
1672 break;
1673 default:
1674 WL_ERR(("Unknown type: %d\n", type));
1675 return err;
1676 }
1677 }
1678
1679 return err;
1680 }
1681 #endif /* WL_LATENCY_MODE */
1682
1683 #ifdef RTT_SUPPORT
1684 void
wl_cfgvendor_rtt_evt(void * ctx,void * rtt_data)1685 wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
1686 {
1687 struct wireless_dev *wdev = (struct wireless_dev *)ctx;
1688 struct wiphy *wiphy;
1689 struct sk_buff *skb = NULL;
1690 uint32 evt_complete = 0;
1691 gfp_t kflags;
1692 rtt_result_t *rtt_result;
1693 rtt_results_header_t *rtt_header;
1694 struct list_head *rtt_cache_list;
1695 struct nlattr *rtt_nl_hdr;
1696 int ret = BCME_OK;
1697 wiphy = wdev->wiphy;
1698
1699 WL_DBG(("In\n"));
1700 /* Push the data to the skb */
1701 if (!rtt_data) {
1702 WL_ERR(("rtt_data is NULL\n"));
1703 return;
1704 }
1705 rtt_cache_list = (struct list_head *)rtt_data;
1706 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1707 if (list_empty(rtt_cache_list)) {
1708 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1709 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1710 skb = cfg80211_vendor_event_alloc(wiphy, NULL, 100,
1711 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1712 #else
1713 skb = cfg80211_vendor_event_alloc(wiphy, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags);
1714 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1715 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1716 if (!skb) {
1717 WL_ERR(("skb alloc failed"));
1718 return;
1719 }
1720 evt_complete = 1;
1721 ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1722 if (ret < 0) {
1723 WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
1724 goto free_mem;
1725 }
1726 cfg80211_vendor_event(skb, kflags);
1727 return;
1728 }
1729 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
1730 list_for_each_entry(rtt_header, rtt_cache_list, list) {
1731 /* Alloc the SKB for vendor_event */
1732 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1733 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1734 skb = cfg80211_vendor_event_alloc(wiphy, NULL, rtt_header->result_tot_len + 100,
1735 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1736 #else
1737 skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100,
1738 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1739 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1740 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1741 if (!skb) {
1742 WL_ERR(("skb alloc failed"));
1743 return;
1744 }
1745 if (list_is_last(&rtt_header->list, rtt_cache_list)) {
1746 evt_complete = 1;
1747 }
1748 ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1749 if (ret < 0) {
1750 WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
1751 goto free_mem;
1752 }
1753 rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET);
1754 if (!rtt_nl_hdr) {
1755 WL_ERR(("rtt_nl_hdr is NULL\n"));
1756 dev_kfree_skb_any(skb);
1757 break;
1758 }
1759 ret = nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN,
1760 &rtt_header->peer_mac);
1761 if (ret < 0) {
1762 WL_ERR(("Failed to put RTT_ATTRIBUTE_TARGET_MAC, ret:%d\n", ret));
1763 goto free_mem;
1764 }
1765 ret = nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt);
1766 if (ret < 0) {
1767 WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_CNT, ret:%d\n", ret));
1768 goto free_mem;
1769 }
1770 list_for_each_entry(rtt_result, &rtt_header->result_list, list) {
1771 ret = nla_put(skb, RTT_ATTRIBUTE_RESULT,
1772 rtt_result->report_len, &rtt_result->report);
1773 if (ret < 0) {
1774 WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT, ret:%d\n", ret));
1775 goto free_mem;
1776 }
1777 ret = nla_put(skb, RTT_ATTRIBUTE_RESULT_DETAIL,
1778 rtt_result->detail_len, &rtt_result->rtt_detail);
1779 if (ret < 0) {
1780 WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_DETAIL, ret:%d\n",
1781 ret));
1782 goto free_mem;
1783 }
1784 }
1785 nla_nest_end(skb, rtt_nl_hdr);
1786 cfg80211_vendor_event(skb, kflags);
1787 }
1788 GCC_DIAGNOSTIC_POP();
1789
1790 return;
1791
1792 free_mem:
1793 /* Free skb memory */
1794 if (skb) {
1795 kfree_skb(skb);
1796 }
1797 }
1798
1799 static int
wl_cfgvendor_rtt_set_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)1800 wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1801 const void *data, int len) {
1802 int err = 0, rem, rem1, rem2, type;
1803 int target_cnt = 0;
1804 rtt_config_params_t rtt_param;
1805 rtt_target_info_t* rtt_target = NULL;
1806 const struct nlattr *iter, *iter1, *iter2;
1807 int8 eabuf[ETHER_ADDR_STR_LEN];
1808 int8 chanbuf[CHANSPEC_STR_LEN];
1809 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1810 rtt_capabilities_t capability;
1811
1812 bzero(&rtt_param, sizeof(rtt_param));
1813
1814 WL_DBG(("In\n"));
1815 err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
1816 if (err < 0) {
1817 WL_ERR(("failed to register rtt_noti_callback\n"));
1818 goto exit;
1819 }
1820 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1821 if (err < 0) {
1822 WL_ERR(("failed to get the capability\n"));
1823 goto exit;
1824 }
1825
1826 if (len <= 0) {
1827 WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
1828 err = BCME_ERROR;
1829 goto exit;
1830 }
1831 nla_for_each_attr(iter, data, len, rem) {
1832 type = nla_type(iter);
1833 switch (type) {
1834 case RTT_ATTRIBUTE_TARGET_CNT:
1835 if (target_cnt != 0) {
1836 WL_ERR(("attempt to overwrite target_cnt"));
1837 err = -EINVAL;
1838 goto exit;
1839 }
1840 target_cnt = nla_get_u8(iter);
1841 if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) {
1842 WL_ERR(("target_cnt is not valid : %d\n",
1843 target_cnt));
1844 err = BCME_RANGE;
1845 goto exit;
1846 }
1847 rtt_param.rtt_target_cnt = target_cnt;
1848
1849 rtt_param.target_info = (rtt_target_info_t *)MALLOCZ(cfg->osh,
1850 TARGET_INFO_SIZE(target_cnt));
1851 if (rtt_param.target_info == NULL) {
1852 WL_ERR(("failed to allocate target info for (%d)\n", target_cnt));
1853 err = BCME_NOMEM;
1854 goto exit;
1855 }
1856 break;
1857 case RTT_ATTRIBUTE_TARGET_INFO:
1858 /* Added this variable for safe check to avoid crash
1859 * incase the caller did not respect the order
1860 */
1861 if (rtt_param.target_info == NULL) {
1862 WL_ERR(("rtt_target_info is NULL\n"));
1863 err = BCME_NOMEM;
1864 goto exit;
1865 }
1866 rtt_target = rtt_param.target_info;
1867 nla_for_each_nested(iter1, iter, rem1) {
1868 if ((uint8 *)rtt_target >= ((uint8 *)rtt_param.target_info +
1869 TARGET_INFO_SIZE(target_cnt))) {
1870 WL_ERR(("rtt_target increased over its max size"));
1871 err = -EINVAL;
1872 goto exit;
1873 }
1874 nla_for_each_nested(iter2, iter1, rem2) {
1875 type = nla_type(iter2);
1876 switch (type) {
1877 case RTT_ATTRIBUTE_TARGET_MAC:
1878 if (nla_len(iter2) != ETHER_ADDR_LEN) {
1879 WL_ERR(("mac_addr length not match\n"));
1880 err = -EINVAL;
1881 goto exit;
1882 }
1883 memcpy(&rtt_target->addr, nla_data(iter2),
1884 ETHER_ADDR_LEN);
1885 break;
1886 case RTT_ATTRIBUTE_TARGET_TYPE:
1887 rtt_target->type = nla_get_u8(iter2);
1888 if (rtt_target->type == RTT_INVALID ||
1889 (rtt_target->type == RTT_ONE_WAY &&
1890 !capability.rtt_one_sided_supported)) {
1891 WL_ERR(("doesn't support RTT type"
1892 " : %d\n",
1893 rtt_target->type));
1894 err = -EINVAL;
1895 goto exit;
1896 }
1897 break;
1898 case RTT_ATTRIBUTE_TARGET_PEER:
1899 rtt_target->peer = nla_get_u8(iter2);
1900 break;
1901 case RTT_ATTRIBUTE_TARGET_CHAN:
1902 memcpy(&rtt_target->channel, nla_data(iter2),
1903 sizeof(rtt_target->channel));
1904 break;
1905 case RTT_ATTRIBUTE_TARGET_PERIOD:
1906 rtt_target->burst_period = nla_get_u32(iter2);
1907 if (rtt_target->burst_period < 32) {
1908 /* 100ms unit */
1909 rtt_target->burst_period *= 100;
1910 } else {
1911 WL_ERR(("%d value must in (0-31)\n",
1912 rtt_target->burst_period));
1913 err = EINVAL;
1914 goto exit;
1915 }
1916 break;
1917 case RTT_ATTRIBUTE_TARGET_NUM_BURST:
1918 rtt_target->num_burst = nla_get_u32(iter2);
1919 if (rtt_target->num_burst > 16) {
1920 WL_ERR(("%d value must in (0-15)\n",
1921 rtt_target->num_burst));
1922 err = -EINVAL;
1923 goto exit;
1924 }
1925 rtt_target->num_burst = BIT(rtt_target->num_burst);
1926 break;
1927 case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST:
1928 rtt_target->num_frames_per_burst =
1929 nla_get_u32(iter2);
1930 break;
1931 case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM:
1932 rtt_target->num_retries_per_ftm =
1933 nla_get_u32(iter2);
1934 break;
1935 case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR:
1936 rtt_target->num_retries_per_ftmr =
1937 nla_get_u32(iter2);
1938 if (rtt_target->num_retries_per_ftmr > 3) {
1939 WL_ERR(("%d value must in (0-3)\n",
1940 rtt_target->num_retries_per_ftmr));
1941 err = -EINVAL;
1942 goto exit;
1943 }
1944 break;
1945 case RTT_ATTRIBUTE_TARGET_LCI:
1946 rtt_target->LCI_request = nla_get_u8(iter2);
1947 break;
1948 case RTT_ATTRIBUTE_TARGET_LCR:
1949 rtt_target->LCI_request = nla_get_u8(iter2);
1950 break;
1951 case RTT_ATTRIBUTE_TARGET_BURST_DURATION:
1952 if ((nla_get_u32(iter2) > 1 &&
1953 nla_get_u32(iter2) < 12)) {
1954 rtt_target->burst_duration =
1955 dhd_rtt_idx_to_burst_duration(
1956 nla_get_u32(iter2));
1957 } else if (nla_get_u32(iter2) == 15) {
1958 /* use default value */
1959 rtt_target->burst_duration = 0;
1960 } else {
1961 WL_ERR(("%d value must in (2-11) or 15\n",
1962 nla_get_u32(iter2)));
1963 err = -EINVAL;
1964 goto exit;
1965 }
1966 break;
1967 case RTT_ATTRIBUTE_TARGET_BW:
1968 rtt_target->bw = nla_get_u8(iter2);
1969 break;
1970 case RTT_ATTRIBUTE_TARGET_PREAMBLE:
1971 rtt_target->preamble = nla_get_u8(iter2);
1972 break;
1973 }
1974 }
1975 /* convert to chanspec value */
1976 rtt_target->chanspec =
1977 dhd_rtt_convert_to_chspec(rtt_target->channel);
1978 if (rtt_target->chanspec == 0) {
1979 WL_ERR(("Channel is not valid \n"));
1980 err = -EINVAL;
1981 goto exit;
1982 }
1983 WL_INFORM_MEM(("Target addr %s, Channel : %s for RTT \n",
1984 bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr,
1985 eabuf),
1986 wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
1987 rtt_target++;
1988 }
1989 break;
1990 }
1991 }
1992 WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
1993 if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
1994 WL_ERR(("Could not set RTT configuration\n"));
1995 err = -EINVAL;
1996 }
1997 exit:
1998 /* free the target info list */
1999 if (rtt_param.target_info) {
2000 MFREE(cfg->osh, rtt_param.target_info,
2001 TARGET_INFO_SIZE(target_cnt));
2002 }
2003 return err;
2004 }
2005
2006 static int
wl_cfgvendor_rtt_cancel_config(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2007 wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
2008 const void *data, int len)
2009 {
2010 int err = 0, rem, type, target_cnt = 0;
2011 int target_idx = 0;
2012 const struct nlattr *iter;
2013 struct ether_addr *mac_list = NULL;
2014 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2015
2016 if (len <= 0) {
2017 WL_ERR(("Length of nlattr is not valid len : %d\n", len));
2018 err = -EINVAL;
2019 goto exit;
2020 }
2021 nla_for_each_attr(iter, data, len, rem) {
2022 type = nla_type(iter);
2023 switch (type) {
2024 case RTT_ATTRIBUTE_TARGET_CNT:
2025 if (mac_list != NULL) {
2026 WL_ERR(("mac_list is not NULL\n"));
2027 err = -EINVAL;
2028 goto exit;
2029 }
2030 target_cnt = nla_get_u8(iter);
2031 if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) {
2032 mac_list = (struct ether_addr *)MALLOCZ(cfg->osh,
2033 target_cnt * ETHER_ADDR_LEN);
2034 if (mac_list == NULL) {
2035 WL_ERR(("failed to allocate mem for mac list\n"));
2036 err = -EINVAL;
2037 goto exit;
2038 }
2039 } else {
2040 /* cancel the current whole RTT process */
2041 goto cancel;
2042 }
2043 break;
2044 case RTT_ATTRIBUTE_TARGET_MAC:
2045 if (mac_list == NULL) {
2046 WL_ERR(("ATTRIBUTE_TARGET_CNT not found before "
2047 " ATTRIBUTE_TARGET_MAC\n"));
2048 err = -EINVAL;
2049 goto exit;
2050 }
2051
2052 if (target_idx >= target_cnt) {
2053 WL_ERR(("More TARGET_MAC entries found, "
2054 "expected TARGET_CNT:%d\n", target_cnt));
2055 err = -EINVAL;
2056 goto exit;
2057 }
2058
2059 if (nla_len(iter) != ETHER_ADDR_LEN) {
2060 WL_ERR(("Invalid TARGET_MAC ATTR len :%d\n", nla_len(iter)));
2061 err = -EINVAL;
2062 goto exit;
2063 }
2064
2065 memcpy(&mac_list[target_idx], nla_data(iter), ETHER_ADDR_LEN);
2066 target_idx++;
2067
2068 break;
2069 default:
2070 WL_ERR(("Uknown type : %d\n", type));
2071 err = -EINVAL;
2072 goto exit;
2073 }
2074 }
2075 cancel:
2076 if (mac_list && dhd_dev_rtt_cancel_cfg(
2077 bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
2078 WL_ERR(("Could not cancel RTT configuration\n"));
2079 err = -EINVAL;
2080 }
2081
2082 exit:
2083 if (mac_list) {
2084 MFREE(cfg->osh, mac_list, target_cnt * ETHER_ADDR_LEN);
2085 }
2086 return err;
2087 }
2088
2089 static int
wl_cfgvendor_rtt_get_capability(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2090 wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
2091 const void *data, int len)
2092 {
2093 int err = 0;
2094 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2095 rtt_capabilities_t capability;
2096
2097 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
2098 if (unlikely(err)) {
2099 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2100 goto exit;
2101 }
2102 err = wl_cfgvendor_send_cmd_reply(wiphy, &capability, sizeof(capability));
2103
2104 if (unlikely(err)) {
2105 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2106 }
2107 exit:
2108 return err;
2109 }
2110 static int
get_responder_info(struct bcm_cfg80211 * cfg,struct wifi_rtt_responder * responder_info)2111 get_responder_info(struct bcm_cfg80211 *cfg,
2112 struct wifi_rtt_responder *responder_info)
2113 {
2114 int err = 0;
2115 rtt_capabilities_t capability;
2116 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
2117 if (unlikely(err)) {
2118 WL_ERR(("Could not get responder capability:%d \n", err));
2119 return err;
2120 }
2121 if (capability.preamble_support & RTT_PREAMBLE_VHT) {
2122 responder_info->preamble = RTT_PREAMBLE_VHT;
2123 } else if (capability.preamble_support & RTT_PREAMBLE_HT) {
2124 responder_info->preamble = RTT_PREAMBLE_HT;
2125 } else {
2126 responder_info->preamble = RTT_PREAMBLE_LEGACY;
2127 }
2128 err = dhd_dev_rtt_avail_channel(bcmcfg_to_prmry_ndev(cfg), &(responder_info->channel));
2129 if (unlikely(err)) {
2130 WL_ERR(("Could not get available channel:%d \n", err));
2131 return err;
2132 }
2133 return err;
2134 }
2135 static int
wl_cfgvendor_rtt_get_responder_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2136 wl_cfgvendor_rtt_get_responder_info(struct wiphy *wiphy, struct wireless_dev *wdev,
2137 const void *data, int len)
2138 {
2139 int err = 0;
2140 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2141 wifi_rtt_responder_t responder_info;
2142
2143 WL_DBG(("Recv -get_avail_ch command \n"));
2144
2145 bzero(&responder_info, sizeof(responder_info));
2146 err = get_responder_info(cfg, &responder_info);
2147 if (unlikely(err)) {
2148 WL_ERR(("Failed to get responder info:%d \n", err));
2149 return err;
2150 }
2151 err = wl_cfgvendor_send_cmd_reply(wiphy, &responder_info, sizeof(responder_info));
2152 if (unlikely(err)) {
2153 WL_ERR(("Vendor cmd reply for -get_avail_ch failed ret:%d \n", err));
2154 }
2155 return err;
2156 }
2157
2158 static int
wl_cfgvendor_rtt_set_responder(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2159 wl_cfgvendor_rtt_set_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
2160 const void *data, int len)
2161 {
2162 int err = 0;
2163 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2164 struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
2165 wifi_rtt_responder_t responder_info;
2166
2167 WL_DBG(("Recv rtt -enable_resp cmd.\n"));
2168
2169 bzero(&responder_info, sizeof(responder_info));
2170
2171 /*
2172 *Passing channel as NULL until implementation
2173 *to get chan info from upper layers is donex
2174 */
2175 err = dhd_dev_rtt_enable_responder(ndev, NULL);
2176 if (unlikely(err)) {
2177 WL_ERR(("Could not enable responder ret:%d \n", err));
2178 goto done;
2179 }
2180 err = get_responder_info(cfg, &responder_info);
2181 if (unlikely(err)) {
2182 WL_ERR(("Failed to get responder info:%d \n", err));
2183 dhd_dev_rtt_cancel_responder(ndev);
2184 goto done;
2185 }
2186 done:
2187 err = wl_cfgvendor_send_cmd_reply(wiphy, &responder_info, sizeof(responder_info));
2188 if (unlikely(err)) {
2189 WL_ERR(("Vendor cmd reply for -enable_resp failed ret:%d \n", err));
2190 }
2191 return err;
2192 }
2193
2194 static int
wl_cfgvendor_rtt_cancel_responder(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2195 wl_cfgvendor_rtt_cancel_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
2196 const void *data, int len)
2197 {
2198 int err = 0;
2199 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2200
2201 WL_DBG(("Recv rtt -cancel_resp cmd \n"));
2202
2203 err = dhd_dev_rtt_cancel_responder(bcmcfg_to_prmry_ndev(cfg));
2204 if (unlikely(err)) {
2205 WL_ERR(("Vendor cmd -cancel_resp failed ret:%d \n", err));
2206 }
2207 return err;
2208 }
2209 #endif /* RTT_SUPPORT */
2210
2211 #ifdef GSCAN_SUPPORT
wl_cfgvendor_enable_lazy_roam(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2212 static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy,
2213 struct wireless_dev *wdev, const void *data, int len)
2214 {
2215 int err = -EINVAL;
2216 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2217 int type;
2218 uint32 lazy_roam_enable_flag;
2219
2220 if (!data) {
2221 WL_ERR(("data is not available\n"));
2222 return -EINVAL;
2223 }
2224
2225 if (len <= 0) {
2226 WL_ERR(("invaild len %d\n", len));
2227 return -EINVAL;
2228 }
2229
2230 type = nla_type(data);
2231
2232 if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) {
2233 lazy_roam_enable_flag = nla_get_u32(data);
2234
2235 err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg),
2236 lazy_roam_enable_flag);
2237 if (unlikely(err))
2238 WL_ERR(("Could not enable lazy roam:%d \n", err));
2239 }
2240
2241 return err;
2242 }
2243
wl_cfgvendor_set_lazy_roam_cfg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2244 static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy,
2245 struct wireless_dev *wdev, const void *data, int len)
2246 {
2247 int err = 0, tmp, type;
2248 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2249 wlc_roam_exp_params_t roam_param;
2250 const struct nlattr *iter;
2251
2252 bzero(&roam_param, sizeof(roam_param));
2253
2254 nla_for_each_attr(iter, data, len, tmp) {
2255 type = nla_type(iter);
2256 switch (type) {
2257 case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD:
2258 roam_param.a_band_boost_threshold = nla_get_u32(iter);
2259 break;
2260 case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD:
2261 roam_param.a_band_penalty_threshold = nla_get_u32(iter);
2262 break;
2263 case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR:
2264 roam_param.a_band_boost_factor = nla_get_u32(iter);
2265 break;
2266 case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR:
2267 roam_param.a_band_penalty_factor = nla_get_u32(iter);
2268 break;
2269 case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST:
2270 roam_param.a_band_max_boost = nla_get_u32(iter);
2271 break;
2272 case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS:
2273 roam_param.cur_bssid_boost = nla_get_u32(iter);
2274 break;
2275 case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER:
2276 roam_param.alert_roam_trigger_threshold = nla_get_u32(iter);
2277 break;
2278 }
2279 }
2280
2281 if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) {
2282 WL_ERR(("Could not set batch cfg\n"));
2283 err = -EINVAL;
2284 }
2285 return err;
2286 }
2287
2288 /* small helper function */
2289 static wl_bssid_pref_cfg_t *
create_bssid_pref_cfg(struct bcm_cfg80211 * cfg,uint32 num,uint32 * buf_len)2290 create_bssid_pref_cfg(struct bcm_cfg80211 *cfg, uint32 num, uint32 *buf_len)
2291 {
2292 wl_bssid_pref_cfg_t *bssid_pref;
2293
2294 *buf_len = sizeof(wl_bssid_pref_cfg_t);
2295 if (num) {
2296 *buf_len += (num - 1) * sizeof(wl_bssid_pref_list_t);
2297 }
2298 bssid_pref = (wl_bssid_pref_cfg_t *)MALLOC(cfg->osh, *buf_len);
2299
2300 return bssid_pref;
2301 }
2302
2303 static int
wl_cfgvendor_set_bssid_pref(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2304 wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy,
2305 struct wireless_dev *wdev, const void *data, int len)
2306 {
2307 int err = 0;
2308 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2309 wl_bssid_pref_cfg_t *bssid_pref = NULL;
2310 wl_bssid_pref_list_t *bssids;
2311 int tmp, tmp1, tmp2, type;
2312 const struct nlattr *outer, *inner, *iter;
2313 uint32 flush = 0, num = 0, buf_len = 0;
2314 uint8 bssid_found = 0, rssi_found = 0;
2315
2316 /* Assumption: NUM attribute must come first */
2317 nla_for_each_attr(iter, data, len, tmp2) {
2318 type = nla_type(iter);
2319 switch (type) {
2320 case GSCAN_ATTRIBUTE_NUM_BSSID:
2321 if (num) {
2322 WL_ERR(("attempt overide bssid num.\n"));
2323 err = -EINVAL;
2324 goto exit;
2325 }
2326 if (nla_len(iter) != sizeof(uint32)) {
2327 WL_ERR(("nla_len not match\n"));
2328 err = -EINVAL;
2329 goto exit;
2330 }
2331 num = nla_get_u32(iter);
2332 if (num == 0 || num > MAX_BSSID_PREF_LIST_NUM) {
2333 WL_ERR(("wrong BSSID num:%d\n", num));
2334 err = -EINVAL;
2335 goto exit;
2336 }
2337 if ((bssid_pref = create_bssid_pref_cfg(cfg, num, &buf_len))
2338 == NULL) {
2339 WL_ERR(("Can't malloc memory\n"));
2340 err = -ENOMEM;
2341 goto exit;
2342 }
2343 break;
2344 case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH:
2345 if (nla_len(iter) != sizeof(uint32)) {
2346 WL_ERR(("nla_len not match\n"));
2347 err = -EINVAL;
2348 goto exit;
2349 }
2350 flush = nla_get_u32(iter);
2351 if (flush != 1) {
2352 WL_ERR(("wrong flush value\n"));
2353 err = -EINVAL;
2354 goto exit;
2355 }
2356 break;
2357 case GSCAN_ATTRIBUTE_BSSID_PREF_LIST:
2358 if (!num || !bssid_pref) {
2359 WL_ERR(("bssid list count not set\n"));
2360 err = -EINVAL;
2361 goto exit;
2362 }
2363 bssid_pref->count = 0;
2364 bssids = bssid_pref->bssids;
2365 nla_for_each_nested(outer, iter, tmp) {
2366 if (bssid_pref->count >= num) {
2367 WL_ERR(("too many bssid list\n"));
2368 err = -EINVAL;
2369 goto exit;
2370 }
2371 bssid_found = 0;
2372 rssi_found = 0;
2373 nla_for_each_nested(inner, outer, tmp1) {
2374 type = nla_type(inner);
2375 switch (type) {
2376 case GSCAN_ATTRIBUTE_BSSID_PREF:
2377 if (nla_len(inner) != ETHER_ADDR_LEN) {
2378 WL_ERR(("nla_len not match.\n"));
2379 err = -EINVAL;
2380 goto exit;
2381 }
2382 memcpy(&(bssids[bssid_pref->count].bssid),
2383 nla_data(inner), ETHER_ADDR_LEN);
2384 /* not used for now */
2385 bssids[bssid_pref->count].flags = 0;
2386 bssid_found = 1;
2387 break;
2388 case GSCAN_ATTRIBUTE_RSSI_MODIFIER:
2389 if (nla_len(inner) != sizeof(uint32)) {
2390 WL_ERR(("nla_len not match.\n"));
2391 err = -EINVAL;
2392 goto exit;
2393 }
2394 bssids[bssid_pref->count].rssi_factor =
2395 (int8) nla_get_u32(inner);
2396 rssi_found = 1;
2397 break;
2398 default:
2399 WL_ERR(("wrong type:%d\n", type));
2400 err = -EINVAL;
2401 goto exit;
2402 }
2403 if (bssid_found && rssi_found) {
2404 break;
2405 }
2406 }
2407 bssid_pref->count++;
2408 }
2409 break;
2410 default:
2411 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
2412 break;
2413 }
2414 }
2415
2416 if (!bssid_pref) {
2417 /* What if only flush is desired? */
2418 if (flush) {
2419 if ((bssid_pref = create_bssid_pref_cfg(cfg, 0, &buf_len)) == NULL) {
2420 WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__));
2421 err = -ENOMEM;
2422 goto exit;
2423 }
2424 bssid_pref->count = 0;
2425 } else {
2426 err = -EINVAL;
2427 goto exit;
2428 }
2429 }
2430 err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg),
2431 bssid_pref, flush);
2432 exit:
2433 if (bssid_pref) {
2434 MFREE(cfg->osh, bssid_pref, buf_len);
2435 }
2436 return err;
2437 }
2438 #endif /* GSCAN_SUPPORT */
2439 #if defined(GSCAN_SUPPORT) || defined(ROAMEXP_SUPPORT)
2440 static int
wl_cfgvendor_set_bssid_blacklist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2441 wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy,
2442 struct wireless_dev *wdev, const void *data, int len)
2443 {
2444 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2445 maclist_t *blacklist = NULL;
2446 int err = 0;
2447 int type, tmp;
2448 const struct nlattr *iter;
2449 uint32 mem_needed = 0, flush = 0, num = 0;
2450
2451 /* Assumption: NUM attribute must come first */
2452 nla_for_each_attr(iter, data, len, tmp) {
2453 type = nla_type(iter);
2454 switch (type) {
2455 case GSCAN_ATTRIBUTE_NUM_BSSID:
2456 if (num != 0) {
2457 WL_ERR(("attempt to change BSSID num\n"));
2458 err = -EINVAL;
2459 goto exit;
2460 }
2461 if (nla_len(iter) != sizeof(uint32)) {
2462 WL_ERR(("not matching nla_len.\n"));
2463 err = -EINVAL;
2464 goto exit;
2465 }
2466 num = nla_get_u32(iter);
2467 if (num == 0 || num > MAX_BSSID_BLACKLIST_NUM) {
2468 WL_ERR(("wrong BSSID count:%d\n", num));
2469 err = -EINVAL;
2470 goto exit;
2471 }
2472 if (!blacklist) {
2473 mem_needed = (uint32) (OFFSETOF(maclist_t, ea) +
2474 sizeof(struct ether_addr) * (num));
2475 blacklist = (maclist_t *)
2476 MALLOCZ(cfg->osh, mem_needed);
2477 if (!blacklist) {
2478 WL_ERR(("MALLOCZ failed.\n"));
2479 err = -ENOMEM;
2480 goto exit;
2481 }
2482 }
2483 break;
2484 case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH:
2485 if (nla_len(iter) != sizeof(uint32)) {
2486 WL_ERR(("not matching nla_len.\n"));
2487 err = -EINVAL;
2488 goto exit;
2489 }
2490 flush = nla_get_u32(iter);
2491 if (flush != 1) {
2492 WL_ERR(("flush arg is worng:%d\n", flush));
2493 err = -EINVAL;
2494 goto exit;
2495 }
2496 break;
2497 case GSCAN_ATTRIBUTE_BLACKLIST_BSSID:
2498 if (num == 0 || !blacklist) {
2499 WL_ERR(("number of BSSIDs not received.\n"));
2500 err = -EINVAL;
2501 goto exit;
2502 }
2503 if (nla_len(iter) != ETHER_ADDR_LEN) {
2504 WL_ERR(("not matching nla_len.\n"));
2505 err = -EINVAL;
2506 goto exit;
2507 }
2508 if (blacklist->count >= num) {
2509 WL_ERR(("too many BSSIDs than expected:%d\n",
2510 blacklist->count));
2511 err = -EINVAL;
2512 goto exit;
2513 }
2514 memcpy(&(blacklist->ea[blacklist->count]), nla_data(iter),
2515 ETHER_ADDR_LEN);
2516 blacklist->count++;
2517 break;
2518 default:
2519 WL_ERR(("No such attribute:%d\n", type));
2520 break;
2521 }
2522 }
2523
2524 if (blacklist && (blacklist->count != num)) {
2525 WL_ERR(("not matching bssid count:%d to expected:%d\n",
2526 blacklist->count, num));
2527 err = -EINVAL;
2528 goto exit;
2529 }
2530
2531 err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg),
2532 blacklist, mem_needed, flush);
2533 exit:
2534 MFREE(cfg->osh, blacklist, mem_needed);
2535 return err;
2536 }
2537
2538 static int
wl_cfgvendor_set_ssid_whitelist(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2539 wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy,
2540 struct wireless_dev *wdev, const void *data, int len)
2541 {
2542 int err = 0;
2543 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2544 wl_ssid_whitelist_t *ssid_whitelist = NULL;
2545 wlc_ssid_t *ssid_elem;
2546 int tmp, tmp1, mem_needed = 0, type;
2547 const struct nlattr *iter, *iter1;
2548 uint32 flush = 0, num = 0;
2549 int ssid_found = 0;
2550
2551 /* Assumption: NUM attribute must come first */
2552 nla_for_each_attr(iter, data, len, tmp) {
2553 type = nla_type(iter);
2554 switch (type) {
2555 case GSCAN_ATTRIBUTE_NUM_WL_SSID:
2556 if (num != 0) {
2557 WL_ERR(("try to change SSID num\n"));
2558 err = -EINVAL;
2559 goto exit;
2560 }
2561 if (nla_len(iter) != sizeof(uint32)) {
2562 WL_ERR(("not matching nla_len.\n"));
2563 err = -EINVAL;
2564 goto exit;
2565 }
2566 num = nla_get_u32(iter);
2567 if (num == 0 || num > MAX_SSID_WHITELIST_NUM) {
2568 WL_ERR(("wrong SSID count:%d\n", num));
2569 err = -EINVAL;
2570 goto exit;
2571 }
2572 mem_needed = sizeof(wl_ssid_whitelist_t) +
2573 sizeof(wlc_ssid_t) * num;
2574 ssid_whitelist = (wl_ssid_whitelist_t *)
2575 MALLOCZ(cfg->osh, mem_needed);
2576 if (ssid_whitelist == NULL) {
2577 WL_ERR(("failed to alloc mem\n"));
2578 err = -ENOMEM;
2579 goto exit;
2580 }
2581 break;
2582 case GSCAN_ATTRIBUTE_WL_SSID_FLUSH:
2583 if (nla_len(iter) != sizeof(uint32)) {
2584 WL_ERR(("not matching nla_len.\n"));
2585 err = -EINVAL;
2586 goto exit;
2587 }
2588 flush = nla_get_u32(iter);
2589 if (flush != 1) {
2590 WL_ERR(("flush arg worng:%d\n", flush));
2591 err = -EINVAL;
2592 goto exit;
2593 }
2594 break;
2595 case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM:
2596 if (!num || !ssid_whitelist) {
2597 WL_ERR(("num ssid is not set!\n"));
2598 err = -EINVAL;
2599 goto exit;
2600 }
2601 if (ssid_whitelist->ssid_count >= num) {
2602 WL_ERR(("too many SSIDs:%d\n",
2603 ssid_whitelist->ssid_count));
2604 err = -EINVAL;
2605 goto exit;
2606 }
2607
2608 ssid_elem = &ssid_whitelist->ssids[
2609 ssid_whitelist->ssid_count];
2610 ssid_found = 0;
2611 nla_for_each_nested(iter1, iter, tmp1) {
2612 type = nla_type(iter1);
2613 switch (type) {
2614 case GSCAN_ATTRIBUTE_WL_SSID_LEN:
2615 if (nla_len(iter1) != sizeof(uint32)) {
2616 WL_ERR(("not match nla_len\n"));
2617 err = -EINVAL;
2618 goto exit;
2619 }
2620 ssid_elem->SSID_len = nla_get_u32(iter1);
2621 if (ssid_elem->SSID_len >
2622 DOT11_MAX_SSID_LEN) {
2623 WL_ERR(("wrong SSID len:%d\n",
2624 ssid_elem->SSID_len));
2625 err = -EINVAL;
2626 goto exit;
2627 }
2628 break;
2629 case GSCAN_ATTRIBUTE_WHITELIST_SSID:
2630 if (ssid_elem->SSID_len == 0) {
2631 WL_ERR(("SSID_len not received\n"));
2632 err = -EINVAL;
2633 goto exit;
2634 }
2635 if (nla_len(iter1) != ssid_elem->SSID_len) {
2636 WL_ERR(("not match nla_len\n"));
2637 err = -EINVAL;
2638 goto exit;
2639 }
2640 memcpy(ssid_elem->SSID, nla_data(iter1),
2641 ssid_elem->SSID_len);
2642 ssid_found = 1;
2643 break;
2644 }
2645 if (ssid_found) {
2646 ssid_whitelist->ssid_count++;
2647 break;
2648 }
2649 }
2650 break;
2651 default:
2652 WL_ERR(("No such attribute: %d\n", type));
2653 break;
2654 }
2655 }
2656
2657 if (ssid_whitelist && (ssid_whitelist->ssid_count != num)) {
2658 WL_ERR(("not matching ssid count:%d to expected:%d\n",
2659 ssid_whitelist->ssid_count, num));
2660 err = -EINVAL;
2661 goto exit;
2662 }
2663 err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg),
2664 ssid_whitelist, mem_needed, flush);
2665 if (err == BCME_UNSUPPORTED) {
2666 /* If firmware doesn't support feature, ignore the error
2667 * Android framework doesn't populate/use whitelist ssids
2668 * as of now, but invokes whitelist as part of roam config
2669 * API. so this handler cannot be compiled out. but its
2670 * safe to ignore.
2671 */
2672 WL_ERR(("whilelist ssid not supported. Ignore."));
2673 err = BCME_OK;
2674 }
2675 exit:
2676 MFREE(cfg->osh, ssid_whitelist, mem_needed);
2677 return err;
2678 }
2679 #endif /* GSCAN_SUPPORT || ROAMEXP_SUPPORT */
2680
2681 #ifdef ROAMEXP_SUPPORT
2682 typedef enum {
2683 FW_ROAMING_ENABLE = 1,
2684 FW_ROAMING_DISABLE,
2685 FW_ROAMING_PAUSE,
2686 FW_ROAMING_RESUME
2687 } fw_roaming_state_t;
2688
2689 static int
wl_cfgvendor_set_fw_roaming_state(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2690 wl_cfgvendor_set_fw_roaming_state(struct wiphy *wiphy,
2691 struct wireless_dev *wdev, const void *data, int len)
2692 {
2693 fw_roaming_state_t requested_roaming_state;
2694 int type;
2695 int err = 0;
2696
2697 if (!data) {
2698 WL_ERR(("data is not available\n"));
2699 return -EINVAL;
2700 }
2701
2702 if (len <= 0) {
2703 WL_ERR(("invalid len %d\n", len));
2704 return -EINVAL;
2705 }
2706
2707 /* Get the requested fw roaming state */
2708 type = nla_type(data);
2709 if (type != GSCAN_ATTRIBUTE_ROAM_STATE_SET) {
2710 WL_ERR(("%s: Invalid attribute %d\n", __FUNCTION__, type));
2711 return -EINVAL;
2712 }
2713
2714 requested_roaming_state = nla_get_u32(data);
2715 WL_INFORM(("setting FW roaming state to %d\n", requested_roaming_state));
2716
2717 if ((requested_roaming_state == FW_ROAMING_ENABLE) ||
2718 (requested_roaming_state == FW_ROAMING_RESUME)) {
2719 err = wldev_iovar_setint(wdev_to_ndev(wdev), "roam_off", FALSE);
2720 } else if ((requested_roaming_state == FW_ROAMING_DISABLE) ||
2721 (requested_roaming_state == FW_ROAMING_PAUSE)) {
2722 err = wldev_iovar_setint(wdev_to_ndev(wdev), "roam_off", TRUE);
2723 } else {
2724 err = -EINVAL;
2725 }
2726
2727 return err;
2728 }
2729
2730 static int
wl_cfgvendor_fw_roam_get_capability(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2731 wl_cfgvendor_fw_roam_get_capability(struct wiphy *wiphy,
2732 struct wireless_dev *wdev, const void *data, int len)
2733 {
2734 int err = 0;
2735 wifi_roaming_capabilities_t roaming_capability;
2736
2737 /* Update max number of blacklist bssids supported */
2738 roaming_capability.max_blacklist_size = MAX_BSSID_BLACKLIST_NUM;
2739 roaming_capability.max_whitelist_size = MAX_SSID_WHITELIST_NUM;
2740 err = wl_cfgvendor_send_cmd_reply(wiphy, &roaming_capability,
2741 sizeof(roaming_capability));
2742 if (unlikely(err)) {
2743 WL_ERR(("Vendor cmd reply for fw roam capability failed ret:%d \n", err));
2744 }
2745
2746 return err;
2747 }
2748 #endif /* ROAMEXP_SUPPORT */
2749
2750 static int
wl_cfgvendor_priv_string_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2751 wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
2752 struct wireless_dev *wdev, const void *data, int len)
2753 {
2754 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2755 int ret = 0;
2756 int ret_len = 0, payload = 0, msglen;
2757 const struct bcm_nlmsg_hdr *nlioc = data;
2758 void *buf = NULL, *cur;
2759 int maxmsglen = PAGE_SIZE - 0x100;
2760 struct sk_buff *reply;
2761
2762 #if defined(OEM_ANDROID)
2763 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
2764
2765 /* send to dongle only if we are not waiting for reload already */
2766 if (dhdp && dhdp->hang_was_sent) {
2767 WL_INFORM(("Bus down. HANG was sent up earlier\n"));
2768 DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, DHD_EVENT_TIMEOUT_MS);
2769 DHD_OS_WAKE_UNLOCK(dhdp);
2770 return OSL_ERROR(BCME_DONGLE_DOWN);
2771 }
2772 #endif /* (OEM_ANDROID) */
2773
2774 if (!data) {
2775 WL_ERR(("data is not available\n"));
2776 return BCME_BADARG;
2777 }
2778
2779 if (len <= sizeof(struct bcm_nlmsg_hdr)) {
2780 WL_ERR(("invalid len %d\n", len));
2781 return BCME_BADARG;
2782 }
2783
2784 WL_DBG(("entry: cmd = %d\n", nlioc->cmd));
2785
2786 if (nlioc->offset != sizeof(struct bcm_nlmsg_hdr)) {
2787 WL_ERR(("invalid offset %d\n", nlioc->offset));
2788 return BCME_BADARG;
2789 }
2790 len -= sizeof(struct bcm_nlmsg_hdr);
2791 ret_len = nlioc->len;
2792 if (ret_len > 0 || len > 0) {
2793 if (len >= DHD_IOCTL_MAXLEN) {
2794 WL_ERR(("oversize input buffer %d\n", len));
2795 len = DHD_IOCTL_MAXLEN - 1;
2796 }
2797 if (ret_len >= DHD_IOCTL_MAXLEN) {
2798 WL_ERR(("oversize return buffer %d\n", ret_len));
2799 ret_len = DHD_IOCTL_MAXLEN - 1;
2800 }
2801
2802 payload = max(ret_len, len) + 1;
2803 buf = vzalloc(payload);
2804 if (!buf) {
2805 return -ENOMEM;
2806 }
2807 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2808 memcpy(buf, (void *)((char *)nlioc + nlioc->offset), len);
2809 GCC_DIAGNOSTIC_POP();
2810 *((char *)buf + len) = '\0';
2811 }
2812
2813 ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf);
2814 if (ret) {
2815 WL_ERR(("dhd_cfgvendor returned error %d\n", ret));
2816 vfree(buf);
2817 return ret;
2818 }
2819 cur = buf;
2820 while (ret_len > 0) {
2821 msglen = ret_len > maxmsglen ? maxmsglen : ret_len;
2822 ret_len -= msglen;
2823 payload = msglen + sizeof(msglen);
2824 reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
2825 if (!reply) {
2826 WL_ERR(("Failed to allocate reply msg\n"));
2827 ret = -ENOMEM;
2828 break;
2829 }
2830
2831 if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
2832 nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
2833 kfree_skb(reply);
2834 ret = -ENOBUFS;
2835 break;
2836 }
2837
2838 ret = cfg80211_vendor_cmd_reply(reply);
2839 if (ret) {
2840 WL_ERR(("testmode reply failed:%d\n", ret));
2841 break;
2842 }
2843 cur = (void *)((char *)cur + msglen);
2844 }
2845
2846 return ret;
2847 }
2848
2849 struct net_device *
wl_cfgvendor_get_ndev(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,const char * data,unsigned long int * out_addr)2850 wl_cfgvendor_get_ndev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
2851 const char *data, unsigned long int *out_addr)
2852 {
2853 char *pos, *pos1;
2854 char ifname[IFNAMSIZ + 1] = {0};
2855 struct net_info *iter, *next;
2856 struct net_device *ndev = NULL;
2857 ulong ifname_len;
2858 *out_addr = (unsigned long int) data; /* point to command str by default */
2859
2860 /* check whether ifname=<ifname> is provided in the command */
2861 pos = strstr(data, "ifname=");
2862 if (pos) {
2863 pos += strlen("ifname=");
2864 pos1 = strstr(pos, " ");
2865 if (!pos1) {
2866 WL_ERR(("command format error \n"));
2867 return NULL;
2868 }
2869
2870 ifname_len = pos1 - pos;
2871 if (memcpy_s(ifname, (sizeof(ifname) - 1), pos, ifname_len) != BCME_OK) {
2872 WL_ERR(("Failed to copy data. len: %ld\n", ifname_len));
2873 return NULL;
2874 }
2875 GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
2876 for_each_ndev(cfg, iter, next) {
2877 if (iter->ndev) {
2878 if (strncmp(iter->ndev->name, ifname,
2879 strlen(iter->ndev->name)) == 0) {
2880 /* matching ifname found */
2881 WL_DBG(("matching interface (%s) found ndev:%p \n",
2882 iter->ndev->name, iter->ndev));
2883 *out_addr = (unsigned long int)(pos1 + 1);
2884 /* Returns the command portion after ifname=<name> */
2885 return iter->ndev;
2886 }
2887 }
2888 }
2889 GCC_DIAGNOSTIC_POP();
2890 WL_ERR(("Couldn't find ifname:%s in the netinfo list \n",
2891 ifname));
2892 return NULL;
2893 }
2894
2895 /* If ifname=<name> arg is not provided, use default ndev */
2896 ndev = wdev->netdev ? wdev->netdev : bcmcfg_to_prmry_ndev(cfg);
2897 WL_DBG(("Using default ndev (%s) \n", ndev->name));
2898 return ndev;
2899 }
2900
2901 #ifdef WL_SAE
wl_cfgvendor_map_supp_sae_pwe_to_fw(u32 sup_value,u32 * sae_pwe)2902 static int wl_cfgvendor_map_supp_sae_pwe_to_fw(u32 sup_value, u32 *sae_pwe)
2903 {
2904 s32 ret = BCME_OK;
2905 switch (sup_value) {
2906 case SUPP_SAE_PWE_LOOP:
2907 *sae_pwe = SAE_PWE_LOOP;
2908 break;
2909 case SUPP_SAE_PWE_H2E:
2910 *sae_pwe = SAE_PWE_H2E;
2911 break;
2912 case SUPP_SAE_PWE_TRANS:
2913 *sae_pwe = SAE_PWE_LOOP | SAE_PWE_H2E;
2914 break;
2915 default:
2916 ret = BCME_BADARG;
2917 }
2918 return ret;
2919 }
2920 #endif /* WL_SAE */
2921
2922 int
wl_cfgvendor_connect_params_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2923 wl_cfgvendor_connect_params_handler(struct wiphy *wiphy,
2924 struct wireless_dev *wdev, const void *data, int len)
2925 {
2926 struct net_device *net = wdev->netdev;
2927 int ret = BCME_OK;
2928 int attr_type;
2929 int rem = len;
2930 const struct nlattr *iter;
2931
2932 BCM_REFERENCE(net);
2933
2934 nla_for_each_attr(iter, data, len, rem) {
2935 attr_type = nla_type(iter);
2936 WL_DBG(("attr type: (%u)\n", attr_type));
2937
2938 switch (attr_type) {
2939 #ifdef WL_SAE
2940 case BRCM_ATTR_SAE_PWE: {
2941 u32 sae_pwe = 0;
2942 if (nla_len(iter) != sizeof(uint32)) {
2943 WL_ERR(("Invalid value of sae_pwe\n"));
2944 ret = -EINVAL;
2945 break;
2946 }
2947 ret = wl_cfgvendor_map_supp_sae_pwe_to_fw(nla_get_u32(iter), &sae_pwe);
2948 if (unlikely(ret)) {
2949 WL_ERR(("Invalid sae_pwe\n"));
2950 break;
2951 }
2952 ret = wl_cfg80211_set_wsec_info(net, &sae_pwe,
2953 sizeof(sae_pwe), WL_WSEC_INFO_BSS_SAE_PWE);
2954 if (unlikely(ret)) {
2955 WL_ERR(("set wsec_info_sae_pwe failed \n"));
2956 }
2957 break;
2958 }
2959 #endif /* WL_SAE */
2960 /* Add new attributes here */
2961 default:
2962 WL_DBG(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
2963 }
2964 }
2965
2966 return ret;
2967 }
2968
2969 int
wl_cfgvendor_start_ap_params_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)2970 wl_cfgvendor_start_ap_params_handler(struct wiphy *wiphy,
2971 struct wireless_dev *wdev, const void *data, int len)
2972 {
2973 struct net_device *net = wdev->netdev;
2974 int ret = BCME_OK;
2975 int attr_type;
2976 int rem = len;
2977 const struct nlattr *iter;
2978
2979 BCM_REFERENCE(net);
2980
2981 nla_for_each_attr(iter, data, len, rem) {
2982 attr_type = nla_type(iter);
2983 WL_DBG(("attr type: (%u)\n", attr_type));
2984
2985 switch (attr_type) {
2986 #ifdef WL_SAE
2987 case BRCM_ATTR_SAE_PWE: {
2988 u32 sae_pwe = 0;
2989 if (nla_len(iter) != sizeof(uint32)) {
2990 WL_ERR(("Invalid value of sae_pwe\n"));
2991 ret = -EINVAL;
2992 break;
2993 }
2994 ret = wl_cfgvendor_map_supp_sae_pwe_to_fw(nla_get_u32(iter), &sae_pwe);
2995 if (unlikely(ret)) {
2996 WL_ERR(("Invalid sae_pwe\n"));
2997 break;
2998 }
2999 ret = wl_cfg80211_set_wsec_info(net, &sae_pwe,
3000 sizeof(sae_pwe), WL_WSEC_INFO_BSS_SAE_PWE);
3001 if (unlikely(ret)) {
3002 WL_ERR(("set wsec_info_sae_pwe failed \n"));
3003 }
3004 break;
3005 }
3006 #endif /* WL_SAE */
3007 /* Add new attributes here */
3008 default:
3009 WL_DBG(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
3010 }
3011 }
3012
3013 return ret;
3014 }
3015
3016 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
3017 static int
wl_cfgvendor_set_sae_password(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3018 wl_cfgvendor_set_sae_password(struct wiphy *wiphy,
3019 struct wireless_dev *wdev, const void *data, int len)
3020 {
3021 int err = BCME_OK;
3022 struct net_device *net = wdev->netdev;
3023 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
3024 wsec_pmk_t pmk;
3025 s32 bssidx;
3026
3027 /* This api not needed for wpa_supplicant based sae authentication */
3028 #ifdef WL_CLIENT_SAE
3029 WL_INFORM_MEM(("Ignore for external sae auth\n"));
3030 return BCME_OK;
3031 #endif /* WL_CLIENT_SAE */
3032
3033 /* clear the content of pmk structure before usage */
3034 (void)memset_s(&pmk, sizeof(wsec_pmk_t), 0x0, sizeof(wsec_pmk_t));
3035
3036 if ((bssidx = wl_get_bssidx_by_wdev(cfg, net->ieee80211_ptr)) < 0) {
3037 WL_ERR(("Find p2p index from wdev(%p) failed\n", net->ieee80211_ptr));
3038 return BCME_ERROR;
3039 }
3040
3041 if ((len < WSEC_MIN_PSK_LEN) || (len >= WSEC_MAX_PASSPHRASE_LEN)) {
3042 WL_ERR(("Invalid passphrase length %d..should be >= 8 and < 256\n",
3043 len));
3044 err = BCME_BADLEN;
3045 goto done;
3046 }
3047 /* Set AUTH to SAE */
3048 err = wldev_iovar_setint_bsscfg(net, "wpa_auth", WPA3_AUTH_SAE_PSK, bssidx);
3049 if (unlikely(err)) {
3050 WL_ERR(("could not set wpa_auth (0x%x)\n", err));
3051 goto done;
3052 }
3053 pmk.key_len = htod16(len);
3054 bcopy((const u8*)data, pmk.key, len);
3055 pmk.flags = htod16(WSEC_PASSPHRASE);
3056
3057 err = wldev_ioctl_set(net, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
3058 if (err) {
3059 WL_ERR(("\n failed to set pmk %d\n", err));
3060 goto done;
3061 } else {
3062 WL_INFORM_MEM(("sae passphrase set successfully\n"));
3063 }
3064 done:
3065 return err;
3066 }
3067 #endif /* WL_SAE || WL_CLIENT_SAE */
3068
3069 #ifdef BCM_PRIV_CMD_SUPPORT
3070 /* strlen("ifname=") + IFNAMESIZE + strlen(" ") + '\0' */
3071 #define ANDROID_PRIV_CMD_IF_PREFIX_LEN (7 + IFNAMSIZ + 2)
3072 /* Max length for the reply buffer. For BRCM_ATTR_DRIVER_CMD, the reply
3073 * would be a formatted string and reply buf would be the size of the
3074 * string.
3075 */
3076 #define WL_DRIVER_PRIV_CMD_LEN 512
3077 static int
wl_cfgvendor_priv_bcm_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)3078 wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy,
3079 struct wireless_dev *wdev, const void *data, int len)
3080 {
3081 const struct nlattr *iter;
3082 int err = 0;
3083 int data_len = 0, cmd_len = 0, tmp = 0, type = 0;
3084 struct net_device *ndev = wdev->netdev;
3085 char *cmd = NULL;
3086 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3087 int bytes_written;
3088 struct net_device *net = NULL;
3089 unsigned long int cmd_out = 0;
3090
3091 #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
3092 u32 cmd_buf_len = WL_DRIVER_PRIV_CMD_LEN;
3093 char cmd_prefix[ANDROID_PRIV_CMD_IF_PREFIX_LEN + 1] = {0};
3094 char *cmd_buf = NULL;
3095 char *current_pos;
3096 u32 cmd_offset;
3097 #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
3098
3099 WL_DBG(("%s: Enter \n", __func__));
3100
3101 /* hold wake lock */
3102 net_os_wake_lock(ndev);
3103
3104 nla_for_each_attr(iter, data, len, tmp) {
3105 type = nla_type(iter);
3106 cmd = nla_data(iter);
3107 cmd_len = nla_len(iter);
3108
3109 WL_DBG(("%s: type: %d cmd_len:%d cmd_ptr:%p \n", __func__, type, cmd_len, cmd));
3110 if (!cmd || !cmd_len) {
3111 WL_ERR(("Invalid cmd data \n"));
3112 err = -EINVAL;
3113 goto exit;
3114 }
3115
3116 #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
3117 if (type == BRCM_ATTR_DRIVER_CMD) {
3118 if ((cmd_len >= WL_DRIVER_PRIV_CMD_LEN) ||
3119 (cmd_len < ANDROID_PRIV_CMD_IF_PREFIX_LEN)) {
3120 WL_ERR(("Unexpected command length (%u)."
3121 "Ignore the command\n", cmd_len));
3122 err = -EINVAL;
3123 goto exit;
3124 }
3125
3126 /* check whether there is any ifname prefix provided */
3127 if (memcpy_s(cmd_prefix, (sizeof(cmd_prefix) - 1),
3128 cmd, ANDROID_PRIV_CMD_IF_PREFIX_LEN) != BCME_OK) {
3129 WL_ERR(("memcpy failed for cmd buffer. len:%d\n", cmd_len));
3130 err = -ENOMEM;
3131 goto exit;
3132 }
3133
3134 net = wl_cfgvendor_get_ndev(cfg, wdev, cmd_prefix, &cmd_out);
3135 if (!cmd_out || !net) {
3136 WL_ERR(("ndev not found\n"));
3137 err = -ENODEV;
3138 goto exit;
3139 }
3140
3141 /* find offset of the command */
3142 current_pos = (char *)cmd_out;
3143 cmd_offset = current_pos - cmd_prefix;
3144
3145 if (!current_pos || (cmd_offset) > ANDROID_PRIV_CMD_IF_PREFIX_LEN) {
3146 WL_ERR(("Invalid len cmd_offset: %u \n", cmd_offset));
3147 err = -EINVAL;
3148 goto exit;
3149 }
3150
3151 /* Private command data in expected to be in str format. To ensure that
3152 * the data is null terminated, copy to a local buffer before use
3153 */
3154 cmd_buf = (char *)MALLOCZ(cfg->osh, cmd_buf_len);
3155 if (!cmd_buf) {
3156 WL_ERR(("memory alloc failed for %u \n", cmd_buf_len));
3157 err = -ENOMEM;
3158 goto exit;
3159 }
3160
3161 /* Point to the start of command */
3162 if (memcpy_s(cmd_buf, (WL_DRIVER_PRIV_CMD_LEN - 1),
3163 (const void *)(cmd + cmd_offset),
3164 (cmd_len - cmd_offset - 1)) != BCME_OK) {
3165 WL_ERR(("memcpy failed for cmd buffer. len:%d\n", cmd_len));
3166 err = -ENOMEM;
3167 goto exit;
3168 }
3169 cmd_buf[WL_DRIVER_PRIV_CMD_LEN - 1] = '\0';
3170
3171 WL_DBG(("vendor_command: %s len: %u \n", cmd_buf, cmd_buf_len));
3172 bytes_written = wl_handle_private_cmd(net, cmd_buf, cmd_buf_len);
3173 WL_DBG(("bytes_written: %d \n", bytes_written));
3174 if (bytes_written == 0) {
3175 snprintf(cmd_buf, cmd_buf_len, "%s", "OK");
3176 data_len = sizeof("OK");
3177 } else if (bytes_written > 0) {
3178 if (bytes_written >= (cmd_buf_len - 1)) {
3179 /* Not expected */
3180 ASSERT(0);
3181 err = -EINVAL;
3182 goto exit;
3183 }
3184 data_len = bytes_written;
3185 } else {
3186 /* -ve return value. Propagate the error back */
3187 err = bytes_written;
3188 goto exit;
3189 }
3190 if ((data_len > 0) && (data_len < (cmd_buf_len - 1)) && cmd_buf) {
3191 err = wl_cfgvendor_send_cmd_reply(wiphy, cmd_buf, data_len);
3192 if (unlikely(err)) {
3193 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
3194 } else {
3195 WL_DBG(("Vendor Command reply sent successfully!\n"));
3196 }
3197 } else {
3198 /* No data to be sent back as reply */
3199 WL_ERR(("Vendor_cmd: No reply expected. data_len:%u cmd_buf %p \n",
3200 data_len, cmd_buf));
3201 }
3202 break;
3203 }
3204 #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
3205
3206 }
3207
3208 exit:
3209
3210 #if defined(WL_ANDROID_PRIV_CMD_OVER_NL80211) && defined(OEM_ANDROID)
3211 if (cmd_buf) {
3212 MFREE(cfg->osh, cmd_buf, cmd_buf_len);
3213 }
3214 #endif /* WL_ANDROID_PRIV_CMD_OVER_NL80211 && OEM_ANDROID */
3215
3216 net_os_wake_unlock(ndev);
3217 return err;
3218 }
3219 #endif /* BCM_PRIV_CMD_SUPPORT */
3220
3221 #ifdef WL_NAN
3222 static const char *
nan_attr_to_str(u16 cmd)3223 nan_attr_to_str(u16 cmd)
3224 {
3225 const char *id2str;
3226
3227 switch (cmd) {
3228 C2S(NAN_ATTRIBUTE_HEADER);
3229 break;
3230 C2S(NAN_ATTRIBUTE_HANDLE);
3231 break;
3232 C2S(NAN_ATTRIBUTE_TRANSAC_ID);
3233 break;
3234 C2S(NAN_ATTRIBUTE_2G_SUPPORT);
3235 break;
3236 C2S(NAN_ATTRIBUTE_SDF_2G_SUPPORT);
3237 break;
3238 C2S(NAN_ATTRIBUTE_SDF_5G_SUPPORT);
3239 break;
3240 C2S(NAN_ATTRIBUTE_5G_SUPPORT);
3241 break;
3242 C2S(NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON);
3243 break;
3244 C2S(NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON);
3245 break;
3246 C2S(NAN_ATTRIBUTE_CLUSTER_LOW);
3247 break;
3248 C2S(NAN_ATTRIBUTE_CLUSTER_HIGH);
3249 break;
3250 C2S(NAN_ATTRIBUTE_SID_BEACON);
3251 break;
3252 C2S(NAN_ATTRIBUTE_RSSI_CLOSE);
3253 break;
3254 C2S(NAN_ATTRIBUTE_RSSI_MIDDLE);
3255 break;
3256 C2S(NAN_ATTRIBUTE_RSSI_PROXIMITY);
3257 break;
3258 C2S(NAN_ATTRIBUTE_RSSI_CLOSE_5G);
3259 break;
3260 C2S(NAN_ATTRIBUTE_RSSI_MIDDLE_5G);
3261 break;
3262 C2S(NAN_ATTRIBUTE_RSSI_PROXIMITY_5G);
3263 break;
3264 C2S(NAN_ATTRIBUTE_HOP_COUNT_LIMIT);
3265 break;
3266 C2S(NAN_ATTRIBUTE_RANDOM_TIME);
3267 break;
3268 C2S(NAN_ATTRIBUTE_MASTER_PREF);
3269 break;
3270 C2S(NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL);
3271 break;
3272 C2S(NAN_ATTRIBUTE_PUBLISH_ID);
3273 break;
3274 C2S(NAN_ATTRIBUTE_TTL);
3275 break;
3276 C2S(NAN_ATTRIBUTE_PERIOD);
3277 break;
3278 C2S(NAN_ATTRIBUTE_REPLIED_EVENT_FLAG);
3279 break;
3280 C2S(NAN_ATTRIBUTE_PUBLISH_TYPE);
3281 break;
3282 C2S(NAN_ATTRIBUTE_TX_TYPE);
3283 break;
3284 C2S(NAN_ATTRIBUTE_PUBLISH_COUNT);
3285 break;
3286 C2S(NAN_ATTRIBUTE_SERVICE_NAME_LEN);
3287 break;
3288 C2S(NAN_ATTRIBUTE_SERVICE_NAME);
3289 break;
3290 C2S(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN);
3291 break;
3292 C2S(NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO);
3293 break;
3294 C2S(NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN);
3295 break;
3296 C2S(NAN_ATTRIBUTE_RX_MATCH_FILTER);
3297 break;
3298 C2S(NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN);
3299 break;
3300 C2S(NAN_ATTRIBUTE_TX_MATCH_FILTER);
3301 break;
3302 C2S(NAN_ATTRIBUTE_SUBSCRIBE_ID);
3303 break;
3304 C2S(NAN_ATTRIBUTE_SUBSCRIBE_TYPE);
3305 break;
3306 C2S(NAN_ATTRIBUTE_SERVICERESPONSEFILTER);
3307 break;
3308 C2S(NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE);
3309 break;
3310 C2S(NAN_ATTRIBUTE_USESERVICERESPONSEFILTER);
3311 break;
3312 C2S(NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION);
3313 break;
3314 C2S(NAN_ATTRIBUTE_SUBSCRIBE_MATCH);
3315 break;
3316 C2S(NAN_ATTRIBUTE_SUBSCRIBE_COUNT);
3317 break;
3318 C2S(NAN_ATTRIBUTE_MAC_ADDR);
3319 break;
3320 C2S(NAN_ATTRIBUTE_MAC_ADDR_LIST);
3321 break;
3322 C2S(NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES);
3323 break;
3324 C2S(NAN_ATTRIBUTE_PUBLISH_MATCH);
3325 break;
3326 C2S(NAN_ATTRIBUTE_ENABLE_STATUS);
3327 break;
3328 C2S(NAN_ATTRIBUTE_JOIN_STATUS);
3329 break;
3330 C2S(NAN_ATTRIBUTE_ROLE);
3331 break;
3332 C2S(NAN_ATTRIBUTE_MASTER_RANK);
3333 break;
3334 C2S(NAN_ATTRIBUTE_ANCHOR_MASTER_RANK);
3335 break;
3336 C2S(NAN_ATTRIBUTE_CNT_PEND_TXFRM);
3337 break;
3338 C2S(NAN_ATTRIBUTE_CNT_BCN_TX);
3339 break;
3340 C2S(NAN_ATTRIBUTE_CNT_BCN_RX);
3341 break;
3342 C2S(NAN_ATTRIBUTE_CNT_SVC_DISC_TX);
3343 break;
3344 C2S(NAN_ATTRIBUTE_CNT_SVC_DISC_RX);
3345 break;
3346 C2S(NAN_ATTRIBUTE_AMBTT);
3347 break;
3348 C2S(NAN_ATTRIBUTE_CLUSTER_ID);
3349 break;
3350 C2S(NAN_ATTRIBUTE_INST_ID);
3351 break;
3352 C2S(NAN_ATTRIBUTE_OUI);
3353 break;
3354 C2S(NAN_ATTRIBUTE_STATUS);
3355 break;
3356 C2S(NAN_ATTRIBUTE_DE_EVENT_TYPE);
3357 break;
3358 C2S(NAN_ATTRIBUTE_MERGE);
3359 break;
3360 C2S(NAN_ATTRIBUTE_IFACE);
3361 break;
3362 C2S(NAN_ATTRIBUTE_CHANNEL);
3363 break;
3364 C2S(NAN_ATTRIBUTE_24G_CHANNEL);
3365 break;
3366 C2S(NAN_ATTRIBUTE_5G_CHANNEL);
3367 break;
3368 C2S(NAN_ATTRIBUTE_PEER_ID);
3369 break;
3370 C2S(NAN_ATTRIBUTE_NDP_ID);
3371 break;
3372 C2S(NAN_ATTRIBUTE_SECURITY);
3373 break;
3374 C2S(NAN_ATTRIBUTE_QOS);
3375 break;
3376 C2S(NAN_ATTRIBUTE_RSP_CODE);
3377 break;
3378 C2S(NAN_ATTRIBUTE_INST_COUNT);
3379 break;
3380 C2S(NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR);
3381 break;
3382 C2S(NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR);
3383 break;
3384 C2S(NAN_ATTRIBUTE_IF_ADDR);
3385 break;
3386 C2S(NAN_ATTRIBUTE_WARMUP_TIME);
3387 break;
3388 C2S(NAN_ATTRIBUTE_RECV_IND_CFG);
3389 break;
3390 C2S(NAN_ATTRIBUTE_CONNMAP);
3391 break;
3392 C2S(NAN_ATTRIBUTE_DWELL_TIME);
3393 break;
3394 C2S(NAN_ATTRIBUTE_SCAN_PERIOD);
3395 break;
3396 C2S(NAN_ATTRIBUTE_RSSI_WINDOW_SIZE);
3397 break;
3398 C2S(NAN_ATTRIBUTE_CONF_CLUSTER_VAL);
3399 break;
3400 C2S(NAN_ATTRIBUTE_CIPHER_SUITE_TYPE);
3401 break;
3402 C2S(NAN_ATTRIBUTE_KEY_TYPE);
3403 break;
3404 C2S(NAN_ATTRIBUTE_KEY_LEN);
3405 break;
3406 C2S(NAN_ATTRIBUTE_SCID);
3407 break;
3408 C2S(NAN_ATTRIBUTE_SCID_LEN);
3409 break;
3410 C2S(NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP);
3411 break;
3412 C2S(NAN_ATTRIBUTE_SDE_CONTROL_SECURITY);
3413 break;
3414 C2S(NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE);
3415 break;
3416 C2S(NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT);
3417 break;
3418 C2S(NAN_ATTRIBUTE_NO_CONFIG_AVAIL);
3419 break;
3420 C2S(NAN_ATTRIBUTE_2G_AWAKE_DW);
3421 break;
3422 C2S(NAN_ATTRIBUTE_5G_AWAKE_DW);
3423 break;
3424 C2S(NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG);
3425 break;
3426 C2S(NAN_ATTRIBUTE_KEY_DATA);
3427 break;
3428 C2S(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN);
3429 break;
3430 C2S(NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO);
3431 break;
3432 C2S(NAN_ATTRIBUTE_REASON);
3433 break;
3434 C2S(NAN_ATTRIBUTE_DISC_IND_CFG);
3435 break;
3436 C2S(NAN_ATTRIBUTE_DWELL_TIME_5G);
3437 break;
3438 C2S(NAN_ATTRIBUTE_SCAN_PERIOD_5G);
3439 break;
3440 C2S(NAN_ATTRIBUTE_SVC_RESPONDER_POLICY);
3441 break;
3442 C2S(NAN_ATTRIBUTE_EVENT_MASK);
3443 break;
3444 C2S(NAN_ATTRIBUTE_SUB_SID_BEACON);
3445 break;
3446 C2S(NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL);
3447 break;
3448 C2S(NAN_ATTRIBUTE_CMD_RESP_DATA);
3449 break;
3450 C2S(NAN_ATTRIBUTE_CMD_USE_NDPE);
3451 break;
3452 C2S(NAN_ATTRIBUTE_ENABLE_MERGE);
3453 break;
3454 C2S(NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL);
3455 break;
3456 C2S(NAN_ATTRIBUTE_NSS);
3457 break;
3458 C2S(NAN_ATTRIBUTE_ENABLE_RANGING);
3459 break;
3460 C2S(NAN_ATTRIBUTE_DW_EARLY_TERM);
3461 break;
3462 default:
3463 id2str = "NAN_ATTRIBUTE_UNKNOWN";
3464 }
3465
3466 return id2str;
3467 }
3468
3469 nan_hal_status_t nan_status_reasonstr_map[] = {
3470 {NAN_STATUS_SUCCESS, "NAN status success"},
3471 {NAN_STATUS_INTERNAL_FAILURE, "NAN Discovery engine failure"},
3472 {NAN_STATUS_PROTOCOL_FAILURE, "protocol failure"},
3473 {NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID, "invalid pub_sub ID"},
3474 {NAN_STATUS_NO_RESOURCE_AVAILABLE, "No space available"},
3475 {NAN_STATUS_INVALID_PARAM, "invalid param"},
3476 {NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID, "invalid req inst id"},
3477 {NAN_STATUS_INVALID_NDP_ID, "invalid ndp id"},
3478 {NAN_STATUS_NAN_NOT_ALLOWED, "Nan not allowed"},
3479 {NAN_STATUS_NO_OTA_ACK, "No OTA ack"},
3480 {NAN_STATUS_ALREADY_ENABLED, "NAN is Already enabled"},
3481 {NAN_STATUS_FOLLOWUP_QUEUE_FULL, "Follow-up queue full"},
3482 {NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED, "unsupported concurrency"},
3483 };
3484
3485 void
wl_cfgvendor_add_nan_reason_str(nan_status_type_t status,nan_hal_resp_t * nan_req_resp)3486 wl_cfgvendor_add_nan_reason_str(nan_status_type_t status, nan_hal_resp_t *nan_req_resp)
3487 {
3488 int i = 0;
3489 int num = (int)(sizeof(nan_status_reasonstr_map)/sizeof(nan_status_reasonstr_map[0]));
3490 for (i = 0; i < num; i++) {
3491 if (nan_status_reasonstr_map[i].status == status) {
3492 strlcpy(nan_req_resp->nan_reason, nan_status_reasonstr_map[i].nan_reason,
3493 sizeof(nan_status_reasonstr_map[i].nan_reason));
3494 break;
3495 }
3496 }
3497 }
3498
3499 nan_status_type_t
wl_cfgvendor_brcm_to_nanhal_status(int32 vendor_status)3500 wl_cfgvendor_brcm_to_nanhal_status(int32 vendor_status)
3501 {
3502 nan_status_type_t hal_status;
3503 switch (vendor_status) {
3504 case BCME_OK:
3505 hal_status = NAN_STATUS_SUCCESS;
3506 break;
3507 case BCME_BUSY:
3508 case BCME_NOTREADY:
3509 hal_status = NAN_STATUS_NAN_NOT_ALLOWED;
3510 break;
3511 case BCME_BADLEN:
3512 case BCME_BADBAND:
3513 case BCME_UNSUPPORTED:
3514 case BCME_USAGE_ERROR:
3515 case BCME_BADARG:
3516 case BCME_NOTENABLED:
3517 hal_status = NAN_STATUS_INVALID_PARAM;
3518 break;
3519 case BCME_NOMEM:
3520 case BCME_NORESOURCE:
3521 case WL_NAN_E_SVC_SUB_LIST_FULL:
3522 hal_status = NAN_STATUS_NO_RESOURCE_AVAILABLE;
3523 break;
3524 case WL_NAN_E_SD_TX_LIST_FULL:
3525 hal_status = NAN_STATUS_FOLLOWUP_QUEUE_FULL;
3526 break;
3527 case WL_NAN_E_BAD_INSTANCE:
3528 hal_status = NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
3529 break;
3530 default:
3531 WL_ERR(("%s Unknown vendor status, status = %d\n",
3532 __func__, vendor_status));
3533 /* Generic error */
3534 hal_status = NAN_STATUS_INTERNAL_FAILURE;
3535 }
3536 return hal_status;
3537 }
3538
3539 static int
wl_cfgvendor_nan_cmd_reply(struct wiphy * wiphy,int nan_cmd,nan_hal_resp_t * nan_req_resp,int ret,int nan_cmd_status)3540 wl_cfgvendor_nan_cmd_reply(struct wiphy *wiphy, int nan_cmd,
3541 nan_hal_resp_t *nan_req_resp, int ret, int nan_cmd_status)
3542 {
3543 int err;
3544 int nan_reply;
3545 nan_req_resp->subcmd = nan_cmd;
3546 if (ret == BCME_OK) {
3547 nan_reply = nan_cmd_status;
3548 } else {
3549 nan_reply = ret;
3550 }
3551 nan_req_resp->status = wl_cfgvendor_brcm_to_nanhal_status(nan_reply);
3552 nan_req_resp->value = ret;
3553 err = wl_cfgvendor_send_cmd_reply(wiphy, nan_req_resp,
3554 sizeof(*nan_req_resp));
3555 return err;
3556 }
3557
3558 static void
wl_cfgvendor_free_disc_cmd_data(struct bcm_cfg80211 * cfg,nan_discover_cmd_data_t * cmd_data)3559 wl_cfgvendor_free_disc_cmd_data(struct bcm_cfg80211 *cfg,
3560 nan_discover_cmd_data_t *cmd_data)
3561 {
3562 if (!cmd_data) {
3563 WL_ERR(("Cmd_data is null\n"));
3564 return;
3565 }
3566 if (cmd_data->svc_info.data) {
3567 MFREE(cfg->osh, cmd_data->svc_info.data, cmd_data->svc_info.dlen);
3568 }
3569 if (cmd_data->svc_hash.data) {
3570 MFREE(cfg->osh, cmd_data->svc_hash.data, cmd_data->svc_hash.dlen);
3571 }
3572 if (cmd_data->rx_match.data) {
3573 MFREE(cfg->osh, cmd_data->rx_match.data, cmd_data->rx_match.dlen);
3574 }
3575 if (cmd_data->tx_match.data) {
3576 MFREE(cfg->osh, cmd_data->tx_match.data, cmd_data->tx_match.dlen);
3577 }
3578 if (cmd_data->mac_list.list) {
3579 MFREE(cfg->osh, cmd_data->mac_list.list,
3580 cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN);
3581 }
3582 if (cmd_data->key.data) {
3583 MFREE(cfg->osh, cmd_data->key.data, NAN_MAX_PMK_LEN);
3584 }
3585 if (cmd_data->sde_svc_info.data) {
3586 MFREE(cfg->osh, cmd_data->sde_svc_info.data, cmd_data->sde_svc_info.dlen);
3587 }
3588 MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
3589 }
3590
3591 static void
wl_cfgvendor_free_dp_cmd_data(struct bcm_cfg80211 * cfg,nan_datapath_cmd_data_t * cmd_data)3592 wl_cfgvendor_free_dp_cmd_data(struct bcm_cfg80211 *cfg,
3593 nan_datapath_cmd_data_t *cmd_data)
3594 {
3595 if (!cmd_data) {
3596 WL_ERR(("Cmd_data is null\n"));
3597 return;
3598 }
3599 if (cmd_data->svc_hash.data) {
3600 MFREE(cfg->osh, cmd_data->svc_hash.data, cmd_data->svc_hash.dlen);
3601 }
3602 if (cmd_data->svc_info.data) {
3603 MFREE(cfg->osh, cmd_data->svc_info.data, cmd_data->svc_info.dlen);
3604 }
3605 if (cmd_data->key.data) {
3606 MFREE(cfg->osh, cmd_data->key.data, NAN_MAX_PMK_LEN);
3607 }
3608 MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
3609 }
3610
3611 #define WL_NAN_EVENT_MAX_BUF 256
3612 #ifdef WL_NAN_DISC_CACHE
3613 static int
wl_cfgvendor_nan_parse_dp_sec_info_args(struct wiphy * wiphy,const void * buf,int len,nan_datapath_sec_info_cmd_data_t * cmd_data)3614 wl_cfgvendor_nan_parse_dp_sec_info_args(struct wiphy *wiphy,
3615 const void *buf, int len, nan_datapath_sec_info_cmd_data_t *cmd_data)
3616 {
3617 int ret = BCME_OK;
3618 int attr_type;
3619 int rem = len;
3620 const struct nlattr *iter;
3621
3622 NAN_DBG_ENTER();
3623
3624 nla_for_each_attr(iter, buf, len, rem) {
3625 attr_type = nla_type(iter);
3626 WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
3627
3628 switch (attr_type) {
3629 case NAN_ATTRIBUTE_MAC_ADDR:
3630 ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
3631 (char*)nla_data(iter), nla_len(iter));
3632 if (ret != BCME_OK) {
3633 WL_ERR(("Failed to copy mac addr\n"));
3634 return ret;
3635 }
3636 break;
3637 case NAN_ATTRIBUTE_PUBLISH_ID:
3638 cmd_data->pub_id = nla_get_u16(iter);
3639 break;
3640 case NAN_ATTRIBUTE_NDP_ID:
3641 cmd_data->ndp_instance_id = nla_get_u32(iter);
3642 break;
3643 default:
3644 WL_ERR(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
3645 ret = BCME_BADARG;
3646 break;
3647 }
3648 }
3649 /* We need to call set_config_handler b/f calling start enable TBD */
3650 NAN_DBG_EXIT();
3651 return ret;
3652 }
3653 #endif /* WL_NAN_DISC_CACHE */
3654
3655 int8 chanbuf[CHANSPEC_STR_LEN];
3656 static int
wl_cfgvendor_nan_parse_datapath_args(struct wiphy * wiphy,const void * buf,int len,nan_datapath_cmd_data_t * cmd_data)3657 wl_cfgvendor_nan_parse_datapath_args(struct wiphy *wiphy,
3658 const void *buf, int len, nan_datapath_cmd_data_t *cmd_data)
3659 {
3660 int ret = BCME_OK;
3661 int attr_type;
3662 int rem = len;
3663 const struct nlattr *iter;
3664 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3665 int chan;
3666
3667 NAN_DBG_ENTER();
3668
3669 nla_for_each_attr(iter, buf, len, rem) {
3670 attr_type = nla_type(iter);
3671 WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
3672
3673 switch (attr_type) {
3674 case NAN_ATTRIBUTE_NDP_ID:
3675 if (nla_len(iter) != sizeof(uint32)) {
3676 ret = -EINVAL;
3677 goto exit;
3678 }
3679 cmd_data->ndp_instance_id = nla_get_u32(iter);
3680 break;
3681 case NAN_ATTRIBUTE_IFACE:
3682 if (nla_len(iter) >= sizeof(cmd_data->ndp_iface)) {
3683 WL_ERR(("iface_name len wrong:%d\n", nla_len(iter)));
3684 ret = -EINVAL;
3685 goto exit;
3686 }
3687 strlcpy((char *)cmd_data->ndp_iface, (char *)nla_data(iter),
3688 nla_len(iter));
3689 break;
3690 case NAN_ATTRIBUTE_SECURITY:
3691 if (nla_len(iter) != sizeof(uint8)) {
3692 ret = -EINVAL;
3693 goto exit;
3694 }
3695 cmd_data->ndp_cfg.security_cfg = nla_get_u8(iter);
3696 break;
3697 case NAN_ATTRIBUTE_QOS:
3698 if (nla_len(iter) != sizeof(uint8)) {
3699 ret = -EINVAL;
3700 goto exit;
3701 }
3702 cmd_data->ndp_cfg.qos_cfg = nla_get_u8(iter);
3703 break;
3704 case NAN_ATTRIBUTE_RSP_CODE:
3705 if (nla_len(iter) != sizeof(uint8)) {
3706 ret = -EINVAL;
3707 goto exit;
3708 }
3709 cmd_data->rsp_code = nla_get_u8(iter);
3710 break;
3711 case NAN_ATTRIBUTE_INST_COUNT:
3712 if (nla_len(iter) != sizeof(uint8)) {
3713 ret = -EINVAL;
3714 goto exit;
3715 }
3716 cmd_data->num_ndp_instances = nla_get_u8(iter);
3717 break;
3718 case NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR:
3719 if (nla_len(iter) != ETHER_ADDR_LEN) {
3720 ret = -EINVAL;
3721 goto exit;
3722 }
3723 ret = memcpy_s((char*)&cmd_data->peer_disc_mac_addr,
3724 ETHER_ADDR_LEN, (char*)nla_data(iter), nla_len(iter));
3725 if (ret != BCME_OK) {
3726 WL_ERR(("Failed to copy peer_disc_mac_addr\n"));
3727 goto exit;
3728 }
3729 break;
3730 case NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR:
3731 if (nla_len(iter) != ETHER_ADDR_LEN) {
3732 ret = -EINVAL;
3733 goto exit;
3734 }
3735 ret = memcpy_s((char*)&cmd_data->peer_ndi_mac_addr,
3736 ETHER_ADDR_LEN, (char*)nla_data(iter), nla_len(iter));
3737 if (ret != BCME_OK) {
3738 WL_ERR(("Failed to copy peer_ndi_mac_addr\n"));
3739 goto exit;
3740 }
3741 break;
3742 case NAN_ATTRIBUTE_MAC_ADDR:
3743 if (nla_len(iter) != ETHER_ADDR_LEN) {
3744 ret = -EINVAL;
3745 goto exit;
3746 }
3747 ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
3748 (char*)nla_data(iter), nla_len(iter));
3749 if (ret != BCME_OK) {
3750 WL_ERR(("Failed to copy mac_addr\n"));
3751 goto exit;
3752 }
3753 break;
3754 case NAN_ATTRIBUTE_IF_ADDR:
3755 if (nla_len(iter) != ETHER_ADDR_LEN) {
3756 ret = -EINVAL;
3757 goto exit;
3758 }
3759 ret = memcpy_s((char*)&cmd_data->if_addr, ETHER_ADDR_LEN,
3760 (char*)nla_data(iter), nla_len(iter));
3761 if (ret != BCME_OK) {
3762 WL_ERR(("Failed to copy if_addr\n"));
3763 goto exit;
3764 }
3765 break;
3766 case NAN_ATTRIBUTE_ENTRY_CONTROL:
3767 if (nla_len(iter) != sizeof(uint8)) {
3768 ret = -EINVAL;
3769 goto exit;
3770 }
3771 cmd_data->avail_params.duration = nla_get_u8(iter);
3772 break;
3773 case NAN_ATTRIBUTE_AVAIL_BIT_MAP:
3774 if (nla_len(iter) != sizeof(uint32)) {
3775 ret = -EINVAL;
3776 goto exit;
3777 }
3778 cmd_data->avail_params.bmap = nla_get_u32(iter);
3779 break;
3780 case NAN_ATTRIBUTE_CHANNEL: {
3781 if (nla_len(iter) != sizeof(uint32)) {
3782 ret = -EINVAL;
3783 goto exit;
3784 }
3785 /* take the default channel start_factor frequency */
3786 chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
3787 if (chan <= CH_MAX_2G_CHANNEL) {
3788 cmd_data->avail_params.chanspec[0] =
3789 wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
3790 } else {
3791 cmd_data->avail_params.chanspec[0] =
3792 wf_channel2chspec(chan, WL_CHANSPEC_BW_80);
3793 }
3794 if (cmd_data->avail_params.chanspec[0] == 0) {
3795 WL_ERR(("Channel is not valid \n"));
3796 ret = -EINVAL;
3797 goto exit;
3798 }
3799 WL_TRACE(("valid chanspec, chanspec = 0x%04x \n",
3800 cmd_data->avail_params.chanspec[0]));
3801 break;
3802 }
3803 case NAN_ATTRIBUTE_NO_CONFIG_AVAIL:
3804 if (nla_len(iter) != sizeof(uint8)) {
3805 ret = -EINVAL;
3806 goto exit;
3807 }
3808 cmd_data->avail_params.no_config_avail = (bool)nla_get_u8(iter);
3809 break;
3810 case NAN_ATTRIBUTE_SERVICE_NAME_LEN: {
3811 if (nla_len(iter) != sizeof(uint16)) {
3812 ret = -EINVAL;
3813 goto exit;
3814 }
3815 if (cmd_data->svc_hash.dlen) {
3816 WL_ERR(("trying to overwrite:%d\n", attr_type));
3817 ret = -EINVAL;
3818 goto exit;
3819 }
3820 cmd_data->svc_hash.dlen = nla_get_u16(iter);
3821 if (cmd_data->svc_hash.dlen != WL_NAN_SVC_HASH_LEN) {
3822 WL_ERR(("invalid svc_hash length = %u\n", cmd_data->svc_hash.dlen));
3823 ret = -EINVAL;
3824 goto exit;
3825 }
3826 break;
3827 }
3828 case NAN_ATTRIBUTE_SERVICE_NAME:
3829 if ((!cmd_data->svc_hash.dlen) ||
3830 (nla_len(iter) != cmd_data->svc_hash.dlen)) {
3831 WL_ERR(("invalid svc_hash length = %d,%d\n",
3832 cmd_data->svc_hash.dlen, nla_len(iter)));
3833 ret = -EINVAL;
3834 goto exit;
3835 }
3836 if (cmd_data->svc_hash.data) {
3837 WL_ERR(("trying to overwrite:%d\n", attr_type));
3838 ret = -EINVAL;
3839 goto exit;
3840 }
3841 cmd_data->svc_hash.data =
3842 MALLOCZ(cfg->osh, cmd_data->svc_hash.dlen);
3843 if (!cmd_data->svc_hash.data) {
3844 WL_ERR(("failed to allocate svc_hash data, len=%d\n",
3845 cmd_data->svc_hash.dlen));
3846 ret = -ENOMEM;
3847 goto exit;
3848 }
3849 ret = memcpy_s(cmd_data->svc_hash.data, cmd_data->svc_hash.dlen,
3850 nla_data(iter), nla_len(iter));
3851 if (ret != BCME_OK) {
3852 WL_ERR(("Failed to copy svc hash data\n"));
3853 goto exit;
3854 }
3855 break;
3856 case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN:
3857 if (nla_len(iter) != sizeof(uint16)) {
3858 ret = -EINVAL;
3859 goto exit;
3860 }
3861 if (cmd_data->svc_info.dlen) {
3862 WL_ERR(("trying to overwrite:%d\n", attr_type));
3863 ret = -EINVAL;
3864 goto exit;
3865 }
3866 cmd_data->svc_info.dlen = nla_get_u16(iter);
3867 if (cmd_data->svc_info.dlen > MAX_APP_INFO_LEN) {
3868 WL_ERR_RLMT(("Not allowed beyond :%d\n", MAX_APP_INFO_LEN));
3869 ret = -EINVAL;
3870 goto exit;
3871 }
3872 break;
3873 case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO:
3874 if ((!cmd_data->svc_info.dlen) ||
3875 (nla_len(iter) != cmd_data->svc_info.dlen)) {
3876 WL_ERR(("failed to allocate svc info by invalid len=%d,%d\n",
3877 cmd_data->svc_info.dlen, nla_len(iter)));
3878 ret = -EINVAL;
3879 goto exit;
3880 }
3881 if (cmd_data->svc_info.data) {
3882 WL_ERR(("trying to overwrite:%d\n", attr_type));
3883 ret = -EINVAL;
3884 goto exit;
3885 }
3886 cmd_data->svc_info.data = MALLOCZ(cfg->osh, cmd_data->svc_info.dlen);
3887 if (cmd_data->svc_info.data == NULL) {
3888 WL_ERR(("failed to allocate svc info data, len=%d\n",
3889 cmd_data->svc_info.dlen));
3890 ret = -ENOMEM;
3891 goto exit;
3892 }
3893 ret = memcpy_s(cmd_data->svc_info.data, cmd_data->svc_info.dlen,
3894 nla_data(iter), nla_len(iter));
3895 if (ret != BCME_OK) {
3896 WL_ERR(("Failed to copy svc info\n"));
3897 goto exit;
3898 }
3899 break;
3900 case NAN_ATTRIBUTE_PUBLISH_ID:
3901 if (nla_len(iter) != sizeof(uint32)) {
3902 ret = -EINVAL;
3903 goto exit;
3904 }
3905 cmd_data->pub_id = nla_get_u32(iter);
3906 break;
3907 case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
3908 if (nla_len(iter) != sizeof(uint8)) {
3909 ret = -EINVAL;
3910 goto exit;
3911 }
3912 cmd_data->csid = nla_get_u8(iter);
3913 WL_TRACE(("CSID = %u\n", cmd_data->csid));
3914 break;
3915 case NAN_ATTRIBUTE_KEY_TYPE:
3916 if (nla_len(iter) != sizeof(uint8)) {
3917 ret = -EINVAL;
3918 goto exit;
3919 }
3920 cmd_data->key_type = nla_get_u8(iter);
3921 WL_TRACE(("Key Type = %u\n", cmd_data->key_type));
3922 break;
3923 case NAN_ATTRIBUTE_KEY_LEN:
3924 if (nla_len(iter) != sizeof(uint32)) {
3925 ret = -EINVAL;
3926 goto exit;
3927 }
3928 if (cmd_data->key.dlen) {
3929 WL_ERR(("trying to overwrite:%d\n", attr_type));
3930 ret = -EINVAL;
3931 goto exit;
3932 }
3933 cmd_data->key.dlen = nla_get_u32(iter);
3934 if ((!cmd_data->key.dlen) || (cmd_data->key.dlen > WL_NAN_NCS_SK_PMK_LEN)) {
3935 WL_ERR(("invalid key length = %u\n", cmd_data->key.dlen));
3936 ret = -EINVAL;
3937 goto exit;
3938 }
3939 WL_TRACE(("valid key length = %u\n", cmd_data->key.dlen));
3940 break;
3941 case NAN_ATTRIBUTE_KEY_DATA:
3942 if ((!cmd_data->key.dlen) ||
3943 (nla_len(iter) != cmd_data->key.dlen)) {
3944 WL_ERR(("failed to allocate key data by invalid len=%d,%d\n",
3945 cmd_data->key.dlen, nla_len(iter)));
3946 ret = -EINVAL;
3947 goto exit;
3948 }
3949 if (cmd_data->key.data) {
3950 WL_ERR(("trying to overwrite key data.\n"));
3951 ret = -EINVAL;
3952 goto exit;
3953 }
3954
3955 cmd_data->key.data = MALLOCZ(cfg->osh, NAN_MAX_PMK_LEN);
3956 if (cmd_data->key.data == NULL) {
3957 WL_ERR(("failed to allocate key data, len=%d\n",
3958 cmd_data->key.dlen));
3959 ret = -ENOMEM;
3960 goto exit;
3961 }
3962 ret = memcpy_s(cmd_data->key.data, NAN_MAX_PMK_LEN,
3963 nla_data(iter), nla_len(iter));
3964 if (ret != BCME_OK) {
3965 WL_ERR(("Failed to key data\n"));
3966 goto exit;
3967 }
3968 break;
3969
3970 default:
3971 WL_ERR(("Unknown type, %d\n", attr_type));
3972 ret = -EINVAL;
3973 goto exit;
3974 }
3975 }
3976 exit:
3977 /* We need to call set_config_handler b/f calling start enable TBD */
3978 NAN_DBG_EXIT();
3979 return ret;
3980 }
3981
3982 static int
wl_cfgvendor_nan_parse_discover_args(struct wiphy * wiphy,const void * buf,int len,nan_discover_cmd_data_t * cmd_data)3983 wl_cfgvendor_nan_parse_discover_args(struct wiphy *wiphy,
3984 const void *buf, int len, nan_discover_cmd_data_t *cmd_data)
3985 {
3986 int ret = BCME_OK;
3987 int attr_type;
3988 int rem = len;
3989 const struct nlattr *iter;
3990 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3991 u8 val_u8;
3992 u32 bit_flag;
3993 u8 flag_match;
3994
3995 NAN_DBG_ENTER();
3996
3997 nla_for_each_attr(iter, buf, len, rem) {
3998 attr_type = nla_type(iter);
3999 WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
4000
4001 switch (attr_type) {
4002 case NAN_ATTRIBUTE_TRANSAC_ID:
4003 if (nla_len(iter) != sizeof(uint16)) {
4004 ret = -EINVAL;
4005 goto exit;
4006 }
4007 cmd_data->token = nla_get_u16(iter);
4008 break;
4009 case NAN_ATTRIBUTE_PERIODIC_SCAN_INTERVAL:
4010 break;
4011
4012 /* Nan Publish/Subscribe request Attributes */
4013 case NAN_ATTRIBUTE_PUBLISH_ID:
4014 if (nla_len(iter) != sizeof(uint16)) {
4015 ret = -EINVAL;
4016 goto exit;
4017 }
4018 cmd_data->pub_id = nla_get_u16(iter);
4019 cmd_data->local_id = cmd_data->pub_id;
4020 break;
4021 case NAN_ATTRIBUTE_MAC_ADDR:
4022 if (nla_len(iter) != ETHER_ADDR_LEN) {
4023 ret = -EINVAL;
4024 goto exit;
4025 }
4026 ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
4027 (char*)nla_data(iter), nla_len(iter));
4028 if (ret != BCME_OK) {
4029 WL_ERR(("Failed to copy mac addr\n"));
4030 return ret;
4031 }
4032 break;
4033 case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN:
4034 if (nla_len(iter) != sizeof(uint16)) {
4035 ret = -EINVAL;
4036 goto exit;
4037 }
4038 if (cmd_data->svc_info.dlen) {
4039 WL_ERR(("trying to overwrite:%d\n", attr_type));
4040 ret = -EINVAL;
4041 goto exit;
4042 }
4043 cmd_data->svc_info.dlen = nla_get_u16(iter);
4044 if (cmd_data->svc_info.dlen > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
4045 WL_ERR_RLMT(("Not allowed beyond :%d\n",
4046 NAN_MAX_SERVICE_SPECIFIC_INFO_LEN));
4047 ret = -EINVAL;
4048 goto exit;
4049 }
4050 break;
4051 case NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO:
4052 if ((!cmd_data->svc_info.dlen) ||
4053 (nla_len(iter) != cmd_data->svc_info.dlen)) {
4054 WL_ERR(("failed to allocate svc info by invalid len=%d,%d\n",
4055 cmd_data->svc_info.dlen, nla_len(iter)));
4056 ret = -EINVAL;
4057 goto exit;
4058 }
4059 if (cmd_data->svc_info.data) {
4060 WL_ERR(("trying to overwrite:%d\n", attr_type));
4061 ret = -EINVAL;
4062 goto exit;
4063 }
4064
4065 cmd_data->svc_info.data = MALLOCZ(cfg->osh, cmd_data->svc_info.dlen);
4066 if (cmd_data->svc_info.data == NULL) {
4067 WL_ERR(("failed to allocate svc info data, len=%d\n",
4068 cmd_data->svc_info.dlen));
4069 ret = -ENOMEM;
4070 goto exit;
4071 }
4072 ret = memcpy_s(cmd_data->svc_info.data, cmd_data->svc_info.dlen,
4073 nla_data(iter), nla_len(iter));
4074 if (ret != BCME_OK) {
4075 WL_ERR(("Failed to copy svc info\n"));
4076 return ret;
4077 }
4078 break;
4079 case NAN_ATTRIBUTE_SUBSCRIBE_ID:
4080 if (nla_len(iter) != sizeof(uint16)) {
4081 ret = -EINVAL;
4082 goto exit;
4083 }
4084 cmd_data->sub_id = nla_get_u16(iter);
4085 cmd_data->local_id = cmd_data->sub_id;
4086 break;
4087 case NAN_ATTRIBUTE_SUBSCRIBE_TYPE:
4088 if (nla_len(iter) != sizeof(uint8)) {
4089 ret = -EINVAL;
4090 goto exit;
4091 }
4092 cmd_data->flags |= nla_get_u8(iter) ? WL_NAN_SUB_ACTIVE : 0;
4093 break;
4094 case NAN_ATTRIBUTE_PUBLISH_COUNT:
4095 if (nla_len(iter) != sizeof(uint8)) {
4096 ret = -EINVAL;
4097 goto exit;
4098 }
4099 cmd_data->life_count = nla_get_u8(iter);
4100 break;
4101 case NAN_ATTRIBUTE_PUBLISH_TYPE: {
4102 if (nla_len(iter) != sizeof(uint8)) {
4103 ret = -EINVAL;
4104 goto exit;
4105 }
4106 val_u8 = nla_get_u8(iter);
4107 if (val_u8 == 0) {
4108 cmd_data->flags |= WL_NAN_PUB_UNSOLICIT;
4109 } else if (val_u8 == 1) {
4110 cmd_data->flags |= WL_NAN_PUB_SOLICIT;
4111 } else {
4112 cmd_data->flags |= WL_NAN_PUB_BOTH;
4113 }
4114 break;
4115 }
4116 case NAN_ATTRIBUTE_PERIOD: {
4117 if (nla_len(iter) != sizeof(uint16)) {
4118 ret = -EINVAL;
4119 goto exit;
4120 }
4121 if (nla_get_u16(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
4122 WL_ERR(("Invalid/Out of bound value = %u\n", nla_get_u16(iter)));
4123 ret = BCME_BADARG;
4124 break;
4125 }
4126 if (nla_get_u16(iter)) {
4127 cmd_data->period = 1 << (nla_get_u16(iter)-1);
4128 }
4129 break;
4130 }
4131 case NAN_ATTRIBUTE_REPLIED_EVENT_FLAG:
4132 break;
4133 case NAN_ATTRIBUTE_TTL:
4134 if (nla_len(iter) != sizeof(uint16)) {
4135 ret = -EINVAL;
4136 goto exit;
4137 }
4138 cmd_data->ttl = nla_get_u16(iter);
4139 break;
4140 case NAN_ATTRIBUTE_SERVICE_NAME_LEN: {
4141 if (nla_len(iter) != sizeof(uint16)) {
4142 ret = -EINVAL;
4143 goto exit;
4144 }
4145 if (cmd_data->svc_hash.dlen) {
4146 WL_ERR(("trying to overwrite:%d\n", attr_type));
4147 ret = -EINVAL;
4148 goto exit;
4149 }
4150
4151 cmd_data->svc_hash.dlen = nla_get_u16(iter);
4152 if (cmd_data->svc_hash.dlen != WL_NAN_SVC_HASH_LEN) {
4153 WL_ERR(("invalid svc_hash length = %u\n", cmd_data->svc_hash.dlen));
4154 ret = -EINVAL;
4155 goto exit;
4156 }
4157 break;
4158 }
4159 case NAN_ATTRIBUTE_SERVICE_NAME:
4160 if ((!cmd_data->svc_hash.dlen) ||
4161 (nla_len(iter) != cmd_data->svc_hash.dlen)) {
4162 WL_ERR(("invalid svc_hash length = %d,%d\n",
4163 cmd_data->svc_hash.dlen, nla_len(iter)));
4164 ret = -EINVAL;
4165 goto exit;
4166 }
4167 if (cmd_data->svc_hash.data) {
4168 WL_ERR(("trying to overwrite:%d\n", attr_type));
4169 ret = -EINVAL;
4170 goto exit;
4171 }
4172
4173 cmd_data->svc_hash.data =
4174 MALLOCZ(cfg->osh, cmd_data->svc_hash.dlen);
4175 if (!cmd_data->svc_hash.data) {
4176 WL_ERR(("failed to allocate svc_hash data, len=%d\n",
4177 cmd_data->svc_hash.dlen));
4178 ret = -ENOMEM;
4179 goto exit;
4180 }
4181 ret = memcpy_s(cmd_data->svc_hash.data, cmd_data->svc_hash.dlen,
4182 nla_data(iter), nla_len(iter));
4183 if (ret != BCME_OK) {
4184 WL_ERR(("Failed to copy svc hash data\n"));
4185 return ret;
4186 }
4187 break;
4188 case NAN_ATTRIBUTE_PEER_ID:
4189 if (nla_len(iter) != sizeof(uint32)) {
4190 ret = -EINVAL;
4191 goto exit;
4192 }
4193 cmd_data->remote_id = nla_get_u32(iter);
4194 break;
4195 case NAN_ATTRIBUTE_INST_ID:
4196 if (nla_len(iter) != sizeof(uint16)) {
4197 ret = -EINVAL;
4198 goto exit;
4199 }
4200 cmd_data->local_id = nla_get_u16(iter);
4201 break;
4202 case NAN_ATTRIBUTE_SUBSCRIBE_COUNT:
4203 if (nla_len(iter) != sizeof(uint8)) {
4204 ret = -EINVAL;
4205 goto exit;
4206 }
4207 cmd_data->life_count = nla_get_u8(iter);
4208 break;
4209 case NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION: {
4210 if (nla_len(iter) != sizeof(uint8)) {
4211 ret = -EINVAL;
4212 goto exit;
4213 }
4214 bit_flag = (u32)nla_get_u8(iter);
4215 cmd_data->flags |=
4216 bit_flag ? WL_NAN_SUB_MATCH_IF_SVC_INFO : 0;
4217 break;
4218 }
4219 case NAN_ATTRIBUTE_SUBSCRIBE_MATCH:
4220 case NAN_ATTRIBUTE_PUBLISH_MATCH: {
4221 if (nla_len(iter) != sizeof(uint8)) {
4222 ret = -EINVAL;
4223 goto exit;
4224 }
4225 flag_match = nla_get_u8(iter);
4226
4227 switch (flag_match) {
4228 case NAN_MATCH_ALG_MATCH_CONTINUOUS:
4229 /* Default fw behaviour, no need to set explicitly */
4230 break;
4231 case NAN_MATCH_ALG_MATCH_ONCE:
4232 cmd_data->flags |= WL_NAN_MATCH_ONCE;
4233 break;
4234 case NAN_MATCH_ALG_MATCH_NEVER:
4235 cmd_data->flags |= WL_NAN_MATCH_NEVER;
4236 break;
4237 default:
4238 WL_ERR(("invalid nan match alg = %u\n", flag_match));
4239 ret = -EINVAL;
4240 goto exit;
4241 }
4242 break;
4243 }
4244 case NAN_ATTRIBUTE_SERVICERESPONSEFILTER:
4245 if (nla_len(iter) != sizeof(uint8)) {
4246 ret = -EINVAL;
4247 goto exit;
4248 }
4249 cmd_data->srf_type = nla_get_u8(iter);
4250 break;
4251 case NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE:
4252 if (nla_len(iter) != sizeof(uint8)) {
4253 ret = -EINVAL;
4254 goto exit;
4255 }
4256 cmd_data->srf_include = nla_get_u8(iter);
4257 break;
4258 case NAN_ATTRIBUTE_USESERVICERESPONSEFILTER:
4259 if (nla_len(iter) != sizeof(uint8)) {
4260 ret = -EINVAL;
4261 goto exit;
4262 }
4263 cmd_data->use_srf = nla_get_u8(iter);
4264 break;
4265 case NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN:
4266 if (nla_len(iter) != sizeof(uint16)) {
4267 ret = -EINVAL;
4268 goto exit;
4269 }
4270 if (cmd_data->rx_match.dlen) {
4271 WL_ERR(("trying to overwrite:%d\n", attr_type));
4272 ret = -EINVAL;
4273 goto exit;
4274 }
4275 cmd_data->rx_match.dlen = nla_get_u16(iter);
4276 if (cmd_data->rx_match.dlen > MAX_MATCH_FILTER_LEN) {
4277 ret = -EINVAL;
4278 WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_MATCH_FILTER_LEN));
4279 goto exit;
4280 }
4281 break;
4282 case NAN_ATTRIBUTE_RX_MATCH_FILTER:
4283 if ((!cmd_data->rx_match.dlen) ||
4284 (nla_len(iter) != cmd_data->rx_match.dlen)) {
4285 WL_ERR(("RX match filter len wrong:%d,%d\n",
4286 cmd_data->rx_match.dlen, nla_len(iter)));
4287 ret = -EINVAL;
4288 goto exit;
4289 }
4290 if (cmd_data->rx_match.data) {
4291 WL_ERR(("trying to overwrite:%d\n", attr_type));
4292 ret = -EINVAL;
4293 goto exit;
4294 }
4295 cmd_data->rx_match.data =
4296 MALLOCZ(cfg->osh, cmd_data->rx_match.dlen);
4297 if (cmd_data->rx_match.data == NULL) {
4298 WL_ERR(("failed to allocate LEN=[%u]\n",
4299 cmd_data->rx_match.dlen));
4300 ret = -ENOMEM;
4301 goto exit;
4302 }
4303 ret = memcpy_s(cmd_data->rx_match.data, cmd_data->rx_match.dlen,
4304 nla_data(iter), nla_len(iter));
4305 if (ret != BCME_OK) {
4306 WL_ERR(("Failed to copy rx match data\n"));
4307 return ret;
4308 }
4309 break;
4310 case NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN:
4311 if (nla_len(iter) != sizeof(uint16)) {
4312 ret = -EINVAL;
4313 goto exit;
4314 }
4315 if (cmd_data->tx_match.dlen) {
4316 WL_ERR(("trying to overwrite:%d\n", attr_type));
4317 ret = -EINVAL;
4318 goto exit;
4319 }
4320 cmd_data->tx_match.dlen = nla_get_u16(iter);
4321 if (cmd_data->tx_match.dlen > MAX_MATCH_FILTER_LEN) {
4322 ret = -EINVAL;
4323 WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_MATCH_FILTER_LEN));
4324 goto exit;
4325 }
4326 break;
4327 case NAN_ATTRIBUTE_TX_MATCH_FILTER:
4328 if ((!cmd_data->tx_match.dlen) ||
4329 (nla_len(iter) != cmd_data->tx_match.dlen)) {
4330 WL_ERR(("TX match filter len wrong:%d,%d\n",
4331 cmd_data->tx_match.dlen, nla_len(iter)));
4332 ret = -EINVAL;
4333 goto exit;
4334 }
4335 if (cmd_data->tx_match.data) {
4336 WL_ERR(("trying to overwrite:%d\n", attr_type));
4337 ret = -EINVAL;
4338 goto exit;
4339 }
4340 cmd_data->tx_match.data =
4341 MALLOCZ(cfg->osh, cmd_data->tx_match.dlen);
4342 if (cmd_data->tx_match.data == NULL) {
4343 WL_ERR(("failed to allocate LEN=[%u]\n",
4344 cmd_data->tx_match.dlen));
4345 ret = -EINVAL;
4346 goto exit;
4347 }
4348 ret = memcpy_s(cmd_data->tx_match.data, cmd_data->tx_match.dlen,
4349 nla_data(iter), nla_len(iter));
4350 if (ret != BCME_OK) {
4351 WL_ERR(("Failed to copy tx match data\n"));
4352 return ret;
4353 }
4354 break;
4355 case NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES:
4356 if (nla_len(iter) != sizeof(uint16)) {
4357 ret = -EINVAL;
4358 goto exit;
4359 }
4360 if (cmd_data->mac_list.num_mac_addr) {
4361 WL_ERR(("trying to overwrite:%d\n", attr_type));
4362 ret = -EINVAL;
4363 goto exit;
4364 }
4365 cmd_data->mac_list.num_mac_addr = nla_get_u16(iter);
4366 if (cmd_data->mac_list.num_mac_addr >= NAN_SRF_MAX_MAC) {
4367 WL_ERR(("trying to overflow num :%d\n",
4368 cmd_data->mac_list.num_mac_addr));
4369 cmd_data->mac_list.num_mac_addr = 0;
4370 ret = -EINVAL;
4371 goto exit;
4372 }
4373 break;
4374 case NAN_ATTRIBUTE_MAC_ADDR_LIST:
4375 if ((!cmd_data->mac_list.num_mac_addr) ||
4376 (nla_len(iter) != (cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN))) {
4377 WL_ERR(("wrong mac list len:%d,%d\n",
4378 cmd_data->mac_list.num_mac_addr, nla_len(iter)));
4379 ret = -EINVAL;
4380 goto exit;
4381 }
4382 if (cmd_data->mac_list.list) {
4383 WL_ERR(("trying to overwrite:%d\n", attr_type));
4384 ret = -EINVAL;
4385 goto exit;
4386 }
4387 cmd_data->mac_list.list =
4388 MALLOCZ(cfg->osh, (cmd_data->mac_list.num_mac_addr
4389 * ETHER_ADDR_LEN));
4390 if (cmd_data->mac_list.list == NULL) {
4391 WL_ERR(("failed to allocate LEN=[%u]\n",
4392 (cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN)));
4393 ret = -ENOMEM;
4394 goto exit;
4395 }
4396 ret = memcpy_s(cmd_data->mac_list.list,
4397 (cmd_data->mac_list.num_mac_addr * ETHER_ADDR_LEN),
4398 nla_data(iter), nla_len(iter));
4399 if (ret != BCME_OK) {
4400 WL_ERR(("Failed to copy list of mac addresses\n"));
4401 return ret;
4402 }
4403 break;
4404 case NAN_ATTRIBUTE_TX_TYPE:
4405 if (nla_len(iter) != sizeof(uint8)) {
4406 ret = -EINVAL;
4407 goto exit;
4408 }
4409 val_u8 = nla_get_u8(iter);
4410 if (val_u8 == 0) {
4411 cmd_data->flags |= WL_NAN_PUB_BCAST;
4412 WL_TRACE(("NAN_ATTRIBUTE_TX_TYPE: flags=NAN_PUB_BCAST\n"));
4413 }
4414 break;
4415 case NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP:
4416 if (nla_len(iter) != sizeof(uint8)) {
4417 ret = -EINVAL;
4418 goto exit;
4419 }
4420 if (nla_get_u8(iter) == 1) {
4421 cmd_data->sde_control_flag
4422 |= NAN_SDE_CF_DP_REQUIRED;
4423 break;
4424 }
4425 break;
4426 case NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT:
4427 if (nla_len(iter) != sizeof(uint8)) {
4428 ret = -EINVAL;
4429 goto exit;
4430 }
4431 cmd_data->sde_control_config = TRUE;
4432 if (nla_get_u8(iter) == 1) {
4433 cmd_data->sde_control_flag
4434 |= NAN_SDE_CF_RANGING_REQUIRED;
4435 break;
4436 }
4437 break;
4438 case NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE:
4439 if (nla_len(iter) != sizeof(uint8)) {
4440 ret = -EINVAL;
4441 goto exit;
4442 }
4443 if (nla_get_u8(iter) == 1) {
4444 cmd_data->sde_control_flag
4445 |= NAN_SDE_CF_MULTICAST_TYPE;
4446 break;
4447 }
4448 break;
4449 case NAN_ATTRIBUTE_SDE_CONTROL_SECURITY:
4450 if (nla_len(iter) != sizeof(uint8)) {
4451 ret = -EINVAL;
4452 goto exit;
4453 }
4454 if (nla_get_u8(iter) == 1) {
4455 cmd_data->sde_control_flag
4456 |= NAN_SDE_CF_SECURITY_REQUIRED;
4457 break;
4458 }
4459 break;
4460 case NAN_ATTRIBUTE_RECV_IND_CFG:
4461 if (nla_len(iter) != sizeof(uint8)) {
4462 ret = -EINVAL;
4463 goto exit;
4464 }
4465 cmd_data->recv_ind_flag = nla_get_u8(iter);
4466 break;
4467 case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
4468 if (nla_len(iter) != sizeof(uint8)) {
4469 ret = -EINVAL;
4470 goto exit;
4471 }
4472 cmd_data->csid = nla_get_u8(iter);
4473 WL_TRACE(("CSID = %u\n", cmd_data->csid));
4474 break;
4475 case NAN_ATTRIBUTE_KEY_TYPE:
4476 if (nla_len(iter) != sizeof(uint8)) {
4477 ret = -EINVAL;
4478 goto exit;
4479 }
4480 cmd_data->key_type = nla_get_u8(iter);
4481 WL_TRACE(("Key Type = %u\n", cmd_data->key_type));
4482 break;
4483 case NAN_ATTRIBUTE_KEY_LEN:
4484 if (nla_len(iter) != sizeof(uint32)) {
4485 ret = -EINVAL;
4486 goto exit;
4487 }
4488 if (cmd_data->key.dlen) {
4489 WL_ERR(("trying to overwrite:%d\n", attr_type));
4490 ret = -EINVAL;
4491 goto exit;
4492 }
4493 cmd_data->key.dlen = nla_get_u32(iter);
4494 if ((!cmd_data->key.dlen) || (cmd_data->key.dlen > WL_NAN_NCS_SK_PMK_LEN)) {
4495 WL_ERR(("invalid key length = %u\n",
4496 cmd_data->key.dlen));
4497 break;
4498 }
4499 WL_TRACE(("valid key length = %u\n", cmd_data->key.dlen));
4500 break;
4501 case NAN_ATTRIBUTE_KEY_DATA:
4502 if (!cmd_data->key.dlen ||
4503 (nla_len(iter) != cmd_data->key.dlen)) {
4504 WL_ERR(("failed to allocate key data by invalid len=%d,%d\n",
4505 cmd_data->key.dlen, nla_len(iter)));
4506 ret = -EINVAL;
4507 goto exit;
4508 }
4509 if (cmd_data->key.data) {
4510 WL_ERR(("trying to overwrite:%d\n", attr_type));
4511 ret = -EINVAL;
4512 goto exit;
4513 }
4514
4515 cmd_data->key.data = MALLOCZ(cfg->osh, NAN_MAX_PMK_LEN);
4516 if (cmd_data->key.data == NULL) {
4517 WL_ERR(("failed to allocate key data, len=%d\n",
4518 cmd_data->key.dlen));
4519 ret = -ENOMEM;
4520 goto exit;
4521 }
4522 ret = memcpy_s(cmd_data->key.data, NAN_MAX_PMK_LEN,
4523 nla_data(iter), nla_len(iter));
4524 if (ret != BCME_OK) {
4525 WL_ERR(("Failed to key data\n"));
4526 return ret;
4527 }
4528 break;
4529 case NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG:
4530 if (nla_len(iter) != sizeof(uint8)) {
4531 ret = -EINVAL;
4532 goto exit;
4533 }
4534 if (nla_get_u8(iter) == 1) {
4535 cmd_data->flags |=
4536 WL_NAN_RANGE_LIMITED;
4537 break;
4538 }
4539 break;
4540 case NAN_ATTRIBUTE_DISC_IND_CFG:
4541 if (nla_len(iter) != sizeof(uint8)) {
4542 ret = -EINVAL;
4543 goto exit;
4544 }
4545 cmd_data->disc_ind_cfg = nla_get_u8(iter);
4546 break;
4547 case NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN:
4548 if (nla_len(iter) != sizeof(uint16)) {
4549 ret = -EINVAL;
4550 goto exit;
4551 }
4552 if (cmd_data->sde_svc_info.dlen) {
4553 WL_ERR(("trying to overwrite:%d\n", attr_type));
4554 ret = -EINVAL;
4555 goto exit;
4556 }
4557 cmd_data->sde_svc_info.dlen = nla_get_u16(iter);
4558 if (cmd_data->sde_svc_info.dlen > MAX_SDEA_SVC_INFO_LEN) {
4559 ret = -EINVAL;
4560 WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_SDEA_SVC_INFO_LEN));
4561 goto exit;
4562 }
4563 break;
4564 case NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO:
4565 if ((!cmd_data->sde_svc_info.dlen) ||
4566 (nla_len(iter) != cmd_data->sde_svc_info.dlen)) {
4567 WL_ERR(("wrong sdea info len:%d,%d\n",
4568 cmd_data->sde_svc_info.dlen, nla_len(iter)));
4569 ret = -EINVAL;
4570 goto exit;
4571 }
4572 if (cmd_data->sde_svc_info.data) {
4573 WL_ERR(("trying to overwrite:%d\n", attr_type));
4574 ret = -EINVAL;
4575 goto exit;
4576 }
4577 cmd_data->sde_svc_info.data = MALLOCZ(cfg->osh,
4578 cmd_data->sde_svc_info.dlen);
4579 if (cmd_data->sde_svc_info.data == NULL) {
4580 WL_ERR(("failed to allocate svc info data, len=%d\n",
4581 cmd_data->sde_svc_info.dlen));
4582 ret = -ENOMEM;
4583 goto exit;
4584 }
4585 ret = memcpy_s(cmd_data->sde_svc_info.data,
4586 cmd_data->sde_svc_info.dlen,
4587 nla_data(iter), nla_len(iter));
4588 if (ret != BCME_OK) {
4589 WL_ERR(("Failed to sdea info data\n"));
4590 return ret;
4591 }
4592 break;
4593 case NAN_ATTRIBUTE_SECURITY:
4594 if (nla_len(iter) != sizeof(uint8)) {
4595 ret = -EINVAL;
4596 goto exit;
4597 }
4598 cmd_data->ndp_cfg.security_cfg = nla_get_u8(iter);
4599 break;
4600 case NAN_ATTRIBUTE_RANGING_INTERVAL:
4601 if (nla_len(iter) != sizeof(uint32)) {
4602 ret = -EINVAL;
4603 goto exit;
4604 }
4605 cmd_data->ranging_intvl_msec = nla_get_u32(iter);
4606 break;
4607 case NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT:
4608 if (nla_len(iter) != sizeof(uint32)) {
4609 ret = -EINVAL;
4610 goto exit;
4611 }
4612 cmd_data->ingress_limit = nla_get_u32(iter);
4613 break;
4614 case NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT:
4615 if (nla_len(iter) != sizeof(uint32)) {
4616 ret = -EINVAL;
4617 goto exit;
4618 }
4619 cmd_data->egress_limit = nla_get_u32(iter);
4620 break;
4621 case NAN_ATTRIBUTE_RANGING_INDICATION:
4622 if (nla_len(iter) != sizeof(uint32)) {
4623 ret = -EINVAL;
4624 goto exit;
4625 }
4626 cmd_data->ranging_indication = nla_get_u32(iter);
4627 break;
4628 /* Nan accept policy: Per service basis policy
4629 * Based on this policy(ALL/NONE), responder side
4630 * will send ACCEPT/REJECT
4631 */
4632 case NAN_ATTRIBUTE_SVC_RESPONDER_POLICY:
4633 if (nla_len(iter) != sizeof(uint8)) {
4634 ret = -EINVAL;
4635 goto exit;
4636 }
4637 cmd_data->service_responder_policy = nla_get_u8(iter);
4638 break;
4639 default:
4640 WL_ERR(("Unknown type, %d\n", attr_type));
4641 ret = -EINVAL;
4642 goto exit;
4643 }
4644 }
4645 exit:
4646 /* We need to call set_config_handler b/f calling start enable TBD */
4647 NAN_DBG_EXIT();
4648 return ret;
4649 }
4650
4651 static int
wl_cfgvendor_nan_parse_args(struct wiphy * wiphy,const void * buf,int len,nan_config_cmd_data_t * cmd_data,uint32 * nan_attr_mask)4652 wl_cfgvendor_nan_parse_args(struct wiphy *wiphy, const void *buf,
4653 int len, nan_config_cmd_data_t *cmd_data, uint32 *nan_attr_mask)
4654 {
4655 int ret = BCME_OK;
4656 int attr_type;
4657 int rem = len;
4658 const struct nlattr *iter;
4659 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
4660 int chan;
4661 u8 sid_beacon = 0, sub_sid_beacon = 0;
4662
4663 NAN_DBG_ENTER();
4664
4665 nla_for_each_attr(iter, buf, len, rem) {
4666 attr_type = nla_type(iter);
4667 WL_TRACE(("attr: %s (%u)\n", nan_attr_to_str(attr_type), attr_type));
4668
4669 switch (attr_type) {
4670 /* NAN Enable request attributes */
4671 case NAN_ATTRIBUTE_2G_SUPPORT:{
4672 if (nla_len(iter) != sizeof(uint8)) {
4673 ret = -EINVAL;
4674 goto exit;
4675 }
4676 cmd_data->support_2g = nla_get_u8(iter);
4677 if (cmd_data->support_2g == 0) {
4678 WL_ERR((" 2.4GHz support is not set \n"));
4679 cmd_data->status = BCME_BADARG;
4680 goto exit;
4681 }
4682 *nan_attr_mask |= NAN_ATTR_SUPPORT_2G_CONFIG;
4683 break;
4684 }
4685 case NAN_ATTRIBUTE_5G_SUPPORT:{
4686 if (nla_len(iter) != sizeof(uint8)) {
4687 ret = -EINVAL;
4688 goto exit;
4689 }
4690 cmd_data->support_5g = nla_get_u8(iter);
4691 *nan_attr_mask |= NAN_ATTR_SUPPORT_5G_CONFIG;
4692 break;
4693 }
4694 case NAN_ATTRIBUTE_CLUSTER_LOW: {
4695 if (nla_len(iter) != sizeof(uint16)) {
4696 ret = -EINVAL;
4697 goto exit;
4698 }
4699 cmd_data->cluster_low = nla_get_u16(iter);
4700 break;
4701 }
4702 case NAN_ATTRIBUTE_CLUSTER_HIGH: {
4703 if (nla_len(iter) != sizeof(uint16)) {
4704 ret = -EINVAL;
4705 goto exit;
4706 }
4707 cmd_data->cluster_high = nla_get_u16(iter);
4708 break;
4709 }
4710 case NAN_ATTRIBUTE_SID_BEACON: {
4711 if (nla_len(iter) != sizeof(uint8)) {
4712 ret = -EINVAL;
4713 goto exit;
4714 }
4715 sid_beacon = nla_get_u8(iter);
4716 cmd_data->sid_beacon.sid_enable = (sid_beacon & 0x01);
4717 if (cmd_data->sid_beacon.sid_enable) {
4718 cmd_data->sid_beacon.sid_count = (sid_beacon >> 1);
4719 *nan_attr_mask |= NAN_ATTR_SID_BEACON_CONFIG;
4720 } else {
4721 WL_ERR((" sid beacon is not valid \n"));
4722 cmd_data->status = BCME_BADARG;
4723 goto exit;
4724 }
4725
4726 break;
4727 }
4728 case NAN_ATTRIBUTE_SUB_SID_BEACON: {
4729 if (nla_len(iter) != sizeof(uint8)) {
4730 ret = -EINVAL;
4731 goto exit;
4732 }
4733 sub_sid_beacon = nla_get_u8(iter);
4734 cmd_data->sid_beacon.sub_sid_enable = (sub_sid_beacon & 0x01);
4735 if (cmd_data->sid_beacon.sub_sid_enable) {
4736 cmd_data->sid_beacon.sub_sid_count = (sub_sid_beacon >> 1);
4737 *nan_attr_mask |= NAN_ATTR_SUB_SID_BEACON_CONFIG;
4738 } else {
4739 WL_ERR((" sub sid beacon is not valid \n"));
4740 cmd_data->status = BCME_BADARG;
4741 goto exit;
4742 }
4743 break;
4744 }
4745 case NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON:
4746 if (nla_len(iter) != sizeof(uint8)) {
4747 ret = -EINVAL;
4748 goto exit;
4749 }
4750 cmd_data->beacon_2g_val = nla_get_u8(iter);
4751 *nan_attr_mask |= NAN_ATTR_SYNC_DISC_2G_BEACON_CONFIG;
4752 break;
4753 case NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON:
4754 if (nla_len(iter) != sizeof(uint8)) {
4755 ret = -EINVAL;
4756 goto exit;
4757 }
4758 cmd_data->beacon_5g_val = nla_get_u8(iter);
4759 *nan_attr_mask |= NAN_ATTR_SYNC_DISC_5G_BEACON_CONFIG;
4760 break;
4761 case NAN_ATTRIBUTE_SDF_2G_SUPPORT:
4762 if (nla_len(iter) != sizeof(uint8)) {
4763 ret = -EINVAL;
4764 goto exit;
4765 }
4766 cmd_data->sdf_2g_val = nla_get_u8(iter);
4767 *nan_attr_mask |= NAN_ATTR_SDF_2G_SUPPORT_CONFIG;
4768 break;
4769 case NAN_ATTRIBUTE_SDF_5G_SUPPORT:
4770 if (nla_len(iter) != sizeof(uint8)) {
4771 ret = -EINVAL;
4772 goto exit;
4773 }
4774 cmd_data->sdf_5g_val = nla_get_u8(iter);
4775 *nan_attr_mask |= NAN_ATTR_SDF_5G_SUPPORT_CONFIG;
4776 break;
4777 case NAN_ATTRIBUTE_HOP_COUNT_LIMIT:
4778 if (nla_len(iter) != sizeof(uint8)) {
4779 ret = -EINVAL;
4780 goto exit;
4781 }
4782 cmd_data->hop_count_limit = nla_get_u8(iter);
4783 if (cmd_data->hop_count_limit == 0) {
4784 WL_ERR((" hop count limit is not valid \n"));
4785 cmd_data->status = BCME_BADARG;
4786 goto exit;
4787 }
4788 *nan_attr_mask |= NAN_ATTR_HOP_COUNT_LIMIT_CONFIG;
4789 break;
4790 case NAN_ATTRIBUTE_RANDOM_TIME:
4791 if (nla_len(iter) != sizeof(uint8)) {
4792 ret = -EINVAL;
4793 goto exit;
4794 }
4795 cmd_data->metrics.random_factor = nla_get_u8(iter);
4796 *nan_attr_mask |= NAN_ATTR_RAND_FACTOR_CONFIG;
4797 break;
4798 case NAN_ATTRIBUTE_MASTER_PREF:
4799 if (nla_len(iter) != sizeof(uint8)) {
4800 ret = -EINVAL;
4801 goto exit;
4802 }
4803 cmd_data->metrics.master_pref = nla_get_u8(iter);
4804 break;
4805 case NAN_ATTRIBUTE_OUI:
4806 if (nla_len(iter) != sizeof(uint32)) {
4807 ret = -EINVAL;
4808 goto exit;
4809 }
4810 cmd_data->nan_oui = nla_get_u32(iter);
4811 *nan_attr_mask |= NAN_ATTR_OUI_CONFIG;
4812 WL_TRACE(("nan_oui=%d\n", cmd_data->nan_oui));
4813 break;
4814 case NAN_ATTRIBUTE_WARMUP_TIME:
4815 if (nla_len(iter) != sizeof(uint16)) {
4816 ret = -EINVAL;
4817 goto exit;
4818 }
4819 cmd_data->warmup_time = nla_get_u16(iter);
4820 break;
4821 case NAN_ATTRIBUTE_AMBTT:
4822 case NAN_ATTRIBUTE_MASTER_RANK:
4823 WL_DBG(("Unhandled attribute, %d\n", attr_type));
4824 break;
4825 case NAN_ATTRIBUTE_CHANNEL: {
4826 if (nla_len(iter) != sizeof(uint32)) {
4827 ret = -EINVAL;
4828 goto exit;
4829 }
4830 /* take the default channel start_factor frequency */
4831 chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4832 if (chan <= CH_MAX_2G_CHANNEL) {
4833 cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4834 } else {
4835 cmd_data->chanspec[0] = wf_channel2chspec(chan, WL_CHANSPEC_BW_80);
4836 }
4837 if (cmd_data->chanspec[0] == 0) {
4838 WL_ERR(("Channel is not valid \n"));
4839 ret = -EINVAL;
4840 goto exit;
4841 }
4842 WL_TRACE(("valid chanspec, chanspec = 0x%04x \n",
4843 cmd_data->chanspec[0]));
4844 break;
4845 }
4846 case NAN_ATTRIBUTE_24G_CHANNEL: {
4847 if (nla_len(iter) != sizeof(uint32)) {
4848 ret = -EINVAL;
4849 goto exit;
4850 }
4851 /* take the default channel start_factor frequency */
4852 chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4853 /* 20MHz as BW */
4854 cmd_data->chanspec[1] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4855 if (cmd_data->chanspec[1] == 0) {
4856 WL_ERR((" 2.4GHz Channel is not valid \n"));
4857 ret = -EINVAL;
4858 break;
4859 }
4860 *nan_attr_mask |= NAN_ATTR_2G_CHAN_CONFIG;
4861 WL_TRACE(("valid 2.4GHz chanspec, chanspec = 0x%04x \n",
4862 cmd_data->chanspec[1]));
4863 break;
4864 }
4865 case NAN_ATTRIBUTE_5G_CHANNEL: {
4866 if (nla_len(iter) != sizeof(uint32)) {
4867 ret = -EINVAL;
4868 goto exit;
4869 }
4870 /* take the default channel start_factor frequency */
4871 chan = wf_mhz2channel((uint)nla_get_u32(iter), 0);
4872 /* 20MHz as BW */
4873 cmd_data->chanspec[2] = wf_channel2chspec(chan, WL_CHANSPEC_BW_20);
4874 if (cmd_data->chanspec[2] == 0) {
4875 WL_ERR((" 5GHz Channel is not valid \n"));
4876 ret = -EINVAL;
4877 break;
4878 }
4879 *nan_attr_mask |= NAN_ATTR_5G_CHAN_CONFIG;
4880 WL_TRACE(("valid 5GHz chanspec, chanspec = 0x%04x \n",
4881 cmd_data->chanspec[2]));
4882 break;
4883 }
4884 case NAN_ATTRIBUTE_CONF_CLUSTER_VAL:
4885 if (nla_len(iter) != sizeof(uint8)) {
4886 ret = -EINVAL;
4887 goto exit;
4888 }
4889 cmd_data->config_cluster_val = nla_get_u8(iter);
4890 *nan_attr_mask |= NAN_ATTR_CLUSTER_VAL_CONFIG;
4891 break;
4892 case NAN_ATTRIBUTE_DWELL_TIME:
4893 if (nla_len(iter) != sizeof(uint8)) {
4894 ret = -EINVAL;
4895 goto exit;
4896 }
4897 cmd_data->dwell_time[0] = nla_get_u8(iter);
4898 if (cmd_data->dwell_time[0] == 0) {
4899 WL_ERR((" 2.4GHz dwell time is not valid \n"));
4900 cmd_data->status = BCME_BADARG;
4901 goto exit;
4902 }
4903 *nan_attr_mask |= NAN_ATTR_2G_DWELL_TIME_CONFIG;
4904 break;
4905 case NAN_ATTRIBUTE_SCAN_PERIOD:
4906 if (nla_len(iter) != sizeof(uint16)) {
4907 ret = -EINVAL;
4908 goto exit;
4909 }
4910 cmd_data->scan_period[0] = nla_get_u16(iter);
4911 if (cmd_data->scan_period[0] == 0) {
4912 WL_ERR((" 2.4GHz scan period is not valid \n"));
4913 cmd_data->status = BCME_BADARG;
4914 goto exit;
4915 }
4916 *nan_attr_mask |= NAN_ATTR_2G_SCAN_PERIOD_CONFIG;
4917 break;
4918 case NAN_ATTRIBUTE_DWELL_TIME_5G:
4919 if (nla_len(iter) != sizeof(uint8)) {
4920 ret = -EINVAL;
4921 goto exit;
4922 }
4923 cmd_data->dwell_time[1] = nla_get_u8(iter);
4924 if (cmd_data->dwell_time[1] == 0) {
4925 WL_ERR((" 5GHz dwell time is not valid \n"));
4926 cmd_data->status = BCME_BADARG;
4927 goto exit;
4928 }
4929 *nan_attr_mask |= NAN_ATTR_5G_DWELL_TIME_CONFIG;
4930 break;
4931 case NAN_ATTRIBUTE_SCAN_PERIOD_5G:
4932 if (nla_len(iter) != sizeof(uint16)) {
4933 ret = -EINVAL;
4934 goto exit;
4935 }
4936 cmd_data->scan_period[1] = nla_get_u16(iter);
4937 if (cmd_data->scan_period[1] == 0) {
4938 WL_ERR((" 5GHz scan period is not valid \n"));
4939 cmd_data->status = BCME_BADARG;
4940 goto exit;
4941 }
4942 *nan_attr_mask |= NAN_ATTR_5G_SCAN_PERIOD_CONFIG;
4943 break;
4944 case NAN_ATTRIBUTE_AVAIL_BIT_MAP:
4945 if (nla_len(iter) != sizeof(uint32)) {
4946 ret = -EINVAL;
4947 goto exit;
4948 }
4949 cmd_data->bmap = nla_get_u32(iter);
4950 break;
4951 case NAN_ATTRIBUTE_ENTRY_CONTROL:
4952 if (nla_len(iter) != sizeof(uint8)) {
4953 ret = -EINVAL;
4954 goto exit;
4955 }
4956 cmd_data->avail_params.duration = nla_get_u8(iter);
4957 break;
4958 case NAN_ATTRIBUTE_RSSI_CLOSE:
4959 if (nla_len(iter) != sizeof(uint8)) {
4960 ret = -EINVAL;
4961 goto exit;
4962 }
4963 cmd_data->rssi_attr.rssi_close_2dot4g_val = nla_get_s8(iter);
4964 if (cmd_data->rssi_attr.rssi_close_2dot4g_val == 0) {
4965 WL_ERR((" 2.4GHz rssi close is not valid \n"));
4966 cmd_data->status = BCME_BADARG;
4967 goto exit;
4968 }
4969 *nan_attr_mask |= NAN_ATTR_RSSI_CLOSE_CONFIG;
4970 break;
4971 case NAN_ATTRIBUTE_RSSI_MIDDLE:
4972 if (nla_len(iter) != sizeof(uint8)) {
4973 ret = -EINVAL;
4974 goto exit;
4975 }
4976 cmd_data->rssi_attr.rssi_middle_2dot4g_val = nla_get_s8(iter);
4977 if (cmd_data->rssi_attr.rssi_middle_2dot4g_val == 0) {
4978 WL_ERR((" 2.4GHz rssi middle is not valid \n"));
4979 cmd_data->status = BCME_BADARG;
4980 goto exit;
4981 }
4982 *nan_attr_mask |= NAN_ATTR_RSSI_MIDDLE_2G_CONFIG;
4983 break;
4984 case NAN_ATTRIBUTE_RSSI_PROXIMITY:
4985 if (nla_len(iter) != sizeof(uint8)) {
4986 ret = -EINVAL;
4987 goto exit;
4988 }
4989 cmd_data->rssi_attr.rssi_proximity_2dot4g_val = nla_get_s8(iter);
4990 if (cmd_data->rssi_attr.rssi_proximity_2dot4g_val == 0) {
4991 WL_ERR((" 2.4GHz rssi proximity is not valid \n"));
4992 cmd_data->status = BCME_BADARG;
4993 goto exit;
4994 }
4995 *nan_attr_mask |= NAN_ATTR_RSSI_PROXIMITY_2G_CONFIG;
4996 break;
4997 case NAN_ATTRIBUTE_RSSI_CLOSE_5G:
4998 if (nla_len(iter) != sizeof(uint8)) {
4999 ret = -EINVAL;
5000 goto exit;
5001 }
5002 cmd_data->rssi_attr.rssi_close_5g_val = nla_get_s8(iter);
5003 if (cmd_data->rssi_attr.rssi_close_5g_val == 0) {
5004 WL_ERR((" 5GHz rssi close is not valid \n"));
5005 cmd_data->status = BCME_BADARG;
5006 goto exit;
5007 }
5008 *nan_attr_mask |= NAN_ATTR_RSSI_CLOSE_5G_CONFIG;
5009 break;
5010 case NAN_ATTRIBUTE_RSSI_MIDDLE_5G:
5011 if (nla_len(iter) != sizeof(uint8)) {
5012 ret = -EINVAL;
5013 goto exit;
5014 }
5015 cmd_data->rssi_attr.rssi_middle_5g_val = nla_get_s8(iter);
5016 if (cmd_data->rssi_attr.rssi_middle_5g_val == 0) {
5017 WL_ERR((" 5Hz rssi middle is not valid \n"));
5018 cmd_data->status = BCME_BADARG;
5019 goto exit;
5020 }
5021 *nan_attr_mask |= NAN_ATTR_RSSI_MIDDLE_5G_CONFIG;
5022 break;
5023 case NAN_ATTRIBUTE_RSSI_PROXIMITY_5G:
5024 if (nla_len(iter) != sizeof(uint8)) {
5025 ret = -EINVAL;
5026 goto exit;
5027 }
5028 cmd_data->rssi_attr.rssi_proximity_5g_val = nla_get_s8(iter);
5029 if (cmd_data->rssi_attr.rssi_proximity_5g_val == 0) {
5030 WL_ERR((" 5GHz rssi proximity is not valid \n"));
5031 cmd_data->status = BCME_BADARG;
5032 goto exit;
5033 }
5034 *nan_attr_mask |= NAN_ATTR_RSSI_PROXIMITY_5G_CONFIG;
5035 break;
5036 case NAN_ATTRIBUTE_RSSI_WINDOW_SIZE:
5037 if (nla_len(iter) != sizeof(uint8)) {
5038 ret = -EINVAL;
5039 goto exit;
5040 }
5041 cmd_data->rssi_attr.rssi_window_size = nla_get_u8(iter);
5042 if (cmd_data->rssi_attr.rssi_window_size == 0) {
5043 WL_ERR((" rssi window size is not valid \n"));
5044 cmd_data->status = BCME_BADARG;
5045 goto exit;
5046 }
5047 *nan_attr_mask |= NAN_ATTR_RSSI_WINDOW_SIZE_CONFIG;
5048 break;
5049 case NAN_ATTRIBUTE_CIPHER_SUITE_TYPE:
5050 if (nla_len(iter) != sizeof(uint8)) {
5051 ret = -EINVAL;
5052 goto exit;
5053 }
5054 cmd_data->csid = nla_get_u8(iter);
5055 WL_TRACE(("CSID = %u\n", cmd_data->csid));
5056 break;
5057 case NAN_ATTRIBUTE_SCID_LEN:
5058 if (nla_len(iter) != sizeof(uint32)) {
5059 ret = -EINVAL;
5060 goto exit;
5061 }
5062 if (cmd_data->scid.dlen) {
5063 WL_ERR(("trying to overwrite:%d\n", attr_type));
5064 ret = -EINVAL;
5065 goto exit;
5066 }
5067 cmd_data->scid.dlen = nla_get_u32(iter);
5068 if (cmd_data->scid.dlen > MAX_SCID_LEN) {
5069 ret = -EINVAL;
5070 WL_ERR_RLMT(("Not allowed beyond %d\n", MAX_SCID_LEN));
5071 goto exit;
5072 }
5073 WL_TRACE(("valid scid length = %u\n", cmd_data->scid.dlen));
5074 break;
5075 case NAN_ATTRIBUTE_SCID:
5076 if (!cmd_data->scid.dlen || (nla_len(iter) != cmd_data->scid.dlen)) {
5077 WL_ERR(("wrong scid len:%d,%d\n", cmd_data->scid.dlen,
5078 nla_len(iter)));
5079 ret = -EINVAL;
5080 goto exit;
5081 }
5082 if (cmd_data->scid.data) {
5083 WL_ERR(("trying to overwrite:%d\n", attr_type));
5084 ret = -EINVAL;
5085 goto exit;
5086 }
5087
5088 cmd_data->scid.data = MALLOCZ(cfg->osh, cmd_data->scid.dlen);
5089 if (cmd_data->scid.data == NULL) {
5090 WL_ERR(("failed to allocate scid, len=%d\n",
5091 cmd_data->scid.dlen));
5092 ret = -ENOMEM;
5093 goto exit;
5094 }
5095 ret = memcpy_s(cmd_data->scid.data, cmd_data->scid.dlen,
5096 nla_data(iter), nla_len(iter));
5097 if (ret != BCME_OK) {
5098 WL_ERR(("Failed to scid data\n"));
5099 return ret;
5100 }
5101 break;
5102 case NAN_ATTRIBUTE_2G_AWAKE_DW:
5103 if (nla_len(iter) != sizeof(uint32)) {
5104 ret = -EINVAL;
5105 goto exit;
5106 }
5107 if (nla_get_u32(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
5108 WL_ERR(("%s: Invalid/Out of bound value = %u\n",
5109 __FUNCTION__, nla_get_u32(iter)));
5110 ret = -EINVAL;
5111 goto exit;
5112 }
5113 if (nla_get_u32(iter)) {
5114 cmd_data->awake_dws.dw_interval_2g =
5115 1 << (nla_get_u32(iter)-1);
5116 }
5117 *nan_attr_mask |= NAN_ATTR_2G_DW_CONFIG;
5118 break;
5119 case NAN_ATTRIBUTE_5G_AWAKE_DW:
5120 if (nla_len(iter) != sizeof(uint32)) {
5121 ret = -EINVAL;
5122 goto exit;
5123 }
5124 if (nla_get_u32(iter) > NAN_MAX_AWAKE_DW_INTERVAL) {
5125 WL_ERR(("%s: Invalid/Out of bound value = %u\n",
5126 __FUNCTION__, nla_get_u32(iter)));
5127 ret = BCME_BADARG;
5128 break;
5129 }
5130 if (nla_get_u32(iter)) {
5131 cmd_data->awake_dws.dw_interval_5g =
5132 1 << (nla_get_u32(iter)-1);
5133 }
5134 *nan_attr_mask |= NAN_ATTR_5G_DW_CONFIG;
5135 break;
5136 case NAN_ATTRIBUTE_DISC_IND_CFG:
5137 if (nla_len(iter) != sizeof(uint8)) {
5138 ret = -EINVAL;
5139 goto exit;
5140 }
5141 cmd_data->disc_ind_cfg = nla_get_u8(iter);
5142 break;
5143 case NAN_ATTRIBUTE_MAC_ADDR:
5144 if (nla_len(iter) != ETHER_ADDR_LEN) {
5145 ret = -EINVAL;
5146 goto exit;
5147 }
5148 ret = memcpy_s((char*)&cmd_data->mac_addr, ETHER_ADDR_LEN,
5149 (char*)nla_data(iter), nla_len(iter));
5150 if (ret != BCME_OK) {
5151 WL_ERR(("Failed to copy mac addr\n"));
5152 return ret;
5153 }
5154 break;
5155 case NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL:
5156 if (nla_len(iter) != sizeof(uint32)) {
5157 ret = -EINVAL;
5158 goto exit;
5159 }
5160 /* run time nmi rand not supported as of now.
5161 * Only during nan enable/iface-create rand mac is used
5162 */
5163 cmd_data->nmi_rand_intvl = nla_get_u32(iter);
5164 if (cmd_data->nmi_rand_intvl > 0) {
5165 cfg->nancfg->mac_rand = true;
5166 } else {
5167 cfg->nancfg->mac_rand = false;
5168 }
5169 break;
5170 case NAN_ATTRIBUTE_CMD_USE_NDPE:
5171 if (nla_len(iter) != sizeof(uint32)) {
5172 ret = -EINVAL;
5173 goto exit;
5174 }
5175 cmd_data->use_ndpe_attr = nla_get_u32(iter);
5176 break;
5177 case NAN_ATTRIBUTE_ENABLE_MERGE:
5178 if (nla_len(iter) != sizeof(uint8)) {
5179 ret = -EINVAL;
5180 goto exit;
5181 }
5182 cmd_data->enable_merge = nla_get_u8(iter);
5183 break;
5184 case NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL:
5185 if (nla_len(iter) != sizeof(uint32)) {
5186 ret = -EINVAL;
5187 goto exit;
5188 }
5189 cmd_data->disc_bcn_interval = nla_get_u32(iter);
5190 *nan_attr_mask |= NAN_ATTR_DISC_BEACON_INTERVAL;
5191 break;
5192 case NAN_ATTRIBUTE_NSS:
5193 if (nla_len(iter) != sizeof(uint32)) {
5194 ret = -EINVAL;
5195 goto exit;
5196 }
5197 /* FW handles it internally,
5198 * nothing to do as per the value rxed from framework, ignore.
5199 */
5200 break;
5201 case NAN_ATTRIBUTE_ENABLE_RANGING:
5202 if (nla_len(iter) != sizeof(uint32)) {
5203 ret = -EINVAL;
5204 goto exit;
5205 }
5206 cfg->nancfg->ranging_enable = nla_get_u32(iter);
5207 if (cfg->nancfg->ranging_enable == 0) {
5208 WL_ERR((" ranging enable is not set \n"));
5209 cmd_data->status = BCME_BADARG;
5210 goto exit;
5211 }
5212 break;
5213 case NAN_ATTRIBUTE_DW_EARLY_TERM:
5214 if (nla_len(iter) != sizeof(uint32)) {
5215 ret = -EINVAL;
5216 goto exit;
5217 }
5218 cmd_data->dw_early_termination = nla_get_u32(iter);
5219 break;
5220 default:
5221 WL_ERR(("%s: Unknown type, %d\n", __FUNCTION__, attr_type));
5222 ret = -EINVAL;
5223 goto exit;
5224 }
5225 }
5226
5227 exit:
5228 /* We need to call set_config_handler b/f calling start enable TBD */
5229 NAN_DBG_EXIT();
5230 if (ret) {
5231 WL_ERR(("%s: Failed to parse attribute %d ret %d",
5232 __FUNCTION__, attr_type, ret));
5233 }
5234 return ret;
5235
5236 }
5237
5238 static int
wl_cfgvendor_nan_dp_estb_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)5239 wl_cfgvendor_nan_dp_estb_event_data_filler(struct sk_buff *msg,
5240 nan_event_data_t *event_data) {
5241 int ret = BCME_OK;
5242 ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
5243 if (unlikely(ret)) {
5244 WL_ERR(("Failed to put NDP ID, ret=%d\n", ret));
5245 goto fail;
5246 }
5247 /*
5248 * NDI mac address of the peer
5249 * (required to derive target ipv6 address)
5250 */
5251 ret = nla_put(msg, NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR, ETH_ALEN,
5252 event_data->responder_ndi.octet);
5253 if (unlikely(ret)) {
5254 WL_ERR(("Failed to put resp ndi, ret=%d\n", ret));
5255 goto fail;
5256 }
5257 ret = nla_put_u8(msg, NAN_ATTRIBUTE_RSP_CODE, event_data->status);
5258 if (unlikely(ret)) {
5259 WL_ERR(("Failed to put response code, ret=%d\n", ret));
5260 goto fail;
5261 }
5262 if (event_data->svc_info.dlen && event_data->svc_info.data) {
5263 ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
5264 event_data->svc_info.dlen);
5265 if (unlikely(ret)) {
5266 WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
5267 goto fail;
5268 }
5269 ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
5270 event_data->svc_info.dlen, event_data->svc_info.data);
5271 if (unlikely(ret)) {
5272 WL_ERR(("Failed to put svc info, ret=%d\n", ret));
5273 goto fail;
5274 }
5275 }
5276
5277 fail:
5278 return ret;
5279 }
5280 static int
wl_cfgvendor_nan_dp_ind_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)5281 wl_cfgvendor_nan_dp_ind_event_data_filler(struct sk_buff *msg,
5282 nan_event_data_t *event_data) {
5283 int ret = BCME_OK;
5284
5285 ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID,
5286 event_data->pub_id);
5287 if (unlikely(ret)) {
5288 WL_ERR(("Failed to put pub ID, ret=%d\n", ret));
5289 goto fail;
5290 }
5291 ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
5292 if (unlikely(ret)) {
5293 WL_ERR(("Failed to put NDP ID, ret=%d\n", ret));
5294 goto fail;
5295 }
5296 /* Discovery MAC addr of the peer/initiator */
5297 ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETH_ALEN,
5298 event_data->remote_nmi.octet);
5299 if (unlikely(ret)) {
5300 WL_ERR(("Failed to put remote NMI, ret=%d\n", ret));
5301 goto fail;
5302 }
5303 ret = nla_put_u8(msg, NAN_ATTRIBUTE_SECURITY, event_data->security);
5304 if (unlikely(ret)) {
5305 WL_ERR(("Failed to put security, ret=%d\n", ret));
5306 goto fail;
5307 }
5308 if (event_data->svc_info.dlen && event_data->svc_info.data) {
5309 ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
5310 event_data->svc_info.dlen);
5311 if (unlikely(ret)) {
5312 WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
5313 goto fail;
5314 }
5315 ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
5316 event_data->svc_info.dlen, event_data->svc_info.data);
5317 if (unlikely(ret)) {
5318 WL_ERR(("Failed to put svc info, ret=%d\n", ret));
5319 goto fail;
5320 }
5321 }
5322
5323 fail:
5324 return ret;
5325 }
5326
5327 static int
wl_cfgvendor_nan_tx_followup_ind_event_data_filler(struct sk_buff * msg,nan_event_data_t * event_data)5328 wl_cfgvendor_nan_tx_followup_ind_event_data_filler(struct sk_buff *msg,
5329 nan_event_data_t *event_data) {
5330 int ret = BCME_OK;
5331 ret = nla_put_u16(msg, NAN_ATTRIBUTE_TRANSAC_ID, event_data->token);
5332 if (unlikely(ret)) {
5333 WL_ERR(("Failed to put transaction id, ret=%d\n", ret));
5334 goto fail;
5335 }
5336 ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->local_inst_id);
5337 if (unlikely(ret)) {
5338 WL_ERR(("Failed to put handle, ret=%d\n", ret));
5339 goto fail;
5340 }
5341 ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
5342 if (unlikely(ret)) {
5343 WL_ERR(("Failed to put nan status, ret=%d\n", ret));
5344 goto fail;
5345 }
5346 if (event_data->status == NAN_STATUS_SUCCESS) {
5347 ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5348 strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
5349 if (unlikely(ret)) {
5350 WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
5351 goto fail;
5352 }
5353 } else {
5354 ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5355 strlen("NAN_STATUS_NO_OTA_ACK"), event_data->nan_reason);
5356 if (unlikely(ret)) {
5357 WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
5358 goto fail;
5359 }
5360 }
5361 fail:
5362 return ret;
5363 }
5364
5365 static int
wl_cfgvendor_nan_svc_terminate_event_filler(struct sk_buff * msg,struct bcm_cfg80211 * cfg,int event_id,nan_event_data_t * event_data)5366 wl_cfgvendor_nan_svc_terminate_event_filler(struct sk_buff *msg,
5367 struct bcm_cfg80211 *cfg, int event_id, nan_event_data_t *event_data) {
5368 int ret = BCME_OK;
5369 ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->local_inst_id);
5370 if (unlikely(ret)) {
5371 WL_ERR(("Failed to put handle, ret=%d\n", ret));
5372 goto fail;
5373 }
5374
5375 if (event_id == GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED) {
5376 ret = nla_put_u16(msg, NAN_ATTRIBUTE_SUBSCRIBE_ID,
5377 event_data->local_inst_id);
5378 if (unlikely(ret)) {
5379 WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
5380 goto fail;
5381 }
5382 } else {
5383 ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID,
5384 event_data->local_inst_id);
5385 if (unlikely(ret)) {
5386 WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
5387 goto fail;
5388 }
5389 }
5390 ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
5391 if (unlikely(ret)) {
5392 WL_ERR(("Failed to put status, ret=%d\n", ret));
5393 goto fail;
5394 }
5395 if (event_data->status == NAN_STATUS_SUCCESS) {
5396 ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5397 strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
5398 if (unlikely(ret)) {
5399 WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
5400 goto fail;
5401 }
5402 } else {
5403 ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5404 strlen("NAN_STATUS_INTERNAL_FAILURE"), event_data->nan_reason);
5405 if (unlikely(ret)) {
5406 WL_ERR(("Failed to put nan reason, ret=%d\n", ret));
5407 goto fail;
5408 }
5409 }
5410
5411 ret = wl_cfgnan_remove_inst_id(cfg, event_data->local_inst_id);
5412 if (ret) {
5413 WL_ERR(("failed to free svc instance-id[%d], ret=%d, event_id = %d\n",
5414 event_data->local_inst_id, ret, event_id));
5415 goto fail;
5416 }
5417 fail:
5418 return ret;
5419 }
5420
5421 static int
wl_cfgvendor_nan_opt_params_filler(struct sk_buff * msg,nan_event_data_t * event_data)5422 wl_cfgvendor_nan_opt_params_filler(struct sk_buff *msg,
5423 nan_event_data_t *event_data) {
5424 int ret = BCME_OK;
5425 /* service specific info data */
5426 if (event_data->svc_info.dlen && event_data->svc_info.data) {
5427 ret = nla_put_u16(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN,
5428 event_data->svc_info.dlen);
5429 if (unlikely(ret)) {
5430 WL_ERR(("Failed to put svc info len, ret=%d\n", ret));
5431 goto fail;
5432 }
5433 ret = nla_put(msg, NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO,
5434 event_data->svc_info.dlen, event_data->svc_info.data);
5435 if (unlikely(ret)) {
5436 WL_ERR(("Failed to put svc info, ret=%d\n", ret));
5437 goto fail;
5438 }
5439 WL_TRACE(("svc info len = %d\n", event_data->svc_info.dlen));
5440 }
5441
5442 /* sdea service specific info data */
5443 if (event_data->sde_svc_info.dlen && event_data->sde_svc_info.data) {
5444 ret = nla_put_u16(msg, NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN,
5445 event_data->sde_svc_info.dlen);
5446 if (unlikely(ret)) {
5447 WL_ERR(("Failed to put sdea svc info len, ret=%d\n", ret));
5448 goto fail;
5449 }
5450 ret = nla_put(msg, NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO,
5451 event_data->sde_svc_info.dlen,
5452 event_data->sde_svc_info.data);
5453 if (unlikely(ret)) {
5454 WL_ERR(("Failed to put sdea svc info, ret=%d\n", ret));
5455 goto fail;
5456 }
5457 WL_TRACE(("sdea svc info len = %d\n", event_data->sde_svc_info.dlen));
5458 }
5459 /* service control discovery range limit */
5460 /* TODO: */
5461
5462 /* service control binding bitmap */
5463 /* TODO: */
5464 fail:
5465 return ret;
5466 }
5467
5468 static int
wl_cfgvendor_nan_tx_followup_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)5469 wl_cfgvendor_nan_tx_followup_event_filler(struct sk_buff *msg,
5470 nan_event_data_t *event_data) {
5471 int ret = BCME_OK;
5472 /* In followup pkt, instance id and requestor instance id are configured
5473 * from the transmitter perspective. As the event is processed with the
5474 * role of receiver, the local handle should use requestor instance
5475 * id (peer_inst_id)
5476 */
5477 WL_TRACE(("handle=%d\n", event_data->requestor_id));
5478 WL_TRACE(("inst id (local id)=%d\n", event_data->local_inst_id));
5479 WL_TRACE(("peer id (remote id)=%d\n", event_data->requestor_id));
5480 WL_TRACE(("peer mac addr=" MACDBG "\n",
5481 MAC2STRDBG(event_data->remote_nmi.octet)));
5482 WL_TRACE(("peer rssi: %d\n", event_data->fup_rssi));
5483 WL_TRACE(("attribute no: %d\n", event_data->attr_num));
5484 WL_TRACE(("attribute len: %d\n", event_data->attr_list_len));
5485
5486 ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->requestor_id);
5487 if (unlikely(ret)) {
5488 WL_ERR(("Failed to put handle, ret=%d\n", ret));
5489 goto fail;
5490 }
5491 ret = nla_put_u32(msg, NAN_ATTRIBUTE_INST_ID, event_data->local_inst_id);
5492 if (unlikely(ret)) {
5493 WL_ERR(("Failed to put local inst id, ret=%d\n", ret));
5494 goto fail;
5495 }
5496 ret = nla_put_u16(msg, NAN_ATTRIBUTE_PEER_ID, event_data->requestor_id);
5497 if (unlikely(ret)) {
5498 WL_ERR(("Failed to put requestor inst id, ret=%d\n", ret));
5499 goto fail;
5500 }
5501 ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETHER_ADDR_LEN,
5502 event_data->remote_nmi.octet);
5503 if (unlikely(ret)) {
5504 WL_ERR(("Failed to put remote nmi, ret=%d\n", ret));
5505 goto fail;
5506 }
5507 ret = nla_put_s8(msg, NAN_ATTRIBUTE_RSSI_PROXIMITY,
5508 event_data->fup_rssi);
5509 if (unlikely(ret)) {
5510 WL_ERR(("Failed to put fup rssi, ret=%d\n", ret));
5511 goto fail;
5512 }
5513 fail:
5514 return ret;
5515 }
5516
5517 static int
wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)5518 wl_cfgvendor_nan_sub_match_event_filler(struct sk_buff *msg,
5519 nan_event_data_t *event_data) {
5520 int ret = BCME_OK;
5521 WL_TRACE(("handle (sub_id)=%d\n", event_data->sub_id));
5522 WL_TRACE(("pub id=%d\n", event_data->pub_id));
5523 WL_TRACE(("sub id=%d\n", event_data->sub_id));
5524 WL_TRACE(("pub mac addr=" MACDBG "\n",
5525 MAC2STRDBG(event_data->remote_nmi.octet)));
5526 WL_TRACE(("attr no: %d\n", event_data->attr_num));
5527 WL_TRACE(("attr len: %d\n", event_data->attr_list_len));
5528
5529 ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, event_data->sub_id);
5530 if (unlikely(ret)) {
5531 WL_ERR(("Failed to put handle, ret=%d\n", ret));
5532 goto fail;
5533 }
5534 ret = nla_put_u16(msg, NAN_ATTRIBUTE_PUBLISH_ID, event_data->pub_id);
5535 if (unlikely(ret)) {
5536 WL_ERR(("Failed to put pub id, ret=%d\n", ret));
5537 goto fail;
5538 }
5539 ret = nla_put_u16(msg, NAN_ATTRIBUTE_SUBSCRIBE_ID, event_data->sub_id);
5540 if (unlikely(ret)) {
5541 WL_ERR(("Failed to put Sub Id, ret=%d\n", ret));
5542 goto fail;
5543 }
5544 ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETHER_ADDR_LEN,
5545 event_data->remote_nmi.octet);
5546 if (unlikely(ret)) {
5547 WL_ERR(("Failed to put remote NMI, ret=%d\n", ret));
5548 goto fail;
5549 }
5550 if (event_data->publish_rssi) {
5551 event_data->publish_rssi = -event_data->publish_rssi;
5552 ret = nla_put_u8(msg, NAN_ATTRIBUTE_RSSI_PROXIMITY,
5553 event_data->publish_rssi);
5554 if (unlikely(ret)) {
5555 WL_ERR(("Failed to put publish rssi, ret=%d\n", ret));
5556 goto fail;
5557 }
5558 }
5559 if (event_data->ranging_result_present) {
5560 ret = nla_put_u32(msg, NAN_ATTRIBUTE_RANGING_INDICATION,
5561 event_data->ranging_ind);
5562 if (unlikely(ret)) {
5563 WL_ERR(("Failed to put ranging ind, ret=%d\n", ret));
5564 goto fail;
5565 }
5566 ret = nla_put_u32(msg, NAN_ATTRIBUTE_RANGING_RESULT,
5567 event_data->range_measurement_cm);
5568 if (unlikely(ret)) {
5569 WL_ERR(("Failed to put range measurement cm, ret=%d\n",
5570 ret));
5571 goto fail;
5572 }
5573 }
5574 /*
5575 * handling optional service control, service response filter
5576 */
5577 if (event_data->tx_match_filter.dlen && event_data->tx_match_filter.data) {
5578 ret = nla_put_u16(msg, NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN,
5579 event_data->tx_match_filter.dlen);
5580 if (unlikely(ret)) {
5581 WL_ERR(("Failed to put tx match filter len, ret=%d\n",
5582 ret));
5583 goto fail;
5584 }
5585 ret = nla_put(msg, NAN_ATTRIBUTE_TX_MATCH_FILTER,
5586 event_data->tx_match_filter.dlen,
5587 event_data->tx_match_filter.data);
5588 if (unlikely(ret)) {
5589 WL_ERR(("Failed to put tx match filter data, ret=%d\n",
5590 ret));
5591 goto fail;
5592 }
5593 WL_TRACE(("tx matching filter (%d):\n",
5594 event_data->tx_match_filter.dlen));
5595 }
5596
5597 fail:
5598 return ret;
5599 }
5600
5601 static int
wl_cfgvendor_nan_de_event_filler(struct sk_buff * msg,nan_event_data_t * event_data)5602 wl_cfgvendor_nan_de_event_filler(struct sk_buff *msg, nan_event_data_t *event_data)
5603 {
5604 int ret = BCME_OK;
5605 ret = nla_put_u8(msg, NAN_ATTRIBUTE_ENABLE_STATUS, event_data->enabled);
5606 if (unlikely(ret)) {
5607 WL_ERR(("Failed to put event_data->enabled, ret=%d\n", ret));
5608 goto fail;
5609 }
5610 ret = nla_put_u8(msg, NAN_ATTRIBUTE_DE_EVENT_TYPE,
5611 event_data->nan_de_evt_type);
5612 if (unlikely(ret)) {
5613 WL_ERR(("Failed to put nan_de_evt_type, ret=%d\n", ret));
5614 goto fail;
5615 }
5616 ret = nla_put(msg, NAN_ATTRIBUTE_CLUSTER_ID, ETH_ALEN,
5617 event_data->clus_id.octet);
5618 if (unlikely(ret)) {
5619 WL_ERR(("Failed to put clust id, ret=%d\n", ret));
5620 goto fail;
5621 }
5622 /* OOB tests requires local nmi */
5623 ret = nla_put(msg, NAN_ATTRIBUTE_MAC_ADDR, ETH_ALEN,
5624 event_data->local_nmi.octet);
5625 if (unlikely(ret)) {
5626 WL_ERR(("Failed to put NMI, ret=%d\n", ret));
5627 goto fail;
5628 }
5629 fail:
5630 return ret;
5631 }
5632
5633 #ifdef RTT_SUPPORT
5634 s32
wl_cfgvendor_send_as_rtt_legacy_event(struct wiphy * wiphy,struct net_device * dev,wl_nan_ev_rng_rpt_ind_t * range_res,uint32 status)5635 wl_cfgvendor_send_as_rtt_legacy_event(struct wiphy *wiphy, struct net_device *dev,
5636 wl_nan_ev_rng_rpt_ind_t *range_res, uint32 status)
5637 {
5638 s32 ret = BCME_OK;
5639 gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5640 rtt_report_t *report = NULL;
5641 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5642 struct sk_buff *msg = NULL;
5643 struct nlattr *rtt_nl_hdr;
5644
5645 NAN_DBG_ENTER();
5646
5647 report = MALLOCZ(cfg->osh, sizeof(*report));
5648 if (!report) {
5649 WL_ERR(("%s: memory allocation failed\n", __func__));
5650 ret = BCME_NOMEM;
5651 goto exit;
5652 }
5653 if (range_res) {
5654 report->distance = range_res->dist_mm/10;
5655 ret = memcpy_s(&report->addr, ETHER_ADDR_LEN,
5656 &range_res->peer_m_addr, ETHER_ADDR_LEN);
5657 if (ret != BCME_OK) {
5658 WL_ERR(("Failed to copy peer_m_addr\n"));
5659 goto exit;
5660 }
5661 }
5662 report->status = (rtt_reason_t)status;
5663 report->type = RTT_TWO_WAY;
5664
5665 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
5666 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
5667 msg = cfg80211_vendor_event_alloc(wiphy, NULL, 100,
5668 GOOGLE_RTT_COMPLETE_EVENT, kflags);
5669 #else
5670 msg = cfg80211_vendor_event_alloc(wiphy, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags);
5671 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
5672 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
5673 if (!msg) {
5674 WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
5675 ret = BCME_NOMEM;
5676 goto exit;
5677 }
5678
5679 ret = nla_put_u32(msg, RTT_ATTRIBUTE_RESULTS_COMPLETE, 1);
5680 if (ret < 0) {
5681 WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS_COMPLETE\n"));
5682 goto exit;
5683 }
5684 rtt_nl_hdr = nla_nest_start(msg, RTT_ATTRIBUTE_RESULTS_PER_TARGET);
5685 if (!rtt_nl_hdr) {
5686 WL_ERR(("rtt_nl_hdr is NULL\n"));
5687 ret = BCME_NOMEM;
5688 goto exit;
5689 }
5690 ret = nla_put(msg, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &report->addr);
5691 if (ret < 0) {
5692 WL_ERR(("Failed to put RTT_ATTRIBUTE_TARGET_MAC\n"));
5693 goto exit;
5694 }
5695 ret = nla_put_u32(msg, RTT_ATTRIBUTE_RESULT_CNT, 1);
5696 if (ret < 0) {
5697 WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULT_CNT\n"));
5698 goto exit;
5699 }
5700 ret = nla_put(msg, RTT_ATTRIBUTE_RESULT,
5701 sizeof(*report), report);
5702 if (ret < 0) {
5703 WL_ERR(("Failed to put RTT_ATTRIBUTE_RESULTS\n"));
5704 goto exit;
5705 }
5706 nla_nest_end(msg, rtt_nl_hdr);
5707 cfg80211_vendor_event(msg, kflags);
5708 if (report) {
5709 MFREE(cfg->osh, report, sizeof(*report));
5710 }
5711
5712 return ret;
5713 exit:
5714 if (msg)
5715 dev_kfree_skb_any(msg);
5716 WL_ERR(("Failed to send event GOOGLE_RTT_COMPLETE_EVENT,"
5717 " -- Free skb, ret = %d\n", ret));
5718 if (report)
5719 MFREE(cfg->osh, report, sizeof(*report));
5720 NAN_DBG_EXIT();
5721 return ret;
5722 }
5723 #endif /* RTT_SUPPORT */
5724
5725 static int
wl_cfgvendor_send_nan_async_resp(struct wiphy * wiphy,struct wireless_dev * wdev,int event_id,u8 * nan_req_resp,u16 len)5726 wl_cfgvendor_send_nan_async_resp(struct wiphy *wiphy, struct wireless_dev *wdev,
5727 int event_id, u8* nan_req_resp, u16 len)
5728 {
5729 int ret = BCME_OK;
5730 int buf_len = NAN_EVENT_BUFFER_SIZE_LARGE;
5731 gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5732
5733 struct sk_buff *msg;
5734
5735 NAN_DBG_ENTER();
5736
5737 /* Allocate the skb for vendor event */
5738 msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, wdev, buf_len,
5739 event_id, kflags);
5740 if (!msg) {
5741 WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
5742 return -ENOMEM;
5743 }
5744
5745 ret = nla_put(msg, NAN_ATTRIBUTE_CMD_RESP_DATA,
5746 len, (u8*)nan_req_resp);
5747 if (unlikely(ret)) {
5748 WL_ERR(("Failed to put resp data, ret=%d\n",
5749 ret));
5750 goto fail;
5751 }
5752 WL_DBG(("Event sent up to hal, event_id = %d, ret = %d\n",
5753 event_id, ret));
5754 cfg80211_vendor_event(msg, kflags);
5755 NAN_DBG_EXIT();
5756 return ret;
5757
5758 fail:
5759 dev_kfree_skb_any(msg);
5760 WL_ERR(("Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n",
5761 event_id, ret));
5762 NAN_DBG_EXIT();
5763 return ret;
5764 }
5765
5766 int
wl_cfgvendor_nan_send_async_disable_resp(struct wireless_dev * wdev)5767 wl_cfgvendor_nan_send_async_disable_resp(struct wireless_dev *wdev)
5768 {
5769 int ret = BCME_OK;
5770 struct wiphy *wiphy = wdev->wiphy;
5771 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5772 nan_hal_resp_t nan_req_resp;
5773 bzero(&nan_req_resp, sizeof(nan_req_resp));
5774 nan_req_resp.status = NAN_STATUS_SUCCESS;
5775 nan_req_resp.value = BCME_OK;
5776 nan_req_resp.subcmd = NAN_WIFI_SUBCMD_DISABLE;
5777 WL_INFORM_MEM(("Send NAN_ASYNC_RESPONSE_DISABLED\n"));
5778 ret = wl_cfgvendor_send_nan_async_resp(wiphy, wdev,
5779 NAN_ASYNC_RESPONSE_DISABLED, (u8*)&nan_req_resp, sizeof(nan_req_resp));
5780 cfg->nancfg->notify_user = false;
5781 return ret;
5782 }
5783
5784 int
wl_cfgvendor_send_nan_event(struct wiphy * wiphy,struct net_device * dev,int event_id,nan_event_data_t * event_data)5785 wl_cfgvendor_send_nan_event(struct wiphy *wiphy, struct net_device *dev,
5786 int event_id, nan_event_data_t *event_data)
5787 {
5788 int ret = BCME_OK;
5789 int buf_len = NAN_EVENT_BUFFER_SIZE_LARGE;
5790 gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
5791
5792 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5793 struct sk_buff *msg;
5794
5795 NAN_DBG_ENTER();
5796
5797 /* Allocate the skb for vendor event */
5798 msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(dev), buf_len,
5799 event_id, kflags);
5800 if (!msg) {
5801 WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
5802 return -ENOMEM;
5803 }
5804
5805 switch (event_id) {
5806 case GOOGLE_NAN_EVENT_DE_EVENT: {
5807 WL_INFORM_MEM(("[NAN] GOOGLE_NAN_DE_EVENT cluster id=" MACDBG "nmi= " MACDBG "\n",
5808 MAC2STRDBG(event_data->clus_id.octet),
5809 MAC2STRDBG(event_data->local_nmi.octet)));
5810 ret = wl_cfgvendor_nan_de_event_filler(msg, event_data);
5811 if (unlikely(ret)) {
5812 WL_ERR(("Failed to fill de event data, ret=%d\n", ret));
5813 goto fail;
5814 }
5815 break;
5816 }
5817 case GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH:
5818 case GOOGLE_NAN_EVENT_FOLLOWUP: {
5819 if (event_id == GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH) {
5820 WL_DBG(("GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH\n"));
5821 ret = wl_cfgvendor_nan_sub_match_event_filler(msg, event_data);
5822 if (unlikely(ret)) {
5823 WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5824 goto fail;
5825 }
5826 } else if (event_id == GOOGLE_NAN_EVENT_FOLLOWUP) {
5827 WL_DBG(("GOOGLE_NAN_EVENT_FOLLOWUP\n"));
5828 ret = wl_cfgvendor_nan_tx_followup_event_filler(msg, event_data);
5829 if (unlikely(ret)) {
5830 WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5831 goto fail;
5832 }
5833 }
5834 ret = wl_cfgvendor_nan_opt_params_filler(msg, event_data);
5835 if (unlikely(ret)) {
5836 WL_ERR(("Failed to fill sub match event data, ret=%d\n", ret));
5837 goto fail;
5838 }
5839 break;
5840 }
5841
5842 case GOOGLE_NAN_EVENT_DISABLED: {
5843 WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DISABLED\n"));
5844 ret = nla_put_u8(msg, NAN_ATTRIBUTE_HANDLE, 0);
5845 if (unlikely(ret)) {
5846 WL_ERR(("Failed to put handle, ret=%d\n", ret));
5847 goto fail;
5848 }
5849 ret = nla_put_u16(msg, NAN_ATTRIBUTE_STATUS, event_data->status);
5850 if (unlikely(ret)) {
5851 WL_ERR(("Failed to put status, ret=%d\n", ret));
5852 goto fail;
5853 }
5854 ret = nla_put(msg, NAN_ATTRIBUTE_REASON,
5855 strlen("NAN_STATUS_SUCCESS"), event_data->nan_reason);
5856 if (unlikely(ret)) {
5857 WL_ERR(("Failed to put reason code, ret=%d\n", ret));
5858 goto fail;
5859 }
5860 break;
5861 }
5862
5863 case GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED:
5864 case GOOGLE_NAN_EVENT_PUBLISH_TERMINATED: {
5865 WL_DBG(("GOOGLE_NAN_SVC_TERMINATED, %d\n", event_id));
5866 ret = wl_cfgvendor_nan_svc_terminate_event_filler(msg, cfg, event_id, event_data);
5867 if (unlikely(ret)) {
5868 WL_ERR(("Failed to fill svc terminate event data, ret=%d\n", ret));
5869 goto fail;
5870 }
5871 break;
5872 }
5873
5874 case GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND: {
5875 WL_DBG(("GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND %d\n",
5876 GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND));
5877 ret = wl_cfgvendor_nan_tx_followup_ind_event_data_filler(msg, event_data);
5878 if (unlikely(ret)) {
5879 WL_ERR(("Failed to fill tx follow up ind event data, ret=%d\n", ret));
5880 goto fail;
5881 }
5882
5883 break;
5884 }
5885
5886 case GOOGLE_NAN_EVENT_DATA_REQUEST: {
5887 WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_REQUEST\n"));
5888 ret = wl_cfgvendor_nan_dp_ind_event_data_filler(msg, event_data);
5889 if (unlikely(ret)) {
5890 WL_ERR(("Failed to fill dp ind event data, ret=%d\n", ret));
5891 goto fail;
5892 }
5893 break;
5894 }
5895
5896 case GOOGLE_NAN_EVENT_DATA_CONFIRMATION: {
5897 WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_CONFIRMATION\n"));
5898
5899 ret = wl_cfgvendor_nan_dp_estb_event_data_filler(msg, event_data);
5900 if (unlikely(ret)) {
5901 WL_ERR(("Failed to fill dp estb event data, ret=%d\n", ret));
5902 goto fail;
5903 }
5904 break;
5905 }
5906
5907 case GOOGLE_NAN_EVENT_DATA_END: {
5908 WL_INFORM_MEM(("[NAN] GOOGLE_NAN_EVENT_DATA_END\n"));
5909 ret = nla_put_u8(msg, NAN_ATTRIBUTE_INST_COUNT, 1);
5910 if (unlikely(ret)) {
5911 WL_ERR(("Failed to put inst count, ret=%d\n", ret));
5912 goto fail;
5913 }
5914 ret = nla_put_u32(msg, NAN_ATTRIBUTE_NDP_ID, event_data->ndp_id);
5915 if (unlikely(ret)) {
5916 WL_ERR(("Failed to put ndp id, ret=%d\n", ret));
5917 goto fail;
5918 }
5919 break;
5920 }
5921
5922 default:
5923 goto fail;
5924 }
5925
5926 cfg80211_vendor_event(msg, kflags);
5927 NAN_DBG_EXIT();
5928 return ret;
5929
5930 fail:
5931 dev_kfree_skb_any(msg);
5932 WL_ERR(("Event not implemented or unknown -- Free skb, event_id = %d, ret = %d\n",
5933 event_id, ret));
5934 NAN_DBG_EXIT();
5935 return ret;
5936 }
5937
5938 static int
wl_cfgvendor_nan_req_subscribe(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)5939 wl_cfgvendor_nan_req_subscribe(struct wiphy *wiphy,
5940 struct wireless_dev *wdev, const void * data, int len)
5941 {
5942 int ret = 0;
5943 nan_discover_cmd_data_t *cmd_data = NULL;
5944 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
5945 nan_hal_resp_t nan_req_resp;
5946
5947 NAN_DBG_ENTER();
5948 /* Blocking Subscribe if NAN is not enable */
5949 if (!cfg->nancfg->nan_enable) {
5950 WL_ERR(("nan is not enabled, subscribe blocked\n"));
5951 ret = BCME_ERROR;
5952 goto exit;
5953 }
5954 cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
5955 if (!cmd_data) {
5956 WL_ERR(("%s: memory allocation failed\n", __func__));
5957 ret = BCME_NOMEM;
5958 goto exit;
5959 }
5960
5961 bzero(&nan_req_resp, sizeof(nan_req_resp));
5962 ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
5963 if (ret) {
5964 WL_ERR(("failed to parse nan disc vendor args, ret = %d\n", ret));
5965 goto exit;
5966 }
5967
5968 if (cmd_data->sub_id == 0) {
5969 ret = wl_cfgnan_generate_inst_id(cfg, &cmd_data->sub_id);
5970 if (ret) {
5971 WL_ERR(("failed to generate instance-id for subscribe\n"));
5972 goto exit;
5973 }
5974 } else {
5975 cmd_data->svc_update = true;
5976 }
5977
5978 ret = wl_cfgnan_subscribe_handler(wdev->netdev, cfg, cmd_data);
5979 if (unlikely(ret) || unlikely(cmd_data->status)) {
5980 WL_ERR(("failed to subscribe error[%d], status = [%d]\n",
5981 ret, cmd_data->status));
5982 wl_cfgnan_remove_inst_id(cfg, cmd_data->sub_id);
5983 goto exit;
5984 }
5985
5986 WL_DBG(("subscriber instance id=%d\n", cmd_data->sub_id));
5987
5988 if (cmd_data->status == WL_NAN_E_OK) {
5989 nan_req_resp.instance_id = cmd_data->sub_id;
5990 } else {
5991 nan_req_resp.instance_id = 0;
5992 }
5993 exit:
5994 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_REQUEST_SUBSCRIBE,
5995 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
5996 wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
5997 NAN_DBG_EXIT();
5998 return ret;
5999 }
6000
6001 static int
wl_cfgvendor_nan_req_publish(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6002 wl_cfgvendor_nan_req_publish(struct wiphy *wiphy,
6003 struct wireless_dev *wdev, const void * data, int len)
6004 {
6005 int ret = 0;
6006 nan_discover_cmd_data_t *cmd_data = NULL;
6007 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6008 nan_hal_resp_t nan_req_resp;
6009 NAN_DBG_ENTER();
6010
6011 /* Blocking Publish if NAN is not enable */
6012 if (!cfg->nancfg->nan_enable) {
6013 WL_ERR(("nan is not enabled publish blocked\n"));
6014 ret = BCME_ERROR;
6015 goto exit;
6016 }
6017 cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6018 if (!cmd_data) {
6019 WL_ERR(("%s: memory allocation failed\n", __func__));
6020 ret = BCME_NOMEM;
6021 goto exit;
6022 }
6023
6024 bzero(&nan_req_resp, sizeof(nan_req_resp));
6025 ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
6026 if (ret) {
6027 WL_ERR(("failed to parse nan disc vendor args, ret = %d\n", ret));
6028 goto exit;
6029 }
6030
6031 if (cmd_data->pub_id == 0) {
6032 ret = wl_cfgnan_generate_inst_id(cfg, &cmd_data->pub_id);
6033 if (ret) {
6034 WL_ERR(("failed to generate instance-id for publisher\n"));
6035 goto exit;
6036 }
6037 } else {
6038 cmd_data->svc_update = true;
6039 }
6040
6041 ret = wl_cfgnan_publish_handler(wdev->netdev, cfg, cmd_data);
6042 if (unlikely(ret) || unlikely(cmd_data->status)) {
6043 WL_ERR(("failed to publish error[%d], status[%d]\n",
6044 ret, cmd_data->status));
6045 wl_cfgnan_remove_inst_id(cfg, cmd_data->pub_id);
6046 goto exit;
6047 }
6048
6049 WL_DBG(("publisher instance id=%d\n", cmd_data->pub_id));
6050
6051 if (cmd_data->status == WL_NAN_E_OK) {
6052 nan_req_resp.instance_id = cmd_data->pub_id;
6053 } else {
6054 nan_req_resp.instance_id = 0;
6055 }
6056 exit:
6057 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_REQUEST_PUBLISH,
6058 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6059 wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
6060 NAN_DBG_EXIT();
6061 return ret;
6062 }
6063
6064 static int
wl_cfgvendor_nan_start_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6065 wl_cfgvendor_nan_start_handler(struct wiphy *wiphy,
6066 struct wireless_dev *wdev, const void *data, int len)
6067 {
6068 int ret = 0;
6069 nan_config_cmd_data_t *cmd_data;
6070 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6071 nan_hal_resp_t nan_req_resp;
6072 uint32 nan_attr_mask = 0;
6073
6074 cmd_data = (nan_config_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6075 if (!cmd_data) {
6076 WL_ERR(("%s: memory allocation failed\n", __func__));
6077 ret = BCME_NOMEM;
6078 goto exit;
6079 }
6080 NAN_DBG_ENTER();
6081
6082 ret = wl_cfgnan_check_nan_disable_pending(cfg, false, true);
6083 if (ret != BCME_OK) {
6084 WL_ERR(("failed to disable nan, error[%d]\n", ret));
6085 goto exit;
6086 }
6087
6088 if (cfg->nancfg->nan_enable) {
6089 WL_ERR(("nan is already enabled\n"));
6090 ret = BCME_OK;
6091 goto exit;
6092 }
6093 bzero(&nan_req_resp, sizeof(nan_req_resp));
6094
6095 cmd_data->sid_beacon.sid_enable = NAN_SID_ENABLE_FLAG_INVALID; /* Setting to some default */
6096 cmd_data->sid_beacon.sid_count = NAN_SID_BEACON_COUNT_INVALID; /* Setting to some default */
6097
6098 ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask);
6099 if (ret) {
6100 WL_ERR(("failed to parse nan vendor args, ret %d\n", ret));
6101 goto exit;
6102 }
6103 if (cmd_data->status == BCME_BADARG) {
6104 WL_ERR(("nan vendor args is invalid\n"));
6105 goto exit;
6106 }
6107
6108 ret = wl_cfgnan_start_handler(wdev->netdev, cfg, cmd_data, nan_attr_mask);
6109 if (ret) {
6110 WL_ERR(("failed to start nan error[%d]\n", ret));
6111 goto exit;
6112 }
6113 /* Initializing Instance Id List */
6114 bzero(cfg->nancfg->nan_inst_ctrl, NAN_ID_CTRL_SIZE * sizeof(nan_svc_inst_t));
6115 exit:
6116 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_ENABLE,
6117 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6118 if (cmd_data) {
6119 if (cmd_data->scid.data) {
6120 MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen);
6121 cmd_data->scid.dlen = 0;
6122 }
6123 MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
6124 }
6125 NAN_DBG_EXIT();
6126 return ret;
6127 }
6128
6129 static int
wl_cfgvendor_terminate_dp_rng_sessions(struct bcm_cfg80211 * cfg,struct wireless_dev * wdev,bool * ssn_exists)6130 wl_cfgvendor_terminate_dp_rng_sessions(struct bcm_cfg80211 *cfg,
6131 struct wireless_dev *wdev, bool *ssn_exists)
6132 {
6133 int ret = 0;
6134 uint8 i = 0;
6135 int status = BCME_ERROR;
6136 wl_nancfg_t *nancfg = cfg->nancfg;
6137 dhd_pub_t *dhdp;
6138 #ifdef RTT_SUPPORT
6139 nan_ranging_inst_t *ranging_inst = NULL;
6140 #endif /* RTT_SUPPORT */
6141
6142 *ssn_exists = false;
6143 dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6144 /* Cleanup active Data Paths If any */
6145 for (i = 0; i < NAN_MAX_NDP_PEER; i++) {
6146 if (nancfg->ndp_id[i]) {
6147 WL_DBG(("Found entry of ndp id = [%d], end dp associated to it\n",
6148 nancfg->ndp_id[i]));
6149 ret = wl_cfgnan_data_path_end_handler(wdev->netdev, cfg,
6150 nancfg->ndp_id[i], &status);
6151 if ((ret == BCME_OK) && cfg->nancfg->nan_enable &&
6152 dhdp->up) {
6153 *ssn_exists = true;
6154 }
6155 }
6156 }
6157
6158 #ifdef RTT_SUPPORT
6159 /* Cancel ranging sessiosns */
6160 for (i = 0; i < NAN_MAX_RANGING_INST; i++) {
6161 ranging_inst = &nancfg->nan_ranging_info[i];
6162 if (ranging_inst->in_use &&
6163 (NAN_RANGING_IS_IN_PROG(ranging_inst->range_status))) {
6164 ret = wl_cfgnan_cancel_ranging(bcmcfg_to_prmry_ndev(cfg), cfg,
6165 &ranging_inst->range_id,
6166 NAN_RNG_TERM_FLAG_NONE, &status);
6167 if (unlikely(ret) || unlikely(status)) {
6168 WL_ERR(("nan range cancel failed ret = %d status = %d\n",
6169 ret, status));
6170 } else {
6171 *ssn_exists = true;
6172 }
6173 }
6174 }
6175 #endif /* RTT_SUPPORT */
6176 return ret;
6177 }
6178
6179 static int
wl_cfgvendor_nan_stop_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6180 wl_cfgvendor_nan_stop_handler(struct wiphy *wiphy,
6181 struct wireless_dev *wdev, const void * data, int len)
6182 {
6183 int ret = BCME_OK;
6184 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6185 bool ssn_exists = false;
6186 uint32 delay_ms = 0;
6187 wl_nancfg_t *nancfg = cfg->nancfg;
6188
6189 NAN_DBG_ENTER();
6190 mutex_lock(&cfg->if_sync);
6191
6192 if (nancfg->nan_init_state == false) {
6193 WL_INFORM_MEM(("nan is not initialized/nmi doesnt exists\n"));
6194 goto exit;
6195 }
6196 if (nancfg->nan_enable == false) {
6197 WL_INFORM_MEM(("nan is in disabled state\n"));
6198 } else {
6199 nancfg->notify_user = true;
6200 wl_cfgvendor_terminate_dp_rng_sessions(cfg, wdev, &ssn_exists);
6201 if (ssn_exists == true) {
6202 /*
6203 * Schedule nan disable with NAN_DISABLE_CMD_DELAY
6204 * delay to make sure
6205 * fw cleans any active Data paths and
6206 * notifies the peer about the dp session terminations
6207 */
6208 WL_INFORM_MEM(("Schedule Nan Disable Req with NAN_DISABLE_CMD_DELAY\n"));
6209 delay_ms = NAN_DISABLE_CMD_DELAY;
6210 DHD_NAN_WAKE_LOCK_TIMEOUT(cfg->pub, NAN_WAKELOCK_TIMEOUT);
6211 } else {
6212 delay_ms = 0;
6213 }
6214 schedule_delayed_work(&nancfg->nan_disable,
6215 msecs_to_jiffies(delay_ms));
6216 }
6217 exit:
6218 mutex_unlock(&cfg->if_sync);
6219 NAN_DBG_EXIT();
6220 return ret;
6221 }
6222
6223 static int
wl_cfgvendor_nan_config_handler(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6224 wl_cfgvendor_nan_config_handler(struct wiphy *wiphy,
6225 struct wireless_dev *wdev, const void *data, int len)
6226 {
6227 int ret = 0;
6228 nan_config_cmd_data_t *cmd_data;
6229 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6230 nan_hal_resp_t nan_req_resp;
6231 uint32 nan_attr_mask = 0;
6232
6233 cmd_data = MALLOCZ(cfg->osh, sizeof(*cmd_data));
6234 if (!cmd_data) {
6235 WL_ERR(("%s: memory allocation failed\n", __func__));
6236 ret = BCME_NOMEM;
6237 goto exit;
6238 }
6239 NAN_DBG_ENTER();
6240
6241 bzero(&nan_req_resp, sizeof(nan_req_resp));
6242
6243 cmd_data->avail_params.duration = NAN_BAND_INVALID; /* Setting to some default */
6244 cmd_data->sid_beacon.sid_enable = NAN_SID_ENABLE_FLAG_INVALID; /* Setting to some default */
6245 cmd_data->sid_beacon.sid_count = NAN_SID_BEACON_COUNT_INVALID; /* Setting to some default */
6246
6247 ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask);
6248 if (ret) {
6249 WL_ERR(("failed to parse nan vendor args, ret = %d\n", ret));
6250 goto exit;
6251 }
6252 if (cmd_data->status == BCME_BADARG) {
6253 WL_ERR(("nan vendor args is invalid\n"));
6254 goto exit;
6255 }
6256
6257 ret = wl_cfgnan_config_handler(wdev->netdev, cfg, cmd_data, nan_attr_mask);
6258 if (ret) {
6259 WL_ERR(("failed in config request, nan error[%d]\n", ret));
6260 goto exit;
6261 }
6262 exit:
6263 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CONFIG,
6264 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6265 if (cmd_data) {
6266 if (cmd_data->scid.data) {
6267 MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen);
6268 cmd_data->scid.dlen = 0;
6269 }
6270 MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
6271 }
6272 NAN_DBG_EXIT();
6273 return ret;
6274 }
6275
6276 static int
wl_cfgvendor_nan_cancel_publish(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6277 wl_cfgvendor_nan_cancel_publish(struct wiphy *wiphy,
6278 struct wireless_dev *wdev, const void * data, int len)
6279 {
6280 int ret = 0;
6281 nan_discover_cmd_data_t *cmd_data = NULL;
6282 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6283 nan_hal_resp_t nan_req_resp;
6284
6285 /* Blocking Cancel_Publish if NAN is not enable */
6286 if (!cfg->nancfg->nan_enable) {
6287 WL_ERR(("nan is not enabled, cancel publish blocked\n"));
6288 ret = BCME_ERROR;
6289 goto exit;
6290 }
6291 cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6292 if (!cmd_data) {
6293 WL_ERR(("%s: memory allocation failed\n", __func__));
6294 ret = BCME_NOMEM;
6295 goto exit;
6296 }
6297 NAN_DBG_ENTER();
6298
6299 bzero(&nan_req_resp, sizeof(nan_req_resp));
6300
6301 ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
6302 if (ret) {
6303 WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
6304 goto exit;
6305 }
6306 nan_req_resp.instance_id = cmd_data->pub_id;
6307 WL_INFORM_MEM(("[NAN] cancel publish instance_id=%d\n", cmd_data->pub_id));
6308
6309 ret = wl_cfgnan_cancel_pub_handler(wdev->netdev, cfg, cmd_data);
6310 if (ret) {
6311 WL_ERR(("failed to cancel publish nan instance-id[%d] error[%d]\n",
6312 cmd_data->pub_id, ret));
6313 goto exit;
6314 }
6315 exit:
6316 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CANCEL_PUBLISH,
6317 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6318 wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
6319 NAN_DBG_EXIT();
6320 return ret;
6321 }
6322
6323 static int
wl_cfgvendor_nan_cancel_subscribe(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6324 wl_cfgvendor_nan_cancel_subscribe(struct wiphy *wiphy,
6325 struct wireless_dev *wdev, const void * data, int len)
6326 {
6327 int ret = 0;
6328 nan_discover_cmd_data_t *cmd_data = NULL;
6329 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6330 nan_hal_resp_t nan_req_resp;
6331
6332 /* Blocking Cancel_Subscribe if NAN is not enableb */
6333 if (!cfg->nancfg->nan_enable) {
6334 WL_ERR(("nan is not enabled, cancel subscribe blocked\n"));
6335 ret = BCME_ERROR;
6336 goto exit;
6337 }
6338 cmd_data = MALLOCZ(cfg->osh, sizeof(*cmd_data));
6339 if (!cmd_data) {
6340 WL_ERR(("%s: memory allocation failed\n", __func__));
6341 ret = BCME_NOMEM;
6342 goto exit;
6343 }
6344 NAN_DBG_ENTER();
6345
6346 bzero(&nan_req_resp, sizeof(nan_req_resp));
6347
6348 ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
6349 if (ret) {
6350 WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
6351 goto exit;
6352 }
6353 nan_req_resp.instance_id = cmd_data->sub_id;
6354 WL_INFORM_MEM(("[NAN] cancel subscribe instance_id=%d\n", cmd_data->sub_id));
6355
6356 ret = wl_cfgnan_cancel_sub_handler(wdev->netdev, cfg, cmd_data);
6357 if (ret) {
6358 WL_ERR(("failed to cancel subscribe nan instance-id[%d] error[%d]\n",
6359 cmd_data->sub_id, ret));
6360 goto exit;
6361 }
6362 exit:
6363 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_CANCEL_SUBSCRIBE,
6364 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6365 wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
6366 NAN_DBG_EXIT();
6367 return ret;
6368 }
6369
6370 static int
wl_cfgvendor_nan_transmit(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6371 wl_cfgvendor_nan_transmit(struct wiphy *wiphy,
6372 struct wireless_dev *wdev, const void * data, int len)
6373 {
6374 int ret = 0;
6375 nan_discover_cmd_data_t *cmd_data = NULL;
6376 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6377 nan_hal_resp_t nan_req_resp;
6378
6379 /* Blocking Transmit if NAN is not enable */
6380 if (!cfg->nancfg->nan_enable) {
6381 WL_ERR(("nan is not enabled, transmit blocked\n"));
6382 ret = BCME_ERROR;
6383 goto exit;
6384 }
6385 cmd_data = (nan_discover_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6386 if (!cmd_data) {
6387 WL_ERR(("%s: memory allocation failed\n", __func__));
6388 ret = BCME_NOMEM;
6389 goto exit;
6390 }
6391 NAN_DBG_ENTER();
6392
6393 bzero(&nan_req_resp, sizeof(nan_req_resp));
6394
6395 ret = wl_cfgvendor_nan_parse_discover_args(wiphy, data, len, cmd_data);
6396 if (ret) {
6397 WL_ERR(("failed to parse nan disc vendor args, ret= %d\n", ret));
6398 goto exit;
6399 }
6400 nan_req_resp.instance_id = cmd_data->local_id;
6401 ret = wl_cfgnan_transmit_handler(wdev->netdev, cfg, cmd_data);
6402 if (ret) {
6403 WL_ERR(("failed to transmit-followup nan error[%d]\n", ret));
6404 goto exit;
6405 }
6406 exit:
6407 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_TRANSMIT,
6408 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6409 wl_cfgvendor_free_disc_cmd_data(cfg, cmd_data);
6410 NAN_DBG_EXIT();
6411 return ret;
6412 }
6413
6414 static int
wl_cfgvendor_nan_get_capablities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6415 wl_cfgvendor_nan_get_capablities(struct wiphy *wiphy,
6416 struct wireless_dev *wdev, const void * data, int len)
6417 {
6418 int ret = 0;
6419 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6420 nan_hal_resp_t nan_req_resp;
6421
6422 NAN_DBG_ENTER();
6423
6424 bzero(&nan_req_resp, sizeof(nan_req_resp));
6425 ret = wl_cfgnan_get_capablities_handler(wdev->netdev, cfg, &nan_req_resp.capabilities);
6426 if (ret) {
6427 WL_ERR(("Could not get capabilities\n"));
6428 ret = -EINVAL;
6429 goto exit;
6430 }
6431 exit:
6432 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_GET_CAPABILITIES,
6433 &nan_req_resp, ret, BCME_OK);
6434 NAN_DBG_EXIT();
6435 return ret;
6436 }
6437
6438 static int
wl_cfgvendor_nan_data_path_iface_create(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6439 wl_cfgvendor_nan_data_path_iface_create(struct wiphy *wiphy,
6440 struct wireless_dev *wdev, const void * data, int len)
6441 {
6442 int ret = 0;
6443 nan_datapath_cmd_data_t *cmd_data = NULL;
6444 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6445 nan_hal_resp_t nan_req_resp;
6446 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6447
6448 if (!cfg->nancfg->nan_init_state) {
6449 WL_ERR(("%s: NAN is not inited or Device doesn't support NAN \n", __func__));
6450 ret = -ENODEV;
6451 goto exit;
6452 }
6453
6454 cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6455 if (!cmd_data) {
6456 WL_ERR(("%s: memory allocation failed\n", __func__));
6457 ret = BCME_NOMEM;
6458 goto exit;
6459 }
6460 NAN_DBG_ENTER();
6461
6462 bzero(&nan_req_resp, sizeof(nan_req_resp));
6463
6464 ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6465 if (ret) {
6466 WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6467 goto exit;
6468 }
6469
6470 if (cfg->nancfg->nan_enable) { /* new framework Impl, iface create called after nan enab */
6471 ret = wl_cfgnan_data_path_iface_create_delete_handler(wdev->netdev,
6472 cfg, cmd_data->ndp_iface,
6473 NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE, dhdp->up);
6474 if (ret != BCME_OK) {
6475 WL_ERR(("failed to create iface, ret = %d\n", ret));
6476 goto exit;
6477 }
6478 }
6479 exit:
6480 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE,
6481 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6482 wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6483 NAN_DBG_EXIT();
6484 return ret;
6485 }
6486
6487 static int
wl_cfgvendor_nan_data_path_iface_delete(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6488 wl_cfgvendor_nan_data_path_iface_delete(struct wiphy *wiphy,
6489 struct wireless_dev *wdev, const void * data, int len)
6490 {
6491 int ret = 0;
6492 nan_datapath_cmd_data_t *cmd_data = NULL;
6493 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6494 nan_hal_resp_t nan_req_resp;
6495 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6496
6497 if (cfg->nancfg->nan_init_state == false) {
6498 WL_ERR(("%s: NAN is not inited or Device doesn't support NAN \n", __func__));
6499 /* Deinit has taken care of cleaing the virtual iface */
6500 ret = BCME_OK;
6501 goto exit;
6502 }
6503
6504 NAN_DBG_ENTER();
6505 cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6506 if (!cmd_data) {
6507 WL_ERR(("%s: memory allocation failed\n", __func__));
6508 ret = BCME_NOMEM;
6509 goto exit;
6510 }
6511 bzero(&nan_req_resp, sizeof(nan_req_resp));
6512 ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6513 if (ret) {
6514 WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6515 goto exit;
6516 }
6517
6518 ret = wl_cfgnan_data_path_iface_create_delete_handler(wdev->netdev, cfg,
6519 (char*)cmd_data->ndp_iface,
6520 NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE, dhdp->up);
6521 if (ret) {
6522 WL_ERR(("failed to delete ndp iface [%d]\n", ret));
6523 goto exit;
6524 }
6525 exit:
6526 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE,
6527 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6528 wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6529 NAN_DBG_EXIT();
6530 return ret;
6531 }
6532
6533 static int
wl_cfgvendor_nan_data_path_request(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6534 wl_cfgvendor_nan_data_path_request(struct wiphy *wiphy,
6535 struct wireless_dev *wdev, const void * data, int len)
6536 {
6537 int ret = 0;
6538 nan_datapath_cmd_data_t *cmd_data = NULL;
6539 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6540 nan_hal_resp_t nan_req_resp;
6541 uint8 ndp_instance_id = 0;
6542
6543 if (!cfg->nancfg->nan_enable) {
6544 WL_ERR(("nan is not enabled, nan data path request blocked\n"));
6545 ret = BCME_ERROR;
6546 goto exit;
6547 }
6548
6549 NAN_DBG_ENTER();
6550 cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6551 if (!cmd_data) {
6552 WL_ERR(("%s: memory allocation failed\n", __func__));
6553 ret = BCME_NOMEM;
6554 goto exit;
6555 }
6556
6557 bzero(&nan_req_resp, sizeof(nan_req_resp));
6558 ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6559 if (ret) {
6560 WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6561 goto exit;
6562 }
6563
6564 ret = wl_cfgnan_data_path_request_handler(wdev->netdev, cfg,
6565 cmd_data, &ndp_instance_id);
6566 if (ret) {
6567 WL_ERR(("failed to request nan data path [%d]\n", ret));
6568 goto exit;
6569 }
6570
6571 if (cmd_data->status == BCME_OK) {
6572 nan_req_resp.ndp_instance_id = cmd_data->ndp_instance_id;
6573 } else {
6574 nan_req_resp.ndp_instance_id = 0;
6575 }
6576 exit:
6577 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_REQUEST,
6578 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6579 wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6580 NAN_DBG_EXIT();
6581 return ret;
6582 }
6583
6584 static int
wl_cfgvendor_nan_data_path_response(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6585 wl_cfgvendor_nan_data_path_response(struct wiphy *wiphy,
6586 struct wireless_dev *wdev, const void * data, int len)
6587 {
6588 int ret = 0;
6589 nan_datapath_cmd_data_t *cmd_data = NULL;
6590 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6591 nan_hal_resp_t nan_req_resp;
6592
6593 if (!cfg->nancfg->nan_enable) {
6594 WL_ERR(("nan is not enabled, nan data path response blocked\n"));
6595 ret = BCME_ERROR;
6596 goto exit;
6597 }
6598 NAN_DBG_ENTER();
6599 cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6600 if (!cmd_data) {
6601 WL_ERR(("%s: memory allocation failed\n", __func__));
6602 ret = BCME_NOMEM;
6603 goto exit;
6604 }
6605
6606 bzero(&nan_req_resp, sizeof(nan_req_resp));
6607 ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6608 if (ret) {
6609 WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6610 goto exit;
6611 }
6612 ret = wl_cfgnan_data_path_response_handler(wdev->netdev, cfg, cmd_data);
6613 if (ret) {
6614 WL_ERR(("failed to response nan data path [%d]\n", ret));
6615 goto exit;
6616 }
6617 exit:
6618 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_RESPONSE,
6619 &nan_req_resp, ret, cmd_data ? cmd_data->status : BCME_OK);
6620 wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6621 NAN_DBG_EXIT();
6622 return ret;
6623 }
6624
6625 static int
wl_cfgvendor_nan_data_path_end(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6626 wl_cfgvendor_nan_data_path_end(struct wiphy *wiphy,
6627 struct wireless_dev *wdev, const void * data, int len)
6628 {
6629 int ret = 0;
6630 nan_datapath_cmd_data_t *cmd_data = NULL;
6631 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6632 nan_hal_resp_t nan_req_resp;
6633 int status = BCME_ERROR;
6634
6635 NAN_DBG_ENTER();
6636 if (!cfg->nancfg->nan_enable) {
6637 WL_ERR(("nan is not enabled, nan data path end blocked\n"));
6638 ret = BCME_OK;
6639 goto exit;
6640 }
6641 cmd_data = (nan_datapath_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6642 if (!cmd_data) {
6643 WL_ERR(("%s: memory allocation failed\n", __func__));
6644 ret = BCME_NOMEM;
6645 goto exit;
6646 }
6647
6648 bzero(&nan_req_resp, sizeof(nan_req_resp));
6649 ret = wl_cfgvendor_nan_parse_datapath_args(wiphy, data, len, cmd_data);
6650 if (ret) {
6651 WL_ERR(("failed to parse nan datapath vendor args, ret = %d\n", ret));
6652 goto exit;
6653 }
6654 ret = wl_cfgnan_data_path_end_handler(wdev->netdev, cfg,
6655 cmd_data->ndp_instance_id, &status);
6656 if (ret) {
6657 WL_ERR(("failed to end nan data path [%d]\n", ret));
6658 goto exit;
6659 }
6660 exit:
6661 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_END,
6662 &nan_req_resp, ret, cmd_data ? status : BCME_OK);
6663 wl_cfgvendor_free_dp_cmd_data(cfg, cmd_data);
6664 NAN_DBG_EXIT();
6665 return ret;
6666 }
6667
6668 #ifdef WL_NAN_DISC_CACHE
6669 static int
wl_cfgvendor_nan_data_path_sec_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6670 wl_cfgvendor_nan_data_path_sec_info(struct wiphy *wiphy,
6671 struct wireless_dev *wdev, const void *data, int len)
6672 {
6673 int ret = 0;
6674 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6675 nan_hal_resp_t nan_req_resp;
6676 nan_datapath_sec_info_cmd_data_t *cmd_data = NULL;
6677 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(wdev->netdev);
6678
6679 NAN_DBG_ENTER();
6680 if (!cfg->nancfg->nan_enable) {
6681 WL_ERR(("nan is not enabled\n"));
6682 ret = BCME_UNSUPPORTED;
6683 goto exit;
6684 }
6685 cmd_data = MALLOCZ(dhdp->osh, sizeof(*cmd_data));
6686 if (!cmd_data) {
6687 WL_ERR(("%s: memory allocation failed\n", __func__));
6688 ret = BCME_NOMEM;
6689 goto exit;
6690 }
6691
6692 ret = wl_cfgvendor_nan_parse_dp_sec_info_args(wiphy, data, len, cmd_data);
6693 if (ret) {
6694 WL_ERR(("failed to parse sec info args\n"));
6695 goto exit;
6696 }
6697
6698 bzero(&nan_req_resp, sizeof(nan_req_resp));
6699 ret = wl_cfgnan_sec_info_handler(cfg, cmd_data, &nan_req_resp);
6700 if (ret) {
6701 WL_ERR(("failed to retrieve svc hash/pub nmi error[%d]\n", ret));
6702 goto exit;
6703 }
6704 exit:
6705 ret = wl_cfgvendor_nan_cmd_reply(wiphy, NAN_WIFI_SUBCMD_DATA_PATH_SEC_INFO,
6706 &nan_req_resp, ret, BCME_OK);
6707 if (cmd_data) {
6708 MFREE(dhdp->osh, cmd_data, sizeof(*cmd_data));
6709 }
6710 NAN_DBG_EXIT();
6711 return ret;
6712 }
6713 #endif /* WL_NAN_DISC_CACHE */
6714
6715 static int
wl_cfgvendor_nan_version_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6716 wl_cfgvendor_nan_version_info(struct wiphy *wiphy,
6717 struct wireless_dev *wdev, const void *data, int len)
6718 {
6719 int ret = BCME_OK;
6720 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6721 uint32 version = NAN_HAL_VERSION_1;
6722
6723 BCM_REFERENCE(cfg);
6724 WL_DBG(("Enter %s version %d\n", __FUNCTION__, version));
6725 ret = wl_cfgvendor_send_cmd_reply(wiphy, &version, sizeof(version));
6726 return ret;
6727 }
6728
6729 static int
wl_cfgvendor_nan_enable_merge(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6730 wl_cfgvendor_nan_enable_merge(struct wiphy *wiphy,
6731 struct wireless_dev *wdev, const void * data, int len)
6732 {
6733 int ret = 0;
6734 nan_config_cmd_data_t *cmd_data = NULL;
6735 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6736 int status = BCME_OK;
6737 uint32 nan_attr_mask = 0;
6738
6739 BCM_REFERENCE(nan_attr_mask);
6740 NAN_DBG_ENTER();
6741 cmd_data = (nan_config_cmd_data_t *)MALLOCZ(cfg->osh, sizeof(*cmd_data));
6742 if (!cmd_data) {
6743 WL_ERR(("%s: memory allocation failed\n", __func__));
6744 ret = BCME_NOMEM;
6745 goto exit;
6746 }
6747
6748 ret = wl_cfgvendor_nan_parse_args(wiphy, data, len, cmd_data, &nan_attr_mask);
6749 if (ret) {
6750 WL_ERR((" Enable merge: failed to parse nan config vendor args, ret = %d\n", ret));
6751 goto exit;
6752 }
6753 ret = wl_cfgnan_set_enable_merge(wdev->netdev, cfg, cmd_data->enable_merge, &status);
6754 if (unlikely(ret) || unlikely(status)) {
6755 WL_ERR(("Enable merge: failed to set config request [%d]\n", ret));
6756 /* As there is no cmd_reply, return status if error is in status else return ret */
6757 if (status) {
6758 ret = status;
6759 }
6760 goto exit;
6761 }
6762 exit:
6763 if (cmd_data) {
6764 if (cmd_data->scid.data) {
6765 MFREE(cfg->osh, cmd_data->scid.data, cmd_data->scid.dlen);
6766 cmd_data->scid.dlen = 0;
6767 }
6768 MFREE(cfg->osh, cmd_data, sizeof(*cmd_data));
6769 }
6770 NAN_DBG_EXIT();
6771 return ret;
6772 }
6773 #endif /* WL_NAN */
6774
6775 #ifdef LINKSTAT_SUPPORT
6776
6777 #define NUM_RATE 32
6778 #define NUM_PEER 1
6779 #define NUM_CHAN 11
6780 #define HEADER_SIZE sizeof(ver_len)
6781
6782 #define NUM_PNO_SCANS 8
6783 #define NUM_CCA_SAMPLING_SECS 1
6784
wl_cfgvendor_lstats_get_bcn_mbss(char * buf,uint32 * rxbeaconmbss)6785 static int wl_cfgvendor_lstats_get_bcn_mbss(char *buf, uint32 *rxbeaconmbss)
6786 {
6787 wl_cnt_info_t *cbuf = (wl_cnt_info_t *)buf;
6788 const void *cnt;
6789
6790 if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6791 WL_CNT_XTLV_CNTV_LE10_UCODE, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6792 *rxbeaconmbss = ((const wl_cnt_v_le10_mcst_t *)cnt)->rxbeaconmbss;
6793 } else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6794 WL_CNT_XTLV_LT40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6795 *rxbeaconmbss = ((const wl_cnt_lt40mcst_v1_t *)cnt)->rxbeaconmbss;
6796 } else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6797 WL_CNT_XTLV_GE40_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6798 *rxbeaconmbss = ((const wl_cnt_ge40mcst_v1_t *)cnt)->rxbeaconmbss;
6799 } else if ((cnt = (const void *)bcm_get_data_from_xtlv_buf(cbuf->data, cbuf->datalen,
6800 WL_CNT_XTLV_GE80_UCODE_V1, NULL, BCM_XTLV_OPTION_ALIGN32)) != NULL) {
6801 *rxbeaconmbss = ((const wl_cnt_ge80mcst_v1_t *)cnt)->rxbeaconmbss;
6802 } else {
6803 *rxbeaconmbss = 0;
6804 return BCME_NOTFOUND;
6805 }
6806
6807 return BCME_OK;
6808 }
6809
fill_chanspec_to_channel_info(chanspec_t cur_chanspec,wifi_channel_info * channel,int * cur_band)6810 static void fill_chanspec_to_channel_info(chanspec_t cur_chanspec,
6811 wifi_channel_info *channel, int *cur_band)
6812 {
6813 int band;
6814 channel->width = WIFI_CHAN_WIDTH_INVALID;
6815
6816 if (CHSPEC_IS20(cur_chanspec)) {
6817 channel->width = WIFI_CHAN_WIDTH_20;
6818 } else if (CHSPEC_IS40(cur_chanspec)) {
6819 channel->width = WIFI_CHAN_WIDTH_40;
6820 } else if (CHSPEC_IS80(cur_chanspec)) {
6821 channel->width = WIFI_CHAN_WIDTH_80;
6822 } else if (CHSPEC_IS160(cur_chanspec)) {
6823 channel->width = WIFI_CHAN_WIDTH_160;
6824 } else if (CHSPEC_IS8080(cur_chanspec)) {
6825 channel->width = WIFI_CHAN_WIDTH_80P80;
6826 }
6827
6828 band = *cur_band = CHSPEC_BAND(cur_chanspec);
6829 channel->center_freq =
6830 wl_channel_to_frequency(wf_chspec_primary20_chan(cur_chanspec),
6831 band);
6832
6833 if (CHSPEC_IS160(cur_chanspec) || CHSPEC_IS8080(cur_chanspec)) {
6834 channel->center_freq0 =
6835 wl_channel_to_frequency(wf_chspec_primary80_channel(cur_chanspec),
6836 band);
6837 channel->center_freq1 =
6838 wl_channel_to_frequency(wf_chspec_secondary80_channel(cur_chanspec),
6839 band);
6840 } else {
6841 channel->center_freq0 =
6842 wl_channel_to_frequency(CHSPEC_CHANNEL(cur_chanspec),
6843 band);
6844 channel->center_freq1 = 0;
6845 }
6846 }
6847
wl_cfgvendor_lstats_get_info(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)6848 static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy,
6849 struct wireless_dev *wdev, const void *data, int len)
6850 {
6851 static char iovar_buf[WLC_IOCTL_MAXLEN];
6852 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
6853 int err = 0, ret = 0, i;
6854 wifi_radio_stat *radio;
6855 wifi_radio_stat_h radio_h;
6856 wifi_channel_stat *chan_stats = NULL;
6857 uint chan_stats_size = 0;
6858 #ifdef CHAN_STATS_SUPPORT
6859 wifi_channel_stat *p_chan_stats = NULL;
6860 cca_congest_ext_channel_req_v2_t *per_chspec_stats = NULL;
6861 uint per_chspec_stats_size = 0;
6862 cca_congest_ext_channel_req_v3_t *all_chan_results;
6863 cca_congest_ext_channel_req_v3_t *all_chan_req = NULL;
6864 uint all_chan_req_size = sizeof(cca_congest_ext_channel_req_v3_t);
6865 #else
6866 /* cca_get_stats_ext iovar for Wifi channel statics */
6867 struct cca_congest_ext_channel_req_v2 *cca_v2_results;
6868 struct cca_congest_ext_channel_req_v2 *cca_v2_req = NULL;
6869 uint cca_v2_req_size = sizeof(cca_congest_ext_channel_req_v2_t);
6870 #endif /* CHAN_STATS_SUPPORT */
6871 const wl_cnt_wlc_t *wlc_cnt;
6872 scb_val_t scbval;
6873 char *output = NULL;
6874 char *outdata = NULL;
6875 wifi_rate_stat_v1 *p_wifi_rate_stat_v1 = NULL;
6876 wifi_rate_stat *p_wifi_rate_stat = NULL;
6877 uint total_len = 0;
6878 uint32 rxbeaconmbss;
6879 wlc_rev_info_t revinfo;
6880 wl_if_stats_t *if_stats = NULL;
6881 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
6882 wl_pwrstats_query_t scan_query;
6883 wl_pwrstats_t *pwrstats;
6884 wl_pwr_scan_stats_t scan_stats;
6885 int scan_time_len;
6886 uint32 tot_pno_dur = 0;
6887 wifi_channel_stat cur_channel_stat;
6888 cca_congest_channel_req_t *cca_result;
6889 cca_congest_channel_req_t cca_req;
6890 uint32 cca_busy_time = 0;
6891 int cur_chansp, cur_band;
6892 chanspec_t cur_chanspec;
6893
6894 COMPAT_STRUCT_IFACE(wifi_iface_stat, iface);
6895
6896 WL_TRACE(("%s: Enter \n", __func__));
6897 RETURN_EIO_IF_NOT_UP(cfg);
6898
6899 BCM_REFERENCE(if_stats);
6900 BCM_REFERENCE(dhdp);
6901 /* Get the device rev info */
6902 bzero(&revinfo, sizeof(revinfo));
6903 err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_REVINFO, &revinfo,
6904 sizeof(revinfo));
6905 if (err != BCME_OK) {
6906 goto exit;
6907 }
6908
6909 outdata = (void *)MALLOCZ(cfg->osh, WLC_IOCTL_MAXLEN);
6910 if (outdata == NULL) {
6911 WL_ERR(("outdata alloc failed\n"));
6912 return BCME_NOMEM;
6913 }
6914
6915 bzero(&scbval, sizeof(scb_val_t));
6916 bzero(outdata, WLC_IOCTL_MAXLEN);
6917 output = outdata;
6918
6919 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0,
6920 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
6921 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
6922 WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wifi_radio_stat)));
6923 goto exit;
6924 }
6925 radio = (wifi_radio_stat *)iovar_buf;
6926
6927 bzero(&radio_h, sizeof(wifi_radio_stat_h));
6928 radio_h.on_time = radio->on_time;
6929 radio_h.tx_time = radio->tx_time;
6930 radio_h.rx_time = radio->rx_time;
6931 radio_h.on_time_scan = radio->on_time_scan;
6932 radio_h.on_time_nbd = radio->on_time_nbd;
6933 radio_h.on_time_gscan = radio->on_time_gscan;
6934 radio_h.on_time_roam_scan = radio->on_time_roam_scan;
6935 radio_h.on_time_pno_scan = radio->on_time_pno_scan;
6936 radio_h.on_time_hs20 = radio->on_time_hs20;
6937 radio_h.num_channels = NUM_PEER;
6938
6939 scan_query.length = 1;
6940 scan_query.type[0] = WL_PWRSTATS_TYPE_SCAN;
6941
6942 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "pwrstats", &scan_query,
6943 sizeof(scan_query), iovar_buf, WLC_IOCTL_MAXLEN, NULL);
6944 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
6945 WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_pwrstats_t)));
6946 goto exit;
6947 }
6948
6949 pwrstats = (wl_pwrstats_t *) iovar_buf;
6950
6951 if (dtoh16(pwrstats->version) != WL_PWRSTATS_VERSION) {
6952 WL_ERR(("PWRSTATS Version mismatch\n"));
6953 err = BCME_ERROR;
6954 goto exit;
6955 }
6956
6957 scan_time_len = dtoh16(((uint16 *)pwrstats->data)[1]);
6958
6959 if (scan_time_len < sizeof(wl_pwr_scan_stats_t)) {
6960 WL_ERR(("WL_PWRSTATS_TYPE_SCAN IOVAR info short len : %d < %d\n",
6961 scan_time_len, (int)sizeof(wl_pwr_scan_stats_t)));
6962 err = BCME_ERROR;
6963 goto exit;
6964 }
6965
6966 (void) memcpy_s(&scan_stats, sizeof(wl_pwr_scan_stats_t), pwrstats->data, scan_time_len);
6967
6968 /* wl_pwr_scan_stats structure has the array of pno_scans.
6969 * scan_data_t pno_scans[8];
6970 * The number of array is 8 : For future PNO bucketing (BSSID, SSID, etc)
6971 * FW sets the number as harcoded.
6972 * If the hardcoded number (8) is changed,
6973 * the loop condition or NUM_PNO_SCANS has to be changed
6974 */
6975
6976 for (i = 0; i < NUM_PNO_SCANS; i++) {
6977 tot_pno_dur += dtoh32(scan_stats.pno_scans[i].dur);
6978 }
6979
6980 /* Android Framework defines the total scan time in ms.
6981 * But FW sends each scan time in us except for roam scan time.
6982 * So we need to scale the times in ms.
6983 */
6984
6985 radio_h.on_time_scan = (uint32)((tot_pno_dur +
6986 dtoh32(scan_stats.user_scans.dur) +
6987 dtoh32(scan_stats.assoc_scans.dur) +
6988 dtoh32(scan_stats.other_scans.dur)) / 1000);
6989
6990 radio_h.on_time_scan += dtoh32(scan_stats.roam_scans.dur);
6991 radio_h.on_time_roam_scan = dtoh32(scan_stats.roam_scans.dur);
6992 radio_h.on_time_pno_scan = (uint32)(tot_pno_dur / 1000);
6993
6994 WL_TRACE(("pwr_scan_stats : %u %u %u %u %u %u\n",
6995 radio_h.on_time_scan,
6996 dtoh32(scan_stats.user_scans.dur),
6997 dtoh32(scan_stats.assoc_scans.dur),
6998 dtoh32(scan_stats.roam_scans.dur),
6999 tot_pno_dur,
7000 dtoh32(scan_stats.other_scans.dur)));
7001
7002 err = wldev_iovar_getint(bcmcfg_to_prmry_ndev(cfg), "chanspec", (int*)&cur_chansp);
7003 if (err != BCME_OK) {
7004 WL_ERR(("error (%d) \n", err));
7005 goto exit;
7006 }
7007
7008 cur_chanspec = wl_chspec_driver_to_host(cur_chansp);
7009
7010 if (!wf_chspec_valid(cur_chanspec)) {
7011 WL_ERR(("Invalid chanspec : %x\n", cur_chanspec));
7012 err = BCME_ERROR;
7013 goto exit;
7014 }
7015
7016 fill_chanspec_to_channel_info(cur_chanspec, &cur_channel_stat.channel, &cur_band);
7017 WL_TRACE(("chanspec : %x, BW : %d, Cur Band : %x, freq : %d, freq0 :%d, freq1 : %d\n",
7018 cur_chanspec,
7019 cur_channel_stat.channel.width,
7020 cur_band,
7021 cur_channel_stat.channel.center_freq,
7022 cur_channel_stat.channel.center_freq0,
7023 cur_channel_stat.channel.center_freq1));
7024
7025 chan_stats_size = sizeof(wifi_channel_stat);
7026 chan_stats = &cur_channel_stat;
7027
7028 #ifdef CHAN_STATS_SUPPORT
7029 /* Option to get all channel statistics */
7030 all_chan_req = (void *)MALLOCZ(cfg->osh, all_chan_req_size);
7031 if (all_chan_req == NULL) {
7032 err = BCME_NOMEM;
7033 WL_ERR(("all_chan_req alloc failed\n"));
7034 goto exit;
7035 }
7036 all_chan_req->num_of_entries = 0;
7037 all_chan_req->ver = WL_CCA_EXT_REQ_VER_V3;
7038 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats_ext",
7039 all_chan_req, all_chan_req_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7040
7041 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
7042 WL_ERR(("cca_get_stats_ext iovar err = %d\n", err));
7043 goto exit;
7044 }
7045
7046 all_chan_results = (cca_congest_ext_channel_req_v3_t *) iovar_buf;
7047 if ((err == BCME_OK) &&
7048 (dtoh16(all_chan_results->ver) == WL_CCA_EXT_REQ_VER_V3)) {
7049 wifi_channel_stat *all_chan_stats = NULL;
7050 int i = 0, num_channels;
7051
7052 num_channels = dtoh16(all_chan_results->num_of_entries);
7053 radio_h.num_channels = num_channels;
7054
7055 chan_stats_size = sizeof(wifi_channel_stat) * num_channels;
7056 chan_stats = (wifi_channel_stat*)MALLOCZ(cfg->osh, chan_stats_size);
7057 p_chan_stats = chan_stats;
7058 if (chan_stats == NULL) {
7059 WL_ERR(("chan_stats alloc failed\n"));
7060 goto exit;
7061 }
7062 bzero(chan_stats, chan_stats_size);
7063 all_chan_stats = chan_stats;
7064
7065 per_chspec_stats_size =
7066 sizeof(cca_congest_ext_channel_req_v2_t) * num_channels;
7067 per_chspec_stats = (cca_congest_ext_channel_req_v2_t *)
7068 MALLOCZ(cfg->osh, per_chspec_stats_size);
7069 if (per_chspec_stats == NULL) {
7070 WL_ERR(("per_chspec_stats alloc failed\n"));
7071 goto exit;
7072 }
7073 (void) memcpy_s(per_chspec_stats, per_chspec_stats_size,
7074 &all_chan_results->per_chan_stats, per_chspec_stats_size);
7075
7076 WL_TRACE(("** Per channel CCA entries ** \n"));
7077
7078 for (i = 0; i < num_channels; i++, all_chan_stats++) {
7079 if (per_chspec_stats[i].num_secs != 1) {
7080 WL_ERR(("Bogus num of seconds returned %d\n",
7081 per_chspec_stats[i].num_secs));
7082 goto exit;
7083 }
7084
7085 fill_chanspec_to_channel_info(per_chspec_stats[i].chanspec,
7086 &all_chan_stats->channel, &cur_band);
7087
7088 all_chan_stats->on_time =
7089 per_chspec_stats[i].secs[0].radio_on_time;
7090 all_chan_stats->cca_busy_time =
7091 per_chspec_stats[i].secs[0].cca_busy_time;
7092
7093 WL_TRACE(("chanspec %x num_sec %d radio_on_time %d cca_busytime %d \n",
7094 per_chspec_stats[i].chanspec, per_chspec_stats[i].num_secs,
7095 per_chspec_stats[i].secs[0].radio_on_time,
7096 per_chspec_stats[i].secs[0].cca_busy_time));
7097 }
7098 }
7099 #else
7100 cca_v2_req = (void *)MALLOCZ(cfg->osh, cca_v2_req_size);
7101 if (cca_v2_req == NULL) {
7102 err = BCME_NOMEM;
7103 WL_ERR(("cca_v2_req alloc failed\n"));
7104 goto exit;
7105 }
7106 cca_v2_req->ver = WL_CCA_EXT_REQ_VER_V2;
7107 cca_v2_req->chanspec =
7108 wl_chspec_host_to_driver(wf_chspec_primary20_chspec(cur_chanspec));
7109
7110 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats_ext", cca_v2_req,
7111 cca_v2_req_size, iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7112
7113 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
7114 WL_ERR(("cca_get_stats_ext iovar err = %d\n", err));
7115 goto exit;
7116 }
7117
7118 cca_v2_results = (struct cca_congest_ext_channel_req_v2 *) iovar_buf;
7119
7120 /* Check the verison for cca_get_stats_ext iovar */
7121 if ((err == BCME_OK) &&
7122 (dtoh16(cca_v2_results->ver) == WL_CCA_EXT_REQ_VER_V2)) {
7123 /* the accumulated time for the current channel */
7124 cur_channel_stat.on_time = dtoh32(cca_v2_results->secs[0].radio_on_time);
7125 cur_channel_stat.cca_busy_time = dtoh32(cca_v2_results->secs[0].cca_busy_time);
7126
7127 WL_TRACE(("wifi chan statics - on_time : %u, cca_busy_time : %u\n",
7128 cur_channel_stat.on_time, cur_channel_stat.cca_busy_time));
7129 }
7130 #endif /* CHAN_STATS_SUPPORT */
7131 else {
7132 /* To get fine-grained cca result,
7133 * you can increase num_secs because num_secs is the time to get samples.
7134 * Also if the time is increased,
7135 * it is necessary to use a loop to add the times of cca_result->sec[].
7136 * For simplicity, the sampling time is set to 1sec.
7137 */
7138 WL_TRACE(("cca_get_stats_ext unsupported or version mismatch\n"));
7139
7140 cca_req.num_secs = NUM_CCA_SAMPLING_SECS;
7141 cca_req.chanspec = wl_chspec_host_to_driver(cur_chanspec);
7142
7143 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cca_get_stats", &cca_req,
7144 sizeof(cca_req), iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7145
7146 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
7147 WL_ERR(("error (%d) - size = %zu\n",
7148 err, sizeof(cca_congest_channel_req_t)));
7149 goto exit;
7150 }
7151
7152 cur_channel_stat.on_time = radio_h.on_time;
7153
7154 if (err == BCME_OK) {
7155 cca_result = (cca_congest_channel_req_t *) iovar_buf;
7156 cca_busy_time = dtoh32(cca_result->secs[0].congest_ibss) +
7157 dtoh32(cca_result->secs[0].congest_obss) +
7158 dtoh32(cca_result->secs[0].interference);
7159
7160 WL_TRACE(("wifi stats : %u, %u, %u, %u, %u\n", cur_channel_stat.on_time,
7161 cca_busy_time,
7162 dtoh32(cca_result->secs[0].congest_ibss),
7163 dtoh32(cca_result->secs[0].congest_obss),
7164 dtoh32(cca_result->secs[0].interference)));
7165 } else {
7166 WL_INFORM(("cca_get_stats is unsupported \n"));
7167 }
7168
7169 /* If cca_get_stats is unsupported, cca_busy_time has zero value as initial value */
7170 cur_channel_stat.cca_busy_time = cca_busy_time;
7171 }
7172
7173 ret = memcpy_s(output, WLC_IOCTL_MAXLEN, &radio_h, sizeof(wifi_radio_stat_h));
7174 if (ret) {
7175 WL_ERR(("Failed to copy wifi_radio_stat_h: %d\n", ret));
7176 goto exit;
7177 }
7178 output += sizeof(wifi_radio_stat_h);
7179
7180 ret = memcpy_s(output, (WLC_IOCTL_MAXLEN - sizeof(wifi_radio_stat_h)),
7181 chan_stats, chan_stats_size);
7182 if (ret) {
7183 WL_ERR(("Failed to copy wifi_channel_stat: %d\n", ret));
7184 goto exit;
7185 }
7186 output += chan_stats_size;
7187
7188 COMPAT_BZERO_IFACE(wifi_iface_stat, iface);
7189 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].ac, WIFI_AC_VO);
7190 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].ac, WIFI_AC_VI);
7191 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].ac, WIFI_AC_BE);
7192 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].ac, WIFI_AC_BK);
7193
7194 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0,
7195 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7196 if (unlikely(err)) {
7197 WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_cnt_wlc_t)));
7198 goto exit;
7199 }
7200
7201 CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MAXLEN);
7202 /* Translate traditional (ver <= 10) counters struct to new xtlv type struct */
7203 /* traditional(ver<=10)counters will use WL_CNT_XTLV_CNTV_LE10_UCODE.
7204 * Other cases will use its xtlv type accroding to corerev
7205 */
7206 err = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WLC_IOCTL_MAXLEN, revinfo.corerev);
7207 if (err != BCME_OK) {
7208 WL_ERR(("wl_cntbuf_to_xtlv_format ERR %d\n", err));
7209 goto exit;
7210 }
7211
7212 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
7213 WL_ERR(("wlc_cnt NULL!\n"));
7214 err = BCME_ERROR;
7215 goto exit;
7216 }
7217
7218 #ifndef DISABLE_IF_COUNTERS
7219 if_stats = (wl_if_stats_t *)MALLOCZ(cfg->osh, sizeof(wl_if_stats_t));
7220 if (!if_stats) {
7221 WL_ERR(("MALLOCZ failed\n"));
7222 err = BCME_NOMEM;
7223 goto exit;
7224 }
7225
7226 if (FW_SUPPORTED(dhdp, ifst)) {
7227 err = wl_cfg80211_ifstats_counters(bcmcfg_to_prmry_ndev(cfg), if_stats);
7228 } else {
7229 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "if_counters",
7230 NULL, 0, (char *)if_stats, sizeof(*if_stats), NULL);
7231 }
7232
7233 if (!err) {
7234 /* Populate from if_stats */
7235 if (dtoh16(if_stats->version) > WL_IF_STATS_T_VERSION) {
7236 WL_ERR(("incorrect version of wl_if_stats_t,"
7237 " expected=%u got=%u\n", WL_IF_STATS_T_VERSION,
7238 if_stats->version));
7239 goto exit;
7240 }
7241 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu, (uint32)if_stats->txframe);
7242 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu,
7243 (uint32)(if_stats->rxframe - if_stats->rxmulti));
7244 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost, (uint32)if_stats->txfail);
7245 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, (uint32)if_stats->txretrans);
7246 } else
7247 #endif /* !DISABLE_IF_COUNTERS */
7248 {
7249 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu,
7250 (wlc_cnt->txfrmsnt - wlc_cnt->txmulti));
7251 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu, wlc_cnt->rxframe);
7252 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost, wlc_cnt->txfail);
7253 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, wlc_cnt->txretrans);
7254 }
7255
7256 err = wl_cfgvendor_lstats_get_bcn_mbss(iovar_buf, &rxbeaconmbss);
7257 if (unlikely(err)) {
7258 WL_ERR(("get_bcn_mbss error (%d)\n", err));
7259 goto exit;
7260 }
7261
7262 err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval);
7263 if (unlikely(err)) {
7264 WL_ERR(("get_rssi error (%d)\n", err));
7265 goto exit;
7266 }
7267
7268 COMPAT_ASSIGN_VALUE(iface, beacon_rx, rxbeaconmbss);
7269 COMPAT_ASSIGN_VALUE(iface, rssi_mgmt, scbval.val);
7270 COMPAT_ASSIGN_VALUE(iface, num_peers, NUM_PEER);
7271 COMPAT_ASSIGN_VALUE(iface, peer_info->num_rate, NUM_RATE);
7272
7273 COMPAT_MEMCOPY_IFACE(output, total_len, wifi_iface_stat, iface, wifi_rate_stat);
7274
7275 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0,
7276 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
7277 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
7278 WL_ERR(("error (%d) - size = %zu\n", err, NUM_RATE*sizeof(wifi_rate_stat)));
7279 goto exit;
7280 }
7281 for (i = 0; i < NUM_RATE; i++) {
7282 p_wifi_rate_stat =
7283 (wifi_rate_stat *)(iovar_buf + i*sizeof(wifi_rate_stat));
7284 p_wifi_rate_stat_v1 = (wifi_rate_stat_v1 *)output;
7285 p_wifi_rate_stat_v1->rate.preamble = p_wifi_rate_stat->rate.preamble;
7286 p_wifi_rate_stat_v1->rate.nss = p_wifi_rate_stat->rate.nss;
7287 p_wifi_rate_stat_v1->rate.bw = p_wifi_rate_stat->rate.bw;
7288 p_wifi_rate_stat_v1->rate.rateMcsIdx = p_wifi_rate_stat->rate.rateMcsIdx;
7289 p_wifi_rate_stat_v1->rate.reserved = p_wifi_rate_stat->rate.reserved;
7290 p_wifi_rate_stat_v1->rate.bitrate = p_wifi_rate_stat->rate.bitrate;
7291 p_wifi_rate_stat_v1->tx_mpdu = p_wifi_rate_stat->tx_mpdu;
7292 p_wifi_rate_stat_v1->rx_mpdu = p_wifi_rate_stat->rx_mpdu;
7293 p_wifi_rate_stat_v1->mpdu_lost = p_wifi_rate_stat->mpdu_lost;
7294 p_wifi_rate_stat_v1->retries = p_wifi_rate_stat->retries;
7295 p_wifi_rate_stat_v1->retries_short = p_wifi_rate_stat->retries_short;
7296 p_wifi_rate_stat_v1->retries_long = p_wifi_rate_stat->retries_long;
7297 output = (char *) &(p_wifi_rate_stat_v1->retries_long);
7298 output += sizeof(p_wifi_rate_stat_v1->retries_long);
7299 }
7300
7301 total_len = sizeof(wifi_radio_stat_h) + chan_stats_size;
7302 total_len = total_len - sizeof(wifi_peer_info) +
7303 NUM_PEER * (sizeof(wifi_peer_info) - sizeof(wifi_rate_stat_v1) +
7304 NUM_RATE * sizeof(wifi_rate_stat_v1));
7305
7306 if (total_len > WLC_IOCTL_MAXLEN) {
7307 WL_ERR(("Error! total_len:%d is unexpected value\n", total_len));
7308 err = BCME_BADLEN;
7309 goto exit;
7310 }
7311 err = wl_cfgvendor_send_cmd_reply(wiphy, outdata, total_len);
7312
7313 if (unlikely(err))
7314 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
7315
7316 exit:
7317 #ifdef CHAN_STATS_SUPPORT
7318 if (all_chan_req) {
7319 MFREE(cfg->osh, all_chan_req, all_chan_req_size);
7320 }
7321 #else
7322 if (cca_v2_req) {
7323 MFREE(cfg->osh, cca_v2_req, cca_v2_req_size);
7324 }
7325 #endif /* CHAN_STATS_SUPPORT */
7326 if (outdata) {
7327 MFREE(cfg->osh, outdata, WLC_IOCTL_MAXLEN);
7328 }
7329 if (if_stats) {
7330 MFREE(cfg->osh, if_stats, sizeof(wl_if_stats_t));
7331 }
7332 #ifdef CHAN_STATS_SUPPORT
7333 if (p_chan_stats) {
7334 MFREE(cfg->osh, p_chan_stats, chan_stats_size);
7335 }
7336 if (per_chspec_stats) {
7337 MFREE(cfg->osh, per_chspec_stats, per_chspec_stats_size);
7338 }
7339 #endif /* CHAN_STATS_SUPPORT */
7340 return err;
7341 }
7342 #endif /* LINKSTAT_SUPPORT */
7343
7344 #ifdef DHD_LOG_DUMP
7345 static int
wl_cfgvendor_get_buf_data(const struct nlattr * iter,struct buf_data ** buf)7346 wl_cfgvendor_get_buf_data(const struct nlattr *iter, struct buf_data **buf)
7347 {
7348 int ret = BCME_OK;
7349
7350 if (nla_len(iter) != sizeof(struct buf_data)) {
7351 WL_ERR(("Invalid len : %d\n", nla_len(iter)));
7352 ret = BCME_BADLEN;
7353 }
7354 (*buf) = (struct buf_data *)nla_data(iter);
7355 if (!(*buf) || (((*buf)->len) <= 0) || !((*buf)->data_buf[0])) {
7356 WL_ERR(("Invalid buffer\n"));
7357 ret = BCME_ERROR;
7358 }
7359 return ret;
7360 }
7361
7362 static int
wl_cfgvendor_dbg_file_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7363 wl_cfgvendor_dbg_file_dump(struct wiphy *wiphy,
7364 struct wireless_dev *wdev, const void *data, int len)
7365 {
7366 int ret = BCME_OK, rem, type = 0;
7367 const struct nlattr *iter;
7368 char *mem_buf = NULL;
7369 struct sk_buff *skb = NULL;
7370 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7371 struct buf_data *buf;
7372 int pos = 0;
7373
7374 /* Alloc the SKB for vendor_event */
7375 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
7376 if (!skb) {
7377 WL_ERR(("skb allocation is failed\n"));
7378 ret = BCME_NOMEM;
7379 goto exit;
7380 }
7381 WL_ERR(("%s\n", __FUNCTION__));
7382 nla_for_each_attr(iter, data, len, rem) {
7383 type = nla_type(iter);
7384 ret = wl_cfgvendor_get_buf_data(iter, &buf);
7385 if (ret)
7386 goto exit;
7387 switch (type) {
7388 case DUMP_BUF_ATTR_MEMDUMP:
7389 ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf,
7390 (uint32 *)(&(buf->len)));
7391 if (ret) {
7392 WL_ERR(("failed to get_socram_dump : %d\n", ret));
7393 goto exit;
7394 }
7395 ret = dhd_export_debug_data(mem_buf, NULL, buf->data_buf[0],
7396 (int)buf->len, &pos);
7397 break;
7398
7399 case DUMP_BUF_ATTR_TIMESTAMP :
7400 ret = dhd_print_time_str(buf->data_buf[0], NULL,
7401 (uint32)buf->len, &pos);
7402 break;
7403 #ifdef EWP_ECNTRS_LOGGING
7404 case DUMP_BUF_ATTR_ECNTRS :
7405 ret = dhd_print_ecntrs_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7406 buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7407 break;
7408 #endif /* EWP_ECNTRS_LOGGING */
7409 #ifdef DHD_STATUS_LOGGING
7410 case DUMP_BUF_ATTR_STATUS_LOG :
7411 ret = dhd_print_status_log_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7412 buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7413 break;
7414 #endif /* DHD_STATUS_LOGGING */
7415 #ifdef EWP_RTT_LOGGING
7416 case DUMP_BUF_ATTR_RTT_LOG :
7417 ret = dhd_print_rtt_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7418 buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7419 break;
7420 #endif /* EWP_RTT_LOGGING */
7421 case DUMP_BUF_ATTR_DHD_DUMP :
7422 ret = dhd_print_dump_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7423 buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7424 break;
7425 #if defined(BCMPCIE)
7426 case DUMP_BUF_ATTR_EXT_TRAP :
7427 ret = dhd_print_ext_trap_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7428 buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7429 break;
7430 #endif /* BCMPCIE */
7431 #if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT)
7432 case DUMP_BUF_ATTR_HEALTH_CHK :
7433 ret = dhd_print_health_chk_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7434 buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7435 break;
7436 #endif
7437 case DUMP_BUF_ATTR_COOKIE :
7438 ret = dhd_print_cookie_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7439 buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7440 break;
7441 #ifdef DHD_DUMP_PCIE_RINGS
7442 case DUMP_BUF_ATTR_FLOWRING_DUMP :
7443 ret = dhd_print_flowring_data(bcmcfg_to_prmry_ndev(cfg), NULL,
7444 buf->data_buf[0], NULL, (uint32)buf->len, &pos);
7445 break;
7446 #endif
7447 case DUMP_BUF_ATTR_GENERAL_LOG :
7448 ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
7449 buf->data_buf[0], NULL, (uint32)buf->len,
7450 DLD_BUF_TYPE_GENERAL, &pos);
7451 break;
7452
7453 case DUMP_BUF_ATTR_PRESERVE_LOG :
7454 ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
7455 buf->data_buf[0], NULL, (uint32)buf->len,
7456 DLD_BUF_TYPE_PRESERVE, &pos);
7457 break;
7458
7459 case DUMP_BUF_ATTR_SPECIAL_LOG :
7460 ret = dhd_get_dld_log_dump(bcmcfg_to_prmry_ndev(cfg), NULL,
7461 buf->data_buf[0], NULL, (uint32)buf->len,
7462 DLD_BUF_TYPE_SPECIAL, &pos);
7463 break;
7464 #ifdef DHD_SSSR_DUMP
7465 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7466 case DUMP_BUF_ATTR_SSSR_C0_D11_BEFORE :
7467 ret = dhd_sssr_dump_d11_buf_before(bcmcfg_to_prmry_ndev(cfg),
7468 buf->data_buf[0], (uint32)buf->len, 0);
7469 break;
7470 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7471
7472 case DUMP_BUF_ATTR_SSSR_C0_D11_AFTER :
7473 ret = dhd_sssr_dump_d11_buf_after(bcmcfg_to_prmry_ndev(cfg),
7474 buf->data_buf[0], (uint32)buf->len, 0);
7475 break;
7476
7477 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7478 case DUMP_BUF_ATTR_SSSR_C1_D11_BEFORE :
7479 ret = dhd_sssr_dump_d11_buf_before(bcmcfg_to_prmry_ndev(cfg),
7480 buf->data_buf[0], (uint32)buf->len, 1);
7481 break;
7482 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7483
7484 case DUMP_BUF_ATTR_SSSR_C1_D11_AFTER :
7485 ret = dhd_sssr_dump_d11_buf_after(bcmcfg_to_prmry_ndev(cfg),
7486 buf->data_buf[0], (uint32)buf->len, 1);
7487 break;
7488
7489 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7490 case DUMP_BUF_ATTR_SSSR_C2_D11_BEFORE :
7491 ret = dhd_sssr_dump_d11_buf_before(bcmcfg_to_prmry_ndev(cfg),
7492 buf->data_buf[0], (uint32)buf->len, 2);
7493 break;
7494 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7495
7496 case DUMP_BUF_ATTR_SSSR_C2_D11_AFTER :
7497 ret = dhd_sssr_dump_d11_buf_after(bcmcfg_to_prmry_ndev(cfg),
7498 buf->data_buf[0], (uint32)buf->len, 2);
7499 break;
7500
7501 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7502 case DUMP_BUF_ATTR_SSSR_DIG_BEFORE :
7503 ret = dhd_sssr_dump_dig_buf_before(bcmcfg_to_prmry_ndev(cfg),
7504 buf->data_buf[0], (uint32)buf->len);
7505 break;
7506 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7507
7508 case DUMP_BUF_ATTR_SSSR_DIG_AFTER :
7509 ret = dhd_sssr_dump_dig_buf_after(bcmcfg_to_prmry_ndev(cfg),
7510 buf->data_buf[0], (uint32)buf->len);
7511 break;
7512 #endif /* DHD_SSSR_DUMP */
7513 #ifdef DHD_PKT_LOGGING
7514 case DUMP_BUF_ATTR_PKTLOG:
7515 ret = dhd_os_get_pktlog_dump(bcmcfg_to_prmry_ndev(cfg),
7516 buf->data_buf[0], (uint32)buf->len);
7517 break;
7518
7519 case DUMP_BUF_ATTR_PKTLOG_DEBUG:
7520 ret = dhd_os_get_pktlog_dump(bcmcfg_to_prmry_ndev(cfg),
7521 buf->data_buf[0], (uint32)buf->len);
7522 break;
7523 #endif /* DHD_PKT_LOGGING */
7524 #ifdef DNGL_AXI_ERROR_LOGGING
7525 case DUMP_BUF_ATTR_AXI_ERROR:
7526 ret = dhd_os_get_axi_error_dump(bcmcfg_to_prmry_ndev(cfg),
7527 buf->data_buf[0], (uint32)buf->len);
7528 break;
7529 #endif /* DNGL_AXI_ERROR_LOGGING */
7530 default:
7531 WL_ERR(("Unknown type: %d\n", type));
7532 ret = BCME_ERROR;
7533 goto exit;
7534 }
7535 }
7536
7537 if (ret)
7538 goto exit;
7539
7540 ret = nla_put_u32(skb, type, (uint32)(ret));
7541 if (ret < 0) {
7542 WL_ERR(("Failed to put type, ret:%d\n", ret));
7543 goto exit;
7544 }
7545 ret = cfg80211_vendor_cmd_reply(skb);
7546 if (ret) {
7547 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
7548 }
7549 return ret;
7550 exit:
7551 if (skb) {
7552 /* Free skb memory */
7553 kfree_skb(skb);
7554 }
7555 return ret;
7556 }
7557 #endif /* DHD_LOG_DUMP */
7558
7559 #ifdef DEBUGABILITY
7560 #ifndef DEBUGABILITY_DISABLE_MEMDUMP
7561 static int
wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7562 wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
7563 struct wireless_dev *wdev, const void *data, int len)
7564 {
7565 int ret = BCME_OK;
7566 uint32 alloc_len;
7567 struct sk_buff *skb = NULL;
7568 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7569 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
7570 u32 supported_features = 0;
7571
7572 WL_ERR(("wl_cfgvendor_dbg_trigger_mem_dump %d\n", __LINE__));
7573
7574 ret = dhd_os_dbg_get_feature(dhdp, &supported_features);
7575 if (!(supported_features & DBG_MEMORY_DUMP_SUPPORTED)) {
7576 WL_ERR(("not support DBG_MEMORY_DUMP_SUPPORTED\n"));
7577 ret = -3; //WIFI_ERROR_NOT_SUPPORTED=-3
7578 goto exit;
7579 }
7580
7581 dhdp->memdump_type = DUMP_TYPE_CFG_VENDOR_TRIGGERED;
7582 ret = dhd_os_socram_dump(bcmcfg_to_prmry_ndev(cfg), &alloc_len);
7583 if (ret) {
7584 WL_ERR(("failed to call dhd_os_socram_dump : %d\n", ret));
7585 goto exit;
7586 }
7587 /* Alloc the SKB for vendor_event */
7588 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
7589 if (!skb) {
7590 WL_ERR(("skb allocation is failed\n"));
7591 ret = BCME_NOMEM;
7592 goto exit;
7593 }
7594 ret = nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, alloc_len);
7595
7596 if (unlikely(ret)) {
7597 WL_ERR(("Failed to put fw dump length, ret=%d\n", ret));
7598 goto exit;
7599 }
7600
7601 ret = cfg80211_vendor_cmd_reply(skb);
7602
7603 if (ret) {
7604 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
7605 goto exit;
7606 }
7607 return ret;
7608 exit:
7609 /* Free skb memory */
7610 if (skb) {
7611 kfree_skb(skb);
7612 }
7613 return ret;
7614 }
7615
7616 static int
wl_cfgvendor_dbg_get_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7617 wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
7618 struct wireless_dev *wdev, const void *data, int len)
7619 {
7620 int ret = BCME_OK, rem, type;
7621 int buf_len = 0;
7622 uintptr_t user_buf = (uintptr_t)NULL;
7623 const struct nlattr *iter;
7624 char *mem_buf = NULL;
7625 struct sk_buff *skb = NULL;
7626 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7627
7628 nla_for_each_attr(iter, data, len, rem) {
7629 type = nla_type(iter);
7630 switch (type) {
7631 case DEBUG_ATTRIBUTE_FW_DUMP_LEN:
7632 /* Check if the iter is valid and
7633 * buffer length is not already initialized.
7634 */
7635 if ((nla_len(iter) == sizeof(uint32)) &&
7636 !buf_len) {
7637 buf_len = nla_get_u32(iter);
7638 if (buf_len <= 0) {
7639 ret = BCME_ERROR;
7640 goto exit;
7641 }
7642 } else {
7643 ret = BCME_ERROR;
7644 goto exit;
7645 }
7646 break;
7647 case DEBUG_ATTRIBUTE_FW_DUMP_DATA:
7648 if (nla_len(iter) != sizeof(uint64)) {
7649 WL_ERR(("Invalid len\n"));
7650 ret = BCME_ERROR;
7651 goto exit;
7652 }
7653 user_buf = (uintptr_t)nla_get_u64(iter);
7654 if (!user_buf) {
7655 ret = BCME_ERROR;
7656 goto exit;
7657 }
7658 break;
7659 default:
7660 WL_ERR(("Unknown type: %d\n", type));
7661 ret = BCME_ERROR;
7662 goto exit;
7663 }
7664 }
7665 if (buf_len > 0 && user_buf) {
7666 #if 0
7667 mem_buf = vmalloc(buf_len);
7668 if (!mem_buf) {
7669 WL_ERR(("failed to allocate mem_buf with size : %d\n", buf_len));
7670 ret = BCME_NOMEM;
7671 goto exit;
7672 }
7673 #endif
7674 ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf, &buf_len);
7675 if (ret) {
7676 WL_ERR(("failed to get_socram_dump : %d\n", ret));
7677 goto free_mem;
7678 }
7679 #ifdef CONFIG_COMPAT
7680 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
7681 if (in_compat_syscall())
7682 #else
7683 if (is_compat_task())
7684 #endif /* LINUX_VER >= 4.6 */
7685 {
7686 void * usr_ptr = compat_ptr((uintptr_t) user_buf);
7687 ret = copy_to_user(usr_ptr, mem_buf, buf_len);
7688 if (ret) {
7689 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
7690 goto free_mem;
7691 }
7692 }
7693 else
7694 #endif /* CONFIG_COMPAT */
7695 {
7696 ret = copy_to_user((void*)user_buf, mem_buf, buf_len);
7697 if (ret) {
7698 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
7699 goto free_mem;
7700 }
7701 }
7702 /* Alloc the SKB for vendor_event */
7703 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, CFG80211_VENDOR_CMD_REPLY_SKB_SZ);
7704 if (!skb) {
7705 WL_ERR(("skb allocation is failed\n"));
7706 ret = BCME_NOMEM;
7707 goto free_mem;
7708 }
7709 /* Indicate the memdump is succesfully copied */
7710 ret = nla_put(skb, DEBUG_ATTRIBUTE_FW_DUMP_DATA, sizeof(ret), &ret);
7711 if (ret < 0) {
7712 WL_ERR(("Failed to put DEBUG_ATTRIBUTE_FW_DUMP_DATA, ret:%d\n", ret));
7713 goto free_mem;
7714 }
7715
7716 ret = cfg80211_vendor_cmd_reply(skb);
7717
7718 if (ret) {
7719 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
7720 }
7721 skb = NULL;
7722 }
7723
7724 free_mem:
7725 // vfree(mem_buf);
7726 /* Free skb memory */
7727 if (skb) {
7728 kfree_skb(skb);
7729 }
7730 exit:
7731 return ret;
7732 }
7733 #else
7734 static int
wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7735 wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
7736 struct wireless_dev *wdev, const void *data, int len)
7737 {
7738 return WIFI_ERROR_NOT_SUPPORTED;
7739 }
7740
7741 static int
wl_cfgvendor_dbg_get_mem_dump(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7742 wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
7743 struct wireless_dev *wdev, const void *data, int len)
7744 {
7745 return WIFI_ERROR_NOT_SUPPORTED;
7746 }
7747 #endif /* !DEBUGABILITY_DISABLE_MEMDUMP */
7748
wl_cfgvendor_dbg_start_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7749 static int wl_cfgvendor_dbg_start_logging(struct wiphy *wiphy,
7750 struct wireless_dev *wdev, const void *data, int len)
7751 {
7752 int ret = BCME_OK, rem, type;
7753 char ring_name[DBGRING_NAME_MAX] = {0};
7754 int log_level = 0, flags = 0, time_intval = 0, threshold = 0;
7755 const struct nlattr *iter;
7756 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7757 dhd_pub_t *dhd_pub = cfg->pub;
7758 nla_for_each_attr(iter, data, len, rem) {
7759 type = nla_type(iter);
7760 switch (type) {
7761 case DEBUG_ATTRIBUTE_RING_NAME:
7762 strncpy(ring_name, nla_data(iter),
7763 MIN(sizeof(ring_name) -1, nla_len(iter)));
7764 break;
7765 case DEBUG_ATTRIBUTE_LOG_LEVEL:
7766 log_level = nla_get_u32(iter);
7767 break;
7768 case DEBUG_ATTRIBUTE_RING_FLAGS:
7769 flags = nla_get_u32(iter);
7770 break;
7771 case DEBUG_ATTRIBUTE_LOG_TIME_INTVAL:
7772 time_intval = nla_get_u32(iter);
7773 break;
7774 case DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE:
7775 threshold = nla_get_u32(iter);
7776 break;
7777 default:
7778 WL_ERR(("Unknown type: %d\n", type));
7779 ret = BCME_BADADDR;
7780 goto exit;
7781 }
7782 }
7783
7784 ret = dhd_os_start_logging(dhd_pub, ring_name, log_level, flags, time_intval, threshold);
7785 if (ret < 0) {
7786 WL_ERR(("start_logging is failed ret: %d\n", ret));
7787 }
7788 exit:
7789 return ret;
7790 }
7791
wl_cfgvendor_dbg_reset_logging(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7792 static int wl_cfgvendor_dbg_reset_logging(struct wiphy *wiphy,
7793 struct wireless_dev *wdev, const void *data, int len)
7794 {
7795 int ret = BCME_OK;
7796 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7797 dhd_pub_t *dhd_pub = cfg->pub;
7798
7799 ret = dhd_os_reset_logging(dhd_pub);
7800 if (ret < 0) {
7801 WL_ERR(("reset logging is failed ret: %d\n", ret));
7802 }
7803
7804 return ret;
7805 }
7806
wl_cfgvendor_dbg_get_ring_status(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7807 static int wl_cfgvendor_dbg_get_ring_status(struct wiphy *wiphy,
7808 struct wireless_dev *wdev, const void *data, int len)
7809 {
7810 int ret = BCME_OK;
7811 int ring_id, i;
7812 int ring_cnt;
7813 struct sk_buff *skb;
7814 dhd_dbg_ring_status_t dbg_ring_status[DEBUG_RING_ID_MAX];
7815 dhd_dbg_ring_status_t ring_status;
7816 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7817 dhd_pub_t *dhd_pub = cfg->pub;
7818 bzero(dbg_ring_status, DBG_RING_STATUS_SIZE * DEBUG_RING_ID_MAX);
7819 ring_cnt = 0;
7820 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
7821 ret = dhd_os_get_ring_status(dhd_pub, ring_id, &ring_status);
7822 if (ret == BCME_NOTFOUND) {
7823 WL_DBG(("The ring (%d) is not found \n", ring_id));
7824 } else if (ret == BCME_OK) {
7825 dbg_ring_status[ring_cnt++] = ring_status;
7826 }
7827 }
7828 /* Alloc the SKB for vendor_event */
7829 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
7830 nla_total_size(DBG_RING_STATUS_SIZE) * ring_cnt + nla_total_size(sizeof(ring_cnt)));
7831 if (!skb) {
7832 WL_ERR(("skb allocation is failed\n"));
7833 ret = BCME_NOMEM;
7834 goto exit;
7835 }
7836
7837 /* Ignore return of nla_put_u32 and nla_put since the skb allocated
7838 * above has a requested size for all payload
7839 */
7840 (void)nla_put_u32(skb, DEBUG_ATTRIBUTE_RING_NUM, ring_cnt);
7841 for (i = 0; i < ring_cnt; i++) {
7842 (void)nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, DBG_RING_STATUS_SIZE,
7843 &dbg_ring_status[i]);
7844 }
7845 ret = cfg80211_vendor_cmd_reply(skb);
7846
7847 if (ret) {
7848 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
7849 }
7850 exit:
7851 return ret;
7852 }
7853
wl_cfgvendor_dbg_get_ring_data(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7854 static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy,
7855 struct wireless_dev *wdev, const void *data, int len)
7856 {
7857 int ret = BCME_OK, rem, type;
7858 char ring_name[DBGRING_NAME_MAX] = {0};
7859 const struct nlattr *iter;
7860 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7861 dhd_pub_t *dhd_pub = cfg->pub;
7862
7863 nla_for_each_attr(iter, data, len, rem) {
7864 type = nla_type(iter);
7865 switch (type) {
7866 case DEBUG_ATTRIBUTE_RING_NAME:
7867 strlcpy(ring_name, nla_data(iter), sizeof(ring_name));
7868 break;
7869 default:
7870 WL_ERR(("Unknown type: %d\n", type));
7871 return ret;
7872 }
7873 }
7874
7875 ret = dhd_os_trigger_get_ring_data(dhd_pub, ring_name);
7876 if (ret < 0) {
7877 WL_ERR(("trigger_get_data failed ret:%d\n", ret));
7878 }
7879
7880 return ret;
7881 }
7882 #endif /* DEBUGABILITY */
7883
wl_cfgvendor_dbg_get_feature(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)7884 static int wl_cfgvendor_dbg_get_feature(struct wiphy *wiphy,
7885 struct wireless_dev *wdev, const void *data, int len)
7886 {
7887 int ret = BCME_OK;
7888 u32 supported_features = 0;
7889 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
7890 dhd_pub_t *dhd_pub = cfg->pub;
7891
7892 ret = dhd_os_dbg_get_feature(dhd_pub, &supported_features);
7893 if (ret < 0) {
7894 WL_ERR(("dbg_get_feature failed ret:%d\n", ret));
7895 goto exit;
7896 }
7897 ret = wl_cfgvendor_send_cmd_reply(wiphy, &supported_features,
7898 sizeof(supported_features));
7899 exit:
7900 return ret;
7901 }
7902
7903 #ifdef DEBUGABILITY
wl_cfgvendor_dbg_ring_send_evt(void * ctx,const int ring_id,const void * data,const uint32 len,const dhd_dbg_ring_status_t ring_status)7904 static void wl_cfgvendor_dbg_ring_send_evt(void *ctx,
7905 const int ring_id, const void *data, const uint32 len,
7906 const dhd_dbg_ring_status_t ring_status)
7907 {
7908 struct net_device *ndev = ctx;
7909 struct wiphy *wiphy;
7910 gfp_t kflags;
7911 struct sk_buff *skb;
7912 struct nlmsghdr *nlh;
7913 struct bcm_cfg80211 *cfg;
7914 if (!ndev) {
7915 WL_ERR(("ndev is NULL\n"));
7916 return;
7917 }
7918 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
7919 wiphy = ndev->ieee80211_ptr->wiphy;
7920 cfg = wiphy_priv(wiphy);
7921
7922 /* If wifi hal is not start, don't send event to wifi hal */
7923 if (!cfg->hal_started) {
7924 WL_ERR(("Hal is not started\n"));
7925 return;
7926 }
7927 /* Alloc the SKB for vendor_event */
7928 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
7929 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
7930 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + CFG80211_VENDOR_EVT_SKB_SZ,
7931 GOOGLE_DEBUG_RING_EVENT, kflags);
7932 #else
7933 skb = cfg80211_vendor_event_alloc(wiphy, len + CFG80211_VENDOR_EVT_SKB_SZ,
7934 GOOGLE_DEBUG_RING_EVENT, kflags);
7935 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
7936 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
7937 if (!skb) {
7938 WL_ERR(("skb alloc failed"));
7939 return;
7940 }
7941 /* Set halpid for sending unicast event to wifi hal */
7942 nlh = (struct nlmsghdr*)skb->data;
7943 nlh->nlmsg_pid = cfg->halpid;
7944 nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, sizeof(ring_status), &ring_status);
7945 nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
7946 cfg80211_vendor_event(skb, kflags);
7947 }
7948 #endif /* DEBUGABILITY */
7949
7950 #ifdef DHD_LOG_DUMP
7951 #ifdef DHD_SSSR_DUMP
7952 #define DUMP_SSSR_DUMP_MAX_COUNT 8
wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff * skb,struct net_device * ndev)7953 static int wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff *skb,
7954 struct net_device *ndev)
7955 {
7956 int ret = BCME_OK;
7957 #ifdef DHD_SSSR_DUMP
7958 uint32 arr_len[DUMP_SSSR_DUMP_MAX_COUNT];
7959 #endif /* DHD_SSSR_DUMP */
7960 char memdump_path[MEMDUMP_PATH_LEN];
7961 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
7962
7963 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7964 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
7965 "sssr_dump_core_0_before_SR");
7966 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_0_BEFORE_DUMP, memdump_path);
7967 if (unlikely(ret)) {
7968 WL_ERR(("Failed to nla put sssr core 0 before dump path, ret=%d\n", ret));
7969 goto exit;
7970 }
7971 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7972
7973 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
7974 "sssr_dump_core_0_after_SR");
7975 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_0_AFTER_DUMP, memdump_path);
7976 if (unlikely(ret)) {
7977 WL_ERR(("Failed to nla put sssr core 1 after dump path, ret=%d\n", ret));
7978 goto exit;
7979 }
7980
7981 #ifdef DHD_SSSR_DUMP_BEFORE_SR
7982 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
7983 "sssr_dump_core_1_before_SR");
7984 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_1_BEFORE_DUMP, memdump_path);
7985 if (unlikely(ret)) {
7986 WL_ERR(("Failed to nla put sssr core 1 before dump path, ret=%d\n", ret));
7987 goto exit;
7988 }
7989 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
7990
7991 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
7992 "sssr_dump_core_1_after_SR");
7993 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_1_AFTER_DUMP, memdump_path);
7994 if (unlikely(ret)) {
7995 WL_ERR(("Failed to nla put sssr core 1 after dump path, ret=%d\n", ret));
7996 goto exit;
7997 }
7998
7999 if (dhdp->sssr_d11_outofreset[2]) {
8000 #ifdef DHD_SSSR_DUMP_BEFORE_SR
8001 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
8002 "sssr_dump_core_2_before_SR");
8003 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_2_BEFORE_DUMP,
8004 memdump_path);
8005 if (unlikely(ret)) {
8006 WL_ERR(("Failed to nla put sssr core 2 before dump path, ret=%d\n",
8007 ret));
8008 goto exit;
8009 }
8010 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
8011
8012 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
8013 "sssr_dump_core_2_after_SR");
8014 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_CORE_2_AFTER_DUMP,
8015 memdump_path);
8016 if (unlikely(ret)) {
8017 WL_ERR(("Failed to nla put sssr core 2 after dump path, ret=%d\n",
8018 ret));
8019 goto exit;
8020 }
8021 }
8022
8023 #ifdef DHD_SSSR_DUMP_BEFORE_SR
8024 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
8025 "sssr_dump_dig_before_SR");
8026 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_DIG_BEFORE_DUMP, memdump_path);
8027 if (unlikely(ret)) {
8028 WL_ERR(("Failed to nla put sssr dig before dump path, ret=%d\n", ret));
8029 goto exit;
8030 }
8031 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
8032
8033 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN,
8034 "sssr_dump_dig_after_SR");
8035 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_SSSR_DIG_AFTER_DUMP, memdump_path);
8036 if (unlikely(ret)) {
8037 WL_ERR(("Failed to nla put sssr dig after dump path, ret=%d\n", ret));
8038 goto exit;
8039 }
8040
8041 #ifdef DHD_SSSR_DUMP
8042 memset(arr_len, 0, sizeof(arr_len));
8043 dhd_nla_put_sssr_dump_len(ndev, arr_len);
8044 #ifdef DHD_SSSR_DUMP_BEFORE_SR
8045 ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C0_D11_BEFORE, arr_len[0]);
8046 ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C1_D11_BEFORE, arr_len[2]);
8047 ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C2_D11_BEFORE, arr_len[4]);
8048 ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_DIG_BEFORE, arr_len[6]);
8049 #endif /* DHD_SSSR_DUMP_BEFORE_SR */
8050 ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C0_D11_AFTER, arr_len[1]);
8051 ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C1_D11_AFTER, arr_len[3]);
8052 ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_C2_D11_AFTER, arr_len[5]);
8053 ret |= nla_put_u32(skb, DUMP_LEN_ATTR_SSSR_DIG_AFTER, arr_len[7]);
8054 if (unlikely(ret)) {
8055 WL_ERR(("Failed to nla put sssr dump len, ret=%d\n", ret));
8056 goto exit;
8057 }
8058 #endif /* DHD_SSSR_DUMP */
8059
8060 exit:
8061 return ret;
8062 }
8063 #else
wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff * skb,struct net_device * ndev)8064 static int wl_cfgvendor_nla_put_sssr_dump_data(struct sk_buff *skb,
8065 struct net_device *ndev)
8066 {
8067 return BCME_OK;
8068 }
8069 #endif /* DHD_SSSR_DUMP */
8070
wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff * skb,struct net_device * ndev)8071 static int wl_cfgvendor_nla_put_debug_dump_data(struct sk_buff *skb,
8072 struct net_device *ndev)
8073 {
8074 int ret = BCME_OK;
8075 uint32 len = 0;
8076 char dump_path[128];
8077
8078 ret = dhd_get_debug_dump_file_name(ndev, NULL, dump_path, sizeof(dump_path));
8079 if (ret < 0) {
8080 WL_ERR(("%s: Failed to get debug dump filename\n", __FUNCTION__));
8081 goto exit;
8082 }
8083 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_DEBUG_DUMP, dump_path);
8084 if (unlikely(ret)) {
8085 WL_ERR(("Failed to nla put debug dump path, ret=%d\n", ret));
8086 goto exit;
8087 }
8088 WL_ERR(("debug_dump path = %s%s\n", dump_path, FILE_NAME_HAL_TAG));
8089 wl_print_verinfo(wl_get_cfg(ndev));
8090
8091 len = dhd_get_time_str_len();
8092 if (len) {
8093 ret = nla_put_u32(skb, DUMP_LEN_ATTR_TIMESTAMP, len);
8094 if (unlikely(ret)) {
8095 WL_ERR(("Failed to nla put time stamp length, ret=%d\n", ret));
8096 goto exit;
8097 }
8098 }
8099
8100 len = dhd_get_dld_len(DLD_BUF_TYPE_GENERAL);
8101 if (len) {
8102 ret = nla_put_u32(skb, DUMP_LEN_ATTR_GENERAL_LOG, len);
8103 if (unlikely(ret)) {
8104 WL_ERR(("Failed to nla put general log length, ret=%d\n", ret));
8105 goto exit;
8106 }
8107 }
8108 #ifdef EWP_ECNTRS_LOGGING
8109 len = dhd_get_ecntrs_len(ndev, NULL);
8110 if (len) {
8111 ret = nla_put_u32(skb, DUMP_LEN_ATTR_ECNTRS, len);
8112 if (unlikely(ret)) {
8113 WL_ERR(("Failed to nla put ecntrs length, ret=%d\n", ret));
8114 goto exit;
8115 }
8116 }
8117 #endif /* EWP_ECNTRS_LOGGING */
8118 len = dhd_get_dld_len(DLD_BUF_TYPE_SPECIAL);
8119 if (len) {
8120 ret = nla_put_u32(skb, DUMP_LEN_ATTR_SPECIAL_LOG, len);
8121 if (unlikely(ret)) {
8122 WL_ERR(("Failed to nla put special log length, ret=%d\n", ret));
8123 goto exit;
8124 }
8125 }
8126 len = dhd_get_dhd_dump_len(ndev, NULL);
8127 if (len) {
8128 ret = nla_put_u32(skb, DUMP_LEN_ATTR_DHD_DUMP, len);
8129 if (unlikely(ret)) {
8130 WL_ERR(("Failed to nla put dhd dump length, ret=%d\n", ret));
8131 goto exit;
8132 }
8133 }
8134
8135 #if defined(BCMPCIE)
8136 len = dhd_get_ext_trap_len(ndev, NULL);
8137 if (len) {
8138 ret = nla_put_u32(skb, DUMP_LEN_ATTR_EXT_TRAP, len);
8139 if (unlikely(ret)) {
8140 WL_ERR(("Failed to nla put ext trap length, ret=%d\n", ret));
8141 goto exit;
8142 }
8143 }
8144 #endif /* BCMPCIE */
8145
8146 #if defined(DHD_FW_COREDUMP) && defined(DNGL_EVENT_SUPPORT)
8147 len = dhd_get_health_chk_len(ndev, NULL);
8148 if (len) {
8149 ret = nla_put_u32(skb, DUMP_LEN_ATTR_HEALTH_CHK, len);
8150 if (unlikely(ret)) {
8151 WL_ERR(("Failed to nla put health check length, ret=%d\n", ret));
8152 goto exit;
8153 }
8154 }
8155 #endif
8156
8157 len = dhd_get_dld_len(DLD_BUF_TYPE_PRESERVE);
8158 if (len) {
8159 ret = nla_put_u32(skb, DUMP_LEN_ATTR_PRESERVE_LOG, len);
8160 if (unlikely(ret)) {
8161 WL_ERR(("Failed to nla put preserve log length, ret=%d\n", ret));
8162 goto exit;
8163 }
8164 }
8165
8166 len = dhd_get_cookie_log_len(ndev, NULL);
8167 if (len) {
8168 ret = nla_put_u32(skb, DUMP_LEN_ATTR_COOKIE, len);
8169 if (unlikely(ret)) {
8170 WL_ERR(("Failed to nla put cookie length, ret=%d\n", ret));
8171 goto exit;
8172 }
8173 }
8174 #ifdef DHD_DUMP_PCIE_RINGS
8175 len = dhd_get_flowring_len(ndev, NULL);
8176 if (len) {
8177 ret = nla_put_u32(skb, DUMP_LEN_ATTR_FLOWRING_DUMP, len);
8178 if (unlikely(ret)) {
8179 WL_ERR(("Failed to nla put flowring dump length, ret=%d\n", ret));
8180 goto exit;
8181 }
8182 }
8183 #endif
8184 #ifdef DHD_STATUS_LOGGING
8185 len = dhd_get_status_log_len(ndev, NULL);
8186 if (len) {
8187 ret = nla_put_u32(skb, DUMP_LEN_ATTR_STATUS_LOG, len);
8188 if (unlikely(ret)) {
8189 WL_ERR(("Failed to nla put status log length, ret=%d\n", ret));
8190 goto exit;
8191 }
8192 }
8193 #endif /* DHD_STATUS_LOGGING */
8194 #ifdef EWP_RTT_LOGGING
8195 len = dhd_get_rtt_len(ndev, NULL);
8196 if (len) {
8197 ret = nla_put_u32(skb, DUMP_LEN_ATTR_RTT_LOG, len);
8198 if (unlikely(ret)) {
8199 WL_ERR(("Failed to nla put rtt log length, ret=%d\n", ret));
8200 goto exit;
8201 }
8202 }
8203 #endif /* EWP_RTT_LOGGING */
8204 exit:
8205 return ret;
8206 }
8207 #ifdef DNGL_AXI_ERROR_LOGGING
wl_cfgvendor_nla_put_axi_error_data(struct sk_buff * skb,struct net_device * ndev)8208 static void wl_cfgvendor_nla_put_axi_error_data(struct sk_buff *skb,
8209 struct net_device *ndev)
8210 {
8211 int ret = 0;
8212 char axierrordump_path[MEMDUMP_PATH_LEN];
8213 int dumpsize = dhd_os_get_axi_error_dump_size(ndev);
8214 if (dumpsize <= 0) {
8215 WL_ERR(("Failed to calcuate axi error dump len\n"));
8216 return;
8217 }
8218 dhd_os_get_axi_error_filename(ndev, axierrordump_path, MEMDUMP_PATH_LEN);
8219 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_AXI_ERROR_DUMP, axierrordump_path);
8220 if (ret) {
8221 WL_ERR(("Failed to put filename\n"));
8222 return;
8223 }
8224 ret = nla_put_u32(skb, DUMP_LEN_ATTR_AXI_ERROR, dumpsize);
8225 if (ret) {
8226 WL_ERR(("Failed to put filesize\n"));
8227 return;
8228 }
8229 }
8230 #endif /* DNGL_AXI_ERROR_LOGGING */
8231 #ifdef DHD_PKT_LOGGING
wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff * skb,struct net_device * ndev,bool pktlogdbg)8232 static int wl_cfgvendor_nla_put_pktlogdump_data(struct sk_buff *skb,
8233 struct net_device *ndev, bool pktlogdbg)
8234 {
8235 int ret = BCME_OK;
8236 char pktlogdump_path[MEMDUMP_PATH_LEN];
8237 uint32 pktlog_dumpsize = dhd_os_get_pktlog_dump_size(ndev);
8238 if (pktlog_dumpsize == 0) {
8239 WL_ERR(("Failed to calcuate pktlog len\n"));
8240 return BCME_ERROR;
8241 }
8242
8243 dhd_os_get_pktlogdump_filename(ndev, pktlogdump_path, MEMDUMP_PATH_LEN);
8244
8245 if (pktlogdbg) {
8246 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_PKTLOG_DEBUG_DUMP, pktlogdump_path);
8247 if (ret) {
8248 WL_ERR(("Failed to put filename\n"));
8249 return ret;
8250 }
8251 ret = nla_put_u32(skb, DUMP_LEN_ATTR_PKTLOG_DEBUG, pktlog_dumpsize);
8252 if (ret) {
8253 WL_ERR(("Failed to put filesize\n"));
8254 return ret;
8255 }
8256 } else {
8257 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_PKTLOG_DUMP, pktlogdump_path);
8258 if (ret) {
8259 WL_ERR(("Failed to put filename\n"));
8260 return ret;
8261 }
8262 ret = nla_put_u32(skb, DUMP_LEN_ATTR_PKTLOG, pktlog_dumpsize);
8263 if (ret) {
8264 WL_ERR(("Failed to put filesize\n"));
8265 return ret;
8266 }
8267 }
8268 return ret;
8269 }
8270 #endif /* DHD_PKT_LOGGING */
8271
wl_cfgvendor_nla_put_memdump_data(struct sk_buff * skb,struct net_device * ndev,const uint32 fw_len)8272 static int wl_cfgvendor_nla_put_memdump_data(struct sk_buff *skb,
8273 struct net_device *ndev, const uint32 fw_len)
8274 {
8275 char memdump_path[MEMDUMP_PATH_LEN];
8276 int ret = BCME_OK;
8277
8278 dhd_get_memdump_filename(ndev, memdump_path, MEMDUMP_PATH_LEN, "mem_dump");
8279 ret = nla_put_string(skb, DUMP_FILENAME_ATTR_MEM_DUMP, memdump_path);
8280 if (unlikely(ret)) {
8281 WL_ERR(("Failed to nla put mem dump path, ret=%d\n", ret));
8282 goto exit;
8283 }
8284 ret = nla_put_u32(skb, DUMP_LEN_ATTR_MEMDUMP, fw_len);
8285 if (unlikely(ret)) {
8286 WL_ERR(("Failed to nla put mem dump length, ret=%d\n", ret));
8287 goto exit;
8288 }
8289
8290 exit:
8291 return ret;
8292 }
8293
wl_cfgvendor_nla_put_dump_data(dhd_pub_t * dhd_pub,struct sk_buff * skb,struct net_device * ndev,const uint32 fw_len)8294 static int wl_cfgvendor_nla_put_dump_data(dhd_pub_t *dhd_pub, struct sk_buff *skb,
8295 struct net_device *ndev, const uint32 fw_len)
8296 {
8297 int ret = BCME_OK;
8298
8299 #ifdef DNGL_AXI_ERROR_LOGGING
8300 if (dhd_pub->smmu_fault_occurred) {
8301 wl_cfgvendor_nla_put_axi_error_data(skb, ndev);
8302 }
8303 #endif /* DNGL_AXI_ERROR_LOGGING */
8304 if (dhd_pub->memdump_enabled || (dhd_pub->memdump_type == DUMP_TYPE_BY_SYSDUMP)) {
8305 if (((ret = wl_cfgvendor_nla_put_debug_dump_data(skb, ndev)) < 0) ||
8306 ((ret = wl_cfgvendor_nla_put_memdump_data(skb, ndev, fw_len)) < 0) ||
8307 ((ret = wl_cfgvendor_nla_put_sssr_dump_data(skb, ndev)) < 0)) {
8308 goto done;
8309 }
8310 #ifdef DHD_PKT_LOGGING
8311 if ((ret = wl_cfgvendor_nla_put_pktlogdump_data(skb, ndev, FALSE)) < 0) {
8312 goto done;
8313 }
8314 #endif /* DHD_PKT_LOGGING */
8315 }
8316 done:
8317 return ret;
8318 }
8319
wl_cfgvendor_dbg_send_file_dump_evt(void * ctx,const void * data,const uint32 len,const uint32 fw_len)8320 static void wl_cfgvendor_dbg_send_file_dump_evt(void *ctx, const void *data,
8321 const uint32 len, const uint32 fw_len)
8322 {
8323 struct net_device *ndev = ctx;
8324 struct wiphy *wiphy;
8325 gfp_t kflags;
8326 struct sk_buff *skb = NULL;
8327 struct bcm_cfg80211 *cfg;
8328 dhd_pub_t *dhd_pub;
8329 int ret = BCME_OK;
8330
8331 if (!ndev) {
8332 WL_ERR(("ndev is NULL\n"));
8333 return;
8334 }
8335
8336 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
8337 wiphy = ndev->ieee80211_ptr->wiphy;
8338 /* Alloc the SKB for vendor_event */
8339 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
8340 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
8341 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + CFG80211_VENDOR_EVT_SKB_SZ,
8342 GOOGLE_FILE_DUMP_EVENT, kflags);
8343 #else
8344 skb = cfg80211_vendor_event_alloc(wiphy, len + CFG80211_VENDOR_EVT_SKB_SZ,
8345 GOOGLE_FILE_DUMP_EVENT, kflags);
8346 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
8347 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
8348 if (!skb) {
8349 WL_ERR(("skb alloc failed"));
8350 return;
8351 }
8352
8353 cfg = wiphy_priv(wiphy);
8354 dhd_pub = cfg->pub;
8355
8356 #ifdef DHD_PKT_LOGGING
8357 if (dhd_pub->pktlog_debug) {
8358 if ((ret = wl_cfgvendor_nla_put_pktlogdump_data(skb, ndev, TRUE)) < 0) {
8359 WL_ERR(("nla put failed\n"));
8360 goto done;
8361 }
8362 dhd_pub->pktlog_debug = FALSE;
8363 } else
8364 #endif /* DHD_PKT_LOGGING */
8365 {
8366 if ((ret = wl_cfgvendor_nla_put_dump_data(dhd_pub, skb, ndev, fw_len)) < 0) {
8367 WL_ERR(("nla put failed\n"));
8368 goto done;
8369 }
8370 }
8371 /* TODO : Similar to above function add for debug_dump, sssr_dump, and pktlog also. */
8372 cfg80211_vendor_event(skb, kflags);
8373 return;
8374 done:
8375 if (skb) {
8376 dev_kfree_skb_any(skb);
8377 }
8378 }
8379 #endif /* DHD_LOG_DUMP */
8380
wl_cfgvendor_dbg_get_version(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8381 static int wl_cfgvendor_dbg_get_version(struct wiphy *wiphy,
8382 struct wireless_dev *wdev, const void *data, int len)
8383 {
8384 int ret = BCME_OK, rem, type;
8385 int buf_len = 1024;
8386 bool dhd_ver = FALSE;
8387 char *buf_ptr, *ver, *p;
8388 const struct nlattr *iter;
8389 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8390
8391 buf_ptr = (char *)MALLOCZ(cfg->osh, buf_len);
8392 if (!buf_ptr) {
8393 WL_ERR(("failed to allocate the buffer for version n"));
8394 ret = BCME_NOMEM;
8395 goto exit;
8396 }
8397 nla_for_each_attr(iter, data, len, rem) {
8398 type = nla_type(iter);
8399 switch (type) {
8400 case DEBUG_ATTRIBUTE_GET_DRIVER:
8401 dhd_ver = TRUE;
8402 break;
8403 case DEBUG_ATTRIBUTE_GET_FW:
8404 dhd_ver = FALSE;
8405 break;
8406 default:
8407 WL_ERR(("Unknown type: %d\n", type));
8408 ret = BCME_ERROR;
8409 goto exit;
8410 }
8411 }
8412 ret = dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg), dhd_ver, &buf_ptr, buf_len);
8413 if (ret < 0) {
8414 WL_ERR(("failed to get the version %d\n", ret));
8415 goto exit;
8416 }
8417 ver = strstr(buf_ptr, "version ");
8418 if (!ver) {
8419 WL_ERR(("failed to locate the version\n"));
8420 goto exit;
8421 }
8422 ver += strlen("version ");
8423 /* Adjust version format to fit in android sys property */
8424 for (p = ver; (*p != ' ') && (*p != '\n') && (*p != 0); p++) {
8425 ;
8426 }
8427 ret = wl_cfgvendor_send_cmd_reply(wiphy, ver, p - ver);
8428 exit:
8429 MFREE(cfg->osh, buf_ptr, buf_len);
8430 return ret;
8431 }
8432
8433 #ifdef DBG_PKT_MON
wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8434 static int wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy *wiphy,
8435 struct wireless_dev *wdev, const void *data, int len)
8436 {
8437 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8438 dhd_pub_t *dhd_pub = cfg->pub;
8439 int ret;
8440
8441 ret = dhd_os_dbg_attach_pkt_monitor(dhd_pub);
8442 if (unlikely(ret)) {
8443 WL_ERR(("failed to start pkt fate monitoring, ret=%d", ret));
8444 }
8445
8446 return ret;
8447 }
8448
8449 typedef int (*dbg_mon_get_pkts_t) (dhd_pub_t *dhdp, void __user *user_buf,
8450 uint16 req_count, uint16 *resp_count);
8451
__wl_cfgvendor_dbg_get_pkt_fates(struct wiphy * wiphy,const void * data,int len,dbg_mon_get_pkts_t dbg_mon_get_pkts)8452 static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy *wiphy,
8453 const void *data, int len, dbg_mon_get_pkts_t dbg_mon_get_pkts)
8454 {
8455 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8456 dhd_pub_t *dhd_pub = cfg->pub;
8457 struct sk_buff *skb = NULL;
8458 const struct nlattr *iter;
8459 void __user *user_buf = NULL;
8460 uint16 req_count = 0, resp_count = 0;
8461 int ret, tmp, type, mem_needed;
8462
8463 nla_for_each_attr(iter, data, len, tmp) {
8464 type = nla_type(iter);
8465 switch (type) {
8466 case DEBUG_ATTRIBUTE_PKT_FATE_NUM:
8467 req_count = nla_get_u32(iter);
8468 break;
8469 case DEBUG_ATTRIBUTE_PKT_FATE_DATA:
8470 user_buf = (void __user *)(unsigned long) nla_get_u64(iter);
8471 break;
8472 default:
8473 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
8474 ret = -EINVAL;
8475 goto exit;
8476 }
8477 }
8478
8479 if (!req_count || !user_buf) {
8480 WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n",
8481 __FUNCTION__, user_buf, req_count));
8482 ret = -EINVAL;
8483 goto exit;
8484 }
8485
8486 ret = dbg_mon_get_pkts(dhd_pub, user_buf, req_count, &resp_count);
8487 if (unlikely(ret)) {
8488 WL_ERR(("failed to get packets, ret:%d \n", ret));
8489 goto exit;
8490 }
8491
8492 mem_needed = VENDOR_REPLY_OVERHEAD + ATTRIBUTE_U32_LEN;
8493 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
8494 if (unlikely(!skb)) {
8495 WL_ERR(("skb alloc failed"));
8496 ret = -ENOMEM;
8497 goto exit;
8498 }
8499
8500 ret = nla_put_u32(skb, DEBUG_ATTRIBUTE_PKT_FATE_NUM, resp_count);
8501 if (ret < 0) {
8502 WL_ERR(("Failed to put DEBUG_ATTRIBUTE_PKT_FATE_NUM, ret:%d\n", ret));
8503 goto exit;
8504 }
8505
8506 ret = cfg80211_vendor_cmd_reply(skb);
8507 if (unlikely(ret)) {
8508 WL_ERR(("vendor Command reply failed ret:%d \n", ret));
8509 }
8510 return ret;
8511
8512 exit:
8513 /* Free skb memory */
8514 if (skb) {
8515 kfree_skb(skb);
8516 }
8517 return ret;
8518 }
8519
wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8520 static int wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy *wiphy,
8521 struct wireless_dev *wdev, const void *data, int len)
8522 {
8523 int ret;
8524
8525 ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
8526 dhd_os_dbg_monitor_get_tx_pkts);
8527 if (unlikely(ret)) {
8528 WL_ERR(("failed to get tx packets, ret:%d \n", ret));
8529 }
8530
8531 return ret;
8532 }
8533
wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8534 static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy *wiphy,
8535 struct wireless_dev *wdev, const void *data, int len)
8536 {
8537 int ret;
8538
8539 ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
8540 dhd_os_dbg_monitor_get_rx_pkts);
8541 if (unlikely(ret)) {
8542 WL_ERR(("failed to get rx packets, ret:%d \n", ret));
8543 }
8544
8545 return ret;
8546 }
8547 #endif /* DBG_PKT_MON */
8548
8549 #ifdef KEEP_ALIVE
8550 /* max size of IP packet for keep alive */
8551 #define MKEEP_ALIVE_IP_PKT_MAX 256
8552
wl_cfgvendor_start_mkeep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8553 static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
8554 const void *data, int len)
8555 {
8556 int ret = BCME_OK, rem, type;
8557 uint8 mkeep_alive_id = 0;
8558 uint8 *ip_pkt = NULL;
8559 uint16 ip_pkt_len = 0;
8560 uint16 ether_type = ETHERTYPE_IP;
8561 uint8 src_mac[ETHER_ADDR_LEN];
8562 uint8 dst_mac[ETHER_ADDR_LEN];
8563 uint32 period_msec = 0;
8564 const struct nlattr *iter;
8565 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8566
8567 nla_for_each_attr(iter, data, len, rem) {
8568 type = nla_type(iter);
8569 switch (type) {
8570 case MKEEP_ALIVE_ATTRIBUTE_ID:
8571 mkeep_alive_id = nla_get_u8(iter);
8572 break;
8573 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
8574 ip_pkt_len = nla_get_u16(iter);
8575 if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
8576 ret = BCME_BADARG;
8577 goto exit;
8578 }
8579 break;
8580 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
8581 if (ip_pkt) {
8582 ret = BCME_BADARG;
8583 WL_ERR(("ip_pkt already allocated\n"));
8584 goto exit;
8585 }
8586 if (!ip_pkt_len) {
8587 ret = BCME_BADARG;
8588 WL_ERR(("ip packet length is 0\n"));
8589 goto exit;
8590 }
8591 ip_pkt = (u8 *)MALLOCZ(cfg->osh, ip_pkt_len);
8592 if (ip_pkt == NULL) {
8593 ret = BCME_NOMEM;
8594 WL_ERR(("Failed to allocate mem for ip packet\n"));
8595 goto exit;
8596 }
8597 memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len);
8598 break;
8599 case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
8600 memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN);
8601 break;
8602 case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
8603 memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN);
8604 break;
8605 case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
8606 period_msec = nla_get_u32(iter);
8607 break;
8608 case MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE:
8609 ether_type = nla_get_u16(iter);
8610 if (!((ether_type == ETHERTYPE_IP) ||
8611 (ether_type == ETHERTYPE_IPV6))) {
8612 WL_ERR(("Invalid ether type, %2x\n", ether_type));
8613 ret = BCME_BADARG;
8614 goto exit;
8615 }
8616 break;
8617 default:
8618 WL_ERR(("Unknown type: %d\n", type));
8619 ret = BCME_BADARG;
8620 goto exit;
8621 }
8622 }
8623
8624 if (ip_pkt == NULL) {
8625 ret = BCME_BADARG;
8626 WL_ERR(("ip packet is NULL\n"));
8627 goto exit;
8628 }
8629
8630 ret = wl_cfg80211_start_mkeep_alive(cfg, mkeep_alive_id,
8631 ether_type, ip_pkt, ip_pkt_len, src_mac, dst_mac, period_msec);
8632 if (ret < 0) {
8633 WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret));
8634 }
8635
8636 exit:
8637 if (ip_pkt) {
8638 MFREE(cfg->osh, ip_pkt, ip_pkt_len);
8639 }
8640
8641 return ret;
8642 }
8643
wl_cfgvendor_stop_mkeep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8644 static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
8645 const void *data, int len)
8646 {
8647 int ret = BCME_OK, rem, type;
8648 uint8 mkeep_alive_id = 0;
8649 const struct nlattr *iter;
8650 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8651
8652 nla_for_each_attr(iter, data, len, rem) {
8653 type = nla_type(iter);
8654 switch (type) {
8655 case MKEEP_ALIVE_ATTRIBUTE_ID:
8656 mkeep_alive_id = nla_get_u8(iter);
8657 break;
8658 default:
8659 WL_ERR(("Unknown type: %d\n", type));
8660 ret = BCME_BADARG;
8661 break;
8662 }
8663 }
8664
8665 ret = wl_cfg80211_stop_mkeep_alive(cfg, mkeep_alive_id);
8666 if (ret < 0) {
8667 WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret));
8668 }
8669
8670 return ret;
8671 }
8672 #endif /* KEEP_ALIVE */
8673
8674 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
8675 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
8676 const struct nla_policy apf_atrribute_policy[APF_ATTRIBUTE_MAX] = {
8677 [APF_ATTRIBUTE_VERSION] = { .type = NLA_U32 },
8678 [APF_ATTRIBUTE_MAX_LEN] = { .type = NLA_U32 },
8679 [APF_ATTRIBUTE_PROGRAM] = { .type = NLA_BINARY },
8680 [APF_ATTRIBUTE_PROGRAM_LEN] = { .type = NLA_U32 },
8681 };
8682 #endif /* LINUX_VERSION >= 5.3 */
8683
8684 static int
wl_cfgvendor_apf_get_capabilities(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8685 wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy,
8686 struct wireless_dev *wdev, const void *data, int len)
8687 {
8688 struct net_device *ndev = wdev_to_ndev(wdev);
8689 struct sk_buff *skb = NULL;
8690 int ret, ver, max_len, mem_needed;
8691
8692 /* APF version */
8693 ver = 0;
8694 ret = dhd_dev_apf_get_version(ndev, &ver);
8695 if (unlikely(ret)) {
8696 WL_ERR(("APF get version failed, ret=%d\n", ret));
8697 return ret;
8698 }
8699
8700 /* APF memory size limit */
8701 max_len = 0;
8702 ret = dhd_dev_apf_get_max_len(ndev, &max_len);
8703 if (unlikely(ret)) {
8704 WL_ERR(("APF get maximum length failed, ret=%d\n", ret));
8705 return ret;
8706 }
8707
8708 mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
8709
8710 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
8711 if (unlikely(!skb)) {
8712 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
8713 return -ENOMEM;
8714 }
8715
8716 ret = nla_put_u32(skb, APF_ATTRIBUTE_VERSION, ver);
8717 if (ret < 0) {
8718 WL_ERR(("Failed to put APF_ATTRIBUTE_VERSION, ret:%d\n", ret));
8719 goto exit;
8720 }
8721 ret = nla_put_u32(skb, APF_ATTRIBUTE_MAX_LEN, max_len);
8722 if (ret < 0) {
8723 WL_ERR(("Failed to put APF_ATTRIBUTE_MAX_LEN, ret:%d\n", ret));
8724 goto exit;
8725 }
8726
8727 ret = cfg80211_vendor_cmd_reply(skb);
8728 if (unlikely(ret)) {
8729 WL_ERR(("vendor command reply failed, ret=%d\n", ret));
8730 }
8731 return ret;
8732 exit:
8733 /* Free skb memory */
8734 kfree_skb(skb);
8735 return ret;
8736 }
8737
8738 static int
wl_cfgvendor_apf_set_filter(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8739 wl_cfgvendor_apf_set_filter(struct wiphy *wiphy,
8740 struct wireless_dev *wdev, const void *data, int len)
8741 {
8742 struct net_device *ndev = wdev_to_ndev(wdev);
8743 const struct nlattr *iter;
8744 u8 *program = NULL;
8745 u32 program_len = 0;
8746 int ret, tmp, type;
8747 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8748
8749 if (len <= 0) {
8750 WL_ERR(("Invalid len: %d\n", len));
8751 ret = -EINVAL;
8752 goto exit;
8753 }
8754 nla_for_each_attr(iter, data, len, tmp) {
8755 type = nla_type(iter);
8756 switch (type) {
8757 case APF_ATTRIBUTE_PROGRAM_LEN:
8758 /* check if the iter value is valid and program_len
8759 * is not already initialized.
8760 */
8761 if (nla_len(iter) == sizeof(uint32) && !program_len) {
8762 program_len = nla_get_u32(iter);
8763 } else {
8764 ret = -EINVAL;
8765 goto exit;
8766 }
8767
8768 if (program_len > WL_APF_PROGRAM_MAX_SIZE) {
8769 WL_ERR(("program len is more than expected len\n"));
8770 ret = -EINVAL;
8771 goto exit;
8772 }
8773
8774 if (unlikely(!program_len)) {
8775 WL_ERR(("zero program length\n"));
8776 ret = -EINVAL;
8777 goto exit;
8778 }
8779 break;
8780 case APF_ATTRIBUTE_PROGRAM:
8781 if (unlikely(program)) {
8782 WL_ERR(("program already allocated\n"));
8783 ret = -EINVAL;
8784 goto exit;
8785 }
8786 if (unlikely(!program_len)) {
8787 WL_ERR(("program len is not set\n"));
8788 ret = -EINVAL;
8789 goto exit;
8790 }
8791 if (nla_len(iter) != program_len) {
8792 WL_ERR(("program_len is not same\n"));
8793 ret = -EINVAL;
8794 goto exit;
8795 }
8796 program = MALLOCZ(cfg->osh, program_len);
8797 if (unlikely(!program)) {
8798 WL_ERR(("%s: can't allocate %d bytes\n",
8799 __FUNCTION__, program_len));
8800 ret = -ENOMEM;
8801 goto exit;
8802 }
8803 memcpy(program, (u8*)nla_data(iter), program_len);
8804 break;
8805 default:
8806 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
8807 ret = -EINVAL;
8808 goto exit;
8809 }
8810 }
8811
8812 ret = dhd_dev_apf_add_filter(ndev, program, program_len);
8813
8814 exit:
8815 if (program) {
8816 MFREE(cfg->osh, program, program_len);
8817 }
8818 return ret;
8819 }
8820 #endif /* PKT_FILTER_SUPPORT && APF */
8821
8822 #ifdef NDO_CONFIG_SUPPORT
wl_cfgvendor_configure_nd_offload(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8823 static int wl_cfgvendor_configure_nd_offload(struct wiphy *wiphy,
8824 struct wireless_dev *wdev, const void *data, int len)
8825 {
8826 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8827 const struct nlattr *iter;
8828 int ret = BCME_OK, rem, type;
8829 u8 enable = 0;
8830
8831 nla_for_each_attr(iter, data, len, rem) {
8832 type = nla_type(iter);
8833 switch (type) {
8834 case ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE:
8835 enable = nla_get_u8(iter);
8836 break;
8837 default:
8838 WL_ERR(("Unknown type: %d\n", type));
8839 ret = BCME_BADARG;
8840 goto exit;
8841 }
8842 }
8843
8844 ret = dhd_dev_ndo_cfg(bcmcfg_to_prmry_ndev(cfg), enable);
8845 if (ret < 0) {
8846 WL_ERR(("dhd_dev_ndo_cfg() failed: %d\n", ret));
8847 }
8848
8849 exit:
8850 return ret;
8851 }
8852 #endif /* NDO_CONFIG_SUPPORT */
8853
8854 #if !defined(BCMSUP_4WAY_HANDSHAKE) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
wl_cfgvendor_set_pmk(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8855 static int wl_cfgvendor_set_pmk(struct wiphy *wiphy,
8856 struct wireless_dev *wdev, const void *data, int len)
8857 {
8858 int ret = 0;
8859 wsec_pmk_t pmk;
8860 const struct nlattr *iter;
8861 int rem, type;
8862 struct net_device *ndev = wdev_to_ndev(wdev);
8863 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8864 struct wl_security *sec;
8865
8866 bzero(&pmk, sizeof(pmk));
8867 nla_for_each_attr(iter, data, len, rem) {
8868 type = nla_type(iter);
8869 switch (type) {
8870 case BRCM_ATTR_DRIVER_KEY_PMK:
8871 pmk.flags = 0;
8872 pmk.key_len = htod16(nla_len(iter));
8873 ret = memcpy_s(pmk.key, sizeof(pmk.key),
8874 (uint8 *)nla_data(iter), nla_len(iter));
8875 if (ret) {
8876 WL_ERR(("Failed to copy pmk: %d\n", ret));
8877 ret = -EINVAL;
8878 goto exit;
8879 }
8880 break;
8881 default:
8882 WL_ERR(("Unknown type: %d\n", type));
8883 ret = BCME_BADARG;
8884 goto exit;
8885 }
8886 }
8887
8888 sec = wl_read_prof(cfg, ndev, WL_PROF_SEC);
8889 if ((sec->wpa_auth == WLAN_AKM_SUITE_8021X) ||
8890 (sec->wpa_auth == WL_AKM_SUITE_SHA256_1X)) {
8891 ret = wldev_iovar_setbuf(ndev, "okc_info_pmk", pmk.key, pmk.key_len, cfg->ioctl_buf,
8892 WLC_IOCTL_SMLEN, &cfg->ioctl_buf_sync);
8893 if (ret) {
8894 /* could fail in case that 'okc' is not supported */
8895 WL_INFORM_MEM(("okc_info_pmk failed, err=%d (ignore)\n", ret));
8896 }
8897 }
8898
8899 ret = wldev_ioctl_set(ndev, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
8900 WL_INFORM_MEM(("IOVAR set_pmk ret:%d", ret));
8901 exit:
8902 return ret;
8903 }
8904 #endif /* !BCMSUP_4WAY_HANDSHAKE || LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
8905
wl_cfgvendor_get_driver_feature(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8906 static int wl_cfgvendor_get_driver_feature(struct wiphy *wiphy,
8907 struct wireless_dev *wdev, const void *data, int len)
8908 {
8909 int ret = BCME_OK;
8910 u8 supported[(BRCM_WLAN_VENDOR_FEATURES_MAX / 8) + 1] = {0};
8911 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8912 dhd_pub_t *dhd_pub = cfg->pub;
8913 struct sk_buff *skb;
8914 int32 mem_needed;
8915
8916 mem_needed = VENDOR_REPLY_OVERHEAD + NLA_HDRLEN + sizeof(supported);
8917
8918 BCM_REFERENCE(dhd_pub);
8919
8920 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
8921 if (FW_SUPPORTED(dhd_pub, idsup)) {
8922 ret = wl_features_set(supported, sizeof(supported),
8923 BRCM_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD);
8924 }
8925 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
8926
8927 /* Alloc the SKB for vendor_event */
8928 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
8929 if (unlikely(!skb)) {
8930 WL_ERR(("skb alloc failed"));
8931 ret = BCME_NOMEM;
8932 goto exit;
8933 }
8934
8935 ret = nla_put(skb, BRCM_ATTR_DRIVER_FEATURE_FLAGS, sizeof(supported), supported);
8936 if (ret) {
8937 kfree_skb(skb);
8938 goto exit;
8939 }
8940 ret = cfg80211_vendor_cmd_reply(skb);
8941 exit:
8942 return ret;
8943 }
8944
8945 #ifdef WL_P2P_RAND
8946 static int
wl_cfgvendor_set_p2p_rand_mac(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)8947 wl_cfgvendor_set_p2p_rand_mac(struct wiphy *wiphy,
8948 struct wireless_dev *wdev, const void *data, int len)
8949 {
8950 int err = 0;
8951 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
8952 int type;
8953 WL_DBG(("%s, wdev->iftype = %d\n", __FUNCTION__, wdev->iftype));
8954 WL_INFORM_MEM(("randomized p2p_dev_addr - "MACDBG"\n", MAC2STRDBG(nla_data(data))));
8955
8956 BCM_REFERENCE(cfg);
8957
8958 type = nla_type(data);
8959
8960 if (type == BRCM_ATTR_DRIVER_RAND_MAC) {
8961 if (nla_len(data) != ETHER_ADDR_LEN) {
8962 WL_ERR(("nla_len not matched.\n"));
8963 err = -EINVAL;
8964 goto exit;
8965 }
8966
8967 if (wdev->iftype != NL80211_IFTYPE_P2P_DEVICE) {
8968 WL_ERR(("wrong interface type , wdev->iftype=%d\n", wdev->iftype));
8969 err = -EINVAL;
8970 goto exit;
8971 }
8972 (void)memcpy_s(wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE), ETHER_ADDR_LEN,
8973 nla_data(data), ETHER_ADDR_LEN);
8974 (void)memcpy_s(wdev->address, ETHER_ADDR_LEN, nla_data(data), ETHER_ADDR_LEN);
8975
8976 err = wl_cfgp2p_disable_discovery(cfg);
8977 if (unlikely(err < 0)) {
8978 WL_ERR(("P2P disable discovery failed, ret=%d\n", err));
8979 goto exit;
8980 }
8981
8982 err = wl_cfgp2p_set_firm_p2p(cfg);
8983 if (unlikely(err < 0)) {
8984 WL_ERR(("Set P2P address in firmware failed, ret=%d\n", err));
8985 goto exit;
8986 }
8987
8988 err = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0);
8989 if (unlikely(err < 0)) {
8990 WL_ERR(("P2P enable discovery failed, ret=%d\n", err));
8991 goto exit;
8992 }
8993 } else {
8994 WL_ERR(("unexpected attrib type:%d\n", type));
8995 err = -EINVAL;
8996 }
8997 exit:
8998 return err;
8999 }
9000 #endif /* WL_P2P_RAND */
9001
9002 #ifdef WL_SAR_TX_POWER
9003 static int
wl_cfgvendor_tx_power_scenario(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9004 wl_cfgvendor_tx_power_scenario(struct wiphy *wiphy,
9005 struct wireless_dev *wdev, const void *data, int len)
9006 {
9007 int err = BCME_ERROR, rem, type;
9008 struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev));
9009 const struct nlattr *iter;
9010 wifi_power_scenario sar_tx_power_val = WIFI_POWER_SCENARIO_INVALID;
9011 wl_sar_modes_t wifi_tx_power_mode = 0;
9012
9013 nla_for_each_attr(iter, data, len, rem) {
9014 type = nla_type(iter);
9015 if (type == ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO) {
9016 sar_tx_power_val = nla_get_s8(iter);
9017 } else {
9018 WL_ERR(("Unknown attr type: %d\n", type));
9019 err = -EINVAL;
9020 goto exit;
9021 }
9022 }
9023 /* If sar tx power is already configured, no need to set it again */
9024 if (cfg->wifi_tx_power_mode == sar_tx_power_val) {
9025 WL_INFORM_MEM(("%s, tx_power_mode %d is already set\n",
9026 __FUNCTION__, sar_tx_power_val));
9027 err = BCME_OK;
9028 goto exit;
9029 }
9030
9031 /* Map Android TX power modes to Brcm power mode */
9032 switch (sar_tx_power_val) {
9033 case WIFI_POWER_SCENARIO_VOICE_CALL:
9034 case WIFI_POWER_SCENARIO_DEFAULT:
9035 wifi_tx_power_mode = HEAD_SAR_BACKOFF_ENABLE;
9036 break;
9037 case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF:
9038 wifi_tx_power_mode = GRIP_SAR_BACKOFF_DISABLE;
9039 break;
9040 case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF:
9041 wifi_tx_power_mode = GRIP_SAR_BACKOFF_ENABLE;
9042 break;
9043 case WIFI_POWER_SCENARIO_ON_BODY_BT:
9044 wifi_tx_power_mode = NR_mmWave_SAR_BACKOFF_ENABLE;
9045 break;
9046 case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON:
9047 wifi_tx_power_mode = NR_Sub6_SAR_BACKOFF_DISABLE;
9048 break;
9049 case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON:
9050 wifi_tx_power_mode = NR_Sub6_SAR_BACKOFF_ENABLE;
9051 break;
9052 default:
9053 WL_ERR(("invalid wifi tx power scenario = %d\n",
9054 sar_tx_power_val));
9055 err = -EINVAL;
9056 goto exit;
9057 }
9058
9059 WL_DBG(("%s, tx_power_mode %d\n", __FUNCTION__, wifi_tx_power_mode));
9060 err = wldev_iovar_setint(wdev_to_ndev(wdev), "sar_enable", wifi_tx_power_mode);
9061 if (unlikely(err)) {
9062 WL_ERR(("%s: Failed to set sar_enable - error (%d)\n", __FUNCTION__, err));
9063 goto exit;
9064 }
9065 /* Cache the tx power mode sent by the hal */
9066 cfg->wifi_tx_power_mode = sar_tx_power_val;
9067 exit:
9068 return err;
9069 }
9070 #endif /* WL_SAR_TX_POWER */
9071
9072 #if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
9073 static int
wl_cfgvendor_twt_setup(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9074 wl_cfgvendor_twt_setup(struct wiphy *wiphy,
9075 struct wireless_dev *wdev, const void *data, int len)
9076 {
9077 wl_twt_config_t val;
9078 s32 bw;
9079 s32 type, rem_attr;
9080 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
9081 u8 resp_buf[WLC_IOCTL_SMLEN] = {0};
9082 const struct nlattr *iter;
9083 uint8 *rem = mybuf;
9084 uint16 rem_len = sizeof(mybuf);
9085
9086 bzero(&val, sizeof(val));
9087 val.version = WL_TWT_SETUP_VER;
9088 val.length = sizeof(val.version) + sizeof(val.length);
9089
9090 /* Default values, Override Below */
9091 val.desc.flow_flags = 0;
9092 val.desc.wake_time_h = 0xFFFFFFFF;
9093 val.desc.wake_time_l = 0xFFFFFFFF;
9094 val.desc.wake_int_min = 0xFFFFFFFF;
9095 val.desc.wake_int_max = 0xFFFFFFFF;
9096 val.desc.wake_dur_min = 0xFFFFFFFF;
9097 val.desc.wake_dur_max = 0xFFFFFFFF;
9098 val.desc.avg_pkt_num = 0xFFFFFFFF;
9099 val.desc.avg_pkt_size = 0xFFFFFFFF;
9100
9101 nla_for_each_attr(iter, data, len, rem_attr) {
9102 type = nla_type(iter);
9103 switch (type) {
9104 case ANDR_TWT_ATTR_CONFIG_ID:
9105 /* Config ID */
9106 val.desc.configID = nla_get_u8(iter);
9107 break;
9108 case ANDR_TWT_ATTR_NEGOTIATION_TYPE:
9109 /* negotiation_type */
9110 val.desc.negotiation_type = nla_get_u8(iter);
9111 break;
9112 case ANDR_TWT_ATTR_TRIGGER_TYPE:
9113 /* Trigger Type */
9114 if (nla_get_u8(iter) == 1) {
9115 val.desc.flow_flags |= WL_TWT_FLOW_FLAG_TRIGGER;
9116 }
9117 break;
9118 case ANDR_TWT_ATTR_WAKE_DURATION:
9119 /* Wake Duration */
9120 val.desc.wake_dur = nla_get_u32(iter);
9121 break;
9122 case ANDR_TWT_ATTR_WAKE_INTERVAL:
9123 /* Wake interval */
9124 val.desc.wake_int = nla_get_u32(iter);
9125 break;
9126 case ANDR_TWT_ATTR_WAKETIME_OFFSET:
9127 /* Wake Time parameter */
9128 val.desc.wake_time_h = 0;
9129 val.desc.wake_time_l = nla_get_u32(iter);
9130 break;
9131 case ANDR_TWT_ATTR_WAKE_INTERVAL_MIN:
9132 /* Minimum allowed Wake interval */
9133 val.desc.wake_int_min = nla_get_u32(iter);
9134 break;
9135 case ANDR_TWT_ATTR_WAKE_INTERVAL_MAX:
9136 /* Max Allowed Wake interval */
9137 val.desc.wake_int_max = nla_get_u32(iter);
9138 break;
9139 case ANDR_TWT_ATTR_WAKE_DURATION_MIN:
9140 /* Minimum allowed Wake duration */
9141 val.desc.wake_dur_min = nla_get_u32(iter);
9142 break;
9143 case ANDR_TWT_ATTR_WAKE_DURATION_MAX:
9144 /* Maximum allowed Wake duration */
9145 val.desc.wake_dur_max = nla_get_u32(iter);
9146 break;
9147 case ANDR_TWT_ATTR_AVG_PKT_NUM:
9148 /* Average number of packets */
9149 val.desc.avg_pkt_num = nla_get_u32(iter);
9150 break;
9151 case ANDR_TWT_ATTR_AVG_PKT_SIZE:
9152 /* Average packets size */
9153 val.desc.avg_pkt_size = nla_get_u32(iter);
9154 break;
9155 default:
9156 WL_ERR(("Invalid setup attribute type %d\n", type));
9157 break;
9158 }
9159 }
9160
9161 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_CONFIG,
9162 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
9163 if (bw != BCME_OK) {
9164 goto exit;
9165 }
9166
9167 bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
9168 mybuf, sizeof(mybuf) - rem_len, resp_buf, WLC_IOCTL_SMLEN, NULL);
9169 if (bw < 0) {
9170 WL_ERR(("twt config set failed. ret:%d\n", bw));
9171 } else {
9172 WL_INFORM(("twt config setup succeeded, config ID %d "
9173 "Negotiation type %d flow flags %d\n", val.desc.configID,
9174 val.desc.negotiation_type, val.desc.flow_flags));
9175 }
9176
9177 exit:
9178 return bw;
9179 }
9180
9181 static int
wl_cfgvendor_twt_teardown(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9182 wl_cfgvendor_twt_teardown(struct wiphy *wiphy,
9183 struct wireless_dev *wdev, const void *data, int len)
9184 {
9185 wl_twt_teardown_t val;
9186 s32 bw;
9187 s32 type, rem_attr;
9188 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
9189 u8 res_buf[WLC_IOCTL_SMLEN] = {0};
9190 const struct nlattr *iter;
9191 uint8 *rem = mybuf;
9192 uint16 rem_len = sizeof(mybuf);
9193
9194 bzero(&val, sizeof(val));
9195 val.version = WL_TWT_TEARDOWN_VER;
9196 val.length = sizeof(val.version) + sizeof(val.length);
9197
9198 /* Default values, Override Below */
9199 val.teardesc.flow_id = 0xFF;
9200 val.teardesc.bid = 0xFF;
9201
9202 nla_for_each_attr(iter, data, len, rem_attr) {
9203 type = nla_type(iter);
9204 switch (type) {
9205 case ANDR_TWT_ATTR_CONFIG_ID:
9206 /* Config ID */
9207 val.configID = nla_get_u8(iter);
9208 break;
9209 case ANDR_TWT_ATTR_NEGOTIATION_TYPE:
9210 /* negotiation_type */
9211 val.teardesc.negotiation_type = nla_get_u8(iter);
9212 break;
9213 case ANDR_TWT_ATTR_ALL_TWT:
9214 /* all twt */
9215 val.teardesc.alltwt = nla_get_u8(iter);
9216 break;
9217 default:
9218 WL_ERR(("Invalid teardown attribute type %d\n", type));
9219 break;
9220 }
9221 }
9222
9223 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_TEARDOWN,
9224 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
9225 if (bw != BCME_OK) {
9226 goto exit;
9227 }
9228
9229 bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
9230 mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
9231 if (bw < 0) {
9232 WL_ERR(("twt teardown failed. ret:%d\n", bw));
9233 } else {
9234 WL_INFORM(("twt teardown succeeded, config ID %d "
9235 "Negotiation type %d alltwt %d\n", val.configID,
9236 val.teardesc.negotiation_type, val.teardesc.alltwt));
9237 }
9238
9239 exit:
9240 return bw;
9241 }
9242
9243 static int
wl_cfgvendor_twt_info_frame(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9244 wl_cfgvendor_twt_info_frame(struct wiphy *wiphy,
9245 struct wireless_dev *wdev, const void *data, int len)
9246 {
9247 wl_twt_info_t val;
9248 int bw;
9249 s32 type, rem_attr;
9250 const struct nlattr *iter;
9251 u8 mybuf[WLC_IOCTL_SMLEN] = {0};
9252 u8 res_buf[WLC_IOCTL_SMLEN] = {0};
9253 uint8 *rem = mybuf;
9254 uint16 rem_len = sizeof(mybuf);
9255 uint32 val32 = 0;
9256
9257 bzero(&val, sizeof(val));
9258 val.version = WL_TWT_INFO_VER;
9259 val.length = sizeof(val.version) + sizeof(val.length);
9260
9261 /* Default values, Override Below */
9262 val.infodesc.flow_id = 0xFF;
9263 val.desc.next_twt_h = 0xFFFFFFFF;
9264 val.desc.next_twt_l = 0xFFFFFFFF;
9265
9266 nla_for_each_attr(iter, data, len, rem_attr) {
9267 type = nla_type(iter);
9268 if (type == ANDR_TWT_ATTR_CONFIG_ID) {
9269 /* Config ID */
9270 val.configID = nla_get_u8(iter);
9271 } else if (type == ANDR_TWT_ATTR_RESUME_TIME) {
9272 /* Resume offset */
9273 val32 = nla_get_u32(iter);
9274 if (!((val32 == 0) || (val32 == -1))) {
9275 val.infodesc.next_twt_h = 0;
9276 val.infodesc.next_twt_l = val32;
9277 val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_RESUME;
9278 }
9279 } else if (type == ANDR_TWT_ATTR_ALL_TWT) {
9280 /* all twt */
9281 val32 = (uint32)nla_get_u8(iter);
9282 if (val32) {
9283 val.infodesc.flow_flags |= WL_TWT_INFO_FLAG_ALL_TWT;
9284 }
9285 } else {
9286 WL_ERR(("Invalid info frame attribute type %d\n", type));
9287 }
9288 }
9289
9290 bw = bcm_pack_xtlv_entry(&rem, &rem_len, WL_TWT_CMD_INFO,
9291 sizeof(val), (uint8 *)&val, BCM_XTLV_OPTION_ALIGN32);
9292 if (bw != BCME_OK) {
9293 goto exit;
9294 }
9295
9296 bw = wldev_iovar_setbuf(wdev_to_ndev(wdev), "twt",
9297 mybuf, sizeof(mybuf) - rem_len, res_buf, WLC_IOCTL_SMLEN, NULL);
9298 if (bw < 0) {
9299 WL_ERR(("twt info frame failed. ret:%d\n", bw));
9300 } else {
9301 WL_INFORM(("twt info frame succeeded, config ID %d\n", val.configID));
9302 }
9303
9304 exit:
9305 return bw;
9306 }
9307
9308 static int
wl_cfgvendor_twt_stats_update_v2(struct wiphy * wiphy,wl_twt_stats_v2_t * stats)9309 wl_cfgvendor_twt_stats_update_v2(struct wiphy *wiphy, wl_twt_stats_v2_t *stats)
9310 {
9311 u32 i;
9312 wl_twt_peer_stats_v2_t *peer_stats;
9313 struct sk_buff *skb;
9314 int32 mem_needed;
9315 int ret = BCME_OK;
9316
9317 mem_needed = BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN;
9318
9319 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
9320 if (unlikely(!skb)) {
9321 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
9322 ret = -ENOMEM;
9323 goto fail;
9324 }
9325
9326 ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_PEER_STATS, stats->num_stats);
9327 if (ret < 0) {
9328 WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_PEER_STATS, ret:%d\n", ret));
9329 goto fail;
9330 }
9331
9332 for (i = 0; i < stats->num_stats; i++) {
9333 peer_stats = &stats->peer_stats_list[i];
9334
9335 WL_INFORM_MEM(("%u %u %u %u %u",
9336 peer_stats->eosp_dur_avg, peer_stats->tx_pkts_avg, peer_stats->rx_pkts_avg,
9337 peer_stats->tx_pkt_sz_avg, peer_stats->rx_pkt_sz_avg));
9338 ret = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, peer_stats->configID);
9339 if (ret < 0) {
9340 WL_ERR(("Failed to put ANDR_TWT_ATTR_CONFIG_ID, ret:%d\n", ret));
9341 goto fail;
9342 }
9343 ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_TX, peer_stats->tx_pkts_avg);
9344 if (ret < 0) {
9345 WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_TX, ret:%d\n", ret));
9346 goto fail;
9347 }
9348 ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, peer_stats->tx_pkt_sz_avg);
9349 if (ret < 0) {
9350 WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_TX, ret:%d\n", ret));
9351 goto fail;
9352 }
9353 ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_NUM_RX, peer_stats->rx_pkts_avg);
9354 if (ret < 0) {
9355 WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_NUM_RX, ret:%d\n", ret));
9356 goto fail;
9357 }
9358 ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, peer_stats->rx_pkt_sz_avg);
9359 if (ret < 0) {
9360 WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_PKT_SIZE_RX, ret:%d\n", ret));
9361 goto fail;
9362 }
9363 ret = nla_put_u32(skb, ANDR_TWT_ATTR_AVG_EOSP_DUR, peer_stats->eosp_dur_avg);
9364 if (ret < 0) {
9365 WL_ERR(("Failed to put ANDR_TWT_ATTR_AVG_EOSP_DUR, ret:%d\n", ret));
9366 goto fail;
9367 }
9368 ret = nla_put_u32(skb, ANDR_TWT_ATTR_EOSP_CNT, peer_stats->eosp_count);
9369 if (ret < 0) {
9370 WL_ERR(("Failed to put ANDR_TWT_ATTR_EOSP_CNT, ret:%d\n", ret));
9371 goto fail;
9372 }
9373 ret = nla_put_u32(skb, ANDR_TWT_ATTR_NUM_SP, peer_stats->sp_seq);
9374 if (ret < 0) {
9375 WL_ERR(("Failed to put ANDR_TWT_ATTR_NUM_SP, ret:%d\n", ret));
9376 goto fail;
9377 }
9378 }
9379
9380 ret = cfg80211_vendor_cmd_reply(skb);
9381 if (unlikely(ret)) {
9382 WL_ERR(("vendor command reply failed, ret=%d\n", ret));
9383 }
9384 return ret;
9385
9386 fail:
9387 /* Free skb for failure cases */
9388 if (skb) {
9389 kfree_skb(skb);
9390 }
9391 return ret;
9392 }
9393
9394 static int
wl_cfgvendor_twt_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len,bool clear_stats)9395 wl_cfgvendor_twt_stats(struct wiphy *wiphy,
9396 struct wireless_dev *wdev, const void *data, int len, bool clear_stats)
9397 {
9398 wl_twt_stats_cmd_v1_t query;
9399 wl_twt_stats_v2_t stats_v2;
9400 s32 type, rem_attr;
9401 const struct nlattr *iter;
9402 int ret = BCME_OK;
9403 char iovbuf[WLC_IOCTL_SMLEN] = {0, };
9404 uint8 *pxtlv = NULL;
9405 uint8 *iovresp = NULL;
9406 uint16 buflen = 0, bufstart = 0;
9407 struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev));
9408
9409 bzero(&query, sizeof(query));
9410 query.version = WL_TWT_STATS_CMD_VERSION_1;
9411 query.length = sizeof(query) - OFFSETOF(wl_twt_stats_cmd_v1_t, peer);
9412
9413 /* Default values, Override Below */
9414 query.num_bid = 0xFF;
9415 query.num_fid = 0xFF;
9416
9417 if (clear_stats) {
9418 query.flags |= WL_TWT_STATS_CMD_FLAGS_RESET;
9419 }
9420 nla_for_each_attr(iter, data, len, rem_attr) {
9421 type = nla_type(iter);
9422 if (type == ANDR_TWT_ATTR_CONFIG_ID) {
9423 /* Config ID */
9424 query.configID = nla_get_u8(iter);
9425 } else {
9426 WL_ERR(("Invalid TWT stats attribute type %d\n", type));
9427 }
9428 }
9429
9430 iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
9431 if (iovresp == NULL) {
9432 WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
9433 goto exit;
9434 }
9435
9436 buflen = bufstart = WLC_IOCTL_SMLEN;
9437 pxtlv = (uint8 *)iovbuf;
9438 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_STATS,
9439 sizeof(query), (uint8 *)&query, BCM_XTLV_OPTION_ALIGN32);
9440 if (ret != BCME_OK) {
9441 WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
9442 goto exit;
9443 }
9444
9445 if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen,
9446 iovresp, WLC_IOCTL_MEDLEN, NULL))) {
9447 WL_ERR(("twt status failed with err=%d \n", ret));
9448 goto exit;
9449 }
9450
9451 (void)memcpy_s(&stats_v2, sizeof(stats_v2), iovresp, sizeof(stats_v2));
9452
9453 if (dtoh16(stats_v2.version) == WL_TWT_STATS_VERSION_2) {
9454 if (!clear_stats) {
9455 WL_ERR(("stats query ver %d, \n", dtoh16(stats_v2.version)));
9456 ret = wl_cfgvendor_twt_stats_update_v2(wiphy, (wl_twt_stats_v2_t*)iovresp);
9457 }
9458 } else {
9459 ret = BCME_UNSUPPORTED;
9460 WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(stats_v2.version)));
9461 goto exit;
9462 }
9463
9464 exit:
9465 if (iovresp) {
9466 MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
9467 }
9468
9469 return ret;
9470 }
9471
9472 static int
wl_cfgvendor_twt_get_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9473 wl_cfgvendor_twt_get_stats(struct wiphy *wiphy,
9474 struct wireless_dev *wdev, const void *data, int len)
9475 {
9476 return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, false);
9477 }
9478
9479 static int
wl_cfgvendor_twt_clear_stats(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9480 wl_cfgvendor_twt_clear_stats(struct wiphy *wiphy,
9481 struct wireless_dev *wdev, const void *data, int len)
9482 {
9483 return wl_cfgvendor_twt_stats(wiphy, wdev, data, len, true);
9484 }
9485
9486 static int
wl_cfgvendor_twt_update_cap(struct wiphy * wiphy,wl_twt_cap_t * result)9487 wl_cfgvendor_twt_update_cap(struct wiphy *wiphy, wl_twt_cap_t *result)
9488 {
9489 struct sk_buff *skb;
9490 int32 mem_needed;
9491 int ret = BCME_OK;
9492
9493 WL_INFORM_MEM(("TWT Capabilites Device,Peer 0x%04x 0x%04x\n",
9494 result->device_cap, result->peer_cap));
9495
9496 mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
9497
9498 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
9499 if (unlikely(!skb)) {
9500 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
9501 ret = -ENOMEM;
9502 goto fail;
9503 }
9504
9505 ret = nla_put_u32(skb, ANDR_TWT_ATTR_DEVICE_CAP, result->device_cap);
9506 if (ret < 0) {
9507 WL_ERR(("Failed to put ANDR_TWT_ATTR_DEVICE_CAP, ret:%d\n", ret));
9508 goto fail;
9509 }
9510 ret = nla_put_u32(skb, ANDR_TWT_ATTR_PEER_CAP, result->peer_cap);
9511 if (ret < 0) {
9512 WL_ERR(("Failed to put ANDR_TWT_ATTR_PEER_CAP, ret:%d\n", ret));
9513 goto fail;
9514 }
9515
9516 ret = cfg80211_vendor_cmd_reply(skb);
9517 if (unlikely(ret)) {
9518 WL_ERR(("vendor command reply failed, ret=%d\n", ret));
9519 }
9520 return ret;
9521
9522 fail:
9523 /* Free skb for failure cases */
9524 if (skb) {
9525 kfree_skb(skb);
9526 }
9527 return ret;
9528 }
9529
9530 static int
wl_cfgvendor_twt_cap(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int len)9531 wl_cfgvendor_twt_cap(struct wiphy *wiphy,
9532 struct wireless_dev *wdev, const void *data, int len)
9533 {
9534 int ret = BCME_OK;
9535 char iovbuf[WLC_IOCTL_SMLEN] = {0, };
9536 uint8 *pxtlv = NULL;
9537 uint8 *iovresp = NULL;
9538 wl_twt_cap_cmd_t cmd_cap;
9539 wl_twt_cap_t result;
9540
9541 uint16 buflen = 0, bufstart = 0;
9542 struct bcm_cfg80211 *cfg = wl_get_cfg(wdev_to_ndev(wdev));
9543
9544 bzero(&cmd_cap, sizeof(cmd_cap));
9545
9546 cmd_cap.version = WL_TWT_CAP_CMD_VERSION_1;
9547 cmd_cap.length = sizeof(cmd_cap) - OFFSETOF(wl_twt_cap_cmd_t, peer);
9548
9549 iovresp = (uint8 *)MALLOCZ(cfg->osh, WLC_IOCTL_MEDLEN);
9550 if (iovresp == NULL) {
9551 WL_ERR(("%s: iov resp memory alloc exited\n", __FUNCTION__));
9552 goto exit;
9553 }
9554
9555 buflen = bufstart = WLC_IOCTL_SMLEN;
9556 pxtlv = (uint8 *)iovbuf;
9557
9558 ret = bcm_pack_xtlv_entry(&pxtlv, &buflen, WL_TWT_CMD_CAP,
9559 sizeof(cmd_cap), (uint8 *)&cmd_cap, BCM_XTLV_OPTION_ALIGN32);
9560 if (ret != BCME_OK) {
9561 WL_ERR(("%s : Error return during pack xtlv :%d\n", __FUNCTION__, ret));
9562 goto exit;
9563 }
9564
9565 if ((ret = wldev_iovar_getbuf(wdev_to_ndev(wdev), "twt", iovbuf, bufstart-buflen,
9566 iovresp, WLC_IOCTL_MEDLEN, NULL))) {
9567 WL_ERR(("Getting twt status failed with err=%d \n", ret));
9568 goto exit;
9569 }
9570
9571 (void)memcpy_s(&result, sizeof(result), iovresp, sizeof(result));
9572
9573 if (dtoh16(result.version) == WL_TWT_CAP_CMD_VERSION_1) {
9574 WL_ERR(("capability ver %d, \n", dtoh16(result.version)));
9575 ret = wl_cfgvendor_twt_update_cap(wiphy, &result);
9576 return ret;
9577 } else {
9578 ret = BCME_UNSUPPORTED;
9579 WL_ERR(("Version 1 unsupported. ver %d, \n", dtoh16(result.version)));
9580 goto exit;
9581 }
9582
9583 exit:
9584 if (iovresp) {
9585 MFREE(cfg->osh, iovresp, WLC_IOCTL_MEDLEN);
9586 }
9587
9588 return ret;
9589 }
9590
9591 static int
wl_cfgvendor_twt_update_setup_response(struct sk_buff * skb,void * event_data)9592 wl_cfgvendor_twt_update_setup_response(struct sk_buff *skb, void *event_data)
9593 {
9594 s32 err = BCME_OK;
9595 const wl_twt_setup_cplt_t *setup_cplt = (wl_twt_setup_cplt_t *)event_data;
9596 const wl_twt_sdesc_t *sdesc = (const wl_twt_sdesc_t *)&setup_cplt[1];
9597
9598 WL_DBG(("TWT_SETUP: status %d, reason %d, configID %d, setup_cmd %d, flow_flags 0x%x,"
9599 " flow_id %d, channel %d, negotiation_type %d, wake_time_h %u, wake_time_l %u,"
9600 " wake_dur %u, wake_int %u\n",
9601 (int)setup_cplt->status, (int)setup_cplt->reason_code, (int)setup_cplt->configID,
9602 (int)sdesc->setup_cmd, sdesc->flow_flags, (int)sdesc->flow_id, (int)sdesc->channel,
9603 (int)sdesc->negotiation_type, sdesc->wake_time_h, sdesc->wake_time_l,
9604 sdesc->wake_dur, sdesc->wake_int));
9605
9606 err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_SETUP);
9607 if (unlikely(err)) {
9608 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
9609 goto fail;
9610 }
9611 err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, setup_cplt->configID);
9612 if (unlikely(err)) {
9613 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n"));
9614 goto fail;
9615 }
9616 err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, setup_cplt->reason_code);
9617 if (unlikely(err)) {
9618 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n"));
9619 goto fail;
9620 }
9621 err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(setup_cplt->status));
9622 if (unlikely(err)) {
9623 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n"));
9624 goto fail;
9625 }
9626 err = nla_put_u8(skb, ANDR_TWT_ATTR_NEGOTIATION_TYPE, sdesc->negotiation_type);
9627 if (unlikely(err)) {
9628 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NEGOTIATION_TYPE failed\n"));
9629 goto fail;
9630 }
9631 err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_DURATION, sdesc->wake_dur);
9632 if (unlikely(err)) {
9633 WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_DURATION failed\n"));
9634 goto fail;
9635 }
9636 err = nla_put_u32(skb, ANDR_TWT_ATTR_WAKE_INTERVAL, sdesc->wake_int);
9637 if (unlikely(err)) {
9638 WL_ERR(("nla_put_u32 WIFI_TWT_ATTR_WAKE_INTERVAL failed\n"));
9639 goto fail;
9640 }
9641 err = nla_put_u8(skb, ANDR_TWT_ATTR_TRIGGER_TYPE,
9642 !!(sdesc->flow_flags & WL_TWT_FLOW_FLAG_TRIGGER));
9643 if (unlikely(err)) {
9644 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_TRIGGER_TYPE failed\n"));
9645 goto fail;
9646 }
9647
9648 fail:
9649 return err;
9650 }
9651
9652 static int
wl_cfgvendor_twt_update_teardown_response(struct sk_buff * skb,void * event_data)9653 wl_cfgvendor_twt_update_teardown_response(struct sk_buff *skb, void *event_data)
9654 {
9655 s32 err = BCME_OK;
9656 const wl_twt_teardown_cplt_t *td_cplt = (wl_twt_teardown_cplt_t *)event_data;
9657 const wl_twt_teardesc_t *teardesc = (const wl_twt_teardesc_t *)&td_cplt[1];
9658
9659 WL_DBG(("TWT_TEARDOWN: status %d, reason %d, configID %d, flow_id %d, negotiation_type %d,"
9660 " bid %d, alltwt %d\n", (int)td_cplt->status, (int)td_cplt->reason_code,
9661 (int)td_cplt->configID, (int)teardesc->flow_id, (int)teardesc->negotiation_type,
9662 (int)teardesc->bid, (int)teardesc->alltwt));
9663
9664 err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_TEARDOWN);
9665 if (unlikely(err)) {
9666 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
9667 goto fail;
9668 }
9669 err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, td_cplt->reason_code);
9670 if (unlikely(err)) {
9671 WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_REASON_CODE failed\n"));
9672 goto fail;
9673 }
9674 err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(td_cplt->status));
9675 if (unlikely(err)) {
9676 WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_STATUS failed\n"));
9677 goto fail;
9678 }
9679 err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, td_cplt->configID);
9680 if (unlikely(err)) {
9681 WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_CONFIG_ID failed\n"));
9682 goto fail;
9683 }
9684 err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT, teardesc->alltwt);
9685 if (unlikely(err)) {
9686 WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_ALL_TWT failed\n"));
9687 goto fail;
9688 }
9689
9690 fail:
9691 return err;
9692 }
9693
9694 static int
wl_cfgvendor_twt_update_infoframe_response(struct sk_buff * skb,void * event_data)9695 wl_cfgvendor_twt_update_infoframe_response(struct sk_buff *skb, void *event_data)
9696 {
9697 s32 err = BCME_OK;
9698 const wl_twt_info_cplt_t *info_cplt = (wl_twt_info_cplt_t *)event_data;
9699 const wl_twt_infodesc_t *infodesc = (const wl_twt_infodesc_t *)&info_cplt[1];
9700
9701 WL_DBG(("TWT_INFOFRM: status %d, reason %d, configID %d, flow_flags 0x%x, flow_id %d,"
9702 " next_twt_h %u, next_twt_l %u\n", (int)info_cplt->status,
9703 (int)info_cplt->reason_code, (int)info_cplt->configID, infodesc->flow_flags,
9704 (int)infodesc->flow_id, infodesc->next_twt_h, infodesc->next_twt_l));
9705
9706 err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_INFO_FRM);
9707 if (unlikely(err)) {
9708 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
9709 goto fail;
9710 }
9711 err = nla_put_u8(skb, ANDR_TWT_ATTR_REASON_CODE, info_cplt->reason_code);
9712 if (unlikely(err)) {
9713 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_REASON_CODE failed\n"));
9714 goto fail;
9715 }
9716 err = nla_put_u8(skb, ANDR_TWT_ATTR_STATUS, !!(info_cplt->status));
9717 if (unlikely(err)) {
9718 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_STATUS failed\n"));
9719 goto fail;
9720 }
9721 err = nla_put_u8(skb, ANDR_TWT_ATTR_CONFIG_ID, info_cplt->configID);
9722 if (unlikely(err)) {
9723 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_CONFIG_ID failed\n"));
9724 goto fail;
9725 }
9726 err = nla_put_u8(skb, ANDR_TWT_ATTR_ALL_TWT,
9727 !!(infodesc->flow_flags & WL_TWT_INFO_FLAG_ALL_TWT));
9728 if (unlikely(err)) {
9729 WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n"));
9730 goto fail;
9731 }
9732 err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_RESUMED,
9733 !!(infodesc->flow_flags & WL_TWT_INFO_FLAG_RESUME));
9734 if (unlikely(err)) {
9735 WL_ERR(("nla_put_u8 ANDR_TWT_ATTR_TWT_RESUMED failed\n"));
9736 goto fail;
9737 }
9738
9739 fail:
9740 return err;
9741 }
9742
9743 static int
wl_cfgvendor_twt_update_notify_response(struct sk_buff * skb,void * event_data)9744 wl_cfgvendor_twt_update_notify_response(struct sk_buff *skb, void *event_data)
9745 {
9746 s32 err = BCME_OK;
9747 const wl_twt_notify_t *notif_cplt = (wl_twt_notify_t *)event_data;
9748
9749 WL_DBG(("TWT_NOTIFY: notification %d\n", (int)notif_cplt->notification));
9750
9751 err = nla_put_u8(skb, ANDR_TWT_ATTR_SUB_EVENT, ANDR_TWT_EVENT_NOTIFY);
9752 if (unlikely(err)) {
9753 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_SUB_EVENT failed\n"));
9754 goto fail;
9755 }
9756
9757 err = nla_put_u8(skb, ANDR_TWT_ATTR_TWT_NOTIFICATION, notif_cplt->notification);
9758 if (unlikely(err)) {
9759 WL_ERR(("nla_put_u8 WIFI_TWT_ATTR_NOTIFICATION failed\n"));
9760 goto fail;
9761 }
9762
9763 fail:
9764 return err;
9765 }
9766
9767 s32
wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 * cfg,bcm_struct_cfgdev * cfgdev,const wl_event_msg_t * e,void * data)9768 wl_cfgvendor_notify_twt_event(struct bcm_cfg80211 *cfg,
9769 bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data)
9770 {
9771 struct sk_buff *skb = NULL;
9772 gfp_t kflags;
9773 struct wiphy *wiphy = bcmcfg_to_wiphy(cfg);
9774 int err = BCME_OK;
9775 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
9776 const wl_twt_event_t *twt_event = (wl_twt_event_t *)data;
9777
9778 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
9779 skb = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(ndev),
9780 BRCM_TWT_HAL_VENDOR_EVENT_BUF_LEN, BRCM_VENDOR_EVENT_TWT, kflags);
9781 if (!skb) {
9782 WL_ERR(("skb alloc failed"));
9783 err = BCME_NOMEM;
9784 goto fail;
9785 }
9786
9787 switch (twt_event->event_type) {
9788 case WL_TWT_EVENT_SETUP:
9789 err = wl_cfgvendor_twt_update_setup_response(skb,
9790 (void*)twt_event->event_info);
9791 break;
9792 case WL_TWT_EVENT_TEARDOWN:
9793 err = wl_cfgvendor_twt_update_teardown_response(skb,
9794 (void*)twt_event->event_info);
9795 break;
9796 case WL_TWT_EVENT_INFOFRM:
9797 err = wl_cfgvendor_twt_update_infoframe_response(skb,
9798 (void*)twt_event->event_info);
9799 break;
9800 case WL_TWT_EVENT_NOTIFY:
9801 err = wl_cfgvendor_twt_update_notify_response(skb,
9802 (void*)twt_event->event_info);
9803 break;
9804 default:
9805 WL_ERR(("Invalid TWT sub event type %d", twt_event->event_type));
9806 err = BCME_UNSUPPORTED;
9807 break;
9808 }
9809
9810 if (err) {
9811 goto fail;
9812 }
9813
9814 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
9815 cfg80211_vendor_event(skb, kflags);
9816 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
9817 WL_ERR(("Successfully sent TWT vendor event type %d\n", twt_event->event_type));
9818 return BCME_OK;
9819
9820 fail:
9821 /* Free skb for failure cases */
9822 if (skb) {
9823 kfree_skb(skb);
9824 }
9825
9826 return err;
9827 }
9828 #endif /* !WL_TWT && WL_TWT_HAL_IF */
9829
9830 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
9831 const struct nla_policy andr_wifi_attr_policy[ANDR_WIFI_ATTRIBUTE_MAX] = {
9832 [ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET] = { .type = NLA_U32 },
9833 [ANDR_WIFI_ATTRIBUTE_FEATURE_SET] = { .type = NLA_U32 },
9834 [ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI] = { .type = NLA_NUL_STRING, .len = 3 },
9835 [ANDR_WIFI_ATTRIBUTE_NODFS_SET] = { .type = NLA_U32 },
9836 [ANDR_WIFI_ATTRIBUTE_COUNTRY] = { .type = NLA_NUL_STRING, .len = 3 },
9837 [ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE] = { .type = NLA_U8 },
9838 [ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE] = { .type = NLA_U32 },
9839 [ANDR_WIFI_ATTRIBUTE_LATENCY_MODE] = { .type = NLA_U32, .len = sizeof(uint32) },
9840 [ANDR_WIFI_ATTRIBUTE_RANDOM_MAC] = { .type = NLA_U32 },
9841 [ANDR_WIFI_ATTRIBUTE_TX_POWER_SCENARIO] = { .type = NLA_S8 },
9842 [ANDR_WIFI_ATTRIBUTE_THERMAL_MITIGATION] = { .type = NLA_S8 },
9843 [ANDR_WIFI_ATTRIBUTE_THERMAL_COMPLETION_WINDOW] = { .type = NLA_U32 },
9844 [ANDR_WIFI_ATTRIBUTE_VOIP_MODE] = { .type = NLA_U32, .len = sizeof(uint32) },
9845 [ANDR_WIFI_ATTRIBUTE_DTIM_MULTIPLIER] = { .type = NLA_U32, .len = sizeof(uint32) },
9846 };
9847
9848 const struct nla_policy dump_buf_policy[DUMP_BUF_ATTR_MAX] = {
9849 [DUMP_BUF_ATTR_MEMDUMP] = { .type = NLA_BINARY },
9850 [DUMP_BUF_ATTR_SSSR_C0_D11_BEFORE] = { .type = NLA_BINARY },
9851 [DUMP_BUF_ATTR_SSSR_C0_D11_AFTER] = { .type = NLA_BINARY },
9852 [DUMP_BUF_ATTR_SSSR_C1_D11_BEFORE] = { .type = NLA_BINARY },
9853 [DUMP_BUF_ATTR_SSSR_C1_D11_AFTER] = { .type = NLA_BINARY },
9854 [DUMP_BUF_ATTR_SSSR_C2_D11_BEFORE] = { .type = NLA_BINARY },
9855 [DUMP_BUF_ATTR_SSSR_C2_D11_AFTER] = { .type = NLA_BINARY },
9856 [DUMP_BUF_ATTR_SSSR_DIG_BEFORE] = { .type = NLA_BINARY },
9857 [DUMP_BUF_ATTR_SSSR_DIG_AFTER] = { .type = NLA_BINARY },
9858 [DUMP_BUF_ATTR_TIMESTAMP] = { .type = NLA_BINARY },
9859 [DUMP_BUF_ATTR_GENERAL_LOG] = { .type = NLA_BINARY },
9860 [DUMP_BUF_ATTR_ECNTRS] = { .type = NLA_BINARY },
9861 [DUMP_BUF_ATTR_SPECIAL_LOG] = { .type = NLA_BINARY },
9862 [DUMP_BUF_ATTR_DHD_DUMP] = { .type = NLA_BINARY },
9863 [DUMP_BUF_ATTR_EXT_TRAP] = { .type = NLA_BINARY },
9864 [DUMP_BUF_ATTR_HEALTH_CHK] = { .type = NLA_BINARY },
9865 [DUMP_BUF_ATTR_PRESERVE_LOG] = { .type = NLA_BINARY },
9866 [DUMP_BUF_ATTR_COOKIE] = { .type = NLA_BINARY },
9867 [DUMP_BUF_ATTR_FLOWRING_DUMP] = { .type = NLA_BINARY },
9868 [DUMP_BUF_ATTR_PKTLOG] = { .type = NLA_BINARY },
9869 [DUMP_BUF_ATTR_PKTLOG_DEBUG] = { .type = NLA_BINARY },
9870 [DUMP_BUF_ATTR_STATUS_LOG] = { .type = NLA_BINARY },
9871 [DUMP_BUF_ATTR_AXI_ERROR] = { .type = NLA_BINARY },
9872 [DUMP_BUF_ATTR_RTT_LOG] = { .type = NLA_BINARY },
9873 [DUMP_BUF_ATTR_SDTC_ETB_DUMP] = { .type = NLA_BINARY },
9874 [DUMP_BUF_ATTR_PKTID_MAP_LOG] = { .type = NLA_BINARY },
9875 [DUMP_BUF_ATTR_PKTID_UNMAP_LOG] = { .type = NLA_BINARY },
9876 };
9877
9878 const struct nla_policy brcm_drv_attr_policy[BRCM_ATTR_DRIVER_MAX] = {
9879 [BRCM_ATTR_DRIVER_CMD] = { .type = NLA_NUL_STRING },
9880 [BRCM_ATTR_DRIVER_KEY_PMK] = { .type = NLA_BINARY, .len = WSEC_MAX_PASSPHRASE_LEN },
9881 [BRCM_ATTR_DRIVER_FEATURE_FLAGS] = { .type = NLA_BINARY, .len =
9882 ((BRCM_WLAN_VENDOR_FEATURES_MAX / 8) + 1) },
9883 [BRCM_ATTR_DRIVER_RAND_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9884 [BRCM_ATTR_SAE_PWE] = { .type = NLA_U32 },
9885 };
9886
9887 #ifdef RTT_SUPPORT
9888 const struct nla_policy rtt_attr_policy[RTT_ATTRIBUTE_MAX] = {
9889 [RTT_ATTRIBUTE_TARGET_CNT] = { .type = NLA_U8 },
9890 [RTT_ATTRIBUTE_TARGET_INFO] = { .type = NLA_NESTED },
9891 [RTT_ATTRIBUTE_TARGET_MAC] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9892 [RTT_ATTRIBUTE_TARGET_TYPE] = { .type = NLA_U8 },
9893 [RTT_ATTRIBUTE_TARGET_PEER] = { .type = NLA_U8 },
9894 [RTT_ATTRIBUTE_TARGET_CHAN] = { .type = NLA_BINARY },
9895 [RTT_ATTRIBUTE_TARGET_PERIOD] = { .type = NLA_U32 },
9896 [RTT_ATTRIBUTE_TARGET_NUM_BURST] = { .type = NLA_U32 },
9897 [RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST] = { .type = NLA_U32 },
9898 [RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM] = { .type = NLA_U32 },
9899 [RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR] = { .type = NLA_U32 },
9900 [RTT_ATTRIBUTE_TARGET_LCI] = { .type = NLA_U8 },
9901 [RTT_ATTRIBUTE_TARGET_LCR] = { .type = NLA_U8 },
9902 [RTT_ATTRIBUTE_TARGET_BURST_DURATION] = { .type = NLA_U32 },
9903 [RTT_ATTRIBUTE_TARGET_PREAMBLE] = { .type = NLA_U8 },
9904 [RTT_ATTRIBUTE_TARGET_BW] = { .type = NLA_U8 },
9905 [RTT_ATTRIBUTE_RESULTS_COMPLETE] = { .type = NLA_U32 },
9906 [RTT_ATTRIBUTE_RESULTS_PER_TARGET] = { .type = NLA_NESTED },
9907 [RTT_ATTRIBUTE_RESULT_CNT] = { .type = NLA_U32 },
9908 [RTT_ATTRIBUTE_RESULT] = { .type = NLA_BINARY, .len = sizeof(rtt_result_t) },
9909 [RTT_ATTRIBUTE_RESULT_DETAIL] = { .type = NLA_BINARY,
9910 .len = sizeof(struct rtt_result_detail) },
9911 };
9912 #endif /* RTT_SUPPORT */
9913
9914 #ifdef KEEP_ALIVE
9915 const struct nla_policy mkeep_alive_attr_policy[MKEEP_ALIVE_ATTRIBUTE_MAX] = {
9916 [MKEEP_ALIVE_ATTRIBUTE_ID] = { .type = NLA_U8 },
9917 [MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = { .type = NLA_BINARY, .len = MKEEP_ALIVE_IP_PKT_MAX },
9918 [MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = { .type = NLA_U16 },
9919 [MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9920 [MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9921 [MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = { .type = NLA_U32 },
9922 [MKEEP_ALIVE_ATTRIBUTE_ETHER_TYPE] = { .type = NLA_U16 }
9923 };
9924 #endif /* KEEP_ALIVE */
9925 #ifdef WL_NAN
9926 const struct nla_policy nan_attr_policy[NAN_ATTRIBUTE_MAX] = {
9927 [NAN_ATTRIBUTE_2G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
9928 [NAN_ATTRIBUTE_5G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
9929 [NAN_ATTRIBUTE_CLUSTER_LOW] = { .type = NLA_U16, .len = sizeof(uint16) },
9930 [NAN_ATTRIBUTE_CLUSTER_HIGH] = { .type = NLA_U16, .len = sizeof(uint16) },
9931 [NAN_ATTRIBUTE_SID_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
9932 [NAN_ATTRIBUTE_SUB_SID_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
9933 [NAN_ATTRIBUTE_SYNC_DISC_2G_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
9934 [NAN_ATTRIBUTE_SYNC_DISC_5G_BEACON] = { .type = NLA_U8, .len = sizeof(uint8) },
9935 [NAN_ATTRIBUTE_SDF_2G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
9936 [NAN_ATTRIBUTE_SDF_5G_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
9937 [NAN_ATTRIBUTE_HOP_COUNT_LIMIT] = { .type = NLA_U8, .len = sizeof(uint8) },
9938 [NAN_ATTRIBUTE_RANDOM_TIME] = { .type = NLA_U8, .len = sizeof(uint8) },
9939 [NAN_ATTRIBUTE_MASTER_PREF] = { .type = NLA_U8, .len = sizeof(uint8) },
9940 [NAN_ATTRIBUTE_OUI] = { .type = NLA_U32, .len = sizeof(uint32) },
9941 [NAN_ATTRIBUTE_WARMUP_TIME] = { .type = NLA_U16, .len = sizeof(uint16) },
9942 [NAN_ATTRIBUTE_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
9943 [NAN_ATTRIBUTE_24G_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
9944 [NAN_ATTRIBUTE_5G_CHANNEL] = { .type = NLA_U32, .len = sizeof(uint32) },
9945 [NAN_ATTRIBUTE_CONF_CLUSTER_VAL] = { .type = NLA_U8, .len = sizeof(uint8) },
9946 [NAN_ATTRIBUTE_DWELL_TIME] = { .type = NLA_U8, .len = sizeof(uint8) },
9947 [NAN_ATTRIBUTE_SCAN_PERIOD] = { .type = NLA_U16, .len = sizeof(uint16) },
9948 [NAN_ATTRIBUTE_DWELL_TIME_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
9949 [NAN_ATTRIBUTE_SCAN_PERIOD_5G] = { .type = NLA_U16, .len = sizeof(uint16) },
9950 [NAN_ATTRIBUTE_AVAIL_BIT_MAP] = { .type = NLA_U32, .len = sizeof(uint32) },
9951 [NAN_ATTRIBUTE_ENTRY_CONTROL] = { .type = NLA_U8, .len = sizeof(uint8) },
9952 [NAN_ATTRIBUTE_RSSI_CLOSE] = { .type = NLA_U8, .len = sizeof(uint8) },
9953 [NAN_ATTRIBUTE_RSSI_MIDDLE] = { .type = NLA_U8, .len = sizeof(uint8) },
9954 [NAN_ATTRIBUTE_RSSI_PROXIMITY] = { .type = NLA_U8, .len = sizeof(uint8) },
9955 [NAN_ATTRIBUTE_RSSI_CLOSE_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
9956 [NAN_ATTRIBUTE_RSSI_MIDDLE_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
9957 [NAN_ATTRIBUTE_RSSI_PROXIMITY_5G] = { .type = NLA_U8, .len = sizeof(uint8) },
9958 [NAN_ATTRIBUTE_RSSI_WINDOW_SIZE] = { .type = NLA_U8, .len = sizeof(uint8) },
9959 [NAN_ATTRIBUTE_CIPHER_SUITE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
9960 [NAN_ATTRIBUTE_SCID_LEN] = { .type = NLA_U32, .len = sizeof(uint32) },
9961 [NAN_ATTRIBUTE_SCID] = { .type = NLA_BINARY, .len = MAX_SCID_LEN },
9962 [NAN_ATTRIBUTE_2G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) },
9963 [NAN_ATTRIBUTE_5G_AWAKE_DW] = { .type = NLA_U32, .len = sizeof(uint32) },
9964 [NAN_ATTRIBUTE_DISC_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) },
9965 [NAN_ATTRIBUTE_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
9966 [NAN_ATTRIBUTE_RANDOMIZATION_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
9967 [NAN_ATTRIBUTE_CMD_USE_NDPE] = { .type = NLA_U32, .len = sizeof(uint32) },
9968 [NAN_ATTRIBUTE_ENABLE_MERGE] = { .type = NLA_U8, .len = sizeof(uint8) },
9969 [NAN_ATTRIBUTE_DISCOVERY_BEACON_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
9970 [NAN_ATTRIBUTE_NSS] = { .type = NLA_U32, .len = sizeof(uint32) },
9971 [NAN_ATTRIBUTE_ENABLE_RANGING] = { .type = NLA_U32, .len = sizeof(uint32) },
9972 [NAN_ATTRIBUTE_DW_EARLY_TERM] = { .type = NLA_U32, .len = sizeof(uint32) },
9973 [NAN_ATTRIBUTE_TRANSAC_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
9974 [NAN_ATTRIBUTE_PUBLISH_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
9975 [NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
9976 [NAN_ATTRIBUTE_SERVICE_SPECIFIC_INFO] = { .type = NLA_BINARY, .len =
9977 NAN_MAX_SERVICE_SPECIFIC_INFO_LEN },
9978 [NAN_ATTRIBUTE_SUBSCRIBE_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
9979 [NAN_ATTRIBUTE_SUBSCRIBE_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
9980 [NAN_ATTRIBUTE_PUBLISH_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
9981 [NAN_ATTRIBUTE_PUBLISH_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
9982 [NAN_ATTRIBUTE_PERIOD] = { .type = NLA_U16, .len = sizeof(uint16) },
9983 [NAN_ATTRIBUTE_TTL] = { .type = NLA_U16, .len = sizeof(uint16) },
9984 [NAN_ATTRIBUTE_SERVICE_NAME_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
9985 [NAN_ATTRIBUTE_SERVICE_NAME] = { .type = NLA_BINARY, .len = WL_NAN_SVC_HASH_LEN },
9986 [NAN_ATTRIBUTE_PEER_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
9987 [NAN_ATTRIBUTE_INST_ID] = { .type = NLA_U16, .len = sizeof(uint16) },
9988 [NAN_ATTRIBUTE_SUBSCRIBE_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
9989 [NAN_ATTRIBUTE_SSIREQUIREDFORMATCHINDICATION] = { .type = NLA_U8, .len = sizeof(uint8) },
9990 [NAN_ATTRIBUTE_SUBSCRIBE_MATCH] = { .type = NLA_U8, .len = sizeof(uint8) },
9991 [NAN_ATTRIBUTE_PUBLISH_MATCH] = { .type = NLA_U8, .len = sizeof(uint8) },
9992 [NAN_ATTRIBUTE_SERVICERESPONSEFILTER] = { .type = NLA_U8, .len = sizeof(uint8) },
9993 [NAN_ATTRIBUTE_SERVICERESPONSEINCLUDE] = { .type = NLA_U8, .len = sizeof(uint8) },
9994 [NAN_ATTRIBUTE_USESERVICERESPONSEFILTER] = { .type = NLA_U8, .len = sizeof(uint8) },
9995 [NAN_ATTRIBUTE_RX_MATCH_FILTER_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
9996 [NAN_ATTRIBUTE_RX_MATCH_FILTER] = { .type = NLA_BINARY, .len = MAX_MATCH_FILTER_LEN },
9997 [NAN_ATTRIBUTE_TX_MATCH_FILTER_LEN] = { .type = NLA_U16, .len = sizeof(uint16) },
9998 [NAN_ATTRIBUTE_TX_MATCH_FILTER] = { .type = NLA_BINARY, .len = MAX_MATCH_FILTER_LEN },
9999 [NAN_ATTRIBUTE_MAC_ADDR_LIST_NUM_ENTRIES] = { .type = NLA_U16, .len = sizeof(uint16) },
10000 [NAN_ATTRIBUTE_MAC_ADDR_LIST] = { .type = NLA_BINARY, .len =
10001 (NAN_SRF_MAX_MAC*ETHER_ADDR_LEN) },
10002 [NAN_ATTRIBUTE_TX_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
10003 [NAN_ATTRIBUTE_SDE_CONTROL_CONFIG_DP] = { .type = NLA_U8, .len = sizeof(uint8) },
10004 [NAN_ATTRIBUTE_SDE_CONTROL_RANGE_SUPPORT] = { .type = NLA_U8, .len = sizeof(uint8) },
10005 [NAN_ATTRIBUTE_SDE_CONTROL_DP_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
10006 [NAN_ATTRIBUTE_SDE_CONTROL_SECURITY] = { .type = NLA_U8, .len = sizeof(uint8) },
10007 [NAN_ATTRIBUTE_RECV_IND_CFG] = { .type = NLA_U8, .len = sizeof(uint8) },
10008 [NAN_ATTRIBUTE_KEY_TYPE] = { .type = NLA_U8, .len = sizeof(uint8) },
10009 [NAN_ATTRIBUTE_KEY_LEN] = { .type = NLA_U32, .len = sizeof(uint32) },
10010 [NAN_ATTRIBUTE_KEY_DATA] = { .type = NLA_BINARY, .len = NAN_MAX_PMK_LEN },
10011 [NAN_ATTRIBUTE_RSSI_THRESHOLD_FLAG] = { .type = NLA_U8, .len = sizeof(uint8) },
10012 [NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO_LEN] = { .type = NLA_U16, .len =
10013 sizeof(uint16) },
10014 [NAN_ATTRIBUTE_SDEA_SERVICE_SPECIFIC_INFO] = { .type = NLA_BINARY, .len =
10015 MAX_SDEA_SVC_INFO_LEN },
10016 [NAN_ATTRIBUTE_SECURITY] = { .type = NLA_U8, .len = sizeof(uint8) },
10017 [NAN_ATTRIBUTE_RANGING_INTERVAL] = { .type = NLA_U32, .len = sizeof(uint32) },
10018 [NAN_ATTRIBUTE_RANGING_INGRESS_LIMIT] = { .type = NLA_U32, .len = sizeof(uint32) },
10019 [NAN_ATTRIBUTE_RANGING_EGRESS_LIMIT] = { .type = NLA_U32, .len = sizeof(uint32) },
10020 [NAN_ATTRIBUTE_RANGING_INDICATION] = { .type = NLA_U32, .len = sizeof(uint32) },
10021 [NAN_ATTRIBUTE_SVC_RESPONDER_POLICY] = { .type = NLA_U8, .len = sizeof(uint8) },
10022 [NAN_ATTRIBUTE_NDP_ID] = { .type = NLA_U32, .len = sizeof(uint32) },
10023 [NAN_ATTRIBUTE_IFACE] = { .type = NLA_BINARY, .len = IFNAMSIZ+1 },
10024 [NAN_ATTRIBUTE_QOS] = { .type = NLA_U8, .len = sizeof(uint8) },
10025 [NAN_ATTRIBUTE_RSP_CODE] = { .type = NLA_U8, .len = sizeof(uint8) },
10026 [NAN_ATTRIBUTE_INST_COUNT] = { .type = NLA_U8, .len = sizeof(uint8) },
10027 [NAN_ATTRIBUTE_PEER_DISC_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
10028 [NAN_ATTRIBUTE_PEER_NDI_MAC_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
10029 [NAN_ATTRIBUTE_IF_ADDR] = { .type = NLA_BINARY, .len = ETHER_ADDR_LEN },
10030 [NAN_ATTRIBUTE_NO_CONFIG_AVAIL] = { .type = NLA_U8, .len = sizeof(uint8) },
10031 [NAN_ATTRIBUTE_CHANNEL_INFO] = { .type = NLA_BINARY, .len =
10032 sizeof(nan_channel_info_t) * NAN_MAX_CHANNEL_INFO_SUPPORTED },
10033 [NAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32, .len = sizeof(uint32) },
10034 [NAN_ATTRIBUTE_INSTANT_MODE_ENABLE] = { .type = NLA_U32, .len = sizeof(uint32) },
10035 [NAN_ATTRIBUTE_INSTANT_COMM_CHAN] = { .type = NLA_U32, .len = sizeof(uint32) },
10036 };
10037 #endif /* WL_NAN */
10038
10039 const struct nla_policy gscan_attr_policy[GSCAN_ATTRIBUTE_MAX] = {
10040 [GSCAN_ATTRIBUTE_BAND] = { .type = NLA_U32 },
10041 [GSCAN_ATTRIBUTE_NUM_CHANNELS] = { .type = NLA_U32 },
10042 [GSCAN_ATTRIBUTE_CHANNEL_LIST] = { .type = NLA_BINARY },
10043 [GSCAN_ATTRIBUTE_WHITELIST_SSID] = { .type = NLA_BINARY, .len = IEEE80211_MAX_SSID_LEN },
10044 [GSCAN_ATTRIBUTE_NUM_WL_SSID] = { .type = NLA_U32 },
10045 [GSCAN_ATTRIBUTE_WL_SSID_LEN] = { .type = NLA_U32 },
10046 [GSCAN_ATTRIBUTE_WL_SSID_FLUSH] = { .type = NLA_U32 },
10047 [GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM] = { .type = NLA_NESTED },
10048 /* length is sizeof(wl_ssid_whitelist_t) * MAX_SSID_WHITELIST_NUM */
10049 [GSCAN_ATTRIBUTE_NUM_BSSID] = { .type = NLA_U32 },
10050 [GSCAN_ATTRIBUTE_BSSID_PREF_LIST] = { .type = NLA_NESTED },
10051 /* length is sizeof(wl_bssid_pref_list_t) * MAX_BSSID_PREF_LIST_NUM */
10052 [GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH] = { .type = NLA_U32 },
10053 [GSCAN_ATTRIBUTE_BSSID_PREF] = { .type = NLA_BINARY, .len = ETH_ALEN },
10054 [GSCAN_ATTRIBUTE_RSSI_MODIFIER] = { .type = NLA_U32 },
10055 [GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH] = { .type = NLA_U32 },
10056 [GSCAN_ATTRIBUTE_BLACKLIST_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN },
10057 [GSCAN_ATTRIBUTE_ROAM_STATE_SET] = { .type = NLA_U32 },
10058 };
10059
10060 #ifdef DHD_WAKE_STATUS
10061 const struct nla_policy wake_stat_attr_policy[WAKE_STAT_ATTRIBUTE_MAX] = {
10062 [WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT] = { .type = NLA_U32 },
10063 #ifdef CUSTOM_WAKE_REASON_STATS
10064 [WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE] = { .type = NLA_BINARY,
10065 .len = (MAX_WAKE_REASON_STATS * sizeof(int))},
10066 #else
10067 [WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE] = { .type = NLA_BINARY,
10068 .len = (WLC_E_LAST * sizeof(uint))},
10069 #endif /* CUSTOM_WAKE_REASON_STATS */
10070 [WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT] = { .type = NLA_U32 },
10071 [WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED] = { .type = NLA_U32 },
10072 [WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW] = { .type = NLA_U32 },
10073 [WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE] = { .type = NLA_U32 },
10074 [WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT] = { .type = NLA_U32 },
10075 [WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED] = { .type = NLA_U32 },
10076 [WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE] = { .type = NLA_U32 },
10077 [WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT] = { .type = NLA_U32 },
10078 [WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT] = { .type = NLA_U32 },
10079 [WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT] = { .type = NLA_U32 },
10080 [WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT] = { .type = NLA_U32 },
10081 [WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT] = { .type = NLA_U32 },
10082 [WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA] = { .type = NLA_U32 },
10083 [WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA] = { .type = NLA_U32 },
10084 [WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS] = { .type = NLA_U32 },
10085 [WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
10086 [WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
10087 [WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT] = { .type = NLA_U32 },
10088 };
10089 #endif /* DHD_WAKE_STATUS */
10090
10091 #ifdef RSSI_MONITOR_SUPPORT
10092 const struct nla_policy rssi_monitor_attr_policy[RSSI_MONITOR_ATTRIBUTE_MAX] = {
10093 [RSSI_MONITOR_ATTRIBUTE_MAX_RSSI] = { .type = NLA_U32 },
10094 [RSSI_MONITOR_ATTRIBUTE_MIN_RSSI] = { .type = NLA_U32 },
10095 [RSSI_MONITOR_ATTRIBUTE_START] = { .type = NLA_U32 }
10096 };
10097 #endif /* RSSI_MONITOR_SUPPORT */
10098
10099
10100 const struct nla_policy hal_start_attr_policy[SET_HAL_START_ATTRIBUTE_MAX] = {
10101 [0] = { .strict_start_type = 0 },
10102 [SET_HAL_START_ATTRIBUTE_DEINIT] = { .type = NLA_UNSPEC },
10103 [SET_HAL_START_ATTRIBUTE_PRE_INIT] = { .type = NLA_NUL_STRING },
10104 [SET_HAL_START_ATTRIBUTE_EVENT_SOCK_PID] = { .type = NLA_U32 },
10105 };
10106
10107 const struct nla_policy andr_dbg_policy[DEBUG_ATTRIBUTE_MAX] = {
10108 [DEBUG_ATTRIBUTE_GET_DRIVER] = { .type = NLA_BINARY },
10109 [DEBUG_ATTRIBUTE_GET_FW] = { .type = NLA_BINARY },
10110 [DEBUG_ATTRIBUTE_RING_ID] = { .type = NLA_U32 },
10111 [DEBUG_ATTRIBUTE_RING_NAME] = { .type = NLA_NUL_STRING },
10112 [DEBUG_ATTRIBUTE_RING_FLAGS] = { .type = NLA_U32 },
10113 [DEBUG_ATTRIBUTE_LOG_LEVEL] = { .type = NLA_U32 },
10114 [DEBUG_ATTRIBUTE_LOG_TIME_INTVAL] = { .type = NLA_U32 },
10115 [DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE] = { .type = NLA_U32 },
10116 [DEBUG_ATTRIBUTE_FW_DUMP_LEN] = { .type = NLA_U32 },
10117 [DEBUG_ATTRIBUTE_FW_DUMP_DATA] = { .type = NLA_U64 },
10118 [DEBUG_ATTRIBUTE_FW_ERR_CODE] = { .type = NLA_U32 },
10119 [DEBUG_ATTRIBUTE_RING_DATA] = { .type = NLA_BINARY },
10120 [DEBUG_ATTRIBUTE_RING_STATUS] = { .type = NLA_BINARY },
10121 [DEBUG_ATTRIBUTE_RING_NUM] = { .type = NLA_U32 },
10122 [DEBUG_ATTRIBUTE_DRIVER_DUMP_LEN] = { .type = NLA_U32 },
10123 [DEBUG_ATTRIBUTE_DRIVER_DUMP_DATA] = { .type = NLA_BINARY },
10124 [DEBUG_ATTRIBUTE_PKT_FATE_NUM] = { .type = NLA_U32 },
10125 [DEBUG_ATTRIBUTE_PKT_FATE_DATA] = { .type = NLA_U64 },
10126 [DEBUG_ATTRIBUTE_HANG_REASON] = { .type = NLA_BINARY },
10127 };
10128
10129 #if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
10130 const struct nla_policy andr_twt_attr_policy[ANDR_TWT_ATTR_MAX] = {
10131 [ANDR_TWT_ATTR_NONE] = { .strict_start_type = 0 },
10132 [ANDR_TWT_ATTR_CONFIG_ID] = { .type = NLA_U8 },
10133 [ANDR_TWT_ATTR_NEGOTIATION_TYPE] = { .type = NLA_U8 },
10134 [ANDR_TWT_ATTR_TRIGGER_TYPE] = { .type = NLA_U8 },
10135 [ANDR_TWT_ATTR_WAKE_DURATION] = { .type = NLA_U32 },
10136 [ANDR_TWT_ATTR_WAKE_INTERVAL] = { .type = NLA_U32 },
10137 [ANDR_TWT_ATTR_WAKE_INTERVAL_MIN] = { .type = NLA_U32 },
10138 [ANDR_TWT_ATTR_WAKE_INTERVAL_MAX] = { .type = NLA_U32 },
10139 [ANDR_TWT_ATTR_WAKE_DURATION_MIN] = { .type = NLA_U32 },
10140 [ANDR_TWT_ATTR_WAKE_DURATION_MAX] = { .type = NLA_U32 },
10141 [ANDR_TWT_ATTR_AVG_PKT_SIZE] = { .type = NLA_U32 },
10142 [ANDR_TWT_ATTR_AVG_PKT_NUM] = { .type = NLA_U32 },
10143 [ANDR_TWT_ATTR_WAKETIME_OFFSET] = { .type = NLA_U32 },
10144 [ANDR_TWT_ATTR_ALL_TWT] = { .type = NLA_U8 },
10145 [ANDR_TWT_ATTR_RESUME_TIME] = { .type = NLA_U32 },
10146 [ANDR_TWT_ATTR_AVG_EOSP_DUR] = { .type = NLA_U32 },
10147 [ANDR_TWT_ATTR_EOSP_CNT] = { .type = NLA_U32 },
10148 [ANDR_TWT_ATTR_NUM_SP] = { .type = NLA_U32 },
10149 [ANDR_TWT_ATTR_DEVICE_CAP] = { .type = NLA_U32 },
10150 [ANDR_TWT_ATTR_PEER_CAP] = { .type = NLA_U32 },
10151 [ANDR_TWT_ATTR_STATUS] = { .type = NLA_U8 },
10152 [ANDR_TWT_ATTR_REASON_CODE] = { .type = NLA_U8 },
10153 [ANDR_TWT_ATTR_TWT_RESUMED] = { .type = NLA_U8 },
10154 [ANDR_TWT_ATTR_TWT_NOTIFICATION] = { .type = NLA_U8 },
10155 [ANDR_TWT_ATTR_SUB_EVENT] = { .type = NLA_U8 },
10156 [ANDR_TWT_ATTR_NUM_PEER_STATS] = { .type = NLA_U8 },
10157 [ANDR_TWT_ATTR_AVG_PKT_NUM_TX] = { .type = NLA_U32 },
10158 [ANDR_TWT_ATTR_AVG_PKT_SIZE_TX] = { .type = NLA_U32 },
10159 [ANDR_TWT_ATTR_AVG_PKT_NUM_RX] = { .type = NLA_U32 },
10160 [ANDR_TWT_ATTR_AVG_PKT_SIZE_RX] = { .type = NLA_U32 },
10161 };
10162 #endif /* !WL_TWT && WL_TWT_HAL_IF */
10163
10164 #endif /* LINUX_VERSION >= 5.3 */
10165
10166 static struct wiphy_vendor_command wl_vendor_cmds [] = {
10167 {
10168 {
10169 .vendor_id = OUI_BRCM,
10170 .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
10171 },
10172 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10173 .doit = wl_cfgvendor_priv_string_handler,
10174 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10175 .policy = brcm_drv_attr_policy,
10176 .maxattr = BRCM_ATTR_DRIVER_MAX
10177 #endif /* LINUX_VERSION >= 5.3 */
10178 },
10179 #ifdef BCM_PRIV_CMD_SUPPORT
10180 {
10181 {
10182 .vendor_id = OUI_BRCM,
10183 .subcmd = BRCM_VENDOR_SCMD_BCM_STR
10184 },
10185 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10186 .doit = wl_cfgvendor_priv_bcm_handler,
10187 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10188 .policy = brcm_drv_attr_policy,
10189 .maxattr = BRCM_ATTR_DRIVER_MAX
10190 #endif /* LINUX_VERSION >= 5.3 */
10191 },
10192 #endif /* BCM_PRIV_CMD_SUPPORT */
10193 #if defined(WL_SAE) || defined(WL_CLIENT_SAE)
10194 {
10195 {
10196 .vendor_id = OUI_BRCM,
10197 .subcmd = BRCM_VENDOR_SCMD_BCM_PSK
10198 },
10199 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10200 .doit = wl_cfgvendor_set_sae_password
10201 },
10202 #endif /* WL_SAE || WL_CLIENT_SAE */
10203 {
10204 {
10205 .vendor_id = OUI_BRCM,
10206 .subcmd = BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS
10207 },
10208 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10209 .doit = wl_cfgvendor_connect_params_handler,
10210 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10211 .policy = brcm_drv_attr_policy,
10212 .maxattr = BRCM_ATTR_DRIVER_MAX
10213 #endif /* LINUX_VERSION >= 5.3 */
10214 },
10215 {
10216 {
10217 .vendor_id = OUI_BRCM,
10218 .subcmd = BRCM_VENDOR_SCMD_SET_START_AP_PARAMS
10219 },
10220 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10221 .doit = wl_cfgvendor_start_ap_params_handler,
10222 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10223 .policy = brcm_drv_attr_policy,
10224 .maxattr = BRCM_ATTR_DRIVER_MAX
10225 #endif /* LINUX_VERSION >= 5.3 */
10226 },
10227 #ifdef GSCAN_SUPPORT
10228 {
10229 {
10230 .vendor_id = OUI_GOOGLE,
10231 .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
10232 },
10233 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10234 .doit = wl_cfgvendor_gscan_get_capabilities
10235 },
10236 {
10237 {
10238 .vendor_id = OUI_GOOGLE,
10239 .subcmd = GSCAN_SUBCMD_SET_CONFIG
10240 },
10241 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10242 .doit = wl_cfgvendor_set_scan_cfg
10243 },
10244 {
10245 {
10246 .vendor_id = OUI_GOOGLE,
10247 .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
10248 },
10249 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10250 .doit = wl_cfgvendor_set_batch_scan_cfg
10251 },
10252 {
10253 {
10254 .vendor_id = OUI_GOOGLE,
10255 .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
10256 },
10257 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10258 .doit = wl_cfgvendor_initiate_gscan
10259 },
10260 {
10261 {
10262 .vendor_id = OUI_GOOGLE,
10263 .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
10264 },
10265 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10266 .doit = wl_cfgvendor_enable_full_scan_result
10267 },
10268 {
10269 {
10270 .vendor_id = OUI_GOOGLE,
10271 .subcmd = GSCAN_SUBCMD_SET_HOTLIST
10272 },
10273 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10274 .doit = wl_cfgvendor_hotlist_cfg
10275 },
10276 {
10277 {
10278 .vendor_id = OUI_GOOGLE,
10279 .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
10280 },
10281 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10282 .doit = wl_cfgvendor_gscan_get_batch_results
10283 },
10284 #endif /* GSCAN_SUPPORT */
10285 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
10286 {
10287 {
10288 .vendor_id = OUI_GOOGLE,
10289 .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
10290 },
10291 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10292 .doit = wl_cfgvendor_gscan_get_channel_list,
10293 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10294 .policy = gscan_attr_policy,
10295 .maxattr = GSCAN_ATTRIBUTE_MAX
10296 #endif /* LINUX_VERSION >= 5.3 */
10297 },
10298 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
10299 #ifdef RTT_SUPPORT
10300 {
10301 {
10302 .vendor_id = OUI_GOOGLE,
10303 .subcmd = RTT_SUBCMD_SET_CONFIG
10304 },
10305 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10306 .doit = wl_cfgvendor_rtt_set_config,
10307 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10308 .policy = rtt_attr_policy,
10309 .maxattr = RTT_ATTRIBUTE_MAX
10310 #endif /* LINUX_VERSION >= 5.3 */
10311 },
10312 {
10313 {
10314 .vendor_id = OUI_GOOGLE,
10315 .subcmd = RTT_SUBCMD_CANCEL_CONFIG
10316 },
10317 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10318 .doit = wl_cfgvendor_rtt_cancel_config,
10319 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10320 .policy = rtt_attr_policy,
10321 .maxattr = RTT_ATTRIBUTE_MAX
10322 #endif /* LINUX_VERSION >= 5.3 */
10323 },
10324 {
10325 {
10326 .vendor_id = OUI_GOOGLE,
10327 .subcmd = RTT_SUBCMD_GETCAPABILITY
10328 },
10329 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10330 .doit = wl_cfgvendor_rtt_get_capability,
10331 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10332 .policy = rtt_attr_policy,
10333 .maxattr = RTT_ATTRIBUTE_MAX
10334 #endif /* LINUX_VERSION >= 5.3 */
10335 },
10336 {
10337 {
10338 .vendor_id = OUI_GOOGLE,
10339 .subcmd = RTT_SUBCMD_GETAVAILCHANNEL
10340 },
10341 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10342 .doit = wl_cfgvendor_rtt_get_responder_info,
10343 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10344 .policy = rtt_attr_policy,
10345 .maxattr = RTT_ATTRIBUTE_MAX
10346 #endif /* LINUX_VERSION >= 5.3 */
10347 },
10348 {
10349 {
10350 .vendor_id = OUI_GOOGLE,
10351 .subcmd = RTT_SUBCMD_SET_RESPONDER
10352 },
10353 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10354 .doit = wl_cfgvendor_rtt_set_responder,
10355 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10356 .policy = rtt_attr_policy,
10357 .maxattr = RTT_ATTRIBUTE_MAX
10358 #endif /* LINUX_VERSION >= 5.3 */
10359 },
10360 {
10361 {
10362 .vendor_id = OUI_GOOGLE,
10363 .subcmd = RTT_SUBCMD_CANCEL_RESPONDER
10364 },
10365 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10366 .doit = wl_cfgvendor_rtt_cancel_responder,
10367 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10368 .policy = rtt_attr_policy,
10369 .maxattr = RTT_ATTRIBUTE_MAX
10370 #endif /* LINUX_VERSION >= 5.3 */
10371 },
10372 #endif /* RTT_SUPPORT */
10373 {
10374 {
10375 .vendor_id = OUI_GOOGLE,
10376 .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
10377 },
10378 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10379 .doit = wl_cfgvendor_get_feature_set,
10380 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10381 .policy = andr_wifi_attr_policy,
10382 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10383 #endif /* LINUX_VERSION >= 5.3 */
10384 },
10385 {
10386 {
10387 .vendor_id = OUI_GOOGLE,
10388 .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
10389 },
10390 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10391 .doit = wl_cfgvendor_get_feature_set_matrix,
10392 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10393 .policy = andr_wifi_attr_policy,
10394 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10395 #endif /* LINUX_VERSION >= 5.3 */
10396 },
10397 {
10398 {
10399 .vendor_id = OUI_GOOGLE,
10400 .subcmd = ANDR_WIFI_RANDOM_MAC_OUI
10401 },
10402 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10403 .doit = wl_cfgvendor_set_rand_mac_oui,
10404 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10405 .policy = andr_wifi_attr_policy,
10406 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10407 #endif /* LINUX_VERSION >= 5.3 */
10408 },
10409 #ifdef CUSTOM_FORCE_NODFS_FLAG
10410 {
10411 {
10412 .vendor_id = OUI_GOOGLE,
10413 .subcmd = ANDR_WIFI_NODFS_CHANNELS
10414 },
10415 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10416 .doit = wl_cfgvendor_set_nodfs_flag,
10417 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10418 .policy = andr_wifi_attr_policy,
10419 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10420 #endif /* LINUX_VERSION >= 5.3 */
10421 },
10422 #endif /* CUSTOM_FORCE_NODFS_FLAG */
10423 {
10424 {
10425 .vendor_id = OUI_GOOGLE,
10426 .subcmd = ANDR_WIFI_SET_COUNTRY
10427 },
10428 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10429 .doit = wl_cfgvendor_set_country,
10430 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10431 .policy = andr_wifi_attr_policy,
10432 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10433 #endif /* LINUX_VERSION >= 5.3 */
10434 },
10435 #ifdef LINKSTAT_SUPPORT
10436 {
10437 {
10438 .vendor_id = OUI_GOOGLE,
10439 .subcmd = LSTATS_SUBCMD_GET_INFO
10440 },
10441 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10442 .doit = wl_cfgvendor_lstats_get_info
10443 },
10444 #endif /* LINKSTAT_SUPPORT */
10445
10446 #ifdef GSCAN_SUPPORT
10447 {
10448 {
10449 .vendor_id = OUI_GOOGLE,
10450 .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID
10451 },
10452 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10453 .doit = wl_cfgvendor_epno_cfg
10454
10455 },
10456 {
10457 {
10458 .vendor_id = OUI_GOOGLE,
10459 .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
10460 },
10461 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10462 .doit = wl_cfgvendor_set_lazy_roam_cfg
10463
10464 },
10465 {
10466 {
10467 .vendor_id = OUI_GOOGLE,
10468 .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM
10469 },
10470 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10471 .doit = wl_cfgvendor_enable_lazy_roam
10472
10473 },
10474 {
10475 {
10476 .vendor_id = OUI_GOOGLE,
10477 .subcmd = WIFI_SUBCMD_SET_BSSID_PREF
10478 },
10479 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10480 .doit = wl_cfgvendor_set_bssid_pref
10481
10482 },
10483 #endif /* GSCAN_SUPPORT */
10484 #if defined(GSCAN_SUPPORT) || defined(ROAMEXP_SUPPORT)
10485 {
10486 {
10487 .vendor_id = OUI_GOOGLE,
10488 .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST
10489 },
10490 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10491 .doit = wl_cfgvendor_set_ssid_whitelist,
10492 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10493 .policy = gscan_attr_policy,
10494 .maxattr = GSCAN_ATTRIBUTE_MAX
10495 #endif /* LINUX_VERSION >= 5.3 */
10496
10497 },
10498 {
10499 {
10500 .vendor_id = OUI_GOOGLE,
10501 .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST
10502 },
10503 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10504 .doit = wl_cfgvendor_set_bssid_blacklist,
10505 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10506 .policy = gscan_attr_policy,
10507 .maxattr = GSCAN_ATTRIBUTE_MAX
10508 #endif /* LINUX_VERSION >= 5.3 */
10509 },
10510 #endif /* GSCAN_SUPPORT || ROAMEXP_SUPPORT */
10511 #ifdef ROAMEXP_SUPPORT
10512 {
10513 {
10514 .vendor_id = OUI_GOOGLE,
10515 .subcmd = WIFI_SUBCMD_FW_ROAM_POLICY
10516 },
10517 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10518 .doit = wl_cfgvendor_set_fw_roaming_state,
10519 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10520 .policy = gscan_attr_policy,
10521 .maxattr = GSCAN_ATTRIBUTE_MAX
10522 #endif /* LINUX_VERSION >= 5.3 */
10523 },
10524 {
10525 {
10526 .vendor_id = OUI_GOOGLE,
10527 .subcmd = WIFI_SUBCMD_ROAM_CAPABILITY
10528 },
10529 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10530 .doit = wl_cfgvendor_fw_roam_get_capability
10531 },
10532 #endif /* ROAMEXP_SUPPORT */
10533 {
10534 {
10535 .vendor_id = OUI_GOOGLE,
10536 .subcmd = DEBUG_GET_VER
10537 },
10538 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10539 .doit = wl_cfgvendor_dbg_get_version,
10540 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10541 .policy = andr_dbg_policy,
10542 .maxattr = DEBUG_ATTRIBUTE_MAX
10543 #endif /* LINUX_VERSION >= 5.3 */
10544 },
10545 #ifdef DHD_LOG_DUMP
10546 {
10547 {
10548 .vendor_id = OUI_GOOGLE,
10549 .subcmd = DEBUG_GET_FILE_DUMP_BUF
10550 },
10551 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10552 .doit = wl_cfgvendor_dbg_file_dump,
10553 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10554 .policy = dump_buf_policy,
10555 .maxattr = DUMP_BUF_ATTR_MAX
10556 #endif /* LINUX_VERSION >= 5.3 */
10557 },
10558 #endif /* DHD_LOG_DUMP */
10559
10560 #ifdef DEBUGABILITY
10561 {
10562 {
10563 .vendor_id = OUI_GOOGLE,
10564 .subcmd = DEBUG_TRIGGER_MEM_DUMP
10565 },
10566 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10567 .doit = wl_cfgvendor_dbg_trigger_mem_dump
10568 },
10569 {
10570 {
10571 .vendor_id = OUI_GOOGLE,
10572 .subcmd = DEBUG_GET_MEM_DUMP
10573 },
10574 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10575 .doit = wl_cfgvendor_dbg_get_mem_dump,
10576 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10577 .policy = andr_dbg_policy,
10578 .maxattr = DEBUG_ATTRIBUTE_MAX
10579 #endif /* LINUX_VERSION >= 5.3 */
10580 },
10581 {
10582 {
10583 .vendor_id = OUI_GOOGLE,
10584 .subcmd = DEBUG_START_LOGGING
10585 },
10586 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10587 .doit = wl_cfgvendor_dbg_start_logging,
10588 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10589 .policy = andr_dbg_policy,
10590 .maxattr = DEBUG_ATTRIBUTE_MAX
10591 #endif /* LINUX_VERSION >= 5.3 */
10592 },
10593 {
10594 {
10595 .vendor_id = OUI_GOOGLE,
10596 .subcmd = DEBUG_RESET_LOGGING
10597 },
10598 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10599 .doit = wl_cfgvendor_dbg_reset_logging
10600 },
10601 {
10602 {
10603 .vendor_id = OUI_GOOGLE,
10604 .subcmd = DEBUG_GET_RING_STATUS
10605 },
10606 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10607 .doit = wl_cfgvendor_dbg_get_ring_status,
10608 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10609 .policy = andr_dbg_policy,
10610 .maxattr = DEBUG_ATTRIBUTE_MAX
10611 #endif /* LINUX_VERSION >= 5.3 */
10612 },
10613 {
10614 {
10615 .vendor_id = OUI_GOOGLE,
10616 .subcmd = DEBUG_GET_RING_DATA
10617 },
10618 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10619 .doit = wl_cfgvendor_dbg_get_ring_data,
10620 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10621 .policy = andr_dbg_policy,
10622 .maxattr = DEBUG_ATTRIBUTE_MAX
10623 #endif /* LINUX_VERSION >= 5.3 */
10624 },
10625 #endif /* DEBUGABILITY */
10626 {
10627 {
10628 .vendor_id = OUI_GOOGLE,
10629 .subcmd = DEBUG_GET_FEATURE
10630 },
10631 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10632 .doit = wl_cfgvendor_dbg_get_feature
10633 },
10634 #ifdef DBG_PKT_MON
10635 {
10636 {
10637 .vendor_id = OUI_GOOGLE,
10638 .subcmd = DEBUG_START_PKT_FATE_MONITORING
10639 },
10640 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10641 .doit = wl_cfgvendor_dbg_start_pkt_fate_monitoring
10642 },
10643 {
10644 {
10645 .vendor_id = OUI_GOOGLE,
10646 .subcmd = DEBUG_GET_TX_PKT_FATES
10647 },
10648 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10649 .doit = wl_cfgvendor_dbg_get_tx_pkt_fates,
10650 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10651 .policy = andr_dbg_policy,
10652 .maxattr = DEBUG_ATTRIBUTE_MAX
10653 #endif /* LINUX_VERSION >= 5.3 */
10654 },
10655 {
10656 {
10657 .vendor_id = OUI_GOOGLE,
10658 .subcmd = DEBUG_GET_RX_PKT_FATES
10659 },
10660 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10661 .doit = wl_cfgvendor_dbg_get_rx_pkt_fates,
10662 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10663 .policy = andr_dbg_policy,
10664 .maxattr = DEBUG_ATTRIBUTE_MAX
10665 #endif /* LINUX_VERSION >= 5.3 */
10666 },
10667 #endif /* DBG_PKT_MON */
10668 #ifdef KEEP_ALIVE
10669 {
10670 {
10671 .vendor_id = OUI_GOOGLE,
10672 .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
10673 },
10674 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10675 .doit = wl_cfgvendor_start_mkeep_alive,
10676 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10677 .policy = mkeep_alive_attr_policy,
10678 .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
10679 #endif /* LINUX_VERSION >= 5.3 */
10680 },
10681 {
10682 {
10683 .vendor_id = OUI_GOOGLE,
10684 .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
10685 },
10686 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10687 .doit = wl_cfgvendor_stop_mkeep_alive,
10688 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10689 .policy = mkeep_alive_attr_policy,
10690 .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
10691 #endif /* LINUX_VERSION >= 5.3 */
10692 },
10693 #endif /* KEEP_ALIVE */
10694 #ifdef WL_NAN
10695 {
10696 {
10697 .vendor_id = OUI_GOOGLE,
10698 .subcmd = NAN_WIFI_SUBCMD_ENABLE
10699 },
10700 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10701 .doit = wl_cfgvendor_nan_start_handler,
10702 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10703 .policy = nan_attr_policy,
10704 .maxattr = NAN_ATTRIBUTE_MAX
10705 #endif /* LINUX_VERSION >= 5.3 */
10706 },
10707 {
10708 {
10709 .vendor_id = OUI_GOOGLE,
10710 .subcmd = NAN_WIFI_SUBCMD_DISABLE
10711 },
10712 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10713 .doit = wl_cfgvendor_nan_stop_handler,
10714 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10715 .policy = nan_attr_policy,
10716 .maxattr = NAN_ATTRIBUTE_MAX
10717 #endif /* LINUX_VERSION >= 5.3 */
10718 },
10719 {
10720 {
10721 .vendor_id = OUI_GOOGLE,
10722 .subcmd = NAN_WIFI_SUBCMD_CONFIG
10723 },
10724 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10725 .doit = wl_cfgvendor_nan_config_handler,
10726 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10727 .policy = nan_attr_policy,
10728 .maxattr = NAN_ATTRIBUTE_MAX
10729 #endif /* LINUX_VERSION >= 5.3 */
10730 },
10731 {
10732 {
10733 .vendor_id = OUI_GOOGLE,
10734 .subcmd = NAN_WIFI_SUBCMD_REQUEST_PUBLISH
10735 },
10736 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10737 .doit = wl_cfgvendor_nan_req_publish,
10738 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10739 .policy = nan_attr_policy,
10740 .maxattr = NAN_ATTRIBUTE_MAX
10741 #endif /* LINUX_VERSION >= 5.3 */
10742 },
10743 {
10744 {
10745 .vendor_id = OUI_GOOGLE,
10746 .subcmd = NAN_WIFI_SUBCMD_REQUEST_SUBSCRIBE
10747 },
10748 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10749 .doit = wl_cfgvendor_nan_req_subscribe,
10750 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10751 .policy = nan_attr_policy,
10752 .maxattr = NAN_ATTRIBUTE_MAX
10753 #endif /* LINUX_VERSION >= 5.3 */
10754 },
10755 {
10756 {
10757 .vendor_id = OUI_GOOGLE,
10758 .subcmd = NAN_WIFI_SUBCMD_CANCEL_PUBLISH
10759 },
10760 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10761 .doit = wl_cfgvendor_nan_cancel_publish,
10762 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10763 .policy = nan_attr_policy,
10764 .maxattr = NAN_ATTRIBUTE_MAX
10765 #endif /* LINUX_VERSION >= 5.3 */
10766 },
10767 {
10768 {
10769 .vendor_id = OUI_GOOGLE,
10770 .subcmd = NAN_WIFI_SUBCMD_CANCEL_SUBSCRIBE
10771 },
10772 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10773 .doit = wl_cfgvendor_nan_cancel_subscribe,
10774 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10775 .policy = nan_attr_policy,
10776 .maxattr = NAN_ATTRIBUTE_MAX
10777 #endif /* LINUX_VERSION >= 5.3 */
10778 },
10779 {
10780 {
10781 .vendor_id = OUI_GOOGLE,
10782 .subcmd = NAN_WIFI_SUBCMD_TRANSMIT
10783 },
10784 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10785 .doit = wl_cfgvendor_nan_transmit,
10786 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10787 .policy = nan_attr_policy,
10788 .maxattr = NAN_ATTRIBUTE_MAX
10789 #endif /* LINUX_VERSION >= 5.3 */
10790 },
10791 {
10792 {
10793 .vendor_id = OUI_GOOGLE,
10794 .subcmd = NAN_WIFI_SUBCMD_GET_CAPABILITIES
10795 },
10796 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10797 .doit = wl_cfgvendor_nan_get_capablities
10798 },
10799
10800 {
10801 {
10802 .vendor_id = OUI_GOOGLE,
10803 .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_CREATE
10804 },
10805 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10806 .doit = wl_cfgvendor_nan_data_path_iface_create,
10807 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10808 .policy = nan_attr_policy,
10809 .maxattr = NAN_ATTRIBUTE_MAX
10810 #endif /* LINUX_VERSION >= 5.3 */
10811 },
10812 {
10813 {
10814 .vendor_id = OUI_GOOGLE,
10815 .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_IFACE_DELETE
10816 },
10817 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10818 .doit = wl_cfgvendor_nan_data_path_iface_delete,
10819 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10820 .policy = nan_attr_policy,
10821 .maxattr = NAN_ATTRIBUTE_MAX
10822 #endif /* LINUX_VERSION >= 5.3 */
10823 },
10824 {
10825 {
10826 .vendor_id = OUI_GOOGLE,
10827 .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_REQUEST
10828 },
10829 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10830 .doit = wl_cfgvendor_nan_data_path_request,
10831 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10832 .policy = nan_attr_policy,
10833 .maxattr = NAN_ATTRIBUTE_MAX
10834 #endif /* LINUX_VERSION >= 5.3 */
10835 },
10836 {
10837 {
10838 .vendor_id = OUI_GOOGLE,
10839 .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_RESPONSE
10840 },
10841 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10842 .doit = wl_cfgvendor_nan_data_path_response,
10843 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10844 .policy = nan_attr_policy,
10845 .maxattr = NAN_ATTRIBUTE_MAX
10846 #endif /* LINUX_VERSION >= 5.3 */
10847 },
10848 {
10849 {
10850 .vendor_id = OUI_GOOGLE,
10851 .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_END
10852 },
10853 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10854 .doit = wl_cfgvendor_nan_data_path_end,
10855 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10856 .policy = nan_attr_policy,
10857 .maxattr = NAN_ATTRIBUTE_MAX
10858 #endif /* LINUX_VERSION >= 5.3 */
10859 },
10860 #ifdef WL_NAN_DISC_CACHE
10861 {
10862 {
10863 .vendor_id = OUI_GOOGLE,
10864 .subcmd = NAN_WIFI_SUBCMD_DATA_PATH_SEC_INFO
10865 },
10866 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10867 .doit = wl_cfgvendor_nan_data_path_sec_info,
10868 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10869 .policy = nan_attr_policy,
10870 .maxattr = NAN_ATTRIBUTE_MAX
10871 #endif /* LINUX_VERSION >= 5.3 */
10872 },
10873 #endif /* WL_NAN_DISC_CACHE */
10874 {
10875 {
10876 .vendor_id = OUI_GOOGLE,
10877 .subcmd = NAN_WIFI_SUBCMD_VERSION_INFO
10878 },
10879 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10880 .doit = wl_cfgvendor_nan_version_info
10881 },
10882 {
10883 {
10884 .vendor_id = OUI_GOOGLE,
10885 .subcmd = NAN_WIFI_SUBCMD_ENABLE_MERGE
10886 },
10887 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10888 .doit = wl_cfgvendor_nan_enable_merge,
10889 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10890 .policy = nan_attr_policy,
10891 .maxattr = NAN_ATTRIBUTE_MAX
10892 #endif /* LINUX_VERSION >= 5.3 */
10893 },
10894 #endif /* WL_NAN */
10895 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
10896 {
10897 {
10898 .vendor_id = OUI_GOOGLE,
10899 .subcmd = APF_SUBCMD_GET_CAPABILITIES
10900 },
10901 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10902 .doit = wl_cfgvendor_apf_get_capabilities,
10903 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10904 .policy = apf_atrribute_policy,
10905 .maxattr = APF_ATTRIBUTE_MAX
10906 #endif /* LINUX_VERSION >= 5.3 */
10907 },
10908
10909 {
10910 {
10911 .vendor_id = OUI_GOOGLE,
10912 .subcmd = APF_SUBCMD_SET_FILTER
10913 },
10914 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10915 .doit = wl_cfgvendor_apf_set_filter,
10916 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10917 .policy = apf_atrribute_policy,
10918 .maxattr = APF_ATTRIBUTE_MAX
10919 #endif /* LINUX_VERSION >= 5.3 */
10920 },
10921 #endif /* PKT_FILTER_SUPPORT && APF */
10922 #ifdef NDO_CONFIG_SUPPORT
10923 {
10924 {
10925 .vendor_id = OUI_GOOGLE,
10926 .subcmd = WIFI_SUBCMD_CONFIG_ND_OFFLOAD
10927 },
10928 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10929 .doit = wl_cfgvendor_configure_nd_offload,
10930 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10931 .policy = andr_wifi_attr_policy,
10932 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10933 #endif /* LINUX_VERSION >= 5.3 */
10934 },
10935 #endif /* NDO_CONFIG_SUPPORT */
10936 #ifdef RSSI_MONITOR_SUPPORT
10937 {
10938 {
10939 .vendor_id = OUI_GOOGLE,
10940 .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR
10941 },
10942 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10943 .doit = wl_cfgvendor_set_rssi_monitor,
10944 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10945 .policy = rssi_monitor_attr_policy,
10946 .maxattr = RSSI_MONITOR_ATTRIBUTE_MAX
10947 #endif /* LINUX_VERSION >= 5.3 */
10948 },
10949 #endif /* RSSI_MONITOR_SUPPORT */
10950 #ifdef DHD_WAKE_STATUS
10951 {
10952 {
10953 .vendor_id = OUI_GOOGLE,
10954 .subcmd = DEBUG_GET_WAKE_REASON_STATS
10955 },
10956 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10957 .doit = wl_cfgvendor_get_wake_reason_stats,
10958 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10959 .policy = wake_stat_attr_policy,
10960 .maxattr = WAKE_STAT_ATTRIBUTE_MAX
10961 #endif /* LINUX_VERSION >= 5.3 */
10962 },
10963 #endif /* DHD_WAKE_STATUS */
10964 #ifdef DHDTCPACK_SUPPRESS
10965 {
10966 {
10967 .vendor_id = OUI_GOOGLE,
10968 .subcmd = WIFI_SUBCMD_CONFIG_TCPACK_SUP
10969 },
10970 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10971 .doit = wl_cfgvendor_set_tcpack_sup_mode,
10972 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10973 .policy = andr_wifi_attr_policy,
10974 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
10975 #endif /* LINUX_VERSION >= 5.3 */
10976 },
10977 #endif /* DHDTCPACK_SUPPRESS */
10978 #if !defined(BCMSUP_4WAY_HANDSHAKE) || (LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0))
10979 {
10980 {
10981 .vendor_id = OUI_BRCM,
10982 .subcmd = BRCM_VENDOR_SCMD_SET_PMK
10983 },
10984 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10985 .doit = wl_cfgvendor_set_pmk,
10986 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
10987 .policy = brcm_drv_attr_policy,
10988 .maxattr = BRCM_ATTR_DRIVER_MAX
10989 #endif /* LINUX_VERSION >= 5.3 */
10990 },
10991 #endif /* !BCMSUP_4WAY_HANDSHAKE || LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) */
10992 {
10993 {
10994 .vendor_id = OUI_BRCM,
10995 .subcmd = BRCM_VENDOR_SCMD_GET_FEATURES
10996 },
10997 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
10998 .doit = wl_cfgvendor_get_driver_feature,
10999 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11000 .policy = brcm_drv_attr_policy,
11001 .maxattr = BRCM_ATTR_DRIVER_MAX
11002 #endif /* LINUX_VERSION >= 5.3 */
11003 },
11004 #if defined(WL_CFG80211) && defined(DHD_FILE_DUMP_EVENT)
11005 {
11006 {
11007 .vendor_id = OUI_GOOGLE,
11008 .subcmd = DEBUG_FILE_DUMP_DONE_IND
11009 },
11010 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11011 .doit = wl_cfgvendor_notify_dump_completion
11012 },
11013 #endif /* WL_CFG80211 && DHD_FILE_DUMP_EVENT */
11014 #if defined(WL_CFG80211)
11015 {
11016 {
11017 .vendor_id = OUI_GOOGLE,
11018 .subcmd = DEBUG_SET_HAL_START
11019 },
11020 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11021 .doit = wl_cfgvendor_set_hal_started,
11022 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11023 .policy = hal_start_attr_policy,
11024 .maxattr = SET_HAL_START_ATTRIBUTE_MAX
11025 #endif /* LINUX_VERSION >= 5.3 */
11026 },
11027 {
11028 {
11029 .vendor_id = OUI_GOOGLE,
11030 .subcmd = DEBUG_SET_HAL_STOP
11031 },
11032 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11033 .doit = wl_cfgvendor_stop_hal
11034 },
11035 {
11036 {
11037 .vendor_id = OUI_GOOGLE,
11038 .subcmd = DEBUG_SET_HAL_PID
11039 },
11040 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11041 .doit = wl_cfgvendor_set_hal_pid,
11042 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11043 .policy = hal_start_attr_policy,
11044 .maxattr = SET_HAL_START_ATTRIBUTE_MAX
11045 #endif /* LINUX_VERSION >= 5.3 */
11046 },
11047 #endif /* WL_CFG80211 */
11048 #ifdef WL_LATENCY_MODE
11049 {
11050 {
11051 .vendor_id = OUI_GOOGLE,
11052 .subcmd = WIFI_SUBCMD_SET_LATENCY_MODE
11053 },
11054 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11055 .doit = wl_cfgvendor_set_latency_mode,
11056 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11057 .policy = andr_wifi_attr_policy,
11058 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
11059 #endif /* LINUX_VERSION >= 5.3 */
11060 },
11061 #endif /* WL_LATENCY_MODE */
11062 #ifdef WL_P2P_RAND
11063 {
11064 {
11065 .vendor_id = OUI_BRCM,
11066 .subcmd = BRCM_VENDOR_SCMD_SET_MAC
11067 },
11068 .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
11069 .doit = wl_cfgvendor_set_p2p_rand_mac,
11070 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11071 .policy = brcm_drv_attr_policy,
11072 .maxattr = BRCM_ATTR_DRIVER_MAX
11073 #endif /* LINUX_VERSION >= 5.3 */
11074 },
11075 #endif /* WL_P2P_RAND */
11076 #ifdef WL_SAR_TX_POWER
11077 {
11078 {
11079 .vendor_id = OUI_GOOGLE,
11080 .subcmd = WIFI_SUBCMD_TX_POWER_SCENARIO
11081 },
11082 .flags = WIPHY_VENDOR_CMD_NEED_WDEV,
11083 .doit = wl_cfgvendor_tx_power_scenario,
11084 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11085 .policy = andr_wifi_attr_policy,
11086 .maxattr = ANDR_WIFI_ATTRIBUTE_MAX
11087 #endif /* LINUX_VERSION >= 5.3 */
11088 }
11089 #endif /* WL_SAR_TX_POWER */
11090 #if !defined(WL_TWT) && defined(WL_TWT_HAL_IF)
11091 {
11092 {
11093 .vendor_id = OUI_GOOGLE,
11094 .subcmd = ANDR_TWT_SUBCMD_SETUP
11095 },
11096 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11097 .doit = wl_cfgvendor_twt_setup,
11098 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11099 .policy = andr_twt_attr_policy,
11100 .maxattr = ANDR_TWT_ATTR_MAX
11101 #endif /* LINUX_VERSION >= 5.3 */
11102 },
11103 {
11104 {
11105 .vendor_id = OUI_GOOGLE,
11106 .subcmd = ANDR_TWT_SUBCMD_TEARDOWN
11107 },
11108 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11109 .doit = wl_cfgvendor_twt_teardown,
11110 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11111 .policy = andr_twt_attr_policy,
11112 .maxattr = ANDR_TWT_ATTR_MAX
11113 #endif /* LINUX_VERSION >= 5.3 */
11114 },
11115 {
11116 {
11117 .vendor_id = OUI_GOOGLE,
11118 .subcmd = ANDR_TWT_SUBCMD_INFO_FRAME
11119 },
11120 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11121 .doit = wl_cfgvendor_twt_info_frame,
11122 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11123 .policy = andr_twt_attr_policy,
11124 .maxattr = ANDR_TWT_ATTR_MAX
11125 #endif /* LINUX_VERSION >= 5.3 */
11126 },
11127 {
11128 {
11129 .vendor_id = OUI_GOOGLE,
11130 .subcmd = ANDR_TWT_SUBCMD_GET_CAP
11131 },
11132 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11133 .doit = wl_cfgvendor_twt_cap,
11134 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11135 .policy = andr_twt_attr_policy,
11136 .maxattr = ANDR_TWT_ATTR_MAX
11137 #endif /* LINUX_VERSION >= 5.3 */
11138 },
11139 {
11140 {
11141 .vendor_id = OUI_GOOGLE,
11142 .subcmd = ANDR_TWT_SUBCMD_GET_STATS
11143 },
11144 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11145 .doit = wl_cfgvendor_twt_get_stats,
11146 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11147 .policy = andr_twt_attr_policy,
11148 .maxattr = ANDR_TWT_ATTR_MAX
11149 #endif /* LINUX_VERSION >= 5.3 */
11150 },
11151 {
11152 {
11153 .vendor_id = OUI_GOOGLE,
11154 .subcmd = ANDR_TWT_SUBCMD_CLR_STATS
11155 },
11156 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
11157 .doit = wl_cfgvendor_twt_clear_stats,
11158 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11159 .policy = andr_twt_attr_policy,
11160 .maxattr = ANDR_TWT_ATTR_MAX
11161 #endif /* LINUX_VERSION >= 5.3 */
11162 },
11163 #endif /* !WL_TWT && WL_TWT_HAL_IF */
11164
11165 };
11166
11167 static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
11168 { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
11169 { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
11170 { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
11171 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
11172 { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
11173 { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
11174 { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
11175 { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
11176 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT },
11177 { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
11178 { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
11179 { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
11180 { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
11181 { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
11182 { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT },
11183 { OUI_GOOGLE, GOOGLE_NAN_EVENT_ENABLED},
11184 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DISABLED},
11185 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH},
11186 { OUI_GOOGLE, GOOGLE_NAN_EVENT_REPLIED},
11187 { OUI_GOOGLE, GOOGLE_NAN_EVENT_PUBLISH_TERMINATED},
11188 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED},
11189 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DE_EVENT},
11190 { OUI_GOOGLE, GOOGLE_NAN_EVENT_FOLLOWUP},
11191 { OUI_GOOGLE, GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND},
11192 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_REQUEST},
11193 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_CONFIRMATION},
11194 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_END},
11195 { OUI_GOOGLE, GOOGLE_NAN_EVENT_BEACON},
11196 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SDF},
11197 { OUI_GOOGLE, GOOGLE_NAN_EVENT_TCA},
11198 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH},
11199 { OUI_GOOGLE, GOOGLE_NAN_EVENT_UNKNOWN},
11200 { OUI_GOOGLE, GOOGLE_ROAM_EVENT_START},
11201 { OUI_BRCM, BRCM_VENDOR_EVENT_HANGED},
11202 { OUI_BRCM, BRCM_VENDOR_EVENT_SAE_KEY},
11203 { OUI_BRCM, BRCM_VENDOR_EVENT_BEACON_RECV},
11204 { OUI_BRCM, BRCM_VENDOR_EVENT_PORT_AUTHORIZED},
11205 { OUI_GOOGLE, GOOGLE_FILE_DUMP_EVENT },
11206 { OUI_BRCM, BRCM_VENDOR_EVENT_CU},
11207 { OUI_BRCM, BRCM_VENDOR_EVENT_WIPS},
11208 { OUI_GOOGLE, NAN_ASYNC_RESPONSE_DISABLED},
11209 { OUI_BRCM, BRCM_VENDOR_EVENT_RCC_INFO},
11210 {OUI_BRCM, BRCM_VENDOR_EVENT_TWT}
11211 };
11212
11213 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11214 static void
wl_cfgvendor_apply_cmd_policy(struct wiphy * wiphy)11215 wl_cfgvendor_apply_cmd_policy(struct wiphy *wiphy)
11216 {
11217 int i;
11218 u32 n_cmds = wiphy->n_vendor_commands;
11219
11220 WL_INFORM(("Apply CMD_RAW_DATA policy\n"));
11221 for (i = 0; i < n_cmds; i++) {
11222 if (wl_vendor_cmds[i].policy == NULL) {
11223 wl_vendor_cmds[i].policy = VENDOR_CMD_RAW_DATA;
11224 }
11225 }
11226 }
11227 #endif /* LINUX VER >= 5.3 */
11228
wl_cfgvendor_attach(struct wiphy * wiphy,dhd_pub_t * dhd)11229 int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd)
11230 {
11231
11232 WL_INFORM_MEM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
11233 NL80211_CMD_VENDOR));
11234
11235 wiphy->vendor_commands = wl_vendor_cmds;
11236 wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
11237
11238 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0))
11239 wl_cfgvendor_apply_cmd_policy(wiphy);
11240 #endif /* LINUX VER >= 5.3 */
11241
11242 wiphy->vendor_events = wl_vendor_events;
11243 wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events);
11244
11245 #ifdef DEBUGABILITY
11246 dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
11247 dhd_os_dbg_register_callback(DHD_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
11248 #ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
11249 dhd_os_dbg_register_callback(DRIVER_LOG_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
11250 dhd_os_dbg_register_callback(ROAM_STATS_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
11251 #endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
11252 #endif /* DEBUGABILITY */
11253 #ifdef DHD_LOG_DUMP
11254 dhd_os_dbg_register_urgent_notifier(dhd, wl_cfgvendor_dbg_send_file_dump_evt);
11255 #endif /* DHD_LOG_DUMP */
11256
11257 return 0;
11258 }
11259
wl_cfgvendor_detach(struct wiphy * wiphy)11260 int wl_cfgvendor_detach(struct wiphy *wiphy)
11261 {
11262 WL_INFORM_MEM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
11263
11264 wiphy->vendor_commands = NULL;
11265 wiphy->vendor_events = NULL;
11266 wiphy->n_vendor_commands = 0;
11267 wiphy->n_vendor_events = 0;
11268
11269 return 0;
11270 }
11271 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */
11272
11273 #ifdef WL_CFGVENDOR_SEND_HANG_EVENT
11274 void
wl_cfgvendor_send_hang_event(struct net_device * dev,u16 reason,char * string,int hang_info_cnt)11275 wl_cfgvendor_send_hang_event(struct net_device *dev, u16 reason, char *string, int hang_info_cnt)
11276 {
11277 struct bcm_cfg80211 *cfg = wl_get_cfg(dev);
11278 struct wiphy *wiphy;
11279 char *hang_info;
11280 int len = 0;
11281 int bytes_written;
11282 uint32 dummy_data = 0;
11283 int reason_hang_info = 0;
11284 int cnt = 0;
11285 dhd_pub_t *dhd;
11286 int hang_reason_mismatch = FALSE;
11287
11288 if (!cfg || !cfg->wdev) {
11289 WL_ERR(("cfg=%p wdev=%p\n", cfg, (cfg ? cfg->wdev : NULL)));
11290 return;
11291 }
11292
11293 wiphy = cfg->wdev->wiphy;
11294
11295 if (!wiphy) {
11296 WL_ERR(("wiphy is NULL\n"));
11297 return;
11298 }
11299
11300 hang_info = MALLOCZ(cfg->osh, VENDOR_SEND_HANG_EXT_INFO_LEN);
11301 if (hang_info == NULL) {
11302 WL_ERR(("alloc hang_info failed\n"));
11303 return;
11304 }
11305
11306 dhd = (dhd_pub_t *)(cfg->pub);
11307
11308 #ifdef WL_BCNRECV
11309 /* check fakeapscan in progress then stop scan */
11310 if (cfg->bcnrecv_info.bcnrecv_state == BEACON_RECV_STARTED) {
11311 wl_android_bcnrecv_stop(dev, WL_BCNRECV_HANG);
11312 }
11313 #endif /* WL_BCNRECV */
11314 sscanf(string, "%d", &reason_hang_info);
11315 bytes_written = 0;
11316 len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
11317 if (strlen(string) == 0 || (reason_hang_info != reason)) {
11318 WL_ERR(("hang reason mismatch: string len %d reason_hang_info %d\n",
11319 (int)strlen(string), reason_hang_info));
11320 hang_reason_mismatch = TRUE;
11321 if (dhd) {
11322 get_debug_dump_time(dhd->debug_dump_time_hang_str);
11323 copy_debug_dump_time(dhd->debug_dump_time_str,
11324 dhd->debug_dump_time_hang_str);
11325 }
11326 /* Fill bigdata key with */
11327 bytes_written += scnprintf(&hang_info[bytes_written], len,
11328 "%d %d %s %08x %08x %08x %08x %08x %08x %08x",
11329 reason, VENDOR_SEND_HANG_EXT_INFO_VER,
11330 dhd->debug_dump_time_hang_str,
11331 0, 0, 0, 0, 0, 0, 0);
11332 if (dhd) {
11333 clear_debug_dump_time(dhd->debug_dump_time_hang_str);
11334 }
11335 } else {
11336 bytes_written += scnprintf(&hang_info[bytes_written], len, "%s", string);
11337 }
11338
11339 WL_ERR(("hang reason: %d info cnt: %d\n", reason, hang_info_cnt));
11340
11341 if (hang_reason_mismatch == FALSE) {
11342 cnt = hang_info_cnt;
11343 } else {
11344 cnt = HANG_FIELD_MISMATCH_CNT;
11345 }
11346
11347 while (cnt < HANG_FIELD_CNT_MAX) {
11348 len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
11349 if (len <= 0) {
11350 break;
11351 }
11352 bytes_written += scnprintf(&hang_info[bytes_written], len,
11353 "%c%08x", HANG_RAW_DEL, dummy_data);
11354 cnt++;
11355 }
11356
11357 WL_ERR(("hang info cnt: %d len: %d\n", cnt, (int)strlen(hang_info)));
11358 WL_ERR(("hang info data: %s\n", hang_info));
11359
11360 wl_cfgvendor_send_async_event(wiphy,
11361 bcmcfg_to_prmry_ndev(cfg), BRCM_VENDOR_EVENT_HANGED,
11362 hang_info, (int)strlen(hang_info));
11363
11364 memset(string, 0, VENDOR_SEND_HANG_EXT_INFO_LEN);
11365
11366 if (hang_info) {
11367 MFREE(cfg->osh, hang_info, VENDOR_SEND_HANG_EXT_INFO_LEN);
11368 }
11369
11370 #ifdef DHD_LOG_DUMP
11371 dhd_logdump_cookie_save(dhd, dhd->debug_dump_time_hang_str, "HANG");
11372 #endif /* DHD_LOG_DUMP */
11373
11374 if (dhd) {
11375 clear_debug_dump_time(dhd->debug_dump_time_str);
11376 }
11377 }
11378
11379 void
wl_cfgvendor_simple_hang_event(struct net_device * dev,u16 reason)11380 wl_cfgvendor_simple_hang_event(struct net_device *dev, u16 reason)
11381 {
11382 struct bcm_cfg80211 *cfg;
11383 struct wiphy *wiphy;
11384 struct sk_buff *msg;
11385 gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
11386 int hang_event_len = 0;
11387 #ifdef DHD_COREDUMP
11388 dhd_pub_t *dhd;
11389 #endif
11390 WL_ERR(("0x%x\n", reason));
11391
11392 cfg = wl_cfg80211_get_bcmcfg();
11393 if (!cfg || !cfg->wdev) {
11394 WL_ERR(("fw dump evt invalid arg\n"));
11395 return;
11396 }
11397
11398 wiphy = bcmcfg_to_wiphy(cfg);
11399 if (!wiphy) {
11400 WL_ERR(("wiphy is NULL\n"));
11401 return;
11402 }
11403
11404 #ifdef DHD_COREDUMP
11405 hang_event_len = DHD_MEMDUMP_LONGSTR_LEN;
11406 #endif
11407
11408 /* Allocate the skb for vendor event */
11409 msg = CFG80211_VENDOR_EVENT_ALLOC(wiphy, ndev_to_wdev(dev),
11410 hang_event_len, BRCM_VENDOR_EVENT_HANGED, kflags);
11411 if (!msg) {
11412 WL_ERR(("%s: fail to allocate skb for vendor event\n", __FUNCTION__));
11413 return;
11414 }
11415
11416 #ifdef DHD_COREDUMP
11417 dhd = (dhd_pub_t *)(cfg->pub);
11418
11419 WL_ERR(("hang reason: %s\n", dhd->memdump_str));
11420 nla_put(msg, DEBUG_ATTRIBUTE_HANG_REASON, DHD_MEMDUMP_LONGSTR_LEN, dhd->memdump_str);
11421 #endif
11422
11423 cfg80211_vendor_event(msg, kflags);
11424 return;
11425 }
11426
11427 void
wl_copy_hang_info_if_falure(struct net_device * dev,u16 reason,s32 ret)11428 wl_copy_hang_info_if_falure(struct net_device *dev, u16 reason, s32 ret)
11429 {
11430 struct bcm_cfg80211 *cfg = NULL;
11431 dhd_pub_t *dhd;
11432 s32 err = 0;
11433 char ioctl_buf[WLC_IOCTL_SMLEN];
11434 memuse_info_t mu;
11435 int bytes_written = 0;
11436 int remain_len = 0;
11437
11438 if (!dev) {
11439 WL_ERR(("dev is null"));
11440 return;
11441
11442 }
11443
11444 cfg = wl_get_cfg(dev);
11445 if (!cfg) {
11446 WL_ERR(("dev=%p cfg=%p\n", dev, cfg));
11447 return;
11448 }
11449
11450 dhd = (dhd_pub_t *)(cfg->pub);
11451
11452 if (!dhd || !dhd->hang_info) {
11453 WL_ERR(("%s dhd=%p hang_info=%p\n", __FUNCTION__,
11454 dhd, (dhd ? dhd->hang_info : NULL)));
11455 return;
11456 }
11457
11458 err = wldev_iovar_getbuf_bsscfg(dev, "memuse",
11459 NULL, 0, ioctl_buf, WLC_IOCTL_SMLEN, 0, NULL);
11460 if (unlikely(err)) {
11461 WL_ERR(("error (%d)\n", err));
11462 return;
11463 }
11464
11465 memcpy(&mu, ioctl_buf, sizeof(memuse_info_t));
11466
11467 if (mu.len >= sizeof(memuse_info_t)) {
11468 WL_ERR(("Heap Total: %d(%dK)\n", mu.arena_size, KB(mu.arena_size)));
11469 WL_ERR(("Free: %d(%dK), LWM: %d(%dK)\n",
11470 mu.arena_free, KB(mu.arena_free),
11471 mu.free_lwm, KB(mu.free_lwm)));
11472 WL_ERR(("In use: %d(%dK), HWM: %d(%dK)\n",
11473 mu.inuse_size, KB(mu.inuse_size),
11474 mu.inuse_hwm, KB(mu.inuse_hwm)));
11475 WL_ERR(("Malloc failure count: %d\n", mu.mf_count));
11476 }
11477
11478 memset(dhd->hang_info, 0, VENDOR_SEND_HANG_EXT_INFO_LEN);
11479 remain_len = VENDOR_SEND_HANG_EXT_INFO_LEN - bytes_written;
11480
11481 get_debug_dump_time(dhd->debug_dump_time_hang_str);
11482 copy_debug_dump_time(dhd->debug_dump_time_str, dhd->debug_dump_time_hang_str);
11483
11484 bytes_written += scnprintf(&dhd->hang_info[bytes_written], remain_len,
11485 "%d %d %s %d %d %d %d %d %08x %08x",
11486 reason, VENDOR_SEND_HANG_EXT_INFO_VER,
11487 dhd->debug_dump_time_hang_str,
11488 ret, mu.arena_size, mu.arena_free, mu.inuse_size, mu.mf_count, 0, 0);
11489
11490 dhd->hang_info_cnt = HANG_FIELD_IF_FAILURE_CNT;
11491
11492 clear_debug_dump_time(dhd->debug_dump_time_hang_str);
11493
11494 return;
11495 }
11496 #endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
11497