wifi: update bcmdhd.1.579.77.41.1.cn from ampak[3/3]
[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 if ((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)) == NULL) {
2329 macstat_cnt = bcm_get_data_from_xtlv_buf(((wl_cnt_info_t *)iovar_buf)->data,
2330 ((wl_cnt_info_t *)iovar_buf)->datalen,
2331 WL_CNT_XTLV_LT40_UCODE_V1, NULL,
2332 BCM_XTLV_OPTION_ALIGN32);
2333 }
2334 }
2335
2336 if (macstat_cnt == NULL) {
2337 printf("wlmTxGetAckedPackets: macstat_cnt NULL!\n");
2338 err = BCME_ERROR;
2339 goto exit;
2340 }
2341
2342 err = wldev_get_rssi(bcmcfg_to_prmry_ndev(cfg), &scbval);
2343 if (unlikely(err)) {
2344 WL_ERR(("get_rssi error (%d)\n", err));
2345 goto exit;
2346 }
2347
2348 COMPAT_ASSIGN_VALUE(iface, beacon_rx, macstat_cnt->rxbeaconmbss);
2349 COMPAT_ASSIGN_VALUE(iface, rssi_mgmt, scbval.val);
2350 COMPAT_ASSIGN_VALUE(iface, num_peers, NUM_PEER);
2351 COMPAT_ASSIGN_VALUE(iface, peer_info->num_rate, NUM_RATE);
2352
2353 #ifdef CONFIG_COMPAT
2354 if (compat_task_state) {
2355 memcpy(output, &compat_iface, sizeof(compat_iface));
2356 output += (sizeof(compat_iface) - sizeof(wifi_rate_stat));
2357 } else
2358 #endif /* CONFIG_COMPAT */
2359 {
2360 memcpy(output, &iface, sizeof(iface));
2361 output += (sizeof(iface) - sizeof(wifi_rate_stat));
2362 }
2363
2364 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "ratestat", NULL, 0,
2365 iovar_buf, WLC_IOCTL_MAXLEN, NULL);
2366 if (err != BCME_OK && err != BCME_UNSUPPORTED) {
2367 WL_ERR(("error (%d) - size = %zu\n", err, NUM_RATE*sizeof(wifi_rate_stat)));
2368 goto exit;
2369 }
2370 for (i = 0; i < NUM_RATE; i++) {
2371 p_wifi_rate_stat =
2372 (wifi_rate_stat *)(iovar_buf + i*sizeof(wifi_rate_stat));
2373 p_wifi_rate_stat_v1 = (wifi_rate_stat_v1 *)output;
2374 p_wifi_rate_stat_v1->rate.preamble = p_wifi_rate_stat->rate.preamble;
2375 p_wifi_rate_stat_v1->rate.nss = p_wifi_rate_stat->rate.nss;
2376 p_wifi_rate_stat_v1->rate.bw = p_wifi_rate_stat->rate.bw;
2377 p_wifi_rate_stat_v1->rate.rateMcsIdx = p_wifi_rate_stat->rate.rateMcsIdx;
2378 p_wifi_rate_stat_v1->rate.reserved = p_wifi_rate_stat->rate.reserved;
2379 p_wifi_rate_stat_v1->rate.bitrate = p_wifi_rate_stat->rate.bitrate;
2380 p_wifi_rate_stat_v1->tx_mpdu = p_wifi_rate_stat->tx_mpdu;
2381 p_wifi_rate_stat_v1->rx_mpdu = p_wifi_rate_stat->rx_mpdu;
2382 p_wifi_rate_stat_v1->mpdu_lost = p_wifi_rate_stat->mpdu_lost;
2383 p_wifi_rate_stat_v1->retries = p_wifi_rate_stat->retries;
2384 p_wifi_rate_stat_v1->retries_short = p_wifi_rate_stat->retries_short;
2385 p_wifi_rate_stat_v1->retries_long = p_wifi_rate_stat->retries_long;
2386 output = (char *) &(p_wifi_rate_stat_v1->retries_long);
2387 output += sizeof(p_wifi_rate_stat_v1->retries_long);
2388 }
2389
2390 total_len = sizeof(wifi_radio_stat_h) +
2391 NUM_CHAN * sizeof(wifi_channel_stat);
2392
2393 #ifdef CONFIG_COMPAT
2394 if (compat_task_state) {
2395 total_len += sizeof(compat_wifi_iface_stat);
2396 } else
2397 #endif /* CONFIG_COMPAT */
2398 {
2399 total_len += sizeof(wifi_iface_stat);
2400 }
2401
2402 total_len = total_len - sizeof(wifi_peer_info) +
2403 NUM_PEER * (sizeof(wifi_peer_info) - sizeof(wifi_rate_stat_v1) +
2404 NUM_RATE * sizeof(wifi_rate_stat_v1));
2405
2406 if (total_len > WLC_IOCTL_MAXLEN) {
2407 WL_ERR(("Error! total_len:%d is unexpected value\n", total_len));
2408 err = BCME_BADLEN;
2409 goto exit;
2410 }
2411 err = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2412 outdata,
2413 total_len);
2414
2415 if (unlikely(err))
2416 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
2417
2418 exit:
2419 if (outdata) {
2420 kfree(outdata);
2421 }
2422 return err;
2423 }
2424 #endif /* LINKSTAT_SUPPORT */
2425
2426 #ifdef DEBUGABILITY
2427 static int wl_cfgvendor_dbg_start_logging(struct wiphy *wiphy,
2428 struct wireless_dev *wdev, const void *data, int len)
2429 {
2430 int ret = BCME_OK, rem, type;
2431 char ring_name[DBGRING_NAME_MAX] = {0};
2432 int log_level = 0, flags = 0, time_intval = 0, threshold = 0;
2433 const struct nlattr *iter;
2434 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2435 dhd_pub_t *dhd_pub = cfg->pub;
2436 nla_for_each_attr(iter, data, len, rem) {
2437 type = nla_type(iter);
2438 switch (type) {
2439 case DEBUG_ATTRIBUTE_RING_NAME:
2440 strncpy(ring_name, nla_data(iter),
2441 MIN(sizeof(ring_name) -1, nla_len(iter)));
2442 break;
2443 case DEBUG_ATTRIBUTE_LOG_LEVEL:
2444 log_level = nla_get_u32(iter);
2445 break;
2446 case DEBUG_ATTRIBUTE_RING_FLAGS:
2447 flags = nla_get_u32(iter);
2448 break;
2449 case DEBUG_ATTRIBUTE_LOG_TIME_INTVAL:
2450 time_intval = nla_get_u32(iter);
2451 break;
2452 case DEBUG_ATTRIBUTE_LOG_MIN_DATA_SIZE:
2453 threshold = nla_get_u32(iter);
2454 break;
2455 default:
2456 WL_ERR(("Unknown type: %d\n", type));
2457 ret = BCME_BADADDR;
2458 goto exit;
2459 }
2460 }
2461
2462 ret = dhd_os_start_logging(dhd_pub, ring_name, log_level, flags, time_intval, threshold);
2463 if (ret < 0) {
2464 WL_ERR(("start_logging is failed ret: %d\n", ret));
2465 }
2466 exit:
2467 return ret;
2468 }
2469
2470 static int wl_cfgvendor_dbg_reset_logging(struct wiphy *wiphy,
2471 struct wireless_dev *wdev, const void *data, int len)
2472 {
2473 int ret = BCME_OK;
2474 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2475 dhd_pub_t *dhd_pub = cfg->pub;
2476
2477 ret = dhd_os_reset_logging(dhd_pub);
2478 if (ret < 0) {
2479 WL_ERR(("reset logging is failed ret: %d\n", ret));
2480 }
2481
2482 return ret;
2483 }
2484
2485 static int
2486 wl_cfgvendor_dbg_trigger_mem_dump(struct wiphy *wiphy,
2487 struct wireless_dev *wdev, const void *data, int len)
2488 {
2489 int ret = BCME_OK;
2490 uint32 alloc_len;
2491 struct sk_buff *skb;
2492 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2493 dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub);
2494
2495 dhdp->memdump_type = DUMP_TYPE_CFG_VENDOR_TRIGGERED;
2496
2497 ret = dhd_os_socram_dump(bcmcfg_to_prmry_ndev(cfg), &alloc_len);
2498 if (ret) {
2499 WL_ERR(("failed to call dhd_os_socram_dump : %d\n", ret));
2500 goto exit;
2501 }
2502 /* Alloc the SKB for vendor_event */
2503 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 100);
2504 if (!skb) {
2505 WL_ERR(("skb allocation is failed\n"));
2506 ret = BCME_NOMEM;
2507 goto exit;
2508 }
2509 nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, alloc_len);
2510
2511 ret = cfg80211_vendor_cmd_reply(skb);
2512
2513 if (ret) {
2514 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2515 }
2516
2517 exit:
2518 return ret;
2519 }
2520
2521 static int
2522 wl_cfgvendor_dbg_get_mem_dump(struct wiphy *wiphy,
2523 struct wireless_dev *wdev, const void *data, int len)
2524 {
2525 int ret = BCME_OK, rem, type;
2526 int buf_len = 0;
2527 uintptr_t user_buf = (uintptr_t)NULL;
2528 const struct nlattr *iter;
2529 char *mem_buf = NULL;
2530 struct sk_buff *skb;
2531 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2532
2533 nla_for_each_attr(iter, data, len, rem) {
2534 type = nla_type(iter);
2535 switch (type) {
2536 case DEBUG_ATTRIBUTE_FW_DUMP_LEN:
2537 /* Check if the iter is valid and
2538 * buffer length is not already initialized.
2539 */
2540 if ((nla_len(iter) == sizeof(uint32)) &&
2541 !buf_len) {
2542 buf_len = nla_get_u32(iter);
2543 } else {
2544 ret = BCME_ERROR;
2545 goto exit;
2546 }
2547 break;
2548 case DEBUG_ATTRIBUTE_FW_DUMP_DATA:
2549 if (nla_len(iter) != sizeof(uint64)) {
2550 WL_ERR(("Invalid len\n"));
2551 ret = BCME_ERROR;
2552 goto exit;
2553 }
2554 user_buf = (uintptr_t)nla_get_u64(iter);
2555 break;
2556 default:
2557 WL_ERR(("Unknown type: %d\n", type));
2558 ret = BCME_ERROR;
2559 goto exit;
2560 }
2561 }
2562 if (buf_len > 0 && user_buf) {
2563 mem_buf = vmalloc(buf_len);
2564 if (!mem_buf) {
2565 WL_ERR(("failed to allocate mem_buf with size : %d\n", buf_len));
2566 ret = BCME_NOMEM;
2567 goto exit;
2568 }
2569 ret = dhd_os_get_socram_dump(bcmcfg_to_prmry_ndev(cfg), &mem_buf, &buf_len);
2570 if (ret) {
2571 WL_ERR(("failed to get_socram_dump : %d\n", ret));
2572 goto free_mem;
2573 }
2574 #ifdef CONFIG_COMPAT
2575 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0))
2576 if (in_compat_syscall())
2577 #else
2578 if (is_compat_task())
2579 #endif
2580 {
2581 void * usr_ptr = compat_ptr((uintptr_t) user_buf);
2582 ret = copy_to_user(usr_ptr, mem_buf, buf_len);
2583 if (ret) {
2584 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
2585 goto free_mem;
2586 }
2587 }
2588 else
2589 #endif /* CONFIG_COMPAT */
2590 {
2591 ret = copy_to_user((void*)user_buf, mem_buf, buf_len);
2592 if (ret) {
2593 WL_ERR(("failed to copy memdump into user buffer : %d\n", ret));
2594 goto free_mem;
2595 }
2596 }
2597 /* Alloc the SKB for vendor_event */
2598 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 100);
2599 if (!skb) {
2600 WL_ERR(("skb allocation is failed\n"));
2601 ret = BCME_NOMEM;
2602 goto free_mem;
2603 }
2604 /* Indicate the memdump is succesfully copied */
2605 nla_put(skb, DEBUG_ATTRIBUTE_FW_DUMP_DATA, sizeof(ret), &ret);
2606
2607 ret = cfg80211_vendor_cmd_reply(skb);
2608
2609 if (ret) {
2610 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2611 }
2612 }
2613
2614 free_mem:
2615 vfree(mem_buf);
2616 exit:
2617 return ret;
2618 }
2619
2620 static int wl_cfgvendor_dbg_get_version(struct wiphy *wiphy,
2621 struct wireless_dev *wdev, const void *data, int len)
2622 {
2623 int ret = BCME_OK, rem, type;
2624 int buf_len = 1024;
2625 bool dhd_ver = FALSE;
2626 char *buf_ptr;
2627 const struct nlattr *iter;
2628 gfp_t kflags;
2629 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2630 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2631 buf_ptr = kzalloc(buf_len, kflags);
2632 if (!buf_ptr) {
2633 WL_ERR(("failed to allocate the buffer for version n"));
2634 ret = BCME_NOMEM;
2635 goto exit;
2636 }
2637 nla_for_each_attr(iter, data, len, rem) {
2638 type = nla_type(iter);
2639 switch (type) {
2640 case DEBUG_ATTRIBUTE_GET_DRIVER:
2641 dhd_ver = TRUE;
2642 break;
2643 case DEBUG_ATTRIBUTE_GET_FW:
2644 dhd_ver = FALSE;
2645 break;
2646 default:
2647 WL_ERR(("Unknown type: %d\n", type));
2648 ret = BCME_ERROR;
2649 goto exit;
2650 }
2651 }
2652 ret = dhd_os_get_version(bcmcfg_to_prmry_ndev(cfg), dhd_ver, &buf_ptr, buf_len);
2653 if (ret < 0) {
2654 WL_ERR(("failed to get the version %d\n", ret));
2655 goto exit;
2656 }
2657 ret = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2658 buf_ptr, strlen(buf_ptr));
2659 exit:
2660 kfree(buf_ptr);
2661 return ret;
2662 }
2663
2664 static int wl_cfgvendor_dbg_get_ring_status(struct wiphy *wiphy,
2665 struct wireless_dev *wdev, const void *data, int len)
2666 {
2667 int ret = BCME_OK;
2668 int ring_id, i;
2669 int ring_cnt;
2670 struct sk_buff *skb;
2671 dhd_dbg_ring_status_t dbg_ring_status[DEBUG_RING_ID_MAX];
2672 dhd_dbg_ring_status_t ring_status;
2673 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2674 dhd_pub_t *dhd_pub = cfg->pub;
2675 memset(dbg_ring_status, 0, DBG_RING_STATUS_SIZE * DEBUG_RING_ID_MAX);
2676 ring_cnt = 0;
2677 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
2678 ret = dhd_os_get_ring_status(dhd_pub, ring_id, &ring_status);
2679 if (ret == BCME_NOTFOUND) {
2680 WL_DBG(("The ring (%d) is not found \n", ring_id));
2681 } else if (ret == BCME_OK) {
2682 dbg_ring_status[ring_cnt++] = ring_status;
2683 }
2684 }
2685 /* Alloc the SKB for vendor_event */
2686 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
2687 (DBG_RING_STATUS_SIZE * ring_cnt) + 100);
2688 if (!skb) {
2689 WL_ERR(("skb allocation is failed\n"));
2690 ret = BCME_NOMEM;
2691 goto exit;
2692 }
2693
2694 nla_put_u32(skb, DEBUG_ATTRIBUTE_RING_NUM, ring_cnt);
2695 for (i = 0; i < ring_cnt; i++) {
2696 nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, DBG_RING_STATUS_SIZE,
2697 &dbg_ring_status[i]);
2698 }
2699 ret = cfg80211_vendor_cmd_reply(skb);
2700
2701 if (ret) {
2702 WL_ERR(("Vendor Command reply failed ret:%d \n", ret));
2703 }
2704 exit:
2705 return ret;
2706 }
2707
2708 static int wl_cfgvendor_dbg_get_ring_data(struct wiphy *wiphy,
2709 struct wireless_dev *wdev, const void *data, int len)
2710 {
2711 int ret = BCME_OK, rem, type;
2712 char ring_name[DBGRING_NAME_MAX] = {0};
2713 const struct nlattr *iter;
2714 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2715 dhd_pub_t *dhd_pub = cfg->pub;
2716
2717 nla_for_each_attr(iter, data, len, rem) {
2718 type = nla_type(iter);
2719 switch (type) {
2720 case DEBUG_ATTRIBUTE_RING_NAME:
2721 strncpy(ring_name, nla_data(iter),
2722 MIN(sizeof(ring_name) -1, nla_len(iter)));
2723 break;
2724 default:
2725 WL_ERR(("Unknown type: %d\n", type));
2726 return ret;
2727 }
2728 }
2729
2730 ret = dhd_os_trigger_get_ring_data(dhd_pub, ring_name);
2731 if (ret < 0) {
2732 WL_ERR(("trigger_get_data failed ret:%d\n", ret));
2733 }
2734
2735 return ret;
2736 }
2737
2738 static int wl_cfgvendor_dbg_get_feature(struct wiphy *wiphy,
2739 struct wireless_dev *wdev, const void *data, int len)
2740 {
2741 int ret = BCME_OK;
2742 u32 supported_features = 0;
2743 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2744 dhd_pub_t *dhd_pub = cfg->pub;
2745
2746 ret = dhd_os_dbg_get_feature(dhd_pub, &supported_features);
2747 if (ret < 0) {
2748 WL_ERR(("dbg_get_feature failed ret:%d\n", ret));
2749 goto exit;
2750 }
2751 ret = wl_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
2752 &supported_features, sizeof(supported_features));
2753 if (ret < 0) {
2754 WL_ERR(("wl_cfgvendor_send_cmd_reply failed ret:%d\n", ret));
2755 goto exit;
2756 }
2757 exit:
2758 return ret;
2759 }
2760
2761 static void wl_cfgvendor_dbg_ring_send_evt(void *ctx,
2762 const int ring_id, const void *data, const uint32 len,
2763 const dhd_dbg_ring_status_t ring_status)
2764 {
2765 struct net_device *ndev = ctx;
2766 struct wiphy *wiphy;
2767 gfp_t kflags;
2768 struct sk_buff *skb;
2769 if (!ndev) {
2770 WL_ERR(("ndev is NULL\n"));
2771 return;
2772 }
2773 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2774 wiphy = ndev->ieee80211_ptr->wiphy;
2775 /* Alloc the SKB for vendor_event */
2776 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2777 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2778 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + 100,
2779 GOOGLE_DEBUG_RING_EVENT, kflags);
2780 #else
2781 skb = cfg80211_vendor_event_alloc(wiphy, len + 100,
2782 GOOGLE_DEBUG_RING_EVENT, kflags);
2783 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2784 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2785 if (!skb) {
2786 WL_ERR(("skb alloc failed"));
2787 return;
2788 }
2789 nla_put(skb, DEBUG_ATTRIBUTE_RING_STATUS, sizeof(ring_status), &ring_status);
2790 nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
2791 cfg80211_vendor_event(skb, kflags);
2792 }
2793
2794 static void wl_cfgvendor_dbg_send_urgent_evt(void *ctx, const void *data,
2795 const uint32 len, const uint32 fw_len)
2796 {
2797 struct net_device *ndev = ctx;
2798 struct wiphy *wiphy;
2799 gfp_t kflags;
2800 struct sk_buff *skb;
2801 if (!ndev) {
2802 WL_ERR(("ndev is NULL\n"));
2803 return;
2804 }
2805 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2806 wiphy = ndev->ieee80211_ptr->wiphy;
2807 /* Alloc the SKB for vendor_event */
2808 #if (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || \
2809 LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
2810 skb = cfg80211_vendor_event_alloc(wiphy, NULL, len + 100,
2811 GOOGLE_FW_DUMP_EVENT, kflags);
2812 #else
2813 skb = cfg80211_vendor_event_alloc(wiphy, len + 100,
2814 GOOGLE_FW_DUMP_EVENT, kflags);
2815 #endif /* (defined(CONFIG_ARCH_MSM) && defined(SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) || */
2816 /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) */
2817 if (!skb) {
2818 WL_ERR(("skb alloc failed"));
2819 return;
2820 }
2821 nla_put_u32(skb, DEBUG_ATTRIBUTE_FW_DUMP_LEN, fw_len);
2822 nla_put(skb, DEBUG_ATTRIBUTE_RING_DATA, len, data);
2823 cfg80211_vendor_event(skb, kflags);
2824 }
2825 #endif /* DEBUGABILITY */
2826
2827 #ifdef DBG_PKT_MON
2828 static int wl_cfgvendor_dbg_start_pkt_fate_monitoring(struct wiphy *wiphy,
2829 struct wireless_dev *wdev, const void *data, int len)
2830 {
2831 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2832 dhd_pub_t *dhd_pub = cfg->pub;
2833 int ret;
2834
2835 ret = dhd_os_dbg_attach_pkt_monitor(dhd_pub);
2836 if (unlikely(ret)) {
2837 WL_ERR(("failed to start pkt fate monitoring, ret=%d", ret));
2838 }
2839
2840 return ret;
2841 }
2842
2843 typedef int (*dbg_mon_get_pkts_t) (dhd_pub_t *dhdp, void __user *user_buf,
2844 uint16 req_count, uint16 *resp_count);
2845
2846 static int __wl_cfgvendor_dbg_get_pkt_fates(struct wiphy *wiphy,
2847 const void *data, int len, dbg_mon_get_pkts_t dbg_mon_get_pkts)
2848 {
2849 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2850 dhd_pub_t *dhd_pub = cfg->pub;
2851 struct sk_buff *skb = NULL;
2852 const struct nlattr *iter;
2853 void __user *user_buf = NULL;
2854 uint16 req_count = 0, resp_count = 0;
2855 int ret, tmp, type, mem_needed;
2856
2857 nla_for_each_attr(iter, data, len, tmp) {
2858 type = nla_type(iter);
2859 switch (type) {
2860 case DEBUG_ATTRIBUTE_PKT_FATE_NUM:
2861 req_count = nla_get_u32(iter);
2862 break;
2863 case DEBUG_ATTRIBUTE_PKT_FATE_DATA:
2864 user_buf = (void __user *)(unsigned long) nla_get_u64(iter);
2865 break;
2866 default:
2867 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
2868 ret = -EINVAL;
2869 goto exit;
2870 }
2871 }
2872
2873 if (!req_count || !user_buf) {
2874 WL_ERR(("%s: invalid request, user_buf=%p, req_count=%u\n",
2875 __FUNCTION__, user_buf, req_count));
2876 ret = -EINVAL;
2877 goto exit;
2878 }
2879
2880 ret = dbg_mon_get_pkts(dhd_pub, user_buf, req_count, &resp_count);
2881 if (unlikely(ret)) {
2882 WL_ERR(("failed to get packets, ret:%d \n", ret));
2883 goto exit;
2884 }
2885
2886 mem_needed = VENDOR_REPLY_OVERHEAD + ATTRIBUTE_U32_LEN;
2887 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
2888 if (unlikely(!skb)) {
2889 WL_ERR(("skb alloc failed"));
2890 ret = -ENOMEM;
2891 goto exit;
2892 }
2893
2894 nla_put_u32(skb, DEBUG_ATTRIBUTE_PKT_FATE_NUM, resp_count);
2895
2896 ret = cfg80211_vendor_cmd_reply(skb);
2897 if (unlikely(ret)) {
2898 WL_ERR(("vendor Command reply failed ret:%d \n", ret));
2899 }
2900
2901 exit:
2902 return ret;
2903 }
2904
2905 static int wl_cfgvendor_dbg_get_tx_pkt_fates(struct wiphy *wiphy,
2906 struct wireless_dev *wdev, const void *data, int len)
2907 {
2908 int ret;
2909
2910 ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
2911 dhd_os_dbg_monitor_get_tx_pkts);
2912 if (unlikely(ret)) {
2913 WL_ERR(("failed to get tx packets, ret:%d \n", ret));
2914 }
2915
2916 return ret;
2917 }
2918
2919 static int wl_cfgvendor_dbg_get_rx_pkt_fates(struct wiphy *wiphy,
2920 struct wireless_dev *wdev, const void *data, int len)
2921 {
2922 int ret;
2923
2924 ret = __wl_cfgvendor_dbg_get_pkt_fates(wiphy, data, len,
2925 dhd_os_dbg_monitor_get_rx_pkts);
2926 if (unlikely(ret)) {
2927 WL_ERR(("failed to get rx packets, ret:%d \n", ret));
2928 }
2929
2930 return ret;
2931 }
2932 #endif /* DBG_PKT_MON */
2933
2934 #ifdef KEEP_ALIVE
2935 static int wl_cfgvendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
2936 const void *data, int len)
2937 {
2938 /* max size of IP packet for keep alive */
2939 const int MKEEP_ALIVE_IP_PKT_MAX = 256;
2940
2941 int ret = BCME_OK, rem, type;
2942 uint8 mkeep_alive_id = 0;
2943 uint8 *ip_pkt = NULL;
2944 uint16 ip_pkt_len = 0;
2945 uint8 src_mac[ETHER_ADDR_LEN];
2946 uint8 dst_mac[ETHER_ADDR_LEN];
2947 uint32 period_msec = 0;
2948 const struct nlattr *iter;
2949 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2950 dhd_pub_t *dhd_pub = cfg->pub;
2951 gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
2952
2953 nla_for_each_attr(iter, data, len, rem) {
2954 type = nla_type(iter);
2955 switch (type) {
2956 case MKEEP_ALIVE_ATTRIBUTE_ID:
2957 mkeep_alive_id = nla_get_u8(iter);
2958 break;
2959 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
2960 ip_pkt_len = nla_get_u16(iter);
2961 if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
2962 ret = BCME_BADARG;
2963 goto exit;
2964 }
2965 break;
2966 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
2967 if (!ip_pkt_len) {
2968 ret = BCME_BADARG;
2969 WL_ERR(("ip packet length is 0\n"));
2970 goto exit;
2971 }
2972 ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags);
2973 if (ip_pkt == NULL) {
2974 ret = BCME_NOMEM;
2975 WL_ERR(("Failed to allocate mem for ip packet\n"));
2976 goto exit;
2977 }
2978 memcpy(ip_pkt, (u8*)nla_data(iter), ip_pkt_len);
2979 break;
2980 case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
2981 memcpy(src_mac, nla_data(iter), ETHER_ADDR_LEN);
2982 break;
2983 case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
2984 memcpy(dst_mac, nla_data(iter), ETHER_ADDR_LEN);
2985 break;
2986 case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
2987 period_msec = nla_get_u32(iter);
2988 break;
2989 default:
2990 WL_ERR(("Unknown type: %d\n", type));
2991 ret = BCME_BADARG;
2992 goto exit;
2993 }
2994 }
2995
2996 if (ip_pkt == NULL) {
2997 ret = BCME_BADARG;
2998 WL_ERR(("ip packet is NULL\n"));
2999 goto exit;
3000 }
3001
3002 ret = dhd_dev_start_mkeep_alive(dhd_pub, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac,
3003 dst_mac, period_msec);
3004 if (ret < 0) {
3005 WL_ERR(("start_mkeep_alive is failed ret: %d\n", ret));
3006 }
3007
3008 exit:
3009 if (ip_pkt) {
3010 kfree(ip_pkt);
3011 }
3012
3013 return ret;
3014 }
3015
3016 static int wl_cfgvendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
3017 const void *data, int len)
3018 {
3019 int ret = BCME_OK, rem, type;
3020 uint8 mkeep_alive_id = 0;
3021 const struct nlattr *iter;
3022 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3023 dhd_pub_t *dhd_pub = cfg->pub;
3024
3025 nla_for_each_attr(iter, data, len, rem) {
3026 type = nla_type(iter);
3027 switch (type) {
3028 case MKEEP_ALIVE_ATTRIBUTE_ID:
3029 mkeep_alive_id = nla_get_u8(iter);
3030 break;
3031 default:
3032 WL_ERR(("Unknown type: %d\n", type));
3033 ret = BCME_BADARG;
3034 break;
3035 }
3036 }
3037
3038 ret = dhd_dev_stop_mkeep_alive(dhd_pub, mkeep_alive_id);
3039 if (ret < 0) {
3040 WL_ERR(("stop_mkeep_alive is failed ret: %d\n", ret));
3041 }
3042
3043 return ret;
3044 }
3045 #endif /* KEEP_ALIVE */
3046
3047 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
3048 static int
3049 wl_cfgvendor_apf_get_capabilities(struct wiphy *wiphy,
3050 struct wireless_dev *wdev, const void *data, int len)
3051 {
3052 struct net_device *ndev = wdev_to_ndev(wdev);
3053 struct sk_buff *skb;
3054 int ret, ver, max_len, mem_needed;
3055
3056 /* APF version */
3057 ver = 0;
3058 ret = dhd_dev_apf_get_version(ndev, &ver);
3059 if (unlikely(ret)) {
3060 WL_ERR(("APF get version failed, ret=%d\n", ret));
3061 return ret;
3062 }
3063
3064 /* APF memory size limit */
3065 max_len = 0;
3066 ret = dhd_dev_apf_get_max_len(ndev, &max_len);
3067 if (unlikely(ret)) {
3068 WL_ERR(("APF get maximum length failed, ret=%d\n", ret));
3069 return ret;
3070 }
3071
3072 mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
3073
3074 skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
3075 if (unlikely(!skb)) {
3076 WL_ERR(("%s: can't allocate %d bytes\n", __FUNCTION__, mem_needed));
3077 return -ENOMEM;
3078 }
3079
3080 nla_put_u32(skb, APF_ATTRIBUTE_VERSION, ver);
3081 nla_put_u32(skb, APF_ATTRIBUTE_MAX_LEN, max_len);
3082
3083 ret = cfg80211_vendor_cmd_reply(skb);
3084 if (unlikely(ret)) {
3085 WL_ERR(("vendor command reply failed, ret=%d\n", ret));
3086 }
3087
3088 return ret;
3089 }
3090
3091 static int
3092 wl_cfgvendor_apf_set_filter(struct wiphy *wiphy,
3093 struct wireless_dev *wdev, const void *data, int len)
3094 {
3095 struct net_device *ndev = wdev_to_ndev(wdev);
3096 const struct nlattr *iter;
3097 u8 *program = NULL;
3098 u32 program_len = 0;
3099 int ret, tmp, type;
3100 gfp_t kflags;
3101
3102 if (len <= 0) {
3103 WL_ERR(("Invalid len: %d\n", len));
3104 ret = -EINVAL;
3105 goto exit;
3106 }
3107 nla_for_each_attr(iter, data, len, tmp) {
3108 type = nla_type(iter);
3109 switch (type) {
3110 case APF_ATTRIBUTE_PROGRAM_LEN:
3111 /* check if the iter value is valid and program_len
3112 * is not already initialized.
3113 */
3114 if (nla_len(iter) == sizeof(uint32) && !program_len) {
3115 program_len = nla_get_u32(iter);
3116 } else {
3117 ret = -EINVAL;
3118 goto exit;
3119 }
3120
3121 if (program_len > WL_APF_PROGRAM_MAX_SIZE) {
3122 WL_ERR(("program len is more than expected len\n"));
3123 ret = -EINVAL;
3124 goto exit;
3125 }
3126
3127 if (unlikely(!program_len)) {
3128 WL_ERR(("zero program length\n"));
3129 ret = -EINVAL;
3130 goto exit;
3131 }
3132 break;
3133 case APF_ATTRIBUTE_PROGRAM:
3134 if (unlikely(!program_len)) {
3135 WL_ERR(("program len is not set\n"));
3136 ret = -EINVAL;
3137 goto exit;
3138 }
3139 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3140 program = kzalloc(program_len, kflags);
3141 if (unlikely(!program)) {
3142 WL_ERR(("%s: can't allocate %d bytes\n",
3143 __FUNCTION__, program_len));
3144 ret = -ENOMEM;
3145 goto exit;
3146 }
3147 memcpy(program, (u8*)nla_data(iter), program_len);
3148 break;
3149 default:
3150 WL_ERR(("%s: no such attribute %d\n", __FUNCTION__, type));
3151 ret = -EINVAL;
3152 goto exit;
3153 }
3154 }
3155
3156 ret = dhd_dev_apf_add_filter(ndev, program, program_len);
3157
3158 exit:
3159 if (program) {
3160 kfree(program);
3161 }
3162 return ret;
3163 }
3164 #endif /* PKT_FILTER_SUPPORT && APF */
3165
3166 #ifdef NDO_CONFIG_SUPPORT
3167 static int wl_cfgvendor_configure_nd_offload(struct wiphy *wiphy,
3168 struct wireless_dev *wdev, const void *data, int len)
3169 {
3170 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
3171 const struct nlattr *iter;
3172 int ret = BCME_OK, rem, type;
3173 u8 enable = 0;
3174
3175 nla_for_each_attr(iter, data, len, rem) {
3176 type = nla_type(iter);
3177 switch (type) {
3178 case ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE:
3179 enable = nla_get_u8(iter);
3180 break;
3181 default:
3182 WL_ERR(("Unknown type: %d\n", type));
3183 ret = BCME_BADARG;
3184 goto exit;
3185 }
3186 }
3187
3188 ret = dhd_dev_ndo_cfg(bcmcfg_to_prmry_ndev(cfg), enable);
3189 if (ret < 0) {
3190 WL_ERR(("dhd_dev_ndo_cfg() failed: %d\n", ret));
3191 }
3192
3193 exit:
3194 return ret;
3195 }
3196 #endif /* NDO_CONFIG_SUPPORT */
3197
3198 static const struct wiphy_vendor_command wl_vendor_cmds [] = {
3199 {
3200 {
3201 .vendor_id = OUI_BRCM,
3202 .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
3203 },
3204 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3205 .doit = wl_cfgvendor_priv_string_handler
3206 },
3207 {
3208 {
3209 .vendor_id = OUI_BRCM,
3210 .subcmd = BRCM_VENDOR_SCMD_BCM_STR
3211 },
3212 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3213 .doit = wl_cfgvendor_priv_bcm_handler
3214 },
3215 #ifdef GSCAN_SUPPORT
3216 {
3217 {
3218 .vendor_id = OUI_GOOGLE,
3219 .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
3220 },
3221 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3222 .doit = wl_cfgvendor_gscan_get_capabilities
3223 },
3224 {
3225 {
3226 .vendor_id = OUI_GOOGLE,
3227 .subcmd = GSCAN_SUBCMD_SET_CONFIG
3228 },
3229 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3230 .doit = wl_cfgvendor_set_scan_cfg
3231 },
3232 {
3233 {
3234 .vendor_id = OUI_GOOGLE,
3235 .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
3236 },
3237 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3238 .doit = wl_cfgvendor_set_batch_scan_cfg
3239 },
3240 {
3241 {
3242 .vendor_id = OUI_GOOGLE,
3243 .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
3244 },
3245 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3246 .doit = wl_cfgvendor_initiate_gscan
3247 },
3248 {
3249 {
3250 .vendor_id = OUI_GOOGLE,
3251 .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
3252 },
3253 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3254 .doit = wl_cfgvendor_enable_full_scan_result
3255 },
3256 {
3257 {
3258 .vendor_id = OUI_GOOGLE,
3259 .subcmd = GSCAN_SUBCMD_SET_HOTLIST
3260 },
3261 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3262 .doit = wl_cfgvendor_hotlist_cfg
3263 },
3264 {
3265 {
3266 .vendor_id = OUI_GOOGLE,
3267 .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
3268 },
3269 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3270 .doit = wl_cfgvendor_gscan_get_batch_results
3271 },
3272 #endif /* GSCAN_SUPPORT */
3273 #if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
3274 {
3275 {
3276 .vendor_id = OUI_GOOGLE,
3277 .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
3278 },
3279 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3280 .doit = wl_cfgvendor_gscan_get_channel_list
3281 },
3282 #endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
3283 #ifdef RTT_SUPPORT
3284 {
3285 {
3286 .vendor_id = OUI_GOOGLE,
3287 .subcmd = RTT_SUBCMD_SET_CONFIG
3288 },
3289 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3290 .doit = wl_cfgvendor_rtt_set_config
3291 },
3292 {
3293 {
3294 .vendor_id = OUI_GOOGLE,
3295 .subcmd = RTT_SUBCMD_CANCEL_CONFIG
3296 },
3297 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3298 .doit = wl_cfgvendor_rtt_cancel_config
3299 },
3300 {
3301 {
3302 .vendor_id = OUI_GOOGLE,
3303 .subcmd = RTT_SUBCMD_GETCAPABILITY
3304 },
3305 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3306 .doit = wl_cfgvendor_rtt_get_capability
3307 },
3308 {
3309 {
3310 .vendor_id = OUI_GOOGLE,
3311 .subcmd = RTT_SUBCMD_GETAVAILCHANNEL
3312 },
3313 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3314 .doit = wl_cfgvendor_rtt_get_responder_info
3315 },
3316 {
3317 {
3318 .vendor_id = OUI_GOOGLE,
3319 .subcmd = RTT_SUBCMD_SET_RESPONDER
3320 },
3321 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3322 .doit = wl_cfgvendor_rtt_set_responder
3323 },
3324 {
3325 {
3326 .vendor_id = OUI_GOOGLE,
3327 .subcmd = RTT_SUBCMD_CANCEL_RESPONDER
3328 },
3329 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3330 .doit = wl_cfgvendor_rtt_cancel_responder
3331 },
3332 #endif /* RTT_SUPPORT */
3333 {
3334 {
3335 .vendor_id = OUI_GOOGLE,
3336 .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
3337 },
3338 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3339 .doit = wl_cfgvendor_get_feature_set
3340 },
3341 {
3342 {
3343 .vendor_id = OUI_GOOGLE,
3344 .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
3345 },
3346 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3347 .doit = wl_cfgvendor_get_feature_set_matrix
3348 },
3349 {
3350 {
3351 .vendor_id = OUI_GOOGLE,
3352 .subcmd = ANDR_WIFI_RANDOM_MAC_OUI
3353 },
3354 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3355 .doit = wl_cfgvendor_set_rand_mac_oui
3356 },
3357 #ifdef CUSTOM_FORCE_NODFS_FLAG
3358 {
3359 {
3360 .vendor_id = OUI_GOOGLE,
3361 .subcmd = ANDR_WIFI_NODFS_CHANNELS
3362 },
3363 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3364 .doit = wl_cfgvendor_set_nodfs_flag
3365 },
3366 #endif /* CUSTOM_FORCE_NODFS_FLAG */
3367 {
3368 {
3369 .vendor_id = OUI_GOOGLE,
3370 .subcmd = ANDR_WIFI_SET_COUNTRY
3371 },
3372 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3373 .doit = wl_cfgvendor_set_country
3374 },
3375 #ifdef LINKSTAT_SUPPORT
3376 {
3377 {
3378 .vendor_id = OUI_GOOGLE,
3379 .subcmd = LSTATS_SUBCMD_GET_INFO
3380 },
3381 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3382 .doit = wl_cfgvendor_lstats_get_info
3383 },
3384 #endif /* LINKSTAT_SUPPORT */
3385
3386 #ifdef GSCAN_SUPPORT
3387 {
3388 {
3389 .vendor_id = OUI_GOOGLE,
3390 .subcmd = GSCAN_SUBCMD_SET_EPNO_SSID
3391 },
3392 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3393 .doit = wl_cfgvendor_epno_cfg
3394
3395 },
3396 {
3397 {
3398 .vendor_id = OUI_GOOGLE,
3399 .subcmd = WIFI_SUBCMD_SET_SSID_WHITELIST
3400 },
3401 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3402 .doit = wl_cfgvendor_set_ssid_whitelist
3403
3404 },
3405 {
3406 {
3407 .vendor_id = OUI_GOOGLE,
3408 .subcmd = WIFI_SUBCMD_SET_LAZY_ROAM_PARAMS
3409 },
3410 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3411 .doit = wl_cfgvendor_set_lazy_roam_cfg
3412
3413 },
3414 {
3415 {
3416 .vendor_id = OUI_GOOGLE,
3417 .subcmd = WIFI_SUBCMD_ENABLE_LAZY_ROAM
3418 },
3419 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3420 .doit = wl_cfgvendor_enable_lazy_roam
3421
3422 },
3423 {
3424 {
3425 .vendor_id = OUI_GOOGLE,
3426 .subcmd = WIFI_SUBCMD_SET_BSSID_PREF
3427 },
3428 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3429 .doit = wl_cfgvendor_set_bssid_pref
3430
3431 },
3432 {
3433 {
3434 .vendor_id = OUI_GOOGLE,
3435 .subcmd = WIFI_SUBCMD_SET_BSSID_BLACKLIST
3436 },
3437 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3438 .doit = wl_cfgvendor_set_bssid_blacklist
3439 },
3440 #endif /* GSCAN_SUPPORT */
3441 #ifdef DEBUGABILITY
3442 {
3443 {
3444 .vendor_id = OUI_GOOGLE,
3445 .subcmd = DEBUG_START_LOGGING
3446 },
3447 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3448 .doit = wl_cfgvendor_dbg_start_logging
3449 },
3450 {
3451 {
3452 .vendor_id = OUI_GOOGLE,
3453 .subcmd = DEBUG_RESET_LOGGING
3454 },
3455 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3456 .doit = wl_cfgvendor_dbg_reset_logging
3457 },
3458 {
3459 {
3460 .vendor_id = OUI_GOOGLE,
3461 .subcmd = DEBUG_TRIGGER_MEM_DUMP
3462 },
3463 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3464 .doit = wl_cfgvendor_dbg_trigger_mem_dump
3465 },
3466 {
3467 {
3468 .vendor_id = OUI_GOOGLE,
3469 .subcmd = DEBUG_GET_MEM_DUMP
3470 },
3471 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3472 .doit = wl_cfgvendor_dbg_get_mem_dump
3473 },
3474 {
3475 {
3476 .vendor_id = OUI_GOOGLE,
3477 .subcmd = DEBUG_GET_VER
3478 },
3479 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3480 .doit = wl_cfgvendor_dbg_get_version
3481 },
3482 {
3483 {
3484 .vendor_id = OUI_GOOGLE,
3485 .subcmd = DEBUG_GET_RING_STATUS
3486 },
3487 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3488 .doit = wl_cfgvendor_dbg_get_ring_status
3489 },
3490 {
3491 {
3492 .vendor_id = OUI_GOOGLE,
3493 .subcmd = DEBUG_GET_RING_DATA
3494 },
3495 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3496 .doit = wl_cfgvendor_dbg_get_ring_data
3497 },
3498 {
3499 {
3500 .vendor_id = OUI_GOOGLE,
3501 .subcmd = DEBUG_GET_FEATURE
3502 },
3503 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3504 .doit = wl_cfgvendor_dbg_get_feature
3505 },
3506 #endif /* DEBUGABILITY */
3507 #ifdef DBG_PKT_MON
3508 {
3509 {
3510 .vendor_id = OUI_GOOGLE,
3511 .subcmd = DEBUG_START_PKT_FATE_MONITORING
3512 },
3513 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3514 .doit = wl_cfgvendor_dbg_start_pkt_fate_monitoring
3515 },
3516 {
3517 {
3518 .vendor_id = OUI_GOOGLE,
3519 .subcmd = DEBUG_GET_TX_PKT_FATES
3520 },
3521 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3522 .doit = wl_cfgvendor_dbg_get_tx_pkt_fates
3523 },
3524 {
3525 {
3526 .vendor_id = OUI_GOOGLE,
3527 .subcmd = DEBUG_GET_RX_PKT_FATES
3528 },
3529 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3530 .doit = wl_cfgvendor_dbg_get_rx_pkt_fates
3531 },
3532 #endif /* DBG_PKT_MON */
3533 #ifdef KEEP_ALIVE
3534 {
3535 {
3536 .vendor_id = OUI_GOOGLE,
3537 .subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
3538 },
3539 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3540 .doit = wl_cfgvendor_start_mkeep_alive
3541 },
3542 {
3543 {
3544 .vendor_id = OUI_GOOGLE,
3545 .subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
3546 },
3547 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3548 .doit = wl_cfgvendor_stop_mkeep_alive
3549 },
3550 #endif /* KEEP_ALIVE */
3551 #if defined(PKT_FILTER_SUPPORT) && defined(APF)
3552 {
3553 {
3554 .vendor_id = OUI_GOOGLE,
3555 .subcmd = APF_SUBCMD_GET_CAPABILITIES
3556 },
3557 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3558 .doit = wl_cfgvendor_apf_get_capabilities
3559 },
3560
3561 {
3562 {
3563 .vendor_id = OUI_GOOGLE,
3564 .subcmd = APF_SUBCMD_SET_FILTER
3565 },
3566 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3567 .doit = wl_cfgvendor_apf_set_filter
3568 },
3569 #endif /* PKT_FILTER_SUPPORT && APF */
3570 #ifdef NDO_CONFIG_SUPPORT
3571 {
3572 {
3573 .vendor_id = OUI_GOOGLE,
3574 .subcmd = WIFI_SUBCMD_CONFIG_ND_OFFLOAD
3575 },
3576 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3577 .doit = wl_cfgvendor_configure_nd_offload
3578 },
3579 #endif /* NDO_CONFIG_SUPPORT */
3580 #ifdef RSSI_MONITOR_SUPPORT
3581 {
3582 {
3583 .vendor_id = OUI_GOOGLE,
3584 .subcmd = WIFI_SUBCMD_SET_RSSI_MONITOR
3585 },
3586 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3587 .doit = wl_cfgvendor_set_rssi_monitor
3588 },
3589 #endif /* RSSI_MONITOR_SUPPORT */
3590 #ifdef DHDTCPACK_SUPPRESS
3591 {
3592 {
3593 .vendor_id = OUI_GOOGLE,
3594 .subcmd = WIFI_SUBCMD_CONFIG_TCPACK_SUP
3595 },
3596 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3597 .doit = wl_cfgvendor_set_tcpack_sup_mode
3598 },
3599 #endif /* DHDTCPACK_SUPPRESS */
3600 #ifdef DHD_WAKE_STATUS
3601 {
3602 {
3603 .vendor_id = OUI_GOOGLE,
3604 .subcmd = DEBUG_GET_WAKE_REASON_STATS
3605 },
3606 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
3607 .doit = wl_cfgvendor_get_wake_reason_stats
3608 }
3609 #endif /* DHD_WAKE_STATUS */
3610 };
3611
3612 static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
3613 { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
3614 { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
3615 #ifdef GSCAN_SUPPORT
3616 { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
3617 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
3618 { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
3619 { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
3620 #endif /* GSCAN_SUPPORT */
3621 #ifdef RTT_SUPPORT
3622 { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
3623 #endif /* RTT_SUPPORT */
3624 #ifdef GSCAN_SUPPORT
3625 { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
3626 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT },
3627 { OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
3628 #endif /* GSCAN_SUPPORT */
3629 { OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
3630 { OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
3631 #ifdef GSCAN_SUPPORT
3632 { OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
3633 #endif /* GSCAN_SUPPORT */
3634 { OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
3635 { OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT },
3636 { OUI_GOOGLE, GOOGLE_NAN_EVENT_ENABLED},
3637 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DISABLED},
3638 { OUI_GOOGLE, GOOGLE_NAN_EVENT_PUBLISH_TERMINATED},
3639 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH},
3640 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH},
3641 { OUI_GOOGLE, GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED},
3642 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DE_EVENT},
3643 { OUI_GOOGLE, GOOGLE_NAN_EVENT_FOLLOWUP},
3644 { OUI_GOOGLE, GOOGLE_NAN_EVENT_TCA},
3645 #ifdef NAN_DP
3646 { OUI_GOOGLE, GOOGLE_NAN_EVENT_DATA_PATH_OPEN},
3647 #endif /* NAN_DP */
3648 { OUI_GOOGLE, GOOGLE_NAN_EVENT_UNKNOWN}
3649 };
3650
3651 int wl_cfgvendor_attach(struct wiphy *wiphy, dhd_pub_t *dhd)
3652 {
3653
3654 WL_INFORM(("Vendor: Register BRCM cfg80211 vendor cmd(0x%x) interface \n",
3655 NL80211_CMD_VENDOR));
3656
3657 wiphy->vendor_commands = wl_vendor_cmds;
3658 wiphy->n_vendor_commands = ARRAY_SIZE(wl_vendor_cmds);
3659 wiphy->vendor_events = wl_vendor_events;
3660 wiphy->n_vendor_events = ARRAY_SIZE(wl_vendor_events);
3661
3662 #ifdef DEBUGABILITY
3663 dhd_os_dbg_register_callback(FW_VERBOSE_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3664 dhd_os_dbg_register_callback(FW_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3665 dhd_os_dbg_register_callback(DHD_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3666 dhd_os_dbg_register_callback(NAN_EVENT_RING_ID, wl_cfgvendor_dbg_ring_send_evt);
3667 dhd_os_dbg_register_urgent_notifier(dhd, wl_cfgvendor_dbg_send_urgent_evt);
3668 #endif /* DEBUGABILITY */
3669
3670 return 0;
3671 }
3672
3673 int wl_cfgvendor_detach(struct wiphy *wiphy)
3674 {
3675 WL_INFORM(("Vendor: Unregister BRCM cfg80211 vendor interface \n"));
3676
3677 wiphy->vendor_commands = NULL;
3678 wiphy->vendor_events = NULL;
3679 wiphy->n_vendor_commands = 0;
3680 wiphy->n_vendor_events = 0;
3681
3682 return 0;
3683 }
3684 #endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(3, 13, 0)) || defined(WL_VENDOR_EXT_SUPPORT) */