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