bd918e6583de28f08b88f854e985953f0e921310
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd.1.579.77.41.1.cn / wl_cfgvendor.c
1 /*
2 * Linux cfg80211 Vendor Extension Code
3 *
4 * Copyright (C) 1999-2017, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: wl_cfgvendor.c 710862 2017-07-14 07:43:59Z $
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 #include <wl_android.h>
80 #include <wl_cfgvendor.h>
81 #ifdef PROP_TXSTATUS
82 #include <dhd_wlfc.h>
83 #endif
84 #include <brcm_nl80211.h>
85
86 #ifdef STAT_REPORT
87 #include <wl_statreport.h>
88 #endif
89
90 #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT)
91
92 /*
93 * This API is to be used for asynchronous vendor events. This
94 * shouldn't be used in response to a vendor command from its
95 * do_it handler context (instead wl_cfgvendor_send_cmd_reply should
96 * be used).
97 */
98 int wl_cfgvendor_send_async_event(struct wiphy *wiphy,
99 struct net_device *dev, int event_id, const void *data, int len)
100 {
101 u16 kflags;
102 struct sk_buff *skb;
103
104 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
105
106 /* Alloc the SKB for vendor_event */
107 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
108 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
109 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len, event_id, kflags);
110 #else
111 skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
112 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
113 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
114 if (!skb) {
115 WL_ERR(("skb alloc failed"));
116 return -ENOMEM;
117 }
118
119 /* Push the data to the skb */
120 nla_put_nohdr(skb, len, data);
121
122 cfg80211_vendor_event(skb, kflags);
123
124 return 0;
125 }
126
127 static int
128 wl_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
129 struct net_device *dev, const void *data, int len)
130 {
131 struct sk_buff *skb;
132
133 /* Alloc the SKB for vendor_event */
134 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
135 if (unlikely(!skb)) {
136 WL_ERR(("skb alloc failed"));
137 return -ENOMEM;
138 }
139
140 /* Push the data to the skb */
141 nla_put_nohdr(skb, len, data);
142
143 return cfg80211_vendor_cmd_reply(skb);
144 }
145
146 static int
147 wl_cfgvendor_get_feature_set(struct wiphy *wiphy,
148 struct wireless_dev *wdev, const void *data, int len)
149 {
150 int err = 0;
151 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
152 int reply;
153
154 reply = dhd_dev_get_feature_set(bcmcfg_to_prmry_ndev(cfg));
155
156 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
157 &reply, sizeof(int));
158 if (unlikely(err))
159 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
160
161 return err;
162 }
163
164 static int
165 wl_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
166 struct wireless_dev *wdev, const void *data, int len)
167 {
168 int err = 0;
169 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
170 struct sk_buff *skb;
171 int reply;
172 int mem_needed, i;
173
174 mem_needed = VENDOR_REPLY_OVERHEAD +
175 (ATTRIBUTE_U32_LEN * MAX_FEATURE_SET_CONCURRRENT_GROUPS) + ATTRIBUTE_U32_LEN;
176
177 /* Alloc the SKB for vendor_event */
178 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
179 if (unlikely(!skb)) {
180 WL_ERR(("skb alloc failed"));
181 err = -ENOMEM;
182 goto exit;
183 }
184
185 nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, MAX_FEATURE_SET_CONCURRRENT_GROUPS);
186 for (i = 0; i < MAX_FEATURE_SET_CONCURRRENT_GROUPS; i++) {
187 reply = dhd_dev_get_feature_set_matrix(bcmcfg_to_prmry_ndev(cfg), i);
188 if (reply != WIFI_FEATURE_INVALID) {
189 nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply);
190 }
191 }
192
193 err = cfg80211_vendor_cmd_reply(skb);
194
195 if (unlikely(err)) {
196 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
197 }
198 exit:
199 return err;
200 }
201
202 static int
203 wl_cfgvendor_set_rand_mac_oui(struct wiphy *wiphy,
204 struct wireless_dev *wdev, const void *data, int len)
205 {
206 int err = 0;
207 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
208 int type;
209 uint8 random_mac_oui[DOT11_OUI_LEN];
210
211 type = nla_type(data);
212
213 if (type == ANDR_WIFI_ATTRIBUTE_RANDOM_MAC_OUI) {
214 memcpy(random_mac_oui, nla_data(data), DOT11_OUI_LEN);
215
216 err = dhd_dev_cfg_rand_mac_oui(bcmcfg_to_prmry_ndev(cfg), random_mac_oui);
217
218 if (unlikely(err))
219 WL_ERR(("Bad OUI, could not set:%d \n", err));
220
221 } else {
222 err = -1;
223 }
224
225 return err;
226 }
227 #ifdef CUSTOM_FORCE_NODFS_FLAG
228 static int
229 wl_cfgvendor_set_nodfs_flag(struct wiphy *wiphy,
230 struct wireless_dev *wdev, const void *data, int len)
231 {
232 int err = 0;
233 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
234 int type;
235 u32 nodfs;
236
237 type = nla_type(data);
238 if (type == ANDR_WIFI_ATTRIBUTE_NODFS_SET) {
239 nodfs = nla_get_u32(data);
240 err = dhd_dev_set_nodfs(bcmcfg_to_prmry_ndev(cfg), nodfs);
241 } else {
242 err = -1;
243 }
244 return err;
245 }
246 #endif /* CUSTOM_FORCE_NODFS_FLAG */
247
248 static int
249 wl_cfgvendor_set_country(struct wiphy *wiphy,
250 struct wireless_dev *wdev, const void *data, int len)
251 {
252 int err = BCME_ERROR, rem, type;
253 char country_code[WLC_CNTRY_BUF_SZ] = {0};
254 const struct nlattr *iter;
255
256 nla_for_each_attr(iter, data, len, rem) {
257 type = nla_type(iter);
258 switch (type) {
259 case ANDR_WIFI_ATTRIBUTE_COUNTRY:
260 memcpy(country_code, nla_data(iter),
261 MIN(nla_len(iter), WLC_CNTRY_BUF_SZ));
262 break;
263 default:
264 WL_ERR(("Unknown type: %d\n", type));
265 return err;
266 }
267 }
268
269 err = wldev_set_country(wdev->netdev, country_code, true, true, -1);
270 if (err < 0) {
271 WL_ERR(("Set country failed ret:%d\n", err));
272 }
273
274 return err;
275 }
276
277 #ifdef GSCAN_SUPPORT
278 int
279 wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
280 struct net_device *dev, void *data, int len, wl_vendor_event_t event)
281 {
282 u16 kflags;
283 const void *ptr;
284 struct sk_buff *skb;
285 int malloc_len, total, iter_cnt_to_send, cnt;
286 gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
287
288 total = len/sizeof(wifi_gscan_result_t);
289 while (total > 0) {
290 malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD;
291 if (malloc_len > NLMSG_DEFAULT_SIZE) {
292 malloc_len = NLMSG_DEFAULT_SIZE;
293 }
294 iter_cnt_to_send =
295 (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t);
296 total = total - iter_cnt_to_send;
297
298 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
299
300 /* Alloc the SKB for vendor_event */
301 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
302 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
303 skb = cfg80211_vendor_event_alloc(wiphy, NULL, malloc_len, event, kflags);
304 #else
305 skb = cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags);
306 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
307 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
308 if (!skb) {
309 WL_ERR(("skb alloc failed"));
310 return -ENOMEM;
311 }
312
313 while (cache && iter_cnt_to_send) {
314 ptr = (const void *) &cache->results[cache->tot_consumed];
315
316 if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed)) {
317 cnt = iter_cnt_to_send;
318 } else {
319 cnt = (cache->tot_count - cache->tot_consumed);
320 }
321
322 iter_cnt_to_send -= cnt;
323 cache->tot_consumed += cnt;
324 /* Push the data to the skb */
325 nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
326 if (cache->tot_consumed == cache->tot_count) {
327 cache = cache->next;
328 }
329
330 }
331
332 cfg80211_vendor_event(skb, kflags);
333 }
334
335 return 0;
336 }
337
338
339 static int
340 wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
341 struct wireless_dev *wdev, const void *data, int len)
342 {
343 int err = 0;
344 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
345 dhd_pno_gscan_capabilities_t *reply = NULL;
346 uint32 reply_len = 0;
347
348
349 reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
350 DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
351 if (!reply) {
352 WL_ERR(("Could not get capabilities\n"));
353 err = -EINVAL;
354 return err;
355 }
356
357 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
358 reply, reply_len);
359
360 if (unlikely(err)) {
361 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
362 }
363
364 kfree(reply);
365 return err;
366 }
367
368 static int
369 wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
370 struct wireless_dev *wdev, const void *data, int len)
371 {
372 int err = 0;
373 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
374 gscan_results_cache_t *results, *iter;
375 uint32 reply_len, is_done = 1;
376 int32 mem_needed, num_results_iter;
377 wifi_gscan_result_t *ptr;
378 uint16 num_scan_ids, num_results;
379 struct sk_buff *skb;
380 struct nlattr *scan_hdr, *complete_flag;
381
382 err = dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
383 if (err != BCME_OK)
384 return -EBUSY;
385
386 err = dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
387 if (err != BCME_OK) {
388 WL_ERR(("Can't obtain lock to access batch results %d\n", err));
389 return -EBUSY;
390 }
391 results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
392 DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
393
394 if (!results) {
395 WL_ERR(("No results to send %d\n", err));
396 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
397 results, 0);
398
399 if (unlikely(err))
400 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
401 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
402 return err;
403 }
404 num_scan_ids = reply_len & 0xFFFF;
405 num_results = (reply_len & 0xFFFF0000) >> 16;
406 mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
407 (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
408 VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
409
410 if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
411 mem_needed = (int32)NLMSG_DEFAULT_SIZE;
412 }
413
414 WL_TRACE(("is_done %d mem_needed %d max_mem %d\n", is_done, mem_needed,
415 (int)NLMSG_DEFAULT_SIZE));
416 /* Alloc the SKB for vendor_event */
417 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
418 if (unlikely(!skb)) {
419 WL_ERR(("skb alloc failed"));
420 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
421 return -ENOMEM;
422 }
423 iter = results;
424 complete_flag = nla_reserve(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE,
425 sizeof(is_done));
426 mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
427
428 while (iter) {
429 num_results_iter = (mem_needed - (int32)GSCAN_BATCH_RESULT_HDR_LEN);
430 num_results_iter /= (int32)sizeof(wifi_gscan_result_t);
431 if (num_results_iter <= 0 ||
432 ((iter->tot_count - iter->tot_consumed) > num_results_iter)) {
433 break;
434 }
435 scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
436 /* no more room? we are done then (for now) */
437 if (scan_hdr == NULL) {
438 is_done = 0;
439 break;
440 }
441 nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
442 nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
443 nla_put_u32(skb, GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK, iter->scan_ch_bucket);
444
445 num_results_iter = iter->tot_count - iter->tot_consumed;
446
447 nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
448 if (num_results_iter) {
449 ptr = &iter->results[iter->tot_consumed];
450 iter->tot_consumed += num_results_iter;
451 nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
452 num_results_iter * sizeof(wifi_gscan_result_t), ptr);
453 }
454 nla_nest_end(skb, scan_hdr);
455 mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
456 (num_results_iter * sizeof(wifi_gscan_result_t));
457 iter = iter->next;
458 }
459 /* Returns TRUE if all result consumed */
460 is_done = dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
461 memcpy(nla_data(complete_flag), &is_done, sizeof(is_done));
462 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
463 return cfg80211_vendor_cmd_reply(skb);
464 }
465
466 static int
467 wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
468 struct wireless_dev *wdev, const void *data, int len)
469 {
470 int err = 0;
471 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
472 int type, tmp = len;
473 int run = 0xFF;
474 int flush = 0;
475 const struct nlattr *iter;
476
477 nla_for_each_attr(iter, data, len, tmp) {
478 type = nla_type(iter);
479 if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
480 run = nla_get_u32(iter);
481 else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
482 flush = nla_get_u32(iter);
483 }
484
485 if (run != 0xFF) {
486 err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
487
488 if (unlikely(err)) {
489 WL_ERR(("Could not run gscan:%d \n", err));
490 }
491 return err;
492 } else {
493 return -EINVAL;
494 }
495
496
497 }
498
499 static int
500 wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
501 struct wireless_dev *wdev, const void *data, int len)
502 {
503 int err = 0;
504 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
505 int type;
506 bool real_time = FALSE;
507
508 type = nla_type(data);
509
510 if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
511 real_time = nla_get_u32(data);
512
513 err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
514
515 if (unlikely(err)) {
516 WL_ERR(("Could not run gscan:%d \n", err));
517 }
518
519 } else {
520 err = -EINVAL;
521 }
522
523 return err;
524 }
525
526 static int
527 wl_cfgvendor_set_scan_cfg_bucket(const struct nlattr *prev,
528 gscan_scan_params_t *scan_param, int num)
529 {
530 struct dhd_pno_gscan_channel_bucket *ch_bucket;
531 int k = 0;
532 int type, err = 0, rem;
533 const struct nlattr *cur, *next;
534
535 nla_for_each_nested(cur, prev, rem) {
536 type = nla_type(cur);
537 ch_bucket = scan_param->channel_bucket;
538 switch (type) {
539 case GSCAN_ATTRIBUTE_BUCKET_ID:
540 break;
541 case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
542 if (nla_len(cur) != sizeof(uint32)) {
543 err = -EINVAL;
544 goto exit;
545 }
546
547 ch_bucket[num].bucket_freq_multiple =
548 nla_get_u32(cur) / MSEC_PER_SEC;
549 break;
550 case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
551 if (nla_len(cur) != sizeof(uint32)) {
552 err = -EINVAL;
553 goto exit;
554 }
555 ch_bucket[num].num_channels = nla_get_u32(cur);
556 if (ch_bucket[num].num_channels >
557 GSCAN_MAX_CHANNELS_IN_BUCKET) {
558 WL_ERR(("channel range:%d,bucket:%d\n",
559 ch_bucket[num].num_channels,
560 num));
561 err = -EINVAL;
562 goto exit;
563 }
564 break;
565 case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
566 nla_for_each_nested(next, cur, rem) {
567 if (k >= GSCAN_MAX_CHANNELS_IN_BUCKET)
568 break;
569 if (nla_len(next) != sizeof(uint32)) {
570 err = -EINVAL;
571 goto exit;
572 }
573 ch_bucket[num].chan_list[k] = nla_get_u32(next);
574 k++;
575 }
576 break;
577 case GSCAN_ATTRIBUTE_BUCKETS_BAND:
578 if (nla_len(cur) != sizeof(uint32)) {
579 err = -EINVAL;
580 goto exit;
581 }
582 ch_bucket[num].band = (uint16)nla_get_u32(cur);
583 break;
584 case GSCAN_ATTRIBUTE_REPORT_EVENTS:
585 if (nla_len(cur) != sizeof(uint32)) {
586 err = -EINVAL;
587 goto exit;
588 }
589 ch_bucket[num].report_flag = (uint8)nla_get_u32(cur);
590 break;
591 case GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT:
592 if (nla_len(cur) != sizeof(uint32)) {
593 err = -EINVAL;
594 goto exit;
595 }
596 ch_bucket[num].repeat = (uint16)nla_get_u32(cur);
597 break;
598 case GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD:
599 if (nla_len(cur) != sizeof(uint32)) {
600 err = -EINVAL;
601 goto exit;
602 }
603 ch_bucket[num].bucket_max_multiple =
604 nla_get_u32(cur) / MSEC_PER_SEC;
605 break;
606 default:
607 WL_ERR(("unknown attr type:%d\n", type));
608 err = -EINVAL;
609 goto exit;
610 }
611 }
612
613 exit:
614 return err;
615 }
616
617 static int
618 wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy, struct wireless_dev *wdev,
619 const void *data, int len)
620 {
621 int err = 0;
622 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
623 gscan_scan_params_t *scan_param;
624 int j = 0;
625 int type, tmp;
626 const struct nlattr *iter;
627
628 scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL);
629 if (!scan_param) {
630 WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
631 err = -EINVAL;
632 return err;
633
634 }
635
636 scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
637 nla_for_each_attr(iter, data, len, tmp) {
638 type = nla_type(iter);
639
640 if (j >= GSCAN_MAX_CH_BUCKETS) {
641 break;
642 }
643
644 switch (type) {
645 case GSCAN_ATTRIBUTE_BASE_PERIOD:
646 if (nla_len(iter) != sizeof(uint32)) {
647 err = -EINVAL;
648 goto exit;
649 }
650 scan_param->scan_fr = nla_get_u32(iter) / MSEC_PER_SEC;
651 break;
652 case GSCAN_ATTRIBUTE_NUM_BUCKETS:
653 if (nla_len(iter) != sizeof(uint32)) {
654 err = -EINVAL;
655 goto exit;
656 }
657 scan_param->nchannel_buckets = nla_get_u32(iter);
658 if (scan_param->nchannel_buckets >=
659 GSCAN_MAX_CH_BUCKETS) {
660 WL_ERR(("ncha_buck out of range %d\n",
661 scan_param->nchannel_buckets));
662 err = -EINVAL;
663 goto exit;
664 }
665 break;
666 case GSCAN_ATTRIBUTE_CH_BUCKET_1:
667 case GSCAN_ATTRIBUTE_CH_BUCKET_2:
668 case GSCAN_ATTRIBUTE_CH_BUCKET_3:
669 case GSCAN_ATTRIBUTE_CH_BUCKET_4:
670 case GSCAN_ATTRIBUTE_CH_BUCKET_5:
671 case GSCAN_ATTRIBUTE_CH_BUCKET_6:
672 case GSCAN_ATTRIBUTE_CH_BUCKET_7:
673 err = wl_cfgvendor_set_scan_cfg_bucket(iter, scan_param, j);
674 if (err < 0) {
675 WL_ERR(("set_scan_cfg_buck error:%d\n", err));
676 goto exit;
677 }
678 j++;
679 break;
680 default:
681 WL_ERR(("Unknown type %d\n", type));
682 err = -EINVAL;
683 goto exit;
684 }
685 }
686
687 err = dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
688 DHD_PNO_SCAN_CFG_ID, scan_param, FALSE);
689
690 if (err < 0) {
691 WL_ERR(("Could not set GSCAN scan cfg\n"));
692 err = -EINVAL;
693 }
694
695 exit:
696 kfree(scan_param);
697 return err;
698
699 }
700
701 static int
702 wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
703 struct wireless_dev *wdev, const void *data, int len)
704 {
705 int err = 0;
706 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
707 gscan_hotlist_scan_params_t *hotlist_params;
708 int tmp, tmp1, tmp2, type, j = 0, dummy;
709 const struct nlattr *outer, *inner = NULL, *iter;
710 bool flush = FALSE;
711 struct bssid_t *pbssid;
712
713 BCM_REFERENCE(dummy);
714
715 if (len < sizeof(*hotlist_params) || len >= WLC_IOCTL_MAXLEN) {
716 WL_ERR(("buffer length :%d wrong - bail out.\n", len));
717 return -EINVAL;
718 }
719
720 hotlist_params = kzalloc(sizeof(*hotlist_params)
721 + (sizeof(struct bssid_t) * (PFN_SWC_MAX_NUM_APS - 1)),
722 GFP_KERNEL);
723
724 if (!hotlist_params) {
725 WL_ERR(("Cannot Malloc memory.\n"));
726 return -ENOMEM;
727 }
728
729 hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
730
731 nla_for_each_attr(iter, data, len, tmp2) {
732 type = nla_type(iter);
733 switch (type) {
734 case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
735 pbssid = hotlist_params->bssid;
736 nla_for_each_nested(outer, iter, tmp) {
737 nla_for_each_nested(inner, outer, tmp1) {
738 type = nla_type(inner);
739
740 switch (type) {
741 case GSCAN_ATTRIBUTE_BSSID:
742 if (nla_len(inner) != sizeof(pbssid[j].macaddr)) {
743 WL_ERR(("type:%d length:%d not matching.\n",
744 type, nla_len(inner)));
745 err = -EINVAL;
746 goto exit;
747 }
748 memcpy(
749 &(pbssid[j].macaddr),
750 nla_data(inner),
751 sizeof(pbssid[j].macaddr));
752 break;
753 case GSCAN_ATTRIBUTE_RSSI_LOW:
754 if (nla_len(inner) != sizeof(uint8)) {
755 WL_ERR(("type:%d length:%d not matching.\n",
756 type, nla_len(inner)));
757 err = -EINVAL;
758 goto exit;
759 }
760 pbssid[j].rssi_reporting_threshold =
761 (int8)nla_get_u8(inner);
762 break;
763 case GSCAN_ATTRIBUTE_RSSI_HIGH:
764 if (nla_len(inner) != sizeof(uint8)) {
765 WL_ERR(("type:%d length:%d not matching.\n",
766 type, nla_len(inner)));
767 err = -EINVAL;
768 goto exit;
769 }
770 dummy = (int8)nla_get_u8(inner);
771 break;
772 default:
773 WL_ERR(("ATTR unknown %d\n", type));
774 err = -EINVAL;
775 goto exit;
776 }
777 }
778 if (++j >= PFN_SWC_MAX_NUM_APS) {
779 WL_ERR(("cap hotlist max:%d\n", j));
780 break;
781 }
782 }
783 hotlist_params->nbssid = j;
784 break;
785 case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
786 if (nla_len(iter) != sizeof(uint8)) {
787 WL_ERR(("type:%d length:%d not matching.\n",
788 type, nla_len(inner)));
789 err = -EINVAL;
790 goto exit;
791 }
792 flush = nla_get_u8(iter);
793 break;
794 case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
795 if (nla_len(iter) != sizeof(uint32)) {
796 WL_ERR(("type:%d length:%d not matching.\n",
797 type, nla_len(inner)));
798 err = -EINVAL;
799 goto exit;
800 }
801 hotlist_params->lost_ap_window = (uint16)nla_get_u32(iter);
802 break;
803 default:
804 WL_ERR(("Unknown type %d\n", type));
805 err = -EINVAL;
806 goto exit;
807 }
808
809 }
810
811 if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
812 DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
813 WL_ERR(("Could not set GSCAN HOTLIST cfg error: %d\n", err));
814 err = -EINVAL;
815 goto exit;
816 }
817 exit:
818 kfree(hotlist_params);
819 return err;
820 }
821
822 static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy,
823 struct wireless_dev *wdev, const void *data, int len)
824 {
825 int err = 0;
826 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
827 dhd_pno_ssid_t *ssid_elem;
828 int tmp, tmp1, tmp2, type = 0, num = 0;
829 const struct nlattr *outer, *inner, *iter;
830 uint8 flush = FALSE, i = 0;
831 wl_pfn_ssid_params_t params;
832
833 nla_for_each_attr(iter, data, len, tmp2) {
834 type = nla_type(iter);
835 switch (type) {
836 case GSCAN_ATTRIBUTE_EPNO_SSID_LIST:
837 nla_for_each_nested(outer, iter, tmp) {
838 ssid_elem = (dhd_pno_ssid_t *)
839 dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
840 DHD_PNO_GET_NEW_EPNO_SSID_ELEM,
841 NULL, &num);
842 if (!ssid_elem) {
843 WL_ERR(("Failed to get SSID LIST buffer\n"));
844 err = -ENOMEM;
845 goto exit;
846 }
847 i++;
848 nla_for_each_nested(inner, outer, tmp1) {
849 type = nla_type(inner);
850
851 switch (type) {
852 case GSCAN_ATTRIBUTE_EPNO_SSID:
853 memcpy(ssid_elem->SSID,
854 nla_data(inner),
855 DOT11_MAX_SSID_LEN);
856 break;
857 case GSCAN_ATTRIBUTE_EPNO_SSID_LEN:
858 ssid_elem->SSID_len =
859 nla_get_u32(inner);
860 if (ssid_elem->SSID_len >
861 DOT11_MAX_SSID_LEN) {
862 WL_ERR(("SSID too"
863 "long %d\n",
864 ssid_elem->SSID_len));
865 err = -EINVAL;
866 goto exit;
867 }
868 break;
869 case GSCAN_ATTRIBUTE_EPNO_FLAGS:
870 ssid_elem->flags =
871 nla_get_u32(inner);
872 ssid_elem->hidden =
873 ((ssid_elem->flags &
874 DHD_EPNO_HIDDEN_SSID) != 0);
875 break;
876 case GSCAN_ATTRIBUTE_EPNO_AUTH:
877 ssid_elem->wpa_auth =
878 nla_get_u32(inner);
879 break;
880 }
881 }
882 if (!ssid_elem->SSID_len) {
883 WL_ERR(("Broadcast SSID is illegal for ePNO\n"));
884 err = -EINVAL;
885 goto exit;
886 }
887 dhd_pno_translate_epno_fw_flags(&ssid_elem->flags);
888 dhd_pno_set_epno_auth_flag(&ssid_elem->wpa_auth);
889 }
890 break;
891 case GSCAN_ATTRIBUTE_EPNO_SSID_NUM:
892 num = nla_get_u8(iter);
893 break;
894 case GSCAN_ATTRIBUTE_EPNO_FLUSH:
895 flush = (bool)nla_get_u32(iter);
896 /* Flush attribute is expected before any ssid attribute */
897 if (i && flush) {
898 WL_ERR(("Bad attributes\n"));
899 err = -EINVAL;
900 goto exit;
901 }
902 /* Need to flush driver and FW cfg */
903 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
904 DHD_PNO_EPNO_CFG_ID, NULL, flush);
905 dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
906 break;
907 case GSCAN_ATTRIBUTE_EPNO_5G_RSSI_THR:
908 params.min5G_rssi = nla_get_s8(iter);
909 break;
910 case GSCAN_ATTRIBUTE_EPNO_2G_RSSI_THR:
911 params.min2G_rssi = nla_get_s8(iter);
912 break;
913 case GSCAN_ATTRIBUTE_EPNO_INIT_SCORE_MAX:
914 params.init_score_max = nla_get_s16(iter);
915 break;
916 case GSCAN_ATTRIBUTE_EPNO_CUR_CONN_BONUS:
917 params.cur_bssid_bonus = nla_get_s16(iter);
918 break;
919 case GSCAN_ATTRIBUTE_EPNO_SAME_NETWORK_BONUS:
920 params.same_ssid_bonus = nla_get_s16(iter);
921 break;
922 case GSCAN_ATTRIBUTE_EPNO_SECURE_BONUS:
923 params.secure_bonus = nla_get_s16(iter);
924 break;
925 case GSCAN_ATTRIBUTE_EPNO_5G_BONUS:
926 params.band_5g_bonus = nla_get_s16(iter);
927 break;
928 default:
929 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
930 err = -EINVAL;
931 goto exit;
932 }
933 }
934 if (i != num) {
935 WL_ERR(("%s: num_ssid %d does not match ssids sent %d\n", __FUNCTION__,
936 num, i));
937 err = -EINVAL;
938 }
939 exit:
940 /* Flush all configs if error condition */
941 if (err < 0) {
942 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
943 DHD_PNO_EPNO_CFG_ID, NULL, TRUE);
944 dhd_dev_flush_fw_epno(bcmcfg_to_prmry_ndev(cfg));
945 } else if (type != GSCAN_ATTRIBUTE_EPNO_FLUSH) {
946 /* If the last attribute was FLUSH, nothing else to do */
947 dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
948 DHD_PNO_EPNO_PARAMS_ID, &params, FALSE);
949 err = dhd_dev_set_epno(bcmcfg_to_prmry_ndev(cfg));
950 }
951 return err;
952 }
953
954 static int
955 wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
956 struct wireless_dev *wdev, const void *data, int len)
957 {
958 int err = 0, tmp, type;
959 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
960 gscan_batch_params_t batch_param;
961 const struct nlattr *iter;
962
963 batch_param.mscan = batch_param.bestn = 0;
964 batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
965
966 nla_for_each_attr(iter, data, len, tmp) {
967 type = nla_type(iter);
968
969 switch (type) {
970 case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
971 batch_param.bestn = nla_get_u32(iter);
972 break;
973 case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
974 batch_param.mscan = nla_get_u32(iter);
975 break;
976 case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
977 batch_param.buffer_threshold = nla_get_u32(iter);
978 break;
979 default:
980 WL_ERR(("Unknown type %d\n", type));
981 break;
982 }
983 }
984
985 if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
986 DHD_PNO_BATCH_SCAN_CFG_ID, &batch_param, FALSE) < 0) {
987 WL_ERR(("Could not set batch cfg\n"));
988 err = -EINVAL;
989 return err;
990 }
991
992 return err;
993 }
994
995 #endif /* GSCAN_SUPPORT */
996 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
997 static int
998 wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
999 struct wireless_dev *wdev, const void *data, int len)
1000 {
1001 int err = 0, type, band;
1002 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1003 uint16 *reply = NULL;
1004 uint32 reply_len = 0, num_channels, mem_needed;
1005 struct sk_buff *skb;
1006
1007 type = nla_type(data);
1008
1009 if (type == GSCAN_ATTRIBUTE_BAND) {
1010 band = nla_get_u32(data);
1011 } else {
1012 return -EINVAL;
1013 }
1014
1015 reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
1016 DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
1017
1018 if (!reply) {
1019 WL_ERR(("Could not get channel list\n"));
1020 err = -EINVAL;
1021 return err;
1022 }
1023 num_channels = reply_len/ sizeof(uint32);
1024 mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
1025
1026 /* Alloc the SKB for vendor_event */
1027 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1028 if (unlikely(!skb)) {
1029 WL_ERR(("skb alloc failed"));
1030 err = -ENOMEM;
1031 goto exit;
1032 }
1033
1034 nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
1035 nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
1036
1037 err = cfg80211_vendor_cmd_reply(skb);
1038
1039 if (unlikely(err)) {
1040 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1041 }
1042 exit:
1043 kfree(reply);
1044 return err;
1045 }
1046 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
1047
1048 #ifdef RSSI_MONITOR_SUPPORT
1049 static int wl_cfgvendor_set_rssi_monitor(struct wiphy *wiphy,
1050 struct wireless_dev *wdev, const void *data, int len)
1051 {
1052 int err = 0, tmp, type, start = 0;
1053 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1054 int8 max_rssi = 0, min_rssi = 0;
1055 const struct nlattr *iter;
1056
1057 nla_for_each_attr(iter, data, len, tmp) {
1058 type = nla_type(iter);
1059 switch (type) {
1060 case RSSI_MONITOR_ATTRIBUTE_MAX_RSSI:
1061 max_rssi = (int8) nla_get_u32(iter);
1062 break;
1063 case RSSI_MONITOR_ATTRIBUTE_MIN_RSSI:
1064 min_rssi = (int8) nla_get_u32(iter);
1065 break;
1066 case RSSI_MONITOR_ATTRIBUTE_START:
1067 start = nla_get_u32(iter);
1068 }
1069 }
1070
1071 if (dhd_dev_set_rssi_monitor_cfg(bcmcfg_to_prmry_ndev(cfg),
1072 start, max_rssi, min_rssi) < 0) {
1073 WL_ERR(("Could not set rssi monitor cfg\n"));
1074 err = -EINVAL;
1075 }
1076 return err;
1077 }
1078 #endif /* RSSI_MONITOR_SUPPORT */
1079
1080 #ifdef DHDTCPACK_SUPPRESS
1081 static int wl_cfgvendor_set_tcpack_sup_mode(struct wiphy *wiphy,
1082 struct wireless_dev *wdev, const void *data, int len)
1083 {
1084 int err = 0, tmp, type;
1085 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1086 struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1087 uint8 enable = 0;
1088 const struct nlattr *iter;
1089
1090 nla_for_each_attr(iter, data, len, tmp) {
1091 type = nla_type(iter);
1092 if (type == ANDR_WIFI_ATTRIBUTE_TCPACK_SUP_VALUE) {
1093 enable = (int8)nla_get_u32(iter);
1094 }
1095 }
1096
1097 if (dhd_dev_set_tcpack_sup_mode_cfg(ndev, enable) < 0) {
1098 WL_ERR(("Could not set TCP Ack Suppress mode cfg\n"));
1099 err = -EINVAL;
1100 }
1101 return err;
1102 }
1103 #endif /* DHDTCPACK_SUPPRESS */
1104
1105 #ifdef DHD_WAKE_STATUS
1106 static int
1107 wl_cfgvendor_get_wake_reason_stats(struct wiphy *wiphy,
1108 struct wireless_dev *wdev, const void *data, int len)
1109 {
1110 struct net_device *ndev = wdev_to_ndev(wdev);
1111 wake_counts_t *pwake_count_info;
1112 int ret, mem_needed;
1113 #if defined(DHD_WAKE_EVENT_STATUS) && defined(DHD_DEBUG)
1114 int flowid;
1115 #endif /* DHD_WAKE_EVENT_STATUS && DHD_DEBUG */
1116 struct sk_buff *skb;
1117 dhd_pub_t *dhdp = wl_cfg80211_get_dhdp(ndev);
1118
1119 WL_DBG(("Recv get wake status info cmd.\n"));
1120
1121 pwake_count_info = dhd_get_wakecount(dhdp);
1122 mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 20) +
1123 (WLC_E_LAST * sizeof(uint));
1124
1125 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
1126 if (unlikely(!skb)) {
1127 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
1128 return -ENOMEM;
1129 goto exit;
1130 }
1131 #ifdef DHD_WAKE_EVENT_STATUS
1132 WL_ERR(("pwake_count_info->rcwake %d\n", pwake_count_info->rcwake));
1133 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, pwake_count_info->rcwake);
1134 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT_USED, WLC_E_LAST);
1135 nla_put(skb, WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE, (WLC_E_LAST * sizeof(uint)),
1136 pwake_count_info->rc_event);
1137 #ifdef DHD_DEBUG
1138 for (flowid = 0; flowid < WLC_E_LAST; flowid++) {
1139 if (pwake_count_info->rc_event[flowid] != 0) {
1140 WL_ERR((" %s = %u\n", bcmevent_get_name(flowid),
1141 pwake_count_info->rc_event[flowid]));
1142 }
1143 }
1144 #endif /* DHD_DEBUG */
1145 #endif /* DHD_WAKE_EVENT_STATUS */
1146 #ifdef DHD_WAKE_RX_STATUS
1147 WL_ERR(("pwake_count_info->rxwake %d\n", pwake_count_info->rxwake));
1148 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE, pwake_count_info->rxwake);
1149 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT, pwake_count_info->rx_ucast);
1150 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT, pwake_count_info->rx_mcast);
1151 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT, pwake_count_info->rx_bcast);
1152 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT, pwake_count_info->rx_arp);
1153 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT, pwake_count_info->rx_icmpv6);
1154 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA, pwake_count_info->rx_icmpv6_ra);
1155 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA, pwake_count_info->rx_icmpv6_na);
1156 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS, pwake_count_info->rx_icmpv6_ns);
1157 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
1158 pwake_count_info->rx_multi_ipv4);
1159 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
1160 pwake_count_info->rx_multi_ipv6);
1161 nla_put_u32(skb, WAKE_STAT_ATTRIBUTE_OTHER_RX_MULTICAST_ADD_CNT,
1162 pwake_count_info->rx_multi_other);
1163 #endif /* #ifdef DHD_WAKE_RX_STATUS */
1164 ret = cfg80211_vendor_cmd_reply(skb);
1165 if (unlikely(ret)) {
1166 WL_ERR(("Vendor cmd reply for -get wake status failed:%d \n", ret));
1167 }
1168 exit:
1169 return ret;
1170 }
1171 #endif /* DHD_WAKE_STATUS */
1172
1173 #ifdef RTT_SUPPORT
1174 void
1175 wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
1176 {
1177 struct wireless_dev *wdev = (struct wireless_dev *)ctx;
1178 struct wiphy *wiphy;
1179 struct sk_buff *skb;
1180 uint32 evt_complete = 0;
1181 gfp_t kflags;
1182 rtt_result_t *rtt_result;
1183 rtt_results_header_t *rtt_header;
1184 struct list_head *rtt_cache_list;
1185 struct nlattr *rtt_nl_hdr;
1186 wiphy = wdev->wiphy;
1187
1188 WL_DBG(("In\n"));
1189 /* Push the data to the skb */
1190 if (!rtt_data) {
1191 WL_ERR(("rtt_data is NULL\n"));
1192 return;
1193 }
1194 rtt_cache_list = (struct list_head *)rtt_data;
1195 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1196 if (list_empty(rtt_cache_list)) {
1197 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1198 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1199 skb = cfg80211_vendor_event_alloc(wiphy, NULL, 100,
1200 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1201 #else
1202 skb = cfg80211_vendor_event_alloc(wiphy, 100, GOOGLE_RTT_COMPLETE_EVENT, kflags);
1203 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1204 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1205 if (!skb) {
1206 WL_ERR(("skb alloc failed"));
1207 return;
1208 }
1209 evt_complete = 1;
1210 nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1211 cfg80211_vendor_event(skb, kflags);
1212 return;
1213 }
1214 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1215 #pragma GCC diagnostic push
1216 #pragma GCC diagnostic ignored "-Wcast-qual"
1217 #endif
1218 list_for_each_entry(rtt_header, rtt_cache_list, list) {
1219 /* Alloc the SKB for vendor_event */
1220 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
1221 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
1222 skb = cfg80211_vendor_event_alloc(wiphy, NULL, rtt_header->result_tot_len + 100,
1223 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1224 #else
1225 skb = cfg80211_vendor_event_alloc(wiphy, rtt_header->result_tot_len + 100,
1226 GOOGLE_RTT_COMPLETE_EVENT, kflags);
1227 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
1228 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
1229 if (!skb) {
1230 WL_ERR(("skb alloc failed"));
1231 return;
1232 }
1233 if (list_is_last(&rtt_header->list, rtt_cache_list)) {
1234 evt_complete = 1;
1235 }
1236 nla_put_u32(skb, RTT_ATTRIBUTE_RESULTS_COMPLETE, evt_complete);
1237 rtt_nl_hdr = nla_nest_start(skb, RTT_ATTRIBUTE_RESULTS_PER_TARGET);
1238 if (!rtt_nl_hdr) {
1239 WL_ERR(("rtt_nl_hdr is NULL\n"));
1240 break;
1241 }
1242 nla_put(skb, RTT_ATTRIBUTE_TARGET_MAC, ETHER_ADDR_LEN, &rtt_header->peer_mac);
1243 nla_put_u32(skb, RTT_ATTRIBUTE_RESULT_CNT, rtt_header->result_cnt);
1244 list_for_each_entry(rtt_result, &rtt_header->result_list, list) {
1245 nla_put(skb, RTT_ATTRIBUTE_RESULT,
1246 rtt_result->report_len, &rtt_result->report);
1247 }
1248 nla_nest_end(skb, rtt_nl_hdr);
1249 cfg80211_vendor_event(skb, kflags);
1250 }
1251 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1252 #pragma GCC diagnostic pop
1253 #endif
1254 }
1255
1256 static int
1257 wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1258 const void *data, int len) {
1259 int err = 0, rem, rem1, rem2, type;
1260 int target_cnt;
1261 rtt_config_params_t rtt_param;
1262 rtt_target_info_t* rtt_target = NULL;
1263 const struct nlattr *iter, *iter1, *iter2;
1264 int8 eabuf[ETHER_ADDR_STR_LEN];
1265 int8 chanbuf[CHANSPEC_STR_LEN];
1266 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1267 rtt_capabilities_t capability;
1268
1269 memset(&rtt_param, 0, sizeof(rtt_param));
1270
1271 WL_DBG(("In\n"));
1272 err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
1273 if (err < 0) {
1274 WL_ERR(("failed to register rtt_noti_callback\n"));
1275 goto exit;
1276 }
1277 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1278 if (err < 0) {
1279 WL_ERR(("failed to get the capability\n"));
1280 goto exit;
1281 }
1282
1283 if (len <= 0) {
1284 WL_ERR(("Length of the nlattr is not valid len : %d\n", len));
1285 err = BCME_ERROR;
1286 goto exit;
1287 }
1288 nla_for_each_attr(iter, data, len, rem) {
1289 type = nla_type(iter);
1290 switch (type) {
1291 case RTT_ATTRIBUTE_TARGET_CNT:
1292 target_cnt = nla_get_u8(iter);
1293 if ((target_cnt <= 0) || (target_cnt > RTT_MAX_TARGET_CNT)) {
1294 WL_ERR(("target_cnt is not valid : %d\n",
1295 target_cnt));
1296 err = BCME_RANGE;
1297 goto exit;
1298 }
1299 rtt_param.rtt_target_cnt = target_cnt;
1300
1301 rtt_param.target_info = kzalloc(TARGET_INFO_SIZE(target_cnt), GFP_KERNEL);
1302 if (rtt_param.target_info == NULL) {
1303 WL_ERR(("failed to allocate target info for (%d)\n", target_cnt));
1304 err = BCME_NOMEM;
1305 goto exit;
1306 }
1307 break;
1308 case RTT_ATTRIBUTE_TARGET_INFO:
1309 /* Added this variable for safe check to avoid crash
1310 * incase the caller did not respect the order
1311 */
1312 if (rtt_param.target_info == NULL) {
1313 WL_ERR(("rtt_target_info is NULL\n"));
1314 err = BCME_NOMEM;
1315 goto exit;
1316 }
1317 rtt_target = rtt_param.target_info;
1318 nla_for_each_nested(iter1, iter, rem1) {
1319 nla_for_each_nested(iter2, iter1, rem2) {
1320 type = nla_type(iter2);
1321 switch (type) {
1322 case RTT_ATTRIBUTE_TARGET_MAC:
1323 memcpy(&rtt_target->addr, nla_data(iter2),
1324 ETHER_ADDR_LEN);
1325 break;
1326 case RTT_ATTRIBUTE_TARGET_TYPE:
1327 rtt_target->type = nla_get_u8(iter2);
1328 if (rtt_target->type == RTT_INVALID ||
1329 (rtt_target->type == RTT_ONE_WAY &&
1330 !capability.rtt_one_sided_supported)) {
1331 WL_ERR(("doesn't support RTT type"
1332 " : %d\n",
1333 rtt_target->type));
1334 err = -EINVAL;
1335 goto exit;
1336 }
1337 break;
1338 case RTT_ATTRIBUTE_TARGET_PEER:
1339 rtt_target->peer = nla_get_u8(iter2);
1340 break;
1341 case RTT_ATTRIBUTE_TARGET_CHAN:
1342 memcpy(&rtt_target->channel, nla_data(iter2),
1343 sizeof(rtt_target->channel));
1344 break;
1345 case RTT_ATTRIBUTE_TARGET_PERIOD:
1346 rtt_target->burst_period = nla_get_u32(iter2);
1347 if (rtt_target->burst_period < 32) {
1348 /* 100ms unit */
1349 rtt_target->burst_period *= 100;
1350 } else {
1351 WL_ERR(("%d value must in (0-31)\n",
1352 rtt_target->burst_period));
1353 err = EINVAL;
1354 goto exit;
1355 }
1356 break;
1357 case RTT_ATTRIBUTE_TARGET_NUM_BURST:
1358 rtt_target->num_burst = nla_get_u32(iter2);
1359 if (rtt_target->num_burst > 16) {
1360 WL_ERR(("%d value must in (0-15)\n",
1361 rtt_target->num_burst));
1362 err = -EINVAL;
1363 goto exit;
1364 }
1365 rtt_target->num_burst = BIT(rtt_target->num_burst);
1366 break;
1367 case RTT_ATTRIBUTE_TARGET_NUM_FTM_BURST:
1368 rtt_target->num_frames_per_burst =
1369 nla_get_u32(iter2);
1370 break;
1371 case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTM:
1372 rtt_target->num_retries_per_ftm =
1373 nla_get_u32(iter2);
1374 break;
1375 case RTT_ATTRIBUTE_TARGET_NUM_RETRY_FTMR:
1376 rtt_target->num_retries_per_ftmr =
1377 nla_get_u32(iter2);
1378 if (rtt_target->num_retries_per_ftmr > 3) {
1379 WL_ERR(("%d value must in (0-3)\n",
1380 rtt_target->num_retries_per_ftmr));
1381 err = -EINVAL;
1382 goto exit;
1383 }
1384 break;
1385 case RTT_ATTRIBUTE_TARGET_LCI:
1386 rtt_target->LCI_request = nla_get_u8(iter2);
1387 break;
1388 case RTT_ATTRIBUTE_TARGET_LCR:
1389 rtt_target->LCI_request = nla_get_u8(iter2);
1390 break;
1391 case RTT_ATTRIBUTE_TARGET_BURST_DURATION:
1392 if ((nla_get_u32(iter2) > 1 &&
1393 nla_get_u32(iter2) < 12)) {
1394 rtt_target->burst_duration =
1395 dhd_rtt_idx_to_burst_duration(
1396 nla_get_u32(iter2));
1397 } else if (nla_get_u32(iter2) == 15) {
1398 /* use default value */
1399 rtt_target->burst_duration = 0;
1400 } else {
1401 WL_ERR(("%d value must in (2-11) or 15\n",
1402 nla_get_u32(iter2)));
1403 err = -EINVAL;
1404 goto exit;
1405 }
1406 break;
1407 case RTT_ATTRIBUTE_TARGET_BW:
1408 rtt_target->bw = nla_get_u8(iter2);
1409 break;
1410 case RTT_ATTRIBUTE_TARGET_PREAMBLE:
1411 rtt_target->preamble = nla_get_u8(iter2);
1412 break;
1413 }
1414 }
1415 /* convert to chanspec value */
1416 rtt_target->chanspec =
1417 dhd_rtt_convert_to_chspec(rtt_target->channel);
1418 if (rtt_target->chanspec == 0) {
1419 WL_ERR(("Channel is not valid \n"));
1420 err = -EINVAL;
1421 goto exit;
1422 }
1423 WL_INFORM(("Target addr %s, Channel : %s for RTT \n",
1424 bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr,
1425 eabuf),
1426 wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
1427 rtt_target++;
1428 }
1429 break;
1430 }
1431 }
1432 WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
1433 if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
1434 WL_ERR(("Could not set RTT configuration\n"));
1435 err = -EINVAL;
1436 }
1437 exit:
1438 /* free the target info list */
1439 if (rtt_param.target_info) {
1440 kfree(rtt_param.target_info);
1441 rtt_param.target_info = NULL;
1442 }
1443 return err;
1444 }
1445
1446 static int
1447 wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1448 const void *data, int len)
1449 {
1450 int err = 0, rem, type, target_cnt = 0;
1451 int target_cnt_chk = 0;
1452 const struct nlattr *iter;
1453 struct ether_addr *mac_list = NULL, *mac_addr = NULL;
1454 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1455
1456 if (len <= 0) {
1457 WL_ERR(("Length of nlattr is not valid len : %d\n", len));
1458 err = -EINVAL;
1459 goto exit;
1460 }
1461 nla_for_each_attr(iter, data, len, rem) {
1462 type = nla_type(iter);
1463 switch (type) {
1464 case RTT_ATTRIBUTE_TARGET_CNT:
1465 if (mac_list != NULL) {
1466 WL_ERR(("mac_list is not NULL\n"));
1467 err = -EINVAL;
1468 goto exit;
1469 }
1470 target_cnt = nla_get_u8(iter);
1471 if ((target_cnt > 0) && (target_cnt < RTT_MAX_TARGET_CNT)) {
1472 mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN,
1473 GFP_KERNEL);
1474 if (mac_list == NULL) {
1475 WL_ERR(("failed to allocate mem for mac list\n"));
1476 err = -EINVAL;
1477 goto exit;
1478 }
1479 mac_addr = &mac_list[0];
1480 } else {
1481 /* cancel the current whole RTT process */
1482 goto cancel;
1483 }
1484 break;
1485 case RTT_ATTRIBUTE_TARGET_MAC:
1486 if (mac_addr) {
1487 memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN);
1488 target_cnt_chk++;
1489 if (target_cnt_chk > target_cnt) {
1490 WL_ERR(("over target count\n"));
1491 err = -EINVAL;
1492 goto exit;
1493 }
1494 break;
1495 } else {
1496 WL_ERR(("mac_list is NULL\n"));
1497 err = -EINVAL;
1498 goto exit;
1499 }
1500 }
1501 }
1502 cancel:
1503 if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
1504 WL_ERR(("Could not cancel RTT configuration\n"));
1505 err = -EINVAL;
1506 }
1507
1508 exit:
1509 if (mac_list) {
1510 kfree(mac_list);
1511 }
1512 return err;
1513 }
1514
1515 static int
1516 wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
1517 const void *data, int len)
1518 {
1519 int err = 0;
1520 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1521 rtt_capabilities_t capability;
1522
1523 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1524 if (unlikely(err)) {
1525 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1526 goto exit;
1527 }
1528 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
1529 &capability, sizeof(capability));
1530
1531 if (unlikely(err)) {
1532 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1533 }
1534 exit:
1535 return err;
1536 }
1537 static int
1538 get_responder_info(struct bcm_cfg80211 *cfg,
1539 struct wifi_rtt_responder *responder_info)
1540 {
1541 int err = 0;
1542 rtt_capabilities_t capability;
1543 err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1544 if (unlikely(err)) {
1545 WL_ERR(("Could not get responder capability:%d \n", err));
1546 return err;
1547 }
1548 if (capability.preamble_support & RTT_PREAMBLE_VHT) {
1549 responder_info->preamble |= RTT_PREAMBLE_VHT;
1550 }
1551 if (capability.preamble_support & RTT_PREAMBLE_HT) {
1552 responder_info->preamble |= RTT_PREAMBLE_HT;
1553 }
1554 err = dhd_dev_rtt_avail_channel(bcmcfg_to_prmry_ndev(cfg), &(responder_info->channel));
1555 if (unlikely(err)) {
1556 WL_ERR(("Could not get available channel:%d \n", err));
1557 return err;
1558 }
1559 return err;
1560 }
1561 static int
1562 wl_cfgvendor_rtt_get_responder_info(struct wiphy *wiphy, struct wireless_dev *wdev,
1563 const void *data, int len)
1564 {
1565 int err = 0;
1566 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1567 wifi_rtt_responder_t responder_info;
1568
1569 WL_DBG(("Recv -get_avail_ch command \n"));
1570
1571 memset(&responder_info, 0, sizeof(responder_info));
1572 err = get_responder_info(cfg, &responder_info);
1573 if (unlikely(err)) {
1574 WL_ERR(("Failed to get responder info:%d \n", err));
1575 return err;
1576 }
1577 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
1578 &responder_info, sizeof(responder_info));
1579
1580 if (unlikely(err)) {
1581 WL_ERR(("Vendor cmd reply for -get_avail_ch failed ret:%d \n", err));
1582 }
1583 return err;
1584 }
1585
1586 static int
1587 wl_cfgvendor_rtt_set_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
1588 const void *data, int len)
1589 {
1590 int err = 0;
1591 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1592 struct net_device *ndev = wdev_to_wlc_ndev(wdev, cfg);
1593 wifi_rtt_responder_t responder_info;
1594
1595 WL_DBG(("Recv rtt -enable_resp cmd.\n"));
1596
1597 memset(&responder_info, 0, sizeof(responder_info));
1598
1599 /*
1600 *Passing channel as NULL until implementation
1601 *to get chan info from upper layers is donex
1602 */
1603 err = dhd_dev_rtt_enable_responder(ndev, NULL);
1604 if (unlikely(err)) {
1605 WL_ERR(("Could not enable responder ret:%d \n", err));
1606 goto done;
1607 }
1608 err = get_responder_info(cfg, &responder_info);
1609 if (unlikely(err)) {
1610 WL_ERR(("Failed to get responder info:%d \n", err));
1611 dhd_dev_rtt_cancel_responder(ndev);
1612 goto done;
1613 }
1614 done:
1615 err = wl_cfgvendor_send_cmd_reply(wiphy, ndev,
1616 &responder_info, sizeof(responder_info));
1617
1618 if (unlikely(err)) {
1619 WL_ERR(("Vendor cmd reply for -enable_resp failed ret:%d \n", err));
1620 }
1621 return err;
1622 }
1623
1624 static int
1625 wl_cfgvendor_rtt_cancel_responder(struct wiphy *wiphy, struct wireless_dev *wdev,
1626 const void *data, int len)
1627 {
1628 int err = 0;
1629 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1630
1631 WL_DBG(("Recv rtt -cancel_resp cmd \n"));
1632
1633 err = dhd_dev_rtt_cancel_responder(bcmcfg_to_prmry_ndev(cfg));
1634 if (unlikely(err)) {
1635 WL_ERR(("Vendor cmd -cancel_resp failed ret:%d \n", err));
1636 }
1637 return err;
1638 }
1639 #endif /* RTT_SUPPORT */
1640
1641 #ifdef GSCAN_SUPPORT
1642 static int wl_cfgvendor_enable_lazy_roam(struct wiphy *wiphy,
1643 struct wireless_dev *wdev, const void *data, int len)
1644 {
1645 int err = -EINVAL;
1646 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1647 int type;
1648 uint32 lazy_roam_enable_flag;
1649
1650 type = nla_type(data);
1651
1652 if (type == GSCAN_ATTRIBUTE_LAZY_ROAM_ENABLE) {
1653 lazy_roam_enable_flag = nla_get_u32(data);
1654
1655 err = dhd_dev_lazy_roam_enable(bcmcfg_to_prmry_ndev(cfg),
1656 lazy_roam_enable_flag);
1657
1658 if (unlikely(err))
1659 WL_ERR(("Could not enable lazy roam:%d \n", err));
1660
1661 }
1662 return err;
1663 }
1664
1665 static int wl_cfgvendor_set_lazy_roam_cfg(struct wiphy *wiphy,
1666 struct wireless_dev *wdev, const void *data, int len)
1667 {
1668 int err = 0, tmp, type;
1669 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1670 wlc_roam_exp_params_t roam_param;
1671 const struct nlattr *iter;
1672
1673 memset(&roam_param, 0, sizeof(roam_param));
1674
1675 nla_for_each_attr(iter, data, len, tmp) {
1676 type = nla_type(iter);
1677
1678 switch (type) {
1679 case GSCAN_ATTRIBUTE_A_BAND_BOOST_THRESHOLD:
1680 roam_param.a_band_boost_threshold = nla_get_u32(iter);
1681 break;
1682 case GSCAN_ATTRIBUTE_A_BAND_PENALTY_THRESHOLD:
1683 roam_param.a_band_penalty_threshold = nla_get_u32(iter);
1684 break;
1685 case GSCAN_ATTRIBUTE_A_BAND_BOOST_FACTOR:
1686 roam_param.a_band_boost_factor = nla_get_u32(iter);
1687 break;
1688 case GSCAN_ATTRIBUTE_A_BAND_PENALTY_FACTOR:
1689 roam_param.a_band_penalty_factor = nla_get_u32(iter);
1690 break;
1691 case GSCAN_ATTRIBUTE_A_BAND_MAX_BOOST:
1692 roam_param.a_band_max_boost = nla_get_u32(iter);
1693 break;
1694 case GSCAN_ATTRIBUTE_LAZY_ROAM_HYSTERESIS:
1695 roam_param.cur_bssid_boost = nla_get_u32(iter);
1696 break;
1697 case GSCAN_ATTRIBUTE_ALERT_ROAM_RSSI_TRIGGER:
1698 roam_param.alert_roam_trigger_threshold = nla_get_u32(iter);
1699 break;
1700 }
1701 }
1702
1703 if (dhd_dev_set_lazy_roam_cfg(bcmcfg_to_prmry_ndev(cfg), &roam_param) < 0) {
1704 WL_ERR(("Could not set batch cfg\n"));
1705 err = -EINVAL;
1706 }
1707 return err;
1708 }
1709
1710 /* small helper function */
1711 static wl_bssid_pref_cfg_t *
1712 create_bssid_pref_cfg(uint32 num)
1713 {
1714 uint32 mem_needed;
1715 wl_bssid_pref_cfg_t *bssid_pref;
1716
1717 mem_needed = sizeof(wl_bssid_pref_cfg_t);
1718 if (num)
1719 mem_needed += (num - 1) * sizeof(wl_bssid_pref_list_t);
1720 bssid_pref = (wl_bssid_pref_cfg_t *) kmalloc(mem_needed, GFP_KERNEL);
1721 return bssid_pref;
1722 }
1723
1724 static int
1725 wl_cfgvendor_set_bssid_pref(struct wiphy *wiphy,
1726 struct wireless_dev *wdev, const void *data, int len)
1727 {
1728 int err = 0;
1729 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1730 wl_bssid_pref_cfg_t *bssid_pref = NULL;
1731 wl_bssid_pref_list_t *bssids;
1732 int tmp, tmp1, tmp2, type;
1733 const struct nlattr *outer, *inner, *iter;
1734 uint32 flush = 0, i = 0, num = 0;
1735
1736 /* Assumption: NUM attribute must come first */
1737 nla_for_each_attr(iter, data, len, tmp2) {
1738 type = nla_type(iter);
1739 switch (type) {
1740 case GSCAN_ATTRIBUTE_NUM_BSSID:
1741 num = nla_get_u32(iter);
1742 if (num > MAX_BSSID_PREF_LIST_NUM) {
1743 WL_ERR(("Too many Preferred BSSIDs!\n"));
1744 err = -EINVAL;
1745 goto exit;
1746 }
1747 break;
1748 case GSCAN_ATTRIBUTE_BSSID_PREF_FLUSH:
1749 flush = nla_get_u32(iter);
1750 break;
1751 case GSCAN_ATTRIBUTE_BSSID_PREF_LIST:
1752 if (!num)
1753 return -EINVAL;
1754 if ((bssid_pref = create_bssid_pref_cfg(num)) == NULL) {
1755 WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__));
1756 err = -ENOMEM;
1757 goto exit;
1758 }
1759 bssid_pref->count = num;
1760 bssids = bssid_pref->bssids;
1761 nla_for_each_nested(outer, iter, tmp) {
1762 if (i >= num) {
1763 WL_ERR(("CFGs don't seem right!\n"));
1764 err = -EINVAL;
1765 goto exit;
1766 }
1767 nla_for_each_nested(inner, outer, tmp1) {
1768 type = nla_type(inner);
1769 switch (type) {
1770 case GSCAN_ATTRIBUTE_BSSID_PREF:
1771 memcpy(&(bssids[i].bssid),
1772 nla_data(inner), ETHER_ADDR_LEN);
1773 /* not used for now */
1774 bssids[i].flags = 0;
1775 break;
1776 case GSCAN_ATTRIBUTE_RSSI_MODIFIER:
1777 bssids[i].rssi_factor =
1778 (int8) nla_get_u32(inner);
1779 break;
1780 }
1781 }
1782 i++;
1783 }
1784 break;
1785 default:
1786 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1787 break;
1788 }
1789 }
1790
1791 if (!bssid_pref) {
1792 /* What if only flush is desired? */
1793 if (flush) {
1794 if ((bssid_pref = create_bssid_pref_cfg(0)) == NULL) {
1795 WL_ERR(("%s: Can't malloc memory\n", __FUNCTION__));
1796 err = -ENOMEM;
1797 goto exit;
1798 }
1799 bssid_pref->count = 0;
1800 } else {
1801 err = -EINVAL;
1802 goto exit;
1803 }
1804 }
1805 err = dhd_dev_set_lazy_roam_bssid_pref(bcmcfg_to_prmry_ndev(cfg),
1806 bssid_pref, flush);
1807 exit:
1808 kfree(bssid_pref);
1809 return err;
1810 }
1811
1812 static int
1813 wl_cfgvendor_set_bssid_blacklist(struct wiphy *wiphy,
1814 struct wireless_dev *wdev, const void *data, int len)
1815 {
1816 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1817 maclist_t *blacklist = NULL;
1818 int err = 0;
1819 int type, tmp;
1820 const struct nlattr *iter;
1821 uint32 mem_needed = 0, flush = 0, i = 0, num = 0;
1822
1823 /* Assumption: NUM attribute must come first */
1824 nla_for_each_attr(iter, data, len, tmp) {
1825 type = nla_type(iter);
1826 switch (type) {
1827 case GSCAN_ATTRIBUTE_NUM_BSSID:
1828 num = nla_get_u32(iter);
1829 if (num > MAX_BSSID_BLACKLIST_NUM) {
1830 WL_ERR(("Too many Blacklist BSSIDs!\n"));
1831 err = -EINVAL;
1832 goto exit;
1833 }
1834 break;
1835 case GSCAN_ATTRIBUTE_BSSID_BLACKLIST_FLUSH:
1836 flush = nla_get_u32(iter);
1837 break;
1838 case GSCAN_ATTRIBUTE_BLACKLIST_BSSID:
1839 if (num) {
1840 if (!blacklist) {
1841 mem_needed = sizeof(maclist_t) +
1842 sizeof(struct ether_addr) * (num - 1);
1843 blacklist = (maclist_t *)
1844 kmalloc(mem_needed, GFP_KERNEL);
1845 if (!blacklist) {
1846 WL_ERR(("%s: Can't malloc %d bytes\n",
1847 __FUNCTION__, mem_needed));
1848 err = -ENOMEM;
1849 goto exit;
1850 }
1851 blacklist->count = num;
1852 }
1853 if (i >= num) {
1854 WL_ERR(("CFGs don't seem right!\n"));
1855 err = -EINVAL;
1856 goto exit;
1857 }
1858 memcpy(&(blacklist->ea[i]),
1859 nla_data(iter), ETHER_ADDR_LEN);
1860 i++;
1861 }
1862 break;
1863 default:
1864 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1865 break;
1866 }
1867 }
1868 err = dhd_dev_set_blacklist_bssid(bcmcfg_to_prmry_ndev(cfg),
1869 blacklist, mem_needed, flush);
1870 exit:
1871 kfree(blacklist);
1872 return err;
1873 }
1874
1875 static int
1876 wl_cfgvendor_set_ssid_whitelist(struct wiphy *wiphy,
1877 struct wireless_dev *wdev, const void *data, int len)
1878 {
1879 int err = 0;
1880 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1881 wl_ssid_whitelist_t *ssid_whitelist = NULL;
1882 wlc_ssid_t *ssid_elem;
1883 int tmp, tmp2, mem_needed = 0, type;
1884 const struct nlattr *inner, *iter;
1885 uint32 flush = 0, i = 0, num = 0;
1886
1887 /* Assumption: NUM attribute must come first */
1888 nla_for_each_attr(iter, data, len, tmp2) {
1889 type = nla_type(iter);
1890 switch (type) {
1891 case GSCAN_ATTRIBUTE_NUM_WL_SSID:
1892 num = nla_get_u32(iter);
1893 if (num > MAX_SSID_WHITELIST_NUM) {
1894 WL_ERR(("Too many WL SSIDs!\n"));
1895 err = -EINVAL;
1896 goto exit;
1897 }
1898 mem_needed = sizeof(wl_ssid_whitelist_t);
1899 if (num)
1900 mem_needed += (num - 1) * sizeof(ssid_info_t);
1901 ssid_whitelist = (wl_ssid_whitelist_t *)
1902 kzalloc(mem_needed, GFP_KERNEL);
1903 if (ssid_whitelist == NULL) {
1904 WL_ERR(("%s: Can't malloc %d bytes\n",
1905 __FUNCTION__, mem_needed));
1906 err = -ENOMEM;
1907 goto exit;
1908 }
1909 ssid_whitelist->ssid_count = num;
1910 break;
1911 case GSCAN_ATTRIBUTE_WL_SSID_FLUSH:
1912 flush = nla_get_u32(iter);
1913 break;
1914 case GSCAN_ATTRIBUTE_WHITELIST_SSID_ELEM:
1915 if (!num || !ssid_whitelist) {
1916 WL_ERR(("num ssid is not set!\n"));
1917 return -EINVAL;
1918 }
1919 if (i >= num) {
1920 WL_ERR(("CFGs don't seem right!\n"));
1921 err = -EINVAL;
1922 goto exit;
1923 }
1924 ssid_elem = &ssid_whitelist->ssids[i];
1925 nla_for_each_nested(inner, iter, tmp) {
1926 type = nla_type(inner);
1927 switch (type) {
1928 case GSCAN_ATTRIBUTE_WHITELIST_SSID:
1929 memcpy(ssid_elem->SSID,
1930 nla_data(inner),
1931 DOT11_MAX_SSID_LEN);
1932 break;
1933 case GSCAN_ATTRIBUTE_WL_SSID_LEN:
1934 ssid_elem->SSID_len = (uint8)
1935 nla_get_u32(inner);
1936 break;
1937 }
1938 }
1939 i++;
1940 break;
1941 default:
1942 WL_ERR(("%s: No such attribute %d\n", __FUNCTION__, type));
1943 break;
1944 }
1945 }
1946
1947 err = dhd_dev_set_whitelist_ssid(bcmcfg_to_prmry_ndev(cfg),
1948 ssid_whitelist, mem_needed, flush);
1949 exit:
1950 kfree(ssid_whitelist);
1951 return err;
1952 }
1953 #endif /* GSCAN_SUPPORT */
1954
1955 static int
1956 wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
1957 struct wireless_dev *wdev, const void *data, int len)
1958 {
1959 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1960 int ret = 0;
1961 int ret_len = 0, payload = 0, msglen;
1962 const struct bcm_nlmsg_hdr *nlioc = data;
1963 void *buf = NULL, *cur;
1964 int maxmsglen = PAGE_SIZE - 0x100;
1965 struct sk_buff *reply;
1966
1967 WL_ERR(("entry: cmd = %d\n", nlioc->cmd));
1968
1969 len -= sizeof(struct bcm_nlmsg_hdr);
1970 ret_len = nlioc->len;
1971 if (ret_len > 0 || len > 0) {
1972 if (len > DHD_IOCTL_MAXLEN) {
1973 WL_ERR(("oversize input buffer %d\n", len));
1974 len = DHD_IOCTL_MAXLEN;
1975 }
1976 if (ret_len > DHD_IOCTL_MAXLEN) {
1977 WL_ERR(("oversize return buffer %d\n", ret_len));
1978 ret_len = DHD_IOCTL_MAXLEN;
1979 }
1980 payload = max(ret_len, len) + 1;
1981 buf = vzalloc(payload);
1982 if (!buf) {
1983 return -ENOMEM;
1984 }
1985 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1986 #pragma GCC diagnostic push
1987 #pragma GCC diagnostic ignored "-Wcast-qual"
1988 #endif
1989 memcpy(buf, (void *)((char *)nlioc + nlioc->offset), len);
1990 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
1991 #pragma GCC diagnostic pop
1992 #endif
1993 *((char *)buf + len) = '\0';
1994 }
1995
1996 ret = dhd_cfgvendor_priv_string_handler(cfg, wdev, nlioc, buf);
1997 if (ret) {
1998 WL_ERR(("dhd_cfgvendor returned error %d", ret));
1999 vfree(buf);
2000 return ret;
2001 }
2002 cur = buf;
2003 while (ret_len > 0) {
2004 msglen = nlioc->len > maxmsglen ? maxmsglen : ret_len;
2005 ret_len -= msglen;
2006 payload = msglen + sizeof(msglen);
2007 reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
2008 if (!reply) {
2009 WL_ERR(("Failed to allocate reply msg\n"));
2010 ret = -ENOMEM;
2011 break;
2012 }
2013
2014 if (nla_put(reply, BCM_NLATTR_DATA, msglen, cur) ||
2015 nla_put_u16(reply, BCM_NLATTR_LEN, msglen)) {
2016 kfree_skb(reply);
2017 ret = -ENOBUFS;
2018 break;
2019 }
2020
2021 ret = cfg80211_vendor_cmd_reply(reply);
2022 if (ret) {
2023 WL_ERR(("testmode reply failed:%d\n", ret));
2024 break;
2025 }
2026 cur = (void *)((char *)cur + msglen);
2027 }
2028
2029 return ret;
2030 }
2031
2032 struct net_device *
2033 wl_cfgvendor_get_ndev(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
2034 const void *data, unsigned long int *out_addr)
2035 {
2036 char *pos, *pos1;
2037 char ifname[IFNAMSIZ + 1] = {0};
2038 struct net_info *iter, *next;
2039 struct net_device *ndev = NULL;
2040 *out_addr = (unsigned long int) data; /* point to command str by default */
2041
2042 /* check whether ifname=<ifname> is provided in the command */
2043 pos = strstr(data, "ifname=");
2044 if (pos) {
2045 pos += strlen("ifname=");
2046 pos1 = strstr(pos, " ");
2047 if (!pos1) {
2048 WL_ERR(("command format error \n"));
2049 return NULL;
2050 }
2051 memcpy(ifname, pos, (pos1 - pos));
2052 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2053 #pragma GCC diagnostic push
2054 #pragma GCC diagnostic ignored "-Wcast-qual"
2055 #endif
2056 for_each_ndev(cfg, iter, next) {
2057 if (iter->ndev) {
2058 if (strncmp(iter->ndev->name, ifname,
2059 strlen(iter->ndev->name)) == 0) {
2060 /* matching ifname found */
2061 WL_DBG(("matching interface (%s) found ndev:%p \n",
2062 iter->ndev->name, iter->ndev));
2063 *out_addr = (unsigned long int)(pos1 + 1);
2064 /* Returns the command portion after ifname=<name> */
2065 return iter->ndev;
2066 }
2067 }
2068 }
2069 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
2070 #pragma GCC diagnostic pop
2071 #endif
2072 WL_ERR(("Couldn't find ifname:%s in the netinfo list \n",
2073 ifname));
2074 return NULL;
2075 }
2076
2077 /* If ifname=<name> arg is not provided, use default ndev */
2078 ndev = wdev->netdev ? wdev->netdev : bcmcfg_to_prmry_ndev(cfg);
2079 WL_DBG(("Using default ndev (%s) \n", ndev->name));
2080 return ndev;
2081 }
2082
2083 /* Max length for the reply buffer. For BRCM_ATTR_DRIVER_CMD, the reply
2084 * would be a formatted string and reply buf would be the size of the
2085 * string.
2086 */
2087 #define WL_DRIVER_PRIV_CMD_LEN 512
2088 static int
2089 wl_cfgvendor_priv_bcm_handler(struct wiphy *wiphy,
2090 struct wireless_dev *wdev, const void *data, int len)
2091 {
2092 const struct nlattr *iter;
2093 int err = 0;
2094 int data_len = 0, cmd_len = 0, tmp = 0, type = 0;
2095 struct net_device *ndev = wdev->netdev;
2096 char *reply_buf = NULL;
2097 char *cmd = NULL;
2098 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2099 int bytes_written;
2100 struct net_device *net = NULL;
2101 unsigned long int cmd_out = 0;
2102 u32 reply_len = WL_DRIVER_PRIV_CMD_LEN;
2103
2104
2105 WL_DBG(("%s: Enter \n", __func__));
2106
2107 /* hold wake lock */
2108 net_os_wake_lock(ndev);
2109
2110 nla_for_each_attr(iter, data, len, tmp) {
2111 type = nla_type(iter);
2112 cmd = nla_data(iter);
2113 cmd_len = nla_len(iter);
2114
2115 WL_DBG(("%s: type: %d cmd_len:%d cmd_ptr:%p \n", __func__, type, cmd_len, cmd));
2116 if (!cmd || !cmd_len) {
2117 WL_ERR(("Invalid cmd data \n"));
2118 err = -EINVAL;
2119 goto exit;
2120 }
2121
2122 if (type == BRCM_ATTR_DRIVER_CMD) {
2123 if (cmd_len >= WL_DRIVER_PRIV_CMD_LEN) {
2124 WL_ERR(("Unexpected command length. Ignore the command\n"));
2125 err = -EINVAL;
2126 goto exit;
2127 }
2128 net = wl_cfgvendor_get_ndev(cfg, wdev, cmd, &cmd_out);
2129 if (!cmd_out || !net) {
2130 err = -ENODEV;
2131 goto exit;
2132 }
2133 cmd = (char *)cmd_out;
2134 reply_buf = kzalloc(reply_len, GFP_KERNEL);
2135 if (!reply_buf) {
2136 WL_ERR(("memory alloc failed for %u \n", cmd_len));
2137 err = -ENOMEM;
2138 goto exit;
2139 }
2140 memcpy(reply_buf, cmd, cmd_len);
2141 WL_DBG(("vendor_command: %s len: %u \n", cmd, cmd_len));
2142 bytes_written = wl_handle_private_cmd(net, reply_buf, reply_len);
2143 WL_DBG(("bytes_written: %d \n", bytes_written));
2144 if (bytes_written == 0) {
2145 snprintf(reply_buf, reply_len, "%s", "OK");
2146 data_len = strlen("OK");
2147 } else if (bytes_written > 0) {
2148 data_len = bytes_written > reply_len ?
2149 reply_len : bytes_written;
2150 } else {
2151 /* -ve return value. Propagate the error back */
2152 err = bytes_written;
2153 goto exit;
2154 }
2155 break;
2156 }
2157 }
2158
2159 if ((data_len > 0) && reply_buf) {
2160 err = wl_cfgvendor_send_cmd_reply(wiphy, wdev->netdev,
2161 reply_buf, data_len+1);
2162 if (unlikely(err))
2163 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2164 else
2165 WL_DBG(("Vendor Command reply sent successfully!\n"));
2166 } else {
2167 /* No data to be sent back as reply */
2168 WL_ERR(("Vendor_cmd: No reply expected. data_len:%u reply_buf %p \n",
2169 data_len, reply_buf));
2170 }
2171
2172 exit:
2173 if (reply_buf)
2174 kfree(reply_buf);
2175 net_os_wake_unlock(ndev);
2176 return err;
2177 }
2178
2179
2180 #ifdef LINKSTAT_SUPPORT
2181 #define NUM_RATE 32
2182 #define NUM_PEER 1
2183 #define NUM_CHAN 11
2184 #define HEADER_SIZE sizeof(ver_len)
2185 static int wl_cfgvendor_lstats_get_info(struct wiphy *wiphy,
2186 struct wireless_dev *wdev, const void *data, int len)
2187 {
2188 static char iovar_buf[WLC_IOCTL_MAXLEN];
2189 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2190 int err = 0, i;
2191 wifi_radio_stat *radio;
2192 wifi_radio_stat_h radio_h;
2193 wl_wme_cnt_t *wl_wme_cnt;
2194 wl_cnt_ge40mcst_v1_t *macstat_cnt;
2195 wl_cnt_wlc_t *wlc_cnt;
2196 scb_val_t scbval;
2197 char *output = NULL;
2198 char *outdata = NULL;
2199 wifi_rate_stat_v1 *p_wifi_rate_stat_v1 = NULL;
2200 wifi_rate_stat *p_wifi_rate_stat = NULL;
2201 uint total_len = 0;
2202 wifi_iface_stat iface;
2203 wlc_rev_info_t revinfo;
2204 #ifdef CONFIG_COMPAT
2205 compat_wifi_iface_stat compat_iface;
2206 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2207 int compat_task_state = in_compat_syscall();
2208 #else
2209 int compat_task_state = is_compat_task();
2210 #endif
2211 #endif /* CONFIG_COMPAT */
2212
2213 WL_INFORM(("%s: Enter \n", __func__));
2214 RETURN_EIO_IF_NOT_UP(cfg);
2215
2216 /* Get the device rev info */
2217 memset(&revinfo, 0, sizeof(revinfo));
2218 err = wldev_ioctl_get(bcmcfg_to_prmry_ndev(cfg), WLC_GET_REVINFO, &revinfo,
2219 sizeof(revinfo));
2220 if (err != BCME_OK) {
2221 goto exit;
2222 }
2223
2224 outdata = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
2225 if (outdata == NULL) {
2226 WL_ERR(("%s: alloc failed\n", __func__));
2227 return -ENOMEM;
2228 }
2229
2230 memset(&scbval, 0, sizeof(scb_val_t));
2231 memset(outdata, 0, WLC_IOCTL_MAXLEN);
2232 output = outdata;
2233
2234 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "radiostat", NULL, 0,
2235 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2236 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
2237 WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wifi_radio_stat)));
2238 goto exit;
2239 }
2240 radio = (wifi_radio_stat *)iovar_buf;
2241
2242 memset(&radio_h, 0, sizeof(wifi_radio_stat_h));
2243 radio_h.on_time = radio->on_time;
2244 radio_h.tx_time = radio->tx_time;
2245 radio_h.rx_time = radio->rx_time;
2246 radio_h.on_time_scan = radio->on_time_scan;
2247 radio_h.on_time_nbd = radio->on_time_nbd;
2248 radio_h.on_time_gscan = radio->on_time_gscan;
2249 radio_h.on_time_roam_scan = radio->on_time_roam_scan;
2250 radio_h.on_time_pno_scan = radio->on_time_pno_scan;
2251 radio_h.on_time_hs20 = radio->on_time_hs20;
2252 radio_h.num_channels = NUM_CHAN;
2253
2254 memcpy(output, &radio_h, sizeof(wifi_radio_stat_h));
2255
2256 output += sizeof(wifi_radio_stat_h);
2257 output += (NUM_CHAN * sizeof(wifi_channel_stat));
2258
2259 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "wme_counters", NULL, 0,
2260 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2261 if (unlikely(err)) {
2262 WL_ERR(("error (%d)\n", err));
2263 goto exit;
2264 }
2265 wl_wme_cnt = (wl_wme_cnt_t *)iovar_buf;
2266
2267 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].ac, WIFI_AC_VO);
2268 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].tx_mpdu, wl_wme_cnt->tx[AC_VO].packets);
2269 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].rx_mpdu, wl_wme_cnt->rx[AC_VO].packets);
2270 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VO].mpdu_lost,
2271 wl_wme_cnt->tx_failed[WIFI_AC_VO].packets);
2272
2273 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].ac, WIFI_AC_VI);
2274 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].tx_mpdu, wl_wme_cnt->tx[AC_VI].packets);
2275 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].rx_mpdu, wl_wme_cnt->rx[AC_VI].packets);
2276 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_VI].mpdu_lost,
2277 wl_wme_cnt->tx_failed[WIFI_AC_VI].packets);
2278
2279 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].ac, WIFI_AC_BE);
2280 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].tx_mpdu, wl_wme_cnt->tx[AC_BE].packets);
2281 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].rx_mpdu, wl_wme_cnt->rx[AC_BE].packets);
2282 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].mpdu_lost,
2283 wl_wme_cnt->tx_failed[WIFI_AC_BE].packets);
2284
2285 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].ac, WIFI_AC_BK);
2286 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].tx_mpdu, wl_wme_cnt->tx[AC_BK].packets);
2287 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].rx_mpdu, wl_wme_cnt->rx[AC_BK].packets);
2288 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BK].mpdu_lost,
2289 wl_wme_cnt->tx_failed[WIFI_AC_BK].packets);
2290
2291
2292 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "counters", NULL, 0,
2293 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2294 if (unlikely(err)) {
2295 WL_ERR(("error (%d) - size = %zu\n", err, sizeof(wl_cnt_wlc_t)));
2296 goto exit;
2297 }
2298
2299 CHK_CNTBUF_DATALEN(iovar_buf, WLC_IOCTL_MAXLEN);
2300
2301 #ifdef STAT_REPORT
2302 wl_stat_report_gather(cfg, iovar_buf);
2303 #endif
2304
2305 /* Translate traditional (ver <= 10) counters struct to new xtlv type struct */
2306 err = wl_cntbuf_to_xtlv_format(NULL, iovar_buf, WLC_IOCTL_MAXLEN, revinfo.corerev);
2307 if (err != BCME_OK) {
2308 WL_ERR(("%s wl_cntbuf_to_xtlv_format ERR %d\n",
2309 __FUNCTION__, err));
2310 goto exit;
2311 }
2312
2313 if (!(wlc_cnt = GET_WLCCNT_FROM_CNTBUF(iovar_buf))) {
2314 WL_ERR(("%s wlc_cnt NULL!\n", __FUNCTION__));
2315 err = BCME_ERROR;
2316 goto exit;
2317 }
2318
2319 COMPAT_ASSIGN_VALUE(iface, ac[WIFI_AC_BE].retries, wlc_cnt->txretry);
2320
2321 if ((macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
2322 ((wl_cnt_info_t *)iovar_buf)->datalen,
2323 WL_CNT_XTLV_CNTV_LE10_UCODE, NULL,
2324 BCM_XTLV_OPTION_ALIGN32)) == NULL) {
2325 macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
2326 ((wl_cnt_info_t *)iovar_buf)->datalen,
2327 WL_CNT_XTLV_GE40_UCODE_V1, NULL,
2328 BCM_XTLV_OPTION_ALIGN32);
2329 }
2330
2331 if (macstat_cnt == NULL) {
2332 printf("wlmTxGetAckedPackets: macstat_cnt NULL!\n");
2333 err = BCME_ERROR;
2334 goto exit;
2335 }
2336
2337 err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval);
2338 if (unlikely(err)) {
2339 WL_ERR(("get_rssi error (%d)\n", err));
2340 goto exit;
2341 }
2342
2343 COMPAT_ASSIGN_VALUE(iface, beacon_rx, macstat_cnt->rxbeaconmbss);
2344 COMPAT_ASSIGN_VALUE(iface, rssi_mgmt, scbval.val);
2345 COMPAT_ASSIGN_VALUE(iface, num_peers, NUM_PEER);
2346 COMPAT_ASSIGN_VALUE(iface, peer_info->num_rate, NUM_RATE);
2347
2348 #ifdef CONFIG_COMPAT
2349 if (compat_task_state) {
2350 memcpy(output, &compat_iface, sizeof(compat_iface));
2351 output += (sizeof(compat_iface) - sizeof(wifi_rate_stat));
2352 } else
2353 #endif /* CONFIG_COMPAT */
2354 {
2355 memcpy(output, &iface, sizeof(iface));
2356 output += (sizeof(iface) - sizeof(wifi_rate_stat));
2357 }
2358
2359 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0,
2360 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2361 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
2362 WL_ERR(("error (%d) - size = %zu\n", err, NUM_RATE*sizeof(wifi_rate_stat)));
2363 goto exit;
2364 }
2365 for (i = 0; i < NUM_RATE; i++) {
2366 p_wifi_rate_stat =
2367 (wifi_rate_stat *)(iovar_buf + i*sizeof(wifi_rate_stat));
2368 p_wifi_rate_stat_v1 = (wifi_rate_stat_v1 *)output;
2369 p_wifi_rate_stat_v1->rate.preamble = p_wifi_rate_stat->rate.preamble;
2370 p_wifi_rate_stat_v1->rate.nss = p_wifi_rate_stat->rate.nss;
2371 p_wifi_rate_stat_v1->rate.bw = p_wifi_rate_stat->rate.bw;
2372 p_wifi_rate_stat_v1->rate.rateMcsIdx = p_wifi_rate_stat->rate.rateMcsIdx;
2373 p_wifi_rate_stat_v1->rate.reserved = p_wifi_rate_stat->rate.reserved;
2374 p_wifi_rate_stat_v1->rate.bitrate = p_wifi_rate_stat->rate.bitrate;
2375 p_wifi_rate_stat_v1->tx_mpdu = p_wifi_rate_stat->tx_mpdu;
2376 p_wifi_rate_stat_v1->rx_mpdu = p_wifi_rate_stat->rx_mpdu;
2377 p_wifi_rate_stat_v1->mpdu_lost = p_wifi_rate_stat->mpdu_lost;
2378 p_wifi_rate_stat_v1->retries = p_wifi_rate_stat->retries;
2379 p_wifi_rate_stat_v1->retries_short = p_wifi_rate_stat->retries_short;
2380 p_wifi_rate_stat_v1->retries_long = p_wifi_rate_stat->retries_long;
2381 output = (char *) &(p_wifi_rate_stat_v1->retries_long);
2382 output += sizeof(p_wifi_rate_stat_v1->retries_long);
2383 }
2384
2385 total_len = sizeof(wifi_radio_stat_h) +
2386 NUM_CHAN * sizeof(wifi_channel_stat);
2387
2388 #ifdef CONFIG_COMPAT
2389 if (compat_task_state) {
2390 total_len += sizeof(compat_wifi_iface_stat);
2391 } else
2392 #endif /* CONFIG_COMPAT */
2393 {
2394 total_len += sizeof(wifi_iface_stat);
2395 }
2396
2397 total_len = total_len - sizeof(wifi_peer_info) +
2398 NUM_PEER * (sizeof(wifi_peer_info) - sizeof(wifi_rate_stat_v1) +
2399 NUM_RATE * sizeof(wifi_rate_stat_v1));
2400
2401 if (total_len > WLC_IOCTL_MAXLEN) {
2402 WL_ERR(("Error! total_len:%d is unexpected value\n", total_len));
2403 err = BCME_BADLEN;
2404 goto exit;
2405 }
2406 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2407 outdata,
2408 total_len);
2409
2410 if (unlikely(err))
2411 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2412
2413 exit:
2414 if (outdata) {
2415 kfree(outdata);
2416 }
2417 return err;
2418 }
2419 #endif /* LINKSTAT_SUPPORT */
2420
2421 #ifdef DEBUGABILITY
2422 static int wl_cfgvendor_dbg_start_logging(struct wiphy *wiphy,
2423 struct wireless_dev *wdev, const void *data, int len)
2424 {
2425 int ret = BCME_OK, rem, type;
2426 char ring_name[DBGRING_NAME_MAX] = {0};
2427 int log_level = 0, flags = 0, time_intval = 0, threshold = 0;
2428 const struct nlattr *iter;
2429 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2430 dhd_pub_t *dhd_pub = cfg->pub;
2431 nla_for_each_attr(iter, data, len, rem) {
2432 type = nla_type(iter);
2433 switch (type) {
2434 case DEBUG_ATTRIBUTE_RING_NAME:
2435 strncpy(ring_name, nla_data(iter),
2436 MIN(sizeof(ring_name) -1, nla_len(iter)));
2437 break;
2438 case DEBUG_ATTRIBUTE_LOG_LEVEL:
2439 log_level = nla_get_u32(iter);
2440 break;
2441 case DEBUG_ATTRIBUTE_RING_FLAGS:
2442 flags = nla_get_u32(iter);
2443 break;
2444 case DEBUG_ATTRIBUTE_LOG_TIME_INTVAL:
2445 time_intval = nla_get_u32(iter);
2446 break;
2447 case DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE:
2448 threshold = nla_get_u32(iter);
2449 break;
2450 default:
2451 WL_ERR(("Unknown type: %d\n", type));
2452 ret = BCME_BADADDR;
2453 goto exit;
2454 }
2455 }
2456
2457 ret = dhd_os_start_logging(dhd_pub, ring_name, log_level, flags, time_intval, threshold);
2458 if (ret < 0) {
2459 WL_ERR(("start_logging is failed ret: %d\n", ret));
2460 }
2461 exit:
2462 return ret;
2463 }
2464
2465 static int wl_cfgvendor_dbg_reset_logging(struct wiphy *wiphy,
2466 struct wireless_dev *wdev, const void *data, int len)
2467 {
2468 int ret = BCME_OK;
2469 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2470 dhd_pub_t *dhd_pub = cfg->pub;
2471
2472 ret = dhd_os_reset_logging(dhd_pub);
2473 if (ret < 0) {
2474 WL_ERR(("reset logging is failed ret: %d\n", ret));
2475 }
2476
2477 return ret;
2478 }
2479
2480 static int
2481 wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
2482 struct wireless_dev *wdev, const void *data, int len)
2483 {
2484 int ret = BCME_OK;
2485 uint32 alloc_len;
2486 struct sk_buff *skb;
2487 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2488 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
2489
2490 dhdp->memdump_type = DUMP_TYPE_CFG_VENDOR_TRIGGERED;
2491
2492 ret = dhd_os_socram_dump(bcmcfg_to_prmry_ndev(cfg), &alloc_len);
2493 if (ret) {
2494 WL_ERR(("failed to call dhd_os_socram_dump : %d\n", ret));
2495 goto exit;
2496 }
2497 /* Alloc the SKB for vendor_event */
2498 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 100);
2499 if (!skb) {
2500 WL_ERR(("skb allocation is failed\n"));
2501 ret = BCME_NOMEM;
2502 goto exit;
2503 }
2504 nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, alloc_len);
2505
2506 ret = cfg80211_vendor_cmd_reply(skb);
2507
2508 if (ret) {
2509 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2510 }
2511
2512 exit:
2513 return ret;
2514 }
2515
2516 static int
2517 wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
2518 struct wireless_dev *wdev, const void *data, int len)
2519 {
2520 int ret = BCME_OK, rem, type;
2521 int buf_len = 0;
2522 uintptr_t user_buf = (uintptr_t)NULL;
2523 const struct nlattr *iter;
2524 char *mem_buf = NULL;
2525 struct sk_buff *skb;
2526 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2527
2528 nla_for_each_attr(iter, data, len, rem) {
2529 type = nla_type(iter);
2530 switch (type) {
2531 case DEBUG_ATTRIBUTE_FW_DUMP_LEN:
2532 /* Check if the iter is valid and
2533 * buffer length is not already initialized.
2534 */
2535 if ((nla_len(iter) == sizeof(uint32)) &&
2536 !buf_len) {
2537 buf_len = nla_get_u32(iter);
2538 } else {
2539 ret = BCME_ERROR;
2540 goto exit;
2541 }
2542 break;
2543 case DEBUG_ATTRIBUTE_FW_DUMP_DATA:
2544 if (nla_len(iter) != sizeof(uint64)) {
2545 WL_ERR(("Invalid len\n"));
2546 ret = BCME_ERROR;
2547 goto exit;
2548 }
2549 user_buf = (uintptr_t)nla_get_u64(iter);
2550 break;
2551 default:
2552 WL_ERR(("Unknown type: %d\n", type));
2553 ret = BCME_ERROR;
2554 goto exit;
2555 }
2556 }
2557 if (buf_len > 0 && user_buf) {
2558 mem_buf = vmalloc(buf_len);
2559 if (!mem_buf) {
2560 WL_ERR(("failed to allocate mem_buf with size : %d\n", buf_len));
2561 ret = BCME_NOMEM;
2562 goto exit;
2563 }
2564 ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf, &buf_len);
2565 if (ret) {
2566 WL_ERR(("failed to get_socram_dump : %d\n", ret));
2567 goto free_mem;
2568 }
2569 #ifdef CONFIG_COMPAT
2570 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2571 if (in_compat_syscall())
2572 #else
2573 if (is_compat_task())
2574 #endif
2575 {
2576 void * usr_ptr = compat_ptr((uintptr_t) user_buf);
2577 ret = copy_to_user(usr_ptr, mem_buf, buf_len);
2578 if (ret) {
2579 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
2580 goto free_mem;
2581 }
2582 }
2583 else
2584 #endif /* CONFIG_COMPAT */
2585 {
2586 ret = copy_to_user((void*)user_buf, mem_buf, buf_len);
2587 if (ret) {
2588 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
2589 goto free_mem;
2590 }
2591 }
2592 /* Alloc the SKB for vendor_event */
2593 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 100);
2594 if (!skb) {
2595 WL_ERR(("skb allocation is failed\n"));
2596 ret = BCME_NOMEM;
2597 goto free_mem;
2598 }
2599 /* Indicate the memdump is succesfully copied */
2600 nla_put(skb, DEBUG_ATTRIBUTE_FW_DUMP_DATA, sizeof(ret), &ret);
2601
2602 ret = cfg80211_vendor_cmd_reply(skb);
2603
2604 if (ret) {
2605 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2606 }
2607 }
2608
2609 free_mem:
2610 vfree(mem_buf);
2611 exit:
2612 return ret;
2613 }
2614
2615 static int wl_cfgvendor_dbg_get_version(struct wiphy *wiphy,
2616 struct wireless_dev *wdev, const void *data, int len)
2617 {
2618 int ret = BCME_OK, rem, type;
2619 int buf_len = 1024;
2620 bool dhd_ver = FALSE;
2621 char *buf_ptr;
2622 const struct nlattr *iter;
2623 gfp_t kflags;
2624 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2625 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2626 buf_ptr = kzalloc(buf_len, kflags);
2627 if (!buf_ptr) {
2628 WL_ERR(("failed to allocate the buffer for version n"));
2629 ret = BCME_NOMEM;
2630 goto exit;
2631 }
2632 nla_for_each_attr(iter, data, len, rem) {
2633 type = nla_type(iter);
2634 switch (type) {
2635 case DEBUG_ATTRIBUTE_GET_DRIVER:
2636 dhd_ver = TRUE;
2637 break;
2638 case DEBUG_ATTRIBUTE_GET_FW:
2639 dhd_ver = FALSE;
2640 break;
2641 default:
2642 WL_ERR(("Unknown type: %d\n", type));
2643 ret = BCME_ERROR;
2644 goto exit;
2645 }
2646 }
2647 ret = dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg), dhd_ver, &buf_ptr, buf_len);
2648 if (ret < 0) {
2649 WL_ERR(("failed to get the version %d\n", ret));
2650 goto exit;
2651 }
2652 ret = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2653 buf_ptr, strlen(buf_ptr));
2654 exit:
2655 kfree(buf_ptr);
2656 return ret;
2657 }
2658
2659 static int wl_cfgvendor_dbg_get_ring_status(struct wiphy *wiphy,
2660 struct wireless_dev *wdev, const void *data, int len)
2661 {
2662 int ret = BCME_OK;
2663 int ring_id, i;
2664 int ring_cnt;
2665 struct sk_buff *skb;
2666 dhd_dbg_ring_status_t dbg_ring_status[DEBUG_RING_ID_MAX];
2667 dhd_dbg_ring_status_t ring_status;
2668 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2669 dhd_pub_t *dhd_pub = cfg->pub;
2670 memset(dbg_ring_status, 0, DBG_RING_STATUS_SIZE * DEBUG_RING_ID_MAX);
2671 ring_cnt = 0;
2672 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
2673 ret = dhd_os_get_ring_status(dhd_pub, ring_id, &ring_status);
2674 if (ret == BCME_NOTFOUND) {
2675 WL_DBG(("The ring (%d) is not found \n", ring_id));
2676 } else if (ret == BCME_OK) {
2677 dbg_ring_status[ring_cnt++] = ring_status;
2678 }
2679 }
2680 /* Alloc the SKB for vendor_event */
2681 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
2682 (DBG_RING_STATUS_SIZE * ring_cnt) + 100);
2683 if (!skb) {
2684 WL_ERR(("skb allocation is failed\n"));
2685 ret = BCME_NOMEM;
2686 goto exit;
2687 }
2688
2689 nla_put_u32(skb, DEBUG_ATTRIBUTE_RING_NUM, ring_cnt);
2690 for (i = 0; i < ring_cnt; i++) {
2691 nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, DBG_RING_STATUS_SIZE,
2692 &dbg_ring_status[i]);
2693 }
2694 ret = cfg80211_vendor_cmd_reply(skb);
2695
2696 if (ret) {
2697 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2698 }
2699 exit:
2700 return ret;
2701 }
2702
2703 static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy,
2704 struct wireless_dev *wdev, const void *data, int len)
2705 {
2706 int ret = BCME_OK, rem, type;
2707 char ring_name[DBGRING_NAME_MAX] = {0};
2708 const struct nlattr *iter;
2709 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2710 dhd_pub_t *dhd_pub = cfg->pub;
2711
2712 nla_for_each_attr(iter, data, len, rem) {
2713 type = nla_type(iter);
2714 switch (type) {
2715 case DEBUG_ATTRIBUTE_RING_NAME:
2716 strncpy(ring_name, nla_data(iter),
2717 MIN(sizeof(ring_name) -1, nla_len(iter)));
2718 break;
2719 default:
2720 WL_ERR(("Unknown type: %d\n", type));
2721 return ret;
2722 }
2723 }
2724
2725 ret = dhd_os_trigger_get_ring_data(dhd_pub, ring_name);
2726 if (ret < 0) {
2727 WL_ERR(("trigger_get_data failed ret:%d\n", ret));
2728 }
2729
2730 return ret;
2731 }
2732
2733 static int wl_cfgvendor_dbg_get_feature(struct wiphy *wiphy,
2734 struct wireless_dev *wdev, const void *data, int len)
2735 {
2736 int ret = BCME_OK;
2737 u32 supported_features = 0;
2738 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2739 dhd_pub_t *dhd_pub = cfg->pub;
2740
2741 ret = dhd_os_dbg_get_feature(dhd_pub, &supported_features);
2742 if (ret < 0) {
2743 WL_ERR(("dbg_get_feature failed ret:%d\n", ret));
2744 goto exit;
2745 }
2746 ret = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2747 &supported_features, sizeof(supported_features));
2748 if (ret < 0) {
2749 WL_ERR(("wl_cfgvendor_send_cmd_reply failed ret:%d\n", ret));
2750 goto exit;
2751 }
2752 exit:
2753 return ret;
2754 }
2755
2756 static void wl_cfgvendor_dbg_ring_send_evt(void *ctx,
2757 const int ring_id, const void *data, const uint32 len,
2758 const dhd_dbg_ring_status_t ring_status)
2759 {
2760 struct net_device *ndev = ctx;
2761 struct wiphy *wiphy;
2762 gfp_t kflags;
2763 struct sk_buff *skb;
2764 if (!ndev) {
2765 WL_ERR(("ndev is NULL\n"));
2766 return;
2767 }
2768 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2769 wiphy = ndev->ieee80211_ptr->wiphy;
2770 /* Alloc the SKB for vendor_event */
2771 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2772 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2773 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + 100,
2774 GOOGLE_DEBUG_RING_EVENT, kflags);
2775 #else
2776 skb = cfg80211_vendor_event_alloc(wiphy, len + 100,
2777 GOOGLE_DEBUG_RING_EVENT, kflags);
2778 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2779 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2780 if (!skb) {
2781 WL_ERR(("skb alloc failed"));
2782 return;
2783 }
2784 nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, sizeof(ring_status), &ring_status);
2785 nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
2786 cfg80211_vendor_event(skb, kflags);
2787 }
2788
2789 static void wl_cfgvendor_dbg_send_urgent_evt(void *ctx, const void *data,
2790 const uint32 len, const uint32 fw_len)
2791 {
2792 struct net_device *ndev = ctx;
2793 struct wiphy *wiphy;
2794 gfp_t kflags;
2795 struct sk_buff *skb;
2796 if (!ndev) {
2797 WL_ERR(("ndev is NULL\n"));
2798 return;
2799 }
2800 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2801 wiphy = ndev->ieee80211_ptr->wiphy;
2802 /* Alloc the SKB for vendor_event */
2803 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2804 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2805 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + 100,
2806 GOOGLE_FW_DUMP_EVENT, kflags);
2807 #else
2808 skb = cfg80211_vendor_event_alloc(wiphy, len + 100,
2809 GOOGLE_FW_DUMP_EVENT, kflags);
2810 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2811 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2812 if (!skb) {
2813 WL_ERR(("skb alloc failed"));
2814 return;
2815 }
2816 nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, fw_len);
2817 nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
2818 cfg80211_vendor_event(skb, kflags);
2819 }
2820 #endif /* DEBUGABILITY */
2821
2822 #ifdef DBG_PKT_MON
2823 static int wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy *wiphy,
2824 struct wireless_dev *wdev, const void *data, int len)
2825 {
2826 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2827 dhd_pub_t *dhd_pub = cfg->pub;
2828 int ret;
2829
2830 ret = dhd_os_dbg_attach_pkt_monitor(dhd_pub);
2831 if (unlikely(ret)) {
2832 WL_ERR(("failed to start pkt fate monitoring, ret=%d", ret));
2833 }
2834
2835 return ret;
2836 }
2837
2838 typedef int (*dbg_mon_get_pkts_t) (dhd_pub_t *dhdp, void __user *user_buf,
2839 uint16 req_count, uint16 *resp_count);
2840
2841 static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy *wiphy,
2842 const void *data, int len, dbg_mon_get_pkts_t dbg_mon_get_pkts)
2843 {
2844 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2845 dhd_pub_t *dhd_pub = cfg->pub;
2846 struct sk_buff *skb = NULL;
2847 const struct nlattr *iter;
2848 void __user *user_buf = NULL;
2849 uint16 req_count = 0, resp_count = 0;
2850 int ret, tmp, type, mem_needed;
2851
2852 nla_for_each_attr(iter, data, len, tmp) {
2853 type = nla_type(iter);
2854 switch (type) {
2855 case DEBUG_ATTRIBUTE_PKT_FATE_NUM:
2856 req_count = nla_get_u32(iter);
2857 break;
2858 case DEBUG_ATTRIBUTE_PKT_FATE_DATA:
2859 user_buf = (void __user *)(unsigned long) nla_get_u64(iter);
2860 break;
2861 default:
2862 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
2863 ret = -EINVAL;
2864 goto exit;
2865 }
2866 }
2867
2868 if (!req_count || !user_buf) {
2869 WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n",
2870 __FUNCTION__, user_buf, req_count));
2871 ret = -EINVAL;
2872 goto exit;
2873 }
2874
2875 ret = dbg_mon_get_pkts(dhd_pub, user_buf, req_count, &resp_count);
2876 if (unlikely(ret)) {
2877 WL_ERR(("failed to get packets, ret:%d \n", ret));
2878 goto exit;
2879 }
2880
2881 mem_needed = VENDOR_REPLY_OVERHEAD + ATTRIBUTE_U32_LEN;
2882 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
2883 if (unlikely(!skb)) {
2884 WL_ERR(("skb alloc failed"));
2885 ret = -ENOMEM;
2886 goto exit;
2887 }
2888
2889 nla_put_u32(skb, DEBUG_ATTRIBUTE_PKT_FATE_NUM, resp_count);
2890
2891 ret = cfg80211_vendor_cmd_reply(skb);
2892 if (unlikely(ret)) {
2893 WL_ERR(("vendor Command reply failed ret:%d \n", ret));
2894 }
2895
2896 exit:
2897 return ret;
2898 }
2899
2900 static int wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy *wiphy,
2901 struct wireless_dev *wdev, const void *data, int len)
2902 {
2903 int ret;
2904
2905 ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
2906 dhd_os_dbg_monitor_get_tx_pkts);
2907 if (unlikely(ret)) {
2908 WL_ERR(("failed to get tx packets, ret:%d \n", ret));
2909 }
2910
2911 return ret;
2912 }
2913
2914 static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy *wiphy,
2915 struct wireless_dev *wdev, const void *data, int len)
2916 {
2917 int ret;
2918
2919 ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
2920 dhd_os_dbg_monitor_get_rx_pkts);
2921 if (unlikely(ret)) {
2922 WL_ERR(("failed to get rx packets, ret:%d \n", ret));
2923 }
2924
2925 return ret;
2926 }
2927 #endif /* DBG_PKT_MON */
2928
2929 #ifdef KEEP_ALIVE
2930 static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
2931 const void *data, int len)
2932 {
2933 /* max size of IP packet for keep alive */
2934 const int MKEEP_ALIVE_IP_PKT_MAX = 256;
2935
2936 int ret = BCME_OK, rem, type;
2937 uint8 mkeep_alive_id = 0;
2938 uint8 *ip_pkt = NULL;
2939 uint16 ip_pkt_len = 0;
2940 uint8 src_mac[ETHER_ADDR_LEN];
2941 uint8 dst_mac[ETHER_ADDR_LEN];
2942 uint32 period_msec = 0;
2943 const struct nlattr *iter;
2944 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2945 dhd_pub_t *dhd_pub = cfg->pub;
2946 gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2947
2948 nla_for_each_attr(iter, data, len, rem) {
2949 type = nla_type(iter);
2950 switch (type) {
2951 case MKEEP_ALIVE_ATTRIBUTE_ID:
2952 mkeep_alive_id = nla_get_u8(iter);
2953 break;
2954 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
2955 ip_pkt_len = nla_get_u16(iter);
2956 if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
2957 ret = BCME_BADARG;
2958 goto exit;
2959 }
2960 break;
2961 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
2962 if (!ip_pkt_len) {
2963 ret = BCME_BADARG;
2964 WL_ERR(("ip packet length is 0\n"));
2965 goto exit;
2966 }
2967 ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags);
2968 if (ip_pkt == NULL) {
2969 ret = BCME_NOMEM;
2970 WL_ERR(("Failed to allocate mem for ip packet\n"));
2971 goto exit;
2972 }
2973 memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len);
2974 break;
2975 case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
2976 memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN);
2977 break;
2978 case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
2979 memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN);
2980 break;
2981 case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
2982 period_msec = nla_get_u32(iter);
2983 break;
2984 default:
2985 WL_ERR(("Unknown type: %d\n", type));
2986 ret = BCME_BADARG;
2987 goto exit;
2988 }
2989 }
2990
2991 if (ip_pkt == NULL) {
2992 ret = BCME_BADARG;
2993 WL_ERR(("ip packet is NULL\n"));
2994 goto exit;
2995 }
2996
2997 ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac,
2998 dst_mac, period_msec);
2999 if (ret < 0) {
3000 WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret));
3001 }
3002
3003 exit:
3004 if (ip_pkt) {
3005 kfree(ip_pkt);
3006 }
3007
3008 return ret;
3009 }
3010
3011 static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
3012 const void *data, int len)
3013 {
3014 int ret = BCME_OK, rem, type;
3015 uint8 mkeep_alive_id = 0;
3016 const struct nlattr *iter;
3017 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3018 dhd_pub_t *dhd_pub = cfg->pub;
3019
3020 nla_for_each_attr(iter, data, len, rem) {
3021 type = nla_type(iter);
3022 switch (type) {
3023 case MKEEP_ALIVE_ATTRIBUTE_ID:
3024 mkeep_alive_id = nla_get_u8(iter);
3025 break;
3026 default:
3027 WL_ERR(("Unknown type: %d\n", type));
3028 ret = BCME_BADARG;
3029 break;
3030 }
3031 }
3032
3033 ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id);
3034 if (ret < 0) {
3035 WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret));
3036 }
3037
3038 return ret;
3039 }
3040 #endif /* KEEP_ALIVE */
3041
3042 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
3043 static int
3044 wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy,
3045 struct wireless_dev *wdev, const void *data, int len)
3046 {
3047 struct net_device *ndev = wdev_to_ndev(wdev);
3048 struct sk_buff *skb;
3049 int ret, ver, max_len, mem_needed;
3050
3051 /* APF version */
3052 ver = 0;
3053 ret = dhd_dev_apf_get_version(ndev, &ver);
3054 if (unlikely(ret)) {
3055 WL_ERR(("APF get version failed, ret=%d\n", ret));
3056 return ret;
3057 }
3058
3059 /* APF memory size limit */
3060 max_len = 0;
3061 ret = dhd_dev_apf_get_max_len(ndev, &max_len);
3062 if (unlikely(ret)) {
3063 WL_ERR(("APF get maximum length failed, ret=%d\n", ret));
3064 return ret;
3065 }
3066
3067 mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
3068
3069 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
3070 if (unlikely(!skb)) {
3071 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
3072 return -ENOMEM;
3073 }
3074
3075 nla_put_u32(skb, APF_ATTRIBUTE_VERSION, ver);
3076 nla_put_u32(skb, APF_ATTRIBUTE_MAX_LEN, max_len);
3077
3078 ret = cfg80211_vendor_cmd_reply(skb);
3079 if (unlikely(ret)) {
3080 WL_ERR(("vendor command reply failed, ret=%d\n", ret));
3081 }
3082
3083 return ret;
3084 }
3085
3086 static int
3087 wl_cfgvendor_apf_set_filter(struct wiphy *wiphy,
3088 struct wireless_dev *wdev, const void *data, int len)
3089 {
3090 struct net_device *ndev = wdev_to_ndev(wdev);
3091 const struct nlattr *iter;
3092 u8 *program = NULL;
3093 u32 program_len = 0;
3094 int ret, tmp, type;
3095 gfp_t kflags;
3096
3097 if (len <= 0) {
3098 WL_ERR(("Invalid len: %d\n", len));
3099 ret = -EINVAL;
3100 goto exit;
3101 }
3102 nla_for_each_attr(iter, data, len, tmp) {
3103 type = nla_type(iter);
3104 switch (type) {
3105 case APF_ATTRIBUTE_PROGRAM_LEN:
3106 /* check if the iter value is valid and program_len
3107 * is not already initialized.
3108 */
3109 if (nla_len(iter) == sizeof(uint32) && !program_len) {
3110 program_len = nla_get_u32(iter);
3111 } else {
3112 ret = -EINVAL;
3113 goto exit;
3114 }
3115
3116 if (program_len > WL_APF_PROGRAM_MAX_SIZE) {
3117 WL_ERR(("program len is more than expected len\n"));
3118 ret = -EINVAL;
3119 goto exit;
3120 }
3121
3122 if (unlikely(!program_len)) {
3123 WL_ERR(("zero program length\n"));
3124 ret = -EINVAL;
3125 goto exit;
3126 }
3127 break;
3128 case APF_ATTRIBUTE_PROGRAM:
3129 if (unlikely(!program_len)) {
3130 WL_ERR(("program len is not set\n"));
3131 ret = -EINVAL;
3132 goto exit;
3133 }
3134 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3135 program = kzalloc(program_len, kflags);
3136 if (unlikely(!program)) {
3137 WL_ERR(("%s: can't allocate %d bytes\n",
3138 __FUNCTION__, program_len));
3139 ret = -ENOMEM;
3140 goto exit;
3141 }
3142 memcpy(program, (u8*)nla_data(iter), program_len);
3143 break;
3144 default:
3145 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
3146 ret = -EINVAL;
3147 goto exit;
3148 }
3149 }
3150
3151 ret = dhd_dev_apf_add_filter(ndev, program, program_len);
3152
3153 exit:
3154 if (program) {
3155 kfree(program);
3156 }
3157 return ret;
3158 }
3159 #endif /* PKT_FILTER_SUPPORT && APF */
3160
3161 #ifdef NDO_CONFIG_SUPPORT
3162 static int wl_cfgvendor_configure_nd_offload(struct wiphy *wiphy,
3163 struct wireless_dev *wdev, const void *data, int len)
3164 {
3165 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3166 const struct nlattr *iter;
3167 int ret = BCME_OK, rem, type;
3168 u8 enable = 0;
3169
3170 nla_for_each_attr(iter, data, len, rem) {
3171 type = nla_type(iter);
3172 switch (type) {
3173 case ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE:
3174 enable = nla_get_u8(iter);
3175 break;
3176 default:
3177 WL_ERR(("Unknown type: %d\n", type));
3178 ret = BCME_BADARG;
3179 goto exit;
3180 }
3181 }
3182
3183 ret = dhd_dev_ndo_cfg(bcmcfg_to_prmry_ndev(cfg), enable);
3184 if (ret < 0) {
3185 WL_ERR(("dhd_dev_ndo_cfg() failed: %d\n", ret));
3186 }
3187
3188 exit:
3189 return ret;
3190 }
3191 #endif /* NDO_CONFIG_SUPPORT */
3192
3193 static const struct wiphy_vendor_command wl_vendor_cmds [] = {
3194 {
3195 {
3196 .vendor_id = OUI_BRCM,
3197 .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
3198 },
3199 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3200 .doit = wl_cfgvendor_priv_string_handler
3201 },
3202 {
3203 {
3204 .vendor_id = OUI_BRCM,
3205 .subcmd = BRCM_VENDOR_SCMD_BCM_STR
3206 },
3207 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3208 .doit = wl_cfgvendor_priv_bcm_handler
3209 },
3210 #ifdef GSCAN_SUPPORT
3211 {
3212 {
3213 .vendor_id = OUI_GOOGLE,
3214 .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
3215 },
3216 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3217 .doit = wl_cfgvendor_gscan_get_capabilities
3218 },
3219 {
3220 {
3221 .vendor_id = OUI_GOOGLE,
3222 .subcmd = GSCAN_SUBCMD_SET_CONFIG
3223 },
3224 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3225 .doit = wl_cfgvendor_set_scan_cfg
3226 },
3227 {
3228 {
3229 .vendor_id = OUI_GOOGLE,
3230 .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
3231 },
3232 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3233 .doit = wl_cfgvendor_set_batch_scan_cfg
3234 },
3235 {
3236 {
3237 .vendor_id = OUI_GOOGLE,
3238 .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
3239 },
3240 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3241 .doit = wl_cfgvendor_initiate_gscan
3242 },
3243 {
3244 {
3245 .vendor_id = OUI_GOOGLE,
3246 .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
3247 },
3248 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3249 .doit = wl_cfgvendor_enable_full_scan_result
3250 },
3251 {
3252 {
3253 .vendor_id = OUI_GOOGLE,
3254 .subcmd = GSCAN_SUBCMD_SET_HOTLIST
3255 },
3256 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3257 .doit = wl_cfgvendor_hotlist_cfg
3258 },
3259 {
3260 {
3261 .vendor_id = OUI_GOOGLE,
3262 .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
3263 },
3264 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3265 .doit = wl_cfgvendor_gscan_get_batch_results
3266 },
3267 #endif /* GSCAN_SUPPORT */
3268 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
3269 {
3270 {
3271 .vendor_id = OUI_GOOGLE,
3272 .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
3273 },
3274 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3275 .doit = wl_cfgvendor_gscan_get_channel_list
3276 },
3277 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
3278 #ifdef RTT_SUPPORT
3279 {
3280 {
3281 .vendor_id = OUI_GOOGLE,
3282 .subcmd = RTT_SUBCMD_SET_CONFIG
3283 },
3284 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3285 .doit = wl_cfgvendor_rtt_set_config
3286 },
3287 {
3288 {
3289 .vendor_id = OUI_GOOGLE,
3290 .subcmd = RTT_SUBCMD_CANCEL_CONFIG
3291 },
3292 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3293 .doit = wl_cfgvendor_rtt_cancel_config
3294 },
3295 {
3296 {
3297 .vendor_id = OUI_GOOGLE,
3298 .subcmd = RTT_SUBCMD_GETCAPABILITY
3299 },
3300 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3301 .doit = wl_cfgvendor_rtt_get_capability
3302 },
3303 {
3304 {
3305 .vendor_id = OUI_GOOGLE,
3306 .subcmd = RTT_SUBCMD_GETAVAILCHANNEL
3307 },
3308 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3309 .doit = wl_cfgvendor_rtt_get_responder_info
3310 },
3311 {
3312 {
3313 .vendor_id = OUI_GOOGLE,
3314 .subcmd = RTT_SUBCMD_SET_RESPONDER
3315 },
3316 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3317 .doit = wl_cfgvendor_rtt_set_responder
3318 },
3319 {
3320 {
3321 .vendor_id = OUI_GOOGLE,
3322 .subcmd = RTT_SUBCMD_CANCEL_RESPONDER
3323 },
3324 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3325 .doit = wl_cfgvendor_rtt_cancel_responder
3326 },
3327 #endif /* RTT_SUPPORT */
3328 {
3329 {
3330 .vendor_id = OUI_GOOGLE,
3331 .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
3332 },
3333 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3334 .doit = wl_cfgvendor_get_feature_set
3335 },
3336 {
3337 {
3338 .vendor_id = OUI_GOOGLE,
3339 .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
3340 },
3341 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3342 .doit = wl_cfgvendor_get_feature_set_matrix
3343 },
3344 {
3345 {
3346 .vendor_id = OUI_GOOGLE,
3347 .subcmd = ANDR_WIFI_RANDOM_MAC_OUI
3348 },
3349 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3350 .doit = wl_cfgvendor_set_rand_mac_oui
3351 },
3352 #ifdef CUSTOM_FORCE_NODFS_FLAG
3353 {
3354 {
3355 .vendor_id = OUI_GOOGLE,
3356 .subcmd = ANDR_WIFI_NODFS_CHANNELS
3357 },
3358 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3359 .doit = wl_cfgvendor_set_nodfs_flag
3360 },
3361 #endif /* CUSTOM_FORCE_NODFS_FLAG */
3362 {
3363 {
3364 .vendor_id = OUI_GOOGLE,
3365 .subcmd = ANDR_WIFI_SET_COUNTRY
3366 },
3367 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3368 .doit = wl_cfgvendor_set_country
3369 },
3370 #ifdef LINKSTAT_SUPPORT
3371 {
3372 {
3373 .vendor_id = OUI_GOOGLE,
3374 .subcmd = LSTATS_SUBCMD_GET_INFO
3375 },
3376 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3377 .doit = wl_cfgvendor_lstats_get_info
3378 },
3379 #endif /* LINKSTAT_SUPPORT */
3380
3381 #ifdef GSCAN_SUPPORT
3382 {
3383 {
3384 .vendor_id = OUI_GOOGLE,
3385 .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID
3386 },
3387 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3388 .doit = wl_cfgvendor_epno_cfg
3389
3390 },
3391 {
3392 {
3393 .vendor_id = OUI_GOOGLE,
3394 .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST
3395 },
3396 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3397 .doit = wl_cfgvendor_set_ssid_whitelist
3398
3399 },
3400 {
3401 {
3402 .vendor_id = OUI_GOOGLE,
3403 .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
3404 },
3405 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3406 .doit = wl_cfgvendor_set_lazy_roam_cfg
3407
3408 },
3409 {
3410 {
3411 .vendor_id = OUI_GOOGLE,
3412 .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM
3413 },
3414 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3415 .doit = wl_cfgvendor_enable_lazy_roam
3416
3417 },
3418 {
3419 {
3420 .vendor_id = OUI_GOOGLE,
3421 .subcmd = WIFI_SUBCMD_SET_BSSID_PREF
3422 },
3423 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3424 .doit = wl_cfgvendor_set_bssid_pref
3425
3426 },
3427 {
3428 {
3429 .vendor_id = OUI_GOOGLE,
3430 .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST
3431 },
3432 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3433 .doit = wl_cfgvendor_set_bssid_blacklist
3434 },
3435 #endif /* GSCAN_SUPPORT */
3436 #ifdef DEBUGABILITY
3437 {
3438 {
3439 .vendor_id = OUI_GOOGLE,
3440 .subcmd = DEBUG_START_LOGGING
3441 },
3442 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3443 .doit = wl_cfgvendor_dbg_start_logging
3444 },
3445 {
3446 {
3447 .vendor_id = OUI_GOOGLE,
3448 .subcmd = DEBUG_RESET_LOGGING
3449 },
3450 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3451 .doit = wl_cfgvendor_dbg_reset_logging
3452 },
3453 {
3454 {
3455 .vendor_id = OUI_GOOGLE,
3456 .subcmd = DEBUG_TRIGGER_MEM_DUMP
3457 },
3458 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3459 .doit = wl_cfgvendor_dbg_trigger_mem_dump
3460 },
3461 {
3462 {
3463 .vendor_id = OUI_GOOGLE,
3464 .subcmd = DEBUG_GET_MEM_DUMP
3465 },
3466 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3467 .doit = wl_cfgvendor_dbg_get_mem_dump
3468 },
3469 {
3470 {
3471 .vendor_id = OUI_GOOGLE,
3472 .subcmd = DEBUG_GET_VER
3473 },
3474 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3475 .doit = wl_cfgvendor_dbg_get_version
3476 },
3477 {
3478 {
3479 .vendor_id = OUI_GOOGLE,
3480 .subcmd = DEBUG_GET_RING_STATUS
3481 },
3482 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3483 .doit = wl_cfgvendor_dbg_get_ring_status
3484 },
3485 {
3486 {
3487 .vendor_id = OUI_GOOGLE,
3488 .subcmd = DEBUG_GET_RING_DATA
3489 },
3490 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3491 .doit = wl_cfgvendor_dbg_get_ring_data
3492 },
3493 {
3494 {
3495 .vendor_id = OUI_GOOGLE,
3496 .subcmd = DEBUG_GET_FEATURE
3497 },
3498 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3499 .doit = wl_cfgvendor_dbg_get_feature
3500 },
3501 #endif /* DEBUGABILITY */
3502 #ifdef DBG_PKT_MON
3503 {
3504 {
3505 .vendor_id = OUI_GOOGLE,
3506 .subcmd = DEBUG_START_PKT_FATE_MONITORING
3507 },
3508 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3509 .doit = wl_cfgvendor_dbg_start_pkt_fate_monitoring
3510 },
3511 {
3512 {
3513 .vendor_id = OUI_GOOGLE,
3514 .subcmd = DEBUG_GET_TX_PKT_FATES
3515 },
3516 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3517 .doit = wl_cfgvendor_dbg_get_tx_pkt_fates
3518 },
3519 {
3520 {
3521 .vendor_id = OUI_GOOGLE,
3522 .subcmd = DEBUG_GET_RX_PKT_FATES
3523 },
3524 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3525 .doit = wl_cfgvendor_dbg_get_rx_pkt_fates
3526 },
3527 #endif /* DBG_PKT_MON */
3528 #ifdef KEEP_ALIVE
3529 {
3530 {
3531 .vendor_id = OUI_GOOGLE,
3532 .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
3533 },
3534 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3535 .doit = wl_cfgvendor_start_mkeep_alive
3536 },
3537 {
3538 {
3539 .vendor_id = OUI_GOOGLE,
3540 .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
3541 },
3542 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3543 .doit = wl_cfgvendor_stop_mkeep_alive
3544 },
3545 #endif /* KEEP_ALIVE */
3546 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
3547 {
3548 {
3549 .vendor_id = OUI_GOOGLE,
3550 .subcmd = APF_SUBCMD_GET_CAPABILITIES
3551 },
3552 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3553 .doit = wl_cfgvendor_apf_get_capabilities
3554 },
3555
3556 {
3557 {
3558 .vendor_id = OUI_GOOGLE,
3559 .subcmd = APF_SUBCMD_SET_FILTER
3560 },
3561 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3562 .doit = wl_cfgvendor_apf_set_filter
3563 },
3564 #endif /* PKT_FILTER_SUPPORT && APF */
3565 #ifdef NDO_CONFIG_SUPPORT
3566 {
3567 {
3568 .vendor_id = OUI_GOOGLE,
3569 .subcmd = WIFI_SUBCMD_CONFIG_ND_OFFLOAD
3570 },
3571 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3572 .doit = wl_cfgvendor_configure_nd_offload
3573 },
3574 #endif /* NDO_CONFIG_SUPPORT */
3575 #ifdef RSSI_MONITOR_SUPPORT
3576 {
3577 {
3578 .vendor_id = OUI_GOOGLE,
3579 .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR
3580 },
3581 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3582 .doit = wl_cfgvendor_set_rssi_monitor
3583 },
3584 #endif /* RSSI_MONITOR_SUPPORT */
3585 #ifdef DHDTCPACK_SUPPRESS
3586 {
3587 {
3588 .vendor_id = OUI_GOOGLE,
3589 .subcmd = WIFI_SUBCMD_CONFIG_TCPACK_SUP
3590 },
3591 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3592 .doit = wl_cfgvendor_set_tcpack_sup_mode
3593 },
3594 #endif /* DHDTCPACK_SUPPRESS */
3595 #ifdef DHD_WAKE_STATUS
3596 {
3597 {
3598 .vendor_id = OUI_GOOGLE,
3599 .subcmd = DEBUG_GET_WAKE_REASON_STATS
3600 },
3601 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3602 .doit = wl_cfgvendor_get_wake_reason_stats
3603 }
3604 #endif /* DHD_WAKE_STATUS */
3605 };
3606
3607 static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
3608 { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
3609 { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
3610 #ifdef GSCAN_SUPPORT
3611 { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
3612 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
3613 { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
3614 { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
3615 #endif /* GSCAN_SUPPORT */
3616 #ifdef RTT_SUPPORT
3617 { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
3618 #endif /* RTT_SUPPORT */
3619 #ifdef GSCAN_SUPPORT
3620 { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
3621 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT },
3622 { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
3623 #endif /* GSCAN_SUPPORT */
3624 { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
3625 { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
3626 #ifdef GSCAN_SUPPORT
3627 { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
3628 #endif /* GSCAN_SUPPORT */
3629 { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
3630 { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT },
3631 { OUI_GOOGLE, GOOGLE_NAN_EVENT_ENABLED},
3632 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DISABLED},
3633 { OUI_GOOGLE, GOOGLE_NAN_EVENT_PUBLISH_TERMINATED},
3634 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH},
3635 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH},
3636 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED},
3637 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DE_EVENT},
3638 { OUI_GOOGLE, GOOGLE_NAN_EVENT_FOLLOWUP},
3639 { OUI_GOOGLE, GOOGLE_NAN_EVENT_TCA},
3640 #ifdef NAN_DP
3641 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_PATH_OPEN},
3642 #endif /* NAN_DP */
3643 { OUI_GOOGLE, GOOGLE_NAN_EVENT_UNKNOWN}
3644 };
3645
3646 int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd)
3647 {
3648
3649 WL_INFORM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
3650 NL80211_CMD_VENDOR));
3651
3652 wiphy->vendor_commands = wl_vendor_cmds;
3653 wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
3654 wiphy->vendor_events = wl_vendor_events;
3655 wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events);
3656
3657 #ifdef DEBUGABILITY
3658 dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3659 dhd_os_dbg_register_callback(FW_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3660 dhd_os_dbg_register_callback(DHD_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3661 dhd_os_dbg_register_callback(NAN_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3662 dhd_os_dbg_register_urgent_notifier(dhd, wl_cfgvendor_dbg_send_urgent_evt);
3663 #endif /* DEBUGABILITY */
3664
3665 return 0;
3666 }
3667
3668 int wl_cfgvendor_detach(struct wiphy *wiphy)
3669 {
3670 WL_INFORM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
3671
3672 wiphy->vendor_commands = NULL;
3673 wiphy->vendor_events = NULL;
3674 wiphy->n_vendor_commands = 0;
3675 wiphy->n_vendor_events = 0;
3676
3677 return 0;
3678 }
3679 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */