ARM64: DTS: Add rk3399-firefly uart4 device, node as /dev/ttyS1
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723bu / os_dep / linux / rtw_cfgvendor.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2014 Realtek Corporation. All rights reserved.
4  *                                        
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  *
19  ******************************************************************************/
20
21 #include <drv_types.h>
22
23 #ifdef CONFIG_IOCTL_CFG80211
24
25 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT)
26
27 /*
28 #include <linux/kernel.h>
29 #include <linux/if_arp.h>
30 #include <asm/uaccess.h>
31
32 #include <linux/kernel.h>
33 #include <linux/kthread.h>
34 #include <linux/netdevice.h>
35 #include <linux/sched.h>
36 #include <linux/etherdevice.h>
37 #include <linux/wireless.h>
38 #include <linux/ieee80211.h>
39 #include <linux/wait.h>
40 #include <net/cfg80211.h>
41 */
42
43 #include <net/rtnetlink.h>
44
45 #ifdef DBG_MEM_ALLOC
46 extern bool match_mstat_sniff_rules(const enum mstat_f flags, const size_t size);
47 struct sk_buff * dbg_rtw_cfg80211_vendor_event_alloc(struct wiphy *wiphy, int len, int event_id, gfp_t gfp
48         , const enum mstat_f flags, const char *func, const int line)
49 {
50         struct sk_buff *skb;
51         unsigned int truesize = 0;
52
53         skb = cfg80211_vendor_event_alloc(wiphy, len, event_id, gfp);
54
55         if(skb)
56                 truesize = skb->truesize;
57
58         if(!skb || truesize < len || match_mstat_sniff_rules(flags, truesize))
59                 DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d), skb:%p, truesize=%u\n", func, line, __FUNCTION__, len, skb, truesize);
60
61         rtw_mstat_update(
62                 flags
63                 , skb ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
64                 , truesize
65         );
66
67         return skb;
68 }
69
70 void dbg_rtw_cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp
71         , const enum mstat_f flags, const char *func, const int line)
72 {
73         unsigned int truesize = skb->truesize;
74
75         if(match_mstat_sniff_rules(flags, truesize))
76                 DBG_871X("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __FUNCTION__, truesize);
77
78         cfg80211_vendor_event(skb, gfp);
79
80         rtw_mstat_update(
81                 flags
82                 , MSTAT_FREE
83                 , truesize
84         );
85 }
86
87 struct sk_buff *dbg_rtw_cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int len
88         , const enum mstat_f flags, const char *func, const int line)
89 {
90         struct sk_buff *skb;
91         unsigned int truesize = 0;
92
93         skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
94
95         if(skb)
96                 truesize = skb->truesize;
97
98         if(!skb || truesize < len || match_mstat_sniff_rules(flags, truesize))
99                 DBG_871X("DBG_MEM_ALLOC %s:%d %s(%d), skb:%p, truesize=%u\n", func, line, __FUNCTION__, len, skb, truesize);
100
101         rtw_mstat_update(
102                 flags
103                 , skb ? MSTAT_ALLOC_SUCCESS : MSTAT_ALLOC_FAIL
104                 , truesize
105         );
106
107         return skb;
108 }
109
110 int dbg_rtw_cfg80211_vendor_cmd_reply(struct sk_buff *skb
111         , const enum mstat_f flags, const char *func, const int line)
112 {
113         unsigned int truesize = skb->truesize;
114         int ret;
115
116         if(match_mstat_sniff_rules(flags, truesize))
117                 DBG_871X("DBG_MEM_ALLOC %s:%d %s, truesize=%u\n", func, line, __FUNCTION__, truesize);
118
119         ret = cfg80211_vendor_cmd_reply(skb);
120
121         rtw_mstat_update(
122                 flags
123                 , MSTAT_FREE
124                 , truesize
125         );
126
127         return ret;
128 }
129
130 #define rtw_cfg80211_vendor_event_alloc(wiphy, len, event_id, gfp) \
131         dbg_rtw_cfg80211_vendor_event_alloc(wiphy, len, event_id, gfp, MSTAT_FUNC_CFG_VENDOR|MSTAT_TYPE_SKB, __FUNCTION__, __LINE__)
132         
133 #define rtw_cfg80211_vendor_event(skb, gfp) \
134         dbg_rtw_cfg80211_vendor_event(skb, gfp, MSTAT_FUNC_CFG_VENDOR|MSTAT_TYPE_SKB, __FUNCTION__, __LINE__)
135         
136 #define rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len) \
137         dbg_rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len, MSTAT_FUNC_CFG_VENDOR|MSTAT_TYPE_SKB, __FUNCTION__, __LINE__)
138
139 #define rtw_cfg80211_vendor_cmd_reply(skb) \
140                 dbg_rtw_cfg80211_vendor_cmd_reply(skb, MSTAT_FUNC_CFG_VENDOR|MSTAT_TYPE_SKB, __FUNCTION__, __LINE__)
141 #else
142 #define rtw_cfg80211_vendor_event_alloc(wiphy, len, event_id, gfp) \
143         cfg80211_vendor_event_alloc(wiphy, len, event_id, gfp)
144         
145 #define rtw_cfg80211_vendor_event(skb, gfp) \
146         cfg80211_vendor_event(skb, gfp)
147         
148 #define rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len) \
149         cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len)
150
151 #define rtw_cfg80211_vendor_cmd_reply(skb) \
152         cfg80211_vendor_cmd_reply(skb)
153 #endif /* DBG_MEM_ALLOC */
154
155 /*
156  * This API is to be used for asynchronous vendor events. This
157  * shouldn't be used in response to a vendor command from its
158  * do_it handler context (instead rtw_cfgvendor_send_cmd_reply should
159  * be used).
160  */
161 int rtw_cfgvendor_send_async_event(struct wiphy *wiphy,
162         struct net_device *dev, int event_id, const void  *data, int len)
163 {
164         u16 kflags;
165         struct sk_buff *skb;
166
167         kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
168
169         /* Alloc the SKB for vendor_event */
170         skb = rtw_cfg80211_vendor_event_alloc(wiphy, len, event_id, kflags);
171         if (!skb) {
172                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" skb alloc failed", FUNC_NDEV_ARG(dev));
173                 return -ENOMEM;
174         }
175
176         /* Push the data to the skb */
177         nla_put_nohdr(skb, len, data);
178
179         rtw_cfg80211_vendor_event(skb, kflags);
180
181         return 0;
182 }
183
184 static int rtw_cfgvendor_send_cmd_reply(struct wiphy *wiphy,
185         struct net_device *dev, const void  *data, int len)
186 {
187         struct sk_buff *skb;
188
189         /* Alloc the SKB for vendor_event */
190         skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len);
191         if (unlikely(!skb)) {
192                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" skb alloc failed", FUNC_NDEV_ARG(dev));
193                 return -ENOMEM;
194         }
195
196         /* Push the data to the skb */
197         nla_put_nohdr(skb, len, data);
198
199         return rtw_cfg80211_vendor_cmd_reply(skb);
200 }
201
202 #define WIFI_FEATURE_INFRA              0x0001      /* Basic infrastructure mode        */
203 #define WIFI_FEATURE_INFRA_5G           0x0002      /* Support for 5 GHz Band           */
204 #define WIFI_FEATURE_HOTSPOT            0x0004      /* Support for GAS/ANQP             */
205 #define WIFI_FEATURE_P2P                0x0008      /* Wifi-Direct                      */
206 #define WIFI_FEATURE_SOFT_AP            0x0010      /* Soft AP                          */
207 #define WIFI_FEATURE_GSCAN              0x0020      /* Google-Scan APIs                 */
208 #define WIFI_FEATURE_NAN                0x0040      /* Neighbor Awareness Networking    */
209 #define WIFI_FEATURE_D2D_RTT            0x0080      /* Device-to-device RTT             */
210 #define WIFI_FEATURE_D2AP_RTT           0x0100      /* Device-to-AP RTT                 */
211 #define WIFI_FEATURE_BATCH_SCAN         0x0200      /* Batched Scan (legacy)            */
212 #define WIFI_FEATURE_PNO                0x0400      /* Preferred network offload        */
213 #define WIFI_FEATURE_ADDITIONAL_STA     0x0800      /* Support for two STAs             */
214 #define WIFI_FEATURE_TDLS               0x1000      /* Tunnel directed link setup       */
215 #define WIFI_FEATURE_TDLS_OFFCHANNEL    0x2000      /* Support for TDLS off channel     */
216 #define WIFI_FEATURE_EPR                0x4000      /* Enhanced power reporting         */
217 #define WIFI_FEATURE_AP_STA             0x8000      /* Support for AP STA Concurrency   */
218
219 #define MAX_FEATURE_SET_CONCURRRENT_GROUPS  3
220
221 #include <hal_data.h>
222 int rtw_dev_get_feature_set(struct net_device *dev)
223 {
224         _adapter *adapter = (_adapter *)rtw_netdev_priv(dev);
225         HAL_DATA_TYPE *HalData = GET_HAL_DATA(adapter);
226         HAL_VERSION *hal_ver = &HalData->VersionID;
227
228         int feature_set = 0;
229
230         feature_set |= WIFI_FEATURE_INFRA;
231
232         if (IS_8814A_SERIES(*hal_ver) || IS_8812_SERIES(*hal_ver) ||
233                         IS_8821_SERIES(*hal_ver))
234                 feature_set |= WIFI_FEATURE_INFRA_5G;
235
236         feature_set |= WIFI_FEATURE_P2P;
237         feature_set |= WIFI_FEATURE_SOFT_AP;
238
239         feature_set |= WIFI_FEATURE_ADDITIONAL_STA;
240
241         return feature_set;
242 }
243
244 int *rtw_dev_get_feature_set_matrix(struct net_device *dev, int *num)
245 {
246         int feature_set_full, mem_needed;
247         int *ret;
248
249         *num = 0;
250         mem_needed = sizeof(int) * MAX_FEATURE_SET_CONCURRRENT_GROUPS;
251         ret = (int *)rtw_malloc(mem_needed);
252
253         if (!ret) {
254                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" failed to allocate %d bytes\n"
255                         , FUNC_NDEV_ARG(dev), mem_needed);
256                 return ret;
257         }
258
259         feature_set_full = rtw_dev_get_feature_set(dev);
260
261         ret[0] = (feature_set_full & WIFI_FEATURE_INFRA) |
262                  (feature_set_full & WIFI_FEATURE_INFRA_5G) |
263                  (feature_set_full & WIFI_FEATURE_NAN) |
264                  (feature_set_full & WIFI_FEATURE_D2D_RTT) |
265                  (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
266                  (feature_set_full & WIFI_FEATURE_PNO) |
267                  (feature_set_full & WIFI_FEATURE_BATCH_SCAN) |
268                  (feature_set_full & WIFI_FEATURE_GSCAN) |
269                  (feature_set_full & WIFI_FEATURE_HOTSPOT) |
270                  (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA) |
271                  (feature_set_full & WIFI_FEATURE_EPR);
272
273         ret[1] = (feature_set_full & WIFI_FEATURE_INFRA) |
274                  (feature_set_full & WIFI_FEATURE_INFRA_5G) |
275                  /* Not yet verified NAN with P2P */
276                  /* (feature_set_full & WIFI_FEATURE_NAN) | */
277                  (feature_set_full & WIFI_FEATURE_P2P) |
278                  (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
279                  (feature_set_full & WIFI_FEATURE_D2D_RTT) |
280                  (feature_set_full & WIFI_FEATURE_EPR);
281
282         ret[2] = (feature_set_full & WIFI_FEATURE_INFRA) |
283                  (feature_set_full & WIFI_FEATURE_INFRA_5G) |
284                  (feature_set_full & WIFI_FEATURE_NAN) |
285                  (feature_set_full & WIFI_FEATURE_D2D_RTT) |
286                  (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
287                  (feature_set_full & WIFI_FEATURE_TDLS) |
288                  (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL) |
289                  (feature_set_full & WIFI_FEATURE_EPR);
290         *num = MAX_FEATURE_SET_CONCURRRENT_GROUPS;
291
292         return ret;
293 }
294
295 static int rtw_cfgvendor_get_feature_set(struct wiphy *wiphy,
296         struct wireless_dev *wdev, const void  *data, int len)
297 {
298         int err = 0;
299         int reply;
300
301         reply = rtw_dev_get_feature_set(wdev_to_ndev(wdev));
302
303         err =  rtw_cfgvendor_send_cmd_reply(wiphy, wdev_to_ndev(wdev), &reply, sizeof(int));
304
305         if (unlikely(err))
306                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" Vendor Command reply failed ret:%d \n"
307                         , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
308
309         return err;
310 }
311
312 static int rtw_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
313         struct wireless_dev *wdev, const void  *data, int len)
314 {
315         int err = 0;
316         struct sk_buff *skb;
317         int *reply;
318         int num, mem_needed, i;
319
320         reply = rtw_dev_get_feature_set_matrix(wdev_to_ndev(wdev), &num);
321
322         if (!reply) {
323                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" Could not get feature list matrix\n"
324                         , FUNC_NDEV_ARG(wdev_to_ndev(wdev)));
325                 err = -EINVAL;
326                 return err;
327         }
328
329         mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) +
330                      ATTRIBUTE_U32_LEN;
331
332         /* Alloc the SKB for vendor_event */
333         skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
334         if (unlikely(!skb)) {
335                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" skb alloc failed", FUNC_NDEV_ARG(wdev_to_ndev(wdev)));
336                 err = -ENOMEM;
337                 goto exit;
338         }
339
340         nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num);
341         for (i = 0; i < num; i++) {
342                 nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]);
343         }
344
345         err =  rtw_cfg80211_vendor_cmd_reply(skb);
346
347         if (unlikely(err))
348                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" Vendor Command reply failed ret:%d \n"
349                         , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
350 exit:
351         rtw_mfree((u8*)reply, sizeof(int)*num);
352         return err;
353 }
354
355 #if defined(GSCAN_SUPPORT) && 0
356 int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
357         struct net_device *dev, void  *data, int len, wl_vendor_event_t event)
358 {
359         u16 kflags;
360         const void *ptr;
361         struct sk_buff *skb;
362         int malloc_len, total, iter_cnt_to_send, cnt;
363         gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
364
365         total = len/sizeof(wifi_gscan_result_t);
366         while (total > 0) {
367                 malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD;
368                 if (malloc_len > NLMSG_DEFAULT_SIZE) {
369                         malloc_len = NLMSG_DEFAULT_SIZE;
370                 }
371                 iter_cnt_to_send =
372                    (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t);
373                 total = total - iter_cnt_to_send;
374
375                 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
376
377                 /* Alloc the SKB for vendor_event */
378                 skb = rtw_cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags);
379                 if (!skb) {
380                         WL_ERR(("skb alloc failed"));
381                         return -ENOMEM;
382                 }
383
384                 while (cache && iter_cnt_to_send) {
385                         ptr = (const void *) &cache->results[cache->tot_consumed];
386
387                         if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed))
388                                 cnt = iter_cnt_to_send;
389                         else
390                                 cnt = (cache->tot_count - cache->tot_consumed);
391
392                         iter_cnt_to_send -= cnt;
393                         cache->tot_consumed += cnt;
394                         /* Push the data to the skb */
395                         nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
396                         if (cache->tot_consumed == cache->tot_count)
397                                 cache = cache->next;
398
399                 }
400
401                 rtw_cfg80211_vendor_event(skb, kflags);
402         }
403
404         return 0;
405 }
406
407
408 static int wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
409         struct wireless_dev *wdev, const void  *data, int len)
410 {
411         int err = 0;
412         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
413         dhd_pno_gscan_capabilities_t *reply = NULL;
414         uint32 reply_len = 0;
415
416
417         reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
418            DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
419         if (!reply) {
420                 WL_ERR(("Could not get capabilities\n"));
421                 err = -EINVAL;
422                 return err;
423         }
424
425         err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
426                 reply, reply_len);
427
428         if (unlikely(err))
429                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
430
431         kfree(reply);
432         return err;
433 }
434
435 static int wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
436         struct wireless_dev *wdev, const void  *data, int len)
437 {
438         int err = 0, type, band;
439         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
440         uint16 *reply = NULL;
441         uint32 reply_len = 0, num_channels, mem_needed;
442         struct sk_buff *skb;
443
444         type = nla_type(data);
445
446         if (type == GSCAN_ATTRIBUTE_BAND) {
447                 band = nla_get_u32(data);
448         } else {
449                 return -1;
450         }
451
452         reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
453            DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
454
455         if (!reply) {
456                 WL_ERR(("Could not get channel list\n"));
457                 err = -EINVAL;
458                 return err;
459         }
460         num_channels =  reply_len/ sizeof(uint32);
461         mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
462
463         /* Alloc the SKB for vendor_event */
464         skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
465         if (unlikely(!skb)) {
466                 WL_ERR(("skb alloc failed"));
467                 err = -ENOMEM;
468                 goto exit;
469         }
470
471         nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
472         nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
473
474         err =  rtw_cfg80211_vendor_cmd_reply(skb);
475
476         if (unlikely(err))
477                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
478 exit:
479         kfree(reply);
480         return err;
481 }
482
483 static int wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
484         struct wireless_dev *wdev, const void  *data, int len)
485 {
486         int err = 0;
487         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
488         gscan_results_cache_t *results, *iter;
489         uint32 reply_len, complete = 0, num_results_iter;
490         int32 mem_needed;
491         wifi_gscan_result_t *ptr;
492         uint16 num_scan_ids, num_results;
493         struct sk_buff *skb;
494         struct nlattr *scan_hdr;
495
496         dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
497         dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
498         results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
499                      DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
500
501         if (!results) {
502                 WL_ERR(("No results to send %d\n", err));
503                 err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
504                         results, 0);
505
506                 if (unlikely(err))
507                         WL_ERR(("Vendor Command reply failed ret:%d \n", err));
508                 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
509                 return err;
510         }
511         num_scan_ids = reply_len & 0xFFFF;
512         num_results = (reply_len & 0xFFFF0000) >> 16;
513         mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
514                      (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
515                      VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
516
517         if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
518                 mem_needed = (int32)NLMSG_DEFAULT_SIZE;
519                 complete = 0;
520         } else {
521                 complete = 1;
522         }
523
524         WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed,
525                 (int)NLMSG_DEFAULT_SIZE));
526         /* Alloc the SKB for vendor_event */
527         skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
528         if (unlikely(!skb)) {
529                 WL_ERR(("skb alloc failed"));
530                 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
531                 return -ENOMEM;
532         }
533         iter = results;
534
535         nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, complete);
536
537         mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
538
539         while (iter && ((mem_needed - GSCAN_BATCH_RESULT_HDR_LEN)  > 0)) {
540                 scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
541                 nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
542                 nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
543                 num_results_iter =
544                     (mem_needed - GSCAN_BATCH_RESULT_HDR_LEN)/sizeof(wifi_gscan_result_t);
545
546                 if ((iter->tot_count - iter->tot_consumed) < num_results_iter)
547                         num_results_iter = iter->tot_count - iter->tot_consumed;
548
549                 nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
550                 if (num_results_iter) {
551                         ptr = &iter->results[iter->tot_consumed];
552                         iter->tot_consumed += num_results_iter;
553                         nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
554                          num_results_iter * sizeof(wifi_gscan_result_t), ptr);
555                 }
556                 nla_nest_end(skb, scan_hdr);
557                 mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
558                     (num_results_iter * sizeof(wifi_gscan_result_t));
559                 iter = iter->next;
560         }
561
562         dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
563         dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
564
565         return rtw_cfg80211_vendor_cmd_reply(skb);
566 }
567
568 static int wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
569         struct wireless_dev *wdev, const void  *data, int len)
570 {
571         int err = 0;
572         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
573         int type, tmp = len;
574         int run = 0xFF;
575         int flush = 0;
576         const struct nlattr *iter;
577
578         nla_for_each_attr(iter, data, len, tmp) {
579                 type = nla_type(iter);
580                 if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
581                         run = nla_get_u32(iter);
582                 else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
583                         flush = nla_get_u32(iter);
584         }
585
586         if (run != 0xFF) {
587                 err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
588
589                 if (unlikely(err))
590                         WL_ERR(("Could not run gscan:%d \n", err));
591                 return err;
592         } else {
593                 return -1;
594         }
595
596
597 }
598
599 static int wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
600         struct wireless_dev *wdev, const void  *data, int len)
601 {
602         int err = 0;
603         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
604         int type;
605         bool real_time = FALSE;
606
607         type = nla_type(data);
608
609         if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
610                 real_time = nla_get_u32(data);
611
612                 err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
613
614                 if (unlikely(err))
615                         WL_ERR(("Could not run gscan:%d \n", err));
616
617         } else {
618                 err = -1;
619         }
620
621         return err;
622 }
623
624 static int wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy,
625         struct wireless_dev *wdev, const void  *data, int len)
626 {
627         int err = 0;
628         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
629         gscan_scan_params_t *scan_param;
630         int j = 0;
631         int type, tmp, tmp1, tmp2, k = 0;
632         const struct nlattr *iter, *iter1, *iter2;
633         struct dhd_pno_gscan_channel_bucket  *ch_bucket;
634
635         scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL);
636         if (!scan_param) {
637                 WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
638                 err = -EINVAL;
639                 return err;
640
641         }
642
643         scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
644         nla_for_each_attr(iter, data, len, tmp) {
645                 type = nla_type(iter);
646
647                 if (j >= GSCAN_MAX_CH_BUCKETS)
648                         break;
649
650                 switch (type) {
651                         case GSCAN_ATTRIBUTE_BASE_PERIOD:
652                                 scan_param->scan_fr = nla_get_u32(iter)/1000;
653                                 break;
654                         case GSCAN_ATTRIBUTE_NUM_BUCKETS:
655                                 scan_param->nchannel_buckets = nla_get_u32(iter);
656                                 break;
657                         case GSCAN_ATTRIBUTE_CH_BUCKET_1:
658                         case GSCAN_ATTRIBUTE_CH_BUCKET_2:
659                         case GSCAN_ATTRIBUTE_CH_BUCKET_3:
660                         case GSCAN_ATTRIBUTE_CH_BUCKET_4:
661                         case GSCAN_ATTRIBUTE_CH_BUCKET_5:
662                         case GSCAN_ATTRIBUTE_CH_BUCKET_6:
663                         case GSCAN_ATTRIBUTE_CH_BUCKET_7:
664                                 nla_for_each_nested(iter1, iter, tmp1) {
665                                         type = nla_type(iter1);
666                                         ch_bucket =
667                                         scan_param->channel_bucket;
668
669                                         switch (type) {
670                                                 case GSCAN_ATTRIBUTE_BUCKET_ID:
671                                                 break;
672                                                 case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
673                                                         ch_bucket[j].bucket_freq_multiple =
674                                                             nla_get_u32(iter1)/1000;
675                                                         break;
676                                                 case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
677                                                         ch_bucket[j].num_channels =
678                                                              nla_get_u32(iter1);
679                                                         break;
680                                                 case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
681                                                         nla_for_each_nested(iter2, iter1, tmp2) {
682                                                                 if (k >= PFN_SWC_RSSI_WINDOW_MAX)
683                                                                         break;
684                                                                 ch_bucket[j].chan_list[k] =
685                                                                      nla_get_u32(iter2);
686                                                                 k++;
687                                                         }
688                                                         k = 0;
689                                                         break;
690                                                 case GSCAN_ATTRIBUTE_BUCKETS_BAND:
691                                                         ch_bucket[j].band = (uint16)
692                                                              nla_get_u32(iter1);
693                                                         break;
694                                                 case GSCAN_ATTRIBUTE_REPORT_EVENTS:
695                                                         ch_bucket[j].report_flag = (uint8)
696                                                              nla_get_u32(iter1);
697                                                         break;
698                                         }
699                                 }
700                                 j++;
701                                 break;
702                 }
703         }
704
705         if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
706              DHD_PNO_SCAN_CFG_ID, scan_param, 0) < 0) {
707                 WL_ERR(("Could not set GSCAN scan cfg\n"));
708                 err = -EINVAL;
709         }
710
711         kfree(scan_param);
712         return err;
713
714 }
715
716 static int wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
717         struct wireless_dev *wdev, const void  *data, int len)
718 {
719         int err = 0;
720         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
721         gscan_hotlist_scan_params_t *hotlist_params;
722         int tmp, tmp1, tmp2, type, j = 0, dummy;
723         const struct nlattr *outer, *inner, *iter;
724         uint8 flush = 0;
725         struct bssid_t *pbssid;
726
727         hotlist_params = (gscan_hotlist_scan_params_t *)kzalloc(len, GFP_KERNEL);
728         if (!hotlist_params) {
729                 WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes \n", len));
730                 return -1;
731         }
732
733         hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
734
735         nla_for_each_attr(iter, data, len, tmp2) {
736                 type = nla_type(iter);
737                 switch (type) {
738                         case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
739                                 pbssid = hotlist_params->bssid;
740                                 nla_for_each_nested(outer, iter, tmp) {
741                                         nla_for_each_nested(inner, outer, tmp1) {
742                                                 type = nla_type(inner);
743
744                                                 switch (type) {
745                                                         case GSCAN_ATTRIBUTE_BSSID:
746                                                                 memcpy(&(pbssid[j].macaddr),
747                                                                   nla_data(inner), ETHER_ADDR_LEN);
748                                                                 break;
749                                                         case GSCAN_ATTRIBUTE_RSSI_LOW:
750                                                                 pbssid[j].rssi_reporting_threshold =
751                                                                          (int8) nla_get_u8(inner);
752                                                                 break;
753                                                         case GSCAN_ATTRIBUTE_RSSI_HIGH:
754                                                                 dummy = (int8) nla_get_u8(inner);
755                                                                 break;
756                                                 }
757                                         }
758                                         j++;
759                                 }
760                                 hotlist_params->nbssid = j;
761                                 break;
762                         case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
763                                 flush = nla_get_u8(iter);
764                                 break;
765                         case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
766                                 hotlist_params->lost_ap_window = nla_get_u32(iter);
767                                 break;
768                         }
769
770         }
771
772         if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
773               DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
774                 WL_ERR(("Could not set GSCAN HOTLIST cfg\n"));
775                 err = -EINVAL;
776                 goto exit;
777         }
778 exit:
779         kfree(hotlist_params);
780         return err;
781 }
782 static int wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
783         struct wireless_dev *wdev, const void  *data, int len)
784 {
785         int err = 0, tmp, type;
786         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
787         gscan_batch_params_t batch_param;
788         const struct nlattr *iter;
789
790         batch_param.mscan = batch_param.bestn = 0;
791         batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
792
793         nla_for_each_attr(iter, data, len, tmp) {
794                 type = nla_type(iter);
795
796                 switch (type) {
797                         case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
798                                 batch_param.bestn = nla_get_u32(iter);
799                                 break;
800                         case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
801                                 batch_param.mscan = nla_get_u32(iter);
802                                 break;
803                         case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
804                                 batch_param.buffer_threshold = nla_get_u32(iter);
805                                 break;
806                 }
807         }
808
809         if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
810                DHD_PNO_BATCH_SCAN_CFG_ID, &batch_param, 0) < 0) {
811                 WL_ERR(("Could not set batch cfg\n"));
812                 err = -EINVAL;
813                 return err;
814         }
815
816         return err;
817 }
818
819 static int wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy,
820         struct wireless_dev *wdev, const void  *data, int len)
821 {
822         int err = 0;
823         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
824         gscan_swc_params_t *significant_params;
825         int tmp, tmp1, tmp2, type, j = 0;
826         const struct nlattr *outer, *inner, *iter;
827         uint8 flush = 0;
828         wl_pfn_significant_bssid_t *pbssid;
829
830         significant_params = (gscan_swc_params_t *) kzalloc(len, GFP_KERNEL);
831         if (!significant_params) {
832                 WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes \n", len));
833                 return -1;
834         }
835
836
837         nla_for_each_attr(iter, data, len, tmp2) {
838                 type = nla_type(iter);
839
840                 switch (type) {
841                         case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH:
842                         flush = nla_get_u8(iter);
843                         break;
844                         case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE:
845                                 significant_params->rssi_window = nla_get_u16(iter);
846                                 break;
847                         case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
848                                 significant_params->lost_ap_window = nla_get_u16(iter);
849                                 break;
850                         case GSCAN_ATTRIBUTE_MIN_BREACHING:
851                                 significant_params->swc_threshold = nla_get_u16(iter);
852                                 break;
853                         case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS:
854                                 pbssid = significant_params->bssid_elem_list;
855                                 nla_for_each_nested(outer, iter, tmp) {
856                                         nla_for_each_nested(inner, outer, tmp1) {
857                                                         switch (nla_type(inner)) {
858                                                                 case GSCAN_ATTRIBUTE_BSSID:
859                                                                 memcpy(&(pbssid[j].macaddr),
860                                                                      nla_data(inner),
861                                                                      ETHER_ADDR_LEN);
862                                                                 break;
863                                                                 case GSCAN_ATTRIBUTE_RSSI_HIGH:
864                                                                 pbssid[j].rssi_high_threshold =
865                                                                        (int8) nla_get_u8(inner);
866                                                                 break;
867                                                                 case GSCAN_ATTRIBUTE_RSSI_LOW:
868                                                                 pbssid[j].rssi_low_threshold =
869                                                                       (int8) nla_get_u8(inner);
870                                                                 break;
871                                                         }
872                                                 }
873                                         j++;
874                                 }
875                                 break;
876                 }
877         }
878         significant_params->nbssid = j;
879
880         if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
881             DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, significant_params, flush) < 0) {
882                 WL_ERR(("Could not set GSCAN significant cfg\n"));
883                 err = -EINVAL;
884                 goto exit;
885         }
886 exit:
887         kfree(significant_params);
888         return err;
889 }
890 #endif /* GSCAN_SUPPORT */
891
892 #if defined(RTT_SUPPORT) && 0
893 void wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
894 {
895         struct wireless_dev *wdev = (struct wireless_dev *)ctx;
896         struct wiphy *wiphy;
897         struct sk_buff *skb;
898         uint32 tot_len = NLMSG_DEFAULT_SIZE, entry_len = 0;
899         gfp_t kflags;
900         rtt_report_t *rtt_report = NULL;
901         rtt_result_t *rtt_result = NULL;
902         struct list_head *rtt_list;
903         wiphy = wdev->wiphy;
904
905         WL_DBG(("In\n"));
906         /* Push the data to the skb */
907         if (!rtt_data) {
908                 WL_ERR(("rtt_data is NULL\n"));
909                 goto exit;
910         }
911         rtt_list = (struct list_head *)rtt_data;
912         kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
913         /* Alloc the SKB for vendor_event */
914         skb = rtw_cfg80211_vendor_event_alloc(wiphy, tot_len, GOOGLE_RTT_COMPLETE_EVENT, kflags);
915         if (!skb) {
916                 WL_ERR(("skb alloc failed"));
917                 goto exit;
918         }
919         /* fill in the rtt results on each entry */
920         list_for_each_entry(rtt_result, rtt_list, list) {
921                 entry_len = 0;
922                 if (rtt_result->TOF_type == TOF_TYPE_ONE_WAY) {
923                         entry_len = sizeof(rtt_report_t);
924                         rtt_report = kzalloc(entry_len, kflags);
925                         if (!rtt_report) {
926                                 WL_ERR(("rtt_report alloc failed"));
927                                 goto exit;
928                         }
929                         rtt_report->addr = rtt_result->peer_mac;
930                         rtt_report->num_measurement = 1; /* ONE SHOT */
931                         rtt_report->status = rtt_result->err_code;
932                         rtt_report->type = (rtt_result->TOF_type == TOF_TYPE_ONE_WAY) ? RTT_ONE_WAY: RTT_TWO_WAY;
933                         rtt_report->peer = rtt_result->target_info->peer;
934                         rtt_report->channel = rtt_result->target_info->channel;
935                         rtt_report->rssi = rtt_result->avg_rssi;
936                         /* tx_rate */
937                         rtt_report->tx_rate = rtt_result->tx_rate;
938                         /* RTT */
939                         rtt_report->rtt = rtt_result->meanrtt;
940                         rtt_report->rtt_sd = rtt_result->sdrtt;
941                         /* convert to centi meter */
942                         if (rtt_result->distance != 0xffffffff)
943                                 rtt_report->distance = (rtt_result->distance >> 2) * 25;
944                         else /* invalid distance */
945                                 rtt_report->distance = -1;
946
947                         rtt_report->ts = rtt_result->ts;
948                         nla_append(skb, entry_len, rtt_report);
949                         kfree(rtt_report);
950                 }
951         }
952         rtw_cfg80211_vendor_event(skb, kflags);
953 exit:
954         return;
955 }
956
957 static int wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
958                                         const void *data, int len) {
959         int err = 0, rem, rem1, rem2, type;
960         rtt_config_params_t rtt_param;
961         rtt_target_info_t* rtt_target = NULL;
962         const struct nlattr *iter, *iter1, *iter2;
963         int8 eabuf[ETHER_ADDR_STR_LEN];
964         int8 chanbuf[CHANSPEC_STR_LEN];
965         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
966
967         WL_DBG(("In\n"));
968         err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
969         if (err < 0) {
970                 WL_ERR(("failed to register rtt_noti_callback\n"));
971                 goto exit;
972         }
973         memset(&rtt_param, 0, sizeof(rtt_param));
974         nla_for_each_attr(iter, data, len, rem) {
975                 type = nla_type(iter);
976                 switch (type) {
977                 case RTT_ATTRIBUTE_TARGET_CNT:
978                         rtt_param.rtt_target_cnt = nla_get_u8(iter);
979                         if (rtt_param.rtt_target_cnt > RTT_MAX_TARGET_CNT) {
980                                 WL_ERR(("exceed max target count : %d\n",
981                                         rtt_param.rtt_target_cnt));
982                                 err = BCME_RANGE;
983                         }
984                         break;
985                 case RTT_ATTRIBUTE_TARGET_INFO:
986                         rtt_target = rtt_param.target_info;
987                         nla_for_each_nested(iter1, iter, rem1) {
988                                 nla_for_each_nested(iter2, iter1, rem2) {
989                                         type = nla_type(iter2);
990                                         switch (type) {
991                                         case RTT_ATTRIBUTE_TARGET_MAC:
992                                                 memcpy(&rtt_target->addr, nla_data(iter2), ETHER_ADDR_LEN);
993                                                 break;
994                                         case RTT_ATTRIBUTE_TARGET_TYPE:
995                                                 rtt_target->type = nla_get_u8(iter2);
996                                                 break;
997                                         case RTT_ATTRIBUTE_TARGET_PEER:
998                                                 rtt_target->peer= nla_get_u8(iter2);
999                                                 break;
1000                                         case RTT_ATTRIBUTE_TARGET_CHAN:
1001                                                 memcpy(&rtt_target->channel, nla_data(iter2),
1002                                                         sizeof(rtt_target->channel));
1003                                                 break;
1004                                         case RTT_ATTRIBUTE_TARGET_MODE:
1005                                                 rtt_target->continuous = nla_get_u8(iter2);
1006                                                 break;
1007                                         case RTT_ATTRIBUTE_TARGET_INTERVAL:
1008                                                 rtt_target->interval = nla_get_u32(iter2);
1009                                                 break;
1010                                         case RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT:
1011                                                 rtt_target->measure_cnt = nla_get_u32(iter2);
1012                                                 break;
1013                                         case RTT_ATTRIBUTE_TARGET_NUM_PKT:
1014                                                 rtt_target->ftm_cnt = nla_get_u32(iter2);
1015                                                 break;
1016                                         case RTT_ATTRIBUTE_TARGET_NUM_RETRY:
1017                                                 rtt_target->retry_cnt = nla_get_u32(iter2);
1018                                         }
1019                                 }
1020                                 /* convert to chanspec value */
1021                                 rtt_target->chanspec = dhd_rtt_convert_to_chspec(rtt_target->channel);
1022                                 if (rtt_target->chanspec == 0) {
1023                                         WL_ERR(("Channel is not valid \n"));
1024                                         goto exit;
1025                                 }
1026                                 WL_INFORM(("Target addr %s, Channel : %s for RTT \n",
1027                                         bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, eabuf),
1028                                         wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
1029                                 rtt_target++;
1030                         }
1031                         break;
1032                 }
1033         }
1034         WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
1035         if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
1036                 WL_ERR(("Could not set RTT configuration\n"));
1037                 err = -EINVAL;
1038         }
1039 exit:
1040         return err;
1041 }
1042
1043 static int wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1044                                         const void *data, int len)
1045 {
1046         int err = 0, rem, type, target_cnt = 0;
1047         const struct nlattr *iter;
1048         struct ether_addr *mac_list = NULL, *mac_addr = NULL;
1049         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1050
1051         nla_for_each_attr(iter, data, len, rem) {
1052                 type = nla_type(iter);
1053                 switch (type) {
1054                 case RTT_ATTRIBUTE_TARGET_CNT:
1055                         target_cnt = nla_get_u8(iter);
1056                         mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN , GFP_KERNEL);
1057                         if (mac_list == NULL) {
1058                                 WL_ERR(("failed to allocate mem for mac list\n"));
1059                                 goto exit;
1060                         }
1061                         mac_addr = &mac_list[0];
1062                         break;
1063                 case RTT_ATTRIBUTE_TARGET_MAC:
1064                         if (mac_addr)
1065                                 memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN);
1066                         else {
1067                                 WL_ERR(("mac_list is NULL\n"));
1068                                 goto exit;
1069                         }
1070                         break;
1071                 }
1072                 if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
1073                         WL_ERR(("Could not cancel RTT configuration\n"));
1074                         err = -EINVAL;
1075                         goto exit;
1076                 }
1077         }
1078 exit:
1079         if (mac_list)
1080                 kfree(mac_list);
1081         return err;
1082 }
1083 static int wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
1084                                         const void *data, int len)
1085 {
1086         int err = 0;
1087         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1088         rtt_capabilities_t capability;
1089
1090         err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1091         if (unlikely(err)) {
1092                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1093                 goto exit;
1094         }
1095         err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
1096                 &capability, sizeof(capability));
1097
1098         if (unlikely(err)) {
1099                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1100         }
1101 exit:
1102         return err;
1103 }
1104
1105 #endif /* RTT_SUPPORT */
1106 static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
1107         struct wireless_dev *wdev, const void  *data, int len)
1108 {
1109         int err = 0;
1110         u8 resp[1] = {'\0'};
1111
1112         DBG_871X_LEVEL(_drv_always_, FUNC_NDEV_FMT" %s\n", FUNC_NDEV_ARG(wdev_to_ndev(wdev)), (char*)data);
1113         err =  rtw_cfgvendor_send_cmd_reply(wiphy, wdev_to_ndev(wdev), resp, 1);
1114         if (unlikely(err))
1115                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT"Vendor Command reply failed ret:%d \n"
1116                         , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
1117
1118         return err;
1119 #if 0
1120         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1121         int err = 0;
1122         int data_len = 0;
1123
1124         bzero(cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
1125
1126         if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) {
1127                 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0,
1128                         cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
1129                 if (unlikely(err)) {
1130                         WL_ERR(("error (%d)\n", err));
1131                         return err;
1132                 }
1133                 data_len = strlen(cfg->ioctl_buf);
1134                 cfg->ioctl_buf[data_len] = '\0';
1135         }
1136
1137         err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
1138                 cfg->ioctl_buf, data_len+1);
1139         if (unlikely(err))
1140                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1141         else
1142                 WL_INFORM(("Vendor Command reply sent successfully!\n"));
1143
1144         return err;
1145 #endif
1146 }
1147
1148 static const struct wiphy_vendor_command rtw_vendor_cmds [] = {
1149         {
1150                 {
1151                         .vendor_id = OUI_BRCM,
1152                         .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
1153                 },
1154                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1155                 .doit = wl_cfgvendor_priv_string_handler
1156         },
1157 #if defined(GSCAN_SUPPORT) && 0
1158         {
1159                 {
1160                         .vendor_id = OUI_GOOGLE,
1161                         .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
1162                 },
1163                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1164                 .doit = wl_cfgvendor_gscan_get_capabilities
1165         },
1166         {
1167                 {
1168                         .vendor_id = OUI_GOOGLE,
1169                         .subcmd = GSCAN_SUBCMD_SET_CONFIG
1170                 },
1171                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1172                 .doit = wl_cfgvendor_set_scan_cfg
1173         },
1174         {
1175                 {
1176                         .vendor_id = OUI_GOOGLE,
1177                         .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
1178                 },
1179                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1180                 .doit = wl_cfgvendor_set_batch_scan_cfg
1181         },
1182         {
1183                 {
1184                         .vendor_id = OUI_GOOGLE,
1185                         .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
1186                 },
1187                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1188                 .doit = wl_cfgvendor_initiate_gscan
1189         },
1190         {
1191                 {
1192                         .vendor_id = OUI_GOOGLE,
1193                         .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
1194                 },
1195                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1196                 .doit = wl_cfgvendor_enable_full_scan_result
1197         },
1198         {
1199                 {
1200                         .vendor_id = OUI_GOOGLE,
1201                         .subcmd = GSCAN_SUBCMD_SET_HOTLIST
1202                 },
1203                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1204                 .doit = wl_cfgvendor_hotlist_cfg
1205         },
1206         {
1207                 {
1208                         .vendor_id = OUI_GOOGLE,
1209                         .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG
1210                 },
1211                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1212                 .doit = wl_cfgvendor_significant_change_cfg
1213         },
1214         {
1215                 {
1216                         .vendor_id = OUI_GOOGLE,
1217                         .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
1218                 },
1219                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1220                 .doit = wl_cfgvendor_gscan_get_batch_results
1221         },
1222         {
1223                 {
1224                         .vendor_id = OUI_GOOGLE,
1225                         .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
1226                 },
1227                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1228                 .doit = wl_cfgvendor_gscan_get_channel_list
1229         },
1230 #endif /* GSCAN_SUPPORT */
1231 #if defined(RTT_SUPPORT) && 0
1232         {
1233                 {
1234                         .vendor_id = OUI_GOOGLE,
1235                         .subcmd = RTT_SUBCMD_SET_CONFIG
1236                 },
1237                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1238                 .doit = wl_cfgvendor_rtt_set_config
1239         },
1240         {
1241                 {
1242                         .vendor_id = OUI_GOOGLE,
1243                         .subcmd = RTT_SUBCMD_CANCEL_CONFIG
1244                 },
1245                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1246                 .doit = wl_cfgvendor_rtt_cancel_config
1247         },
1248         {
1249                 {
1250                         .vendor_id = OUI_GOOGLE,
1251                         .subcmd = RTT_SUBCMD_GETCAPABILITY
1252                 },
1253                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1254                 .doit = wl_cfgvendor_rtt_get_capability
1255         },
1256 #endif /* RTT_SUPPORT */
1257         {
1258                 {
1259                         .vendor_id = OUI_GOOGLE,
1260                         .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
1261                 },
1262                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1263                 .doit = rtw_cfgvendor_get_feature_set
1264         },
1265         {
1266                 {
1267                         .vendor_id = OUI_GOOGLE,
1268                         .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
1269                 },
1270                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1271                 .doit = rtw_cfgvendor_get_feature_set_matrix
1272         }
1273 };
1274
1275 static const struct  nl80211_vendor_cmd_info rtw_vendor_events [] = {
1276                 { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
1277                 { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
1278 #if defined(GSCAN_SUPPORT) && 0
1279                 { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
1280                 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
1281                 { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
1282                 { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
1283 #endif /* GSCAN_SUPPORT */
1284 #if defined(RTT_SUPPORT) && 0
1285                 { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
1286 #endif /* RTT_SUPPORT */
1287 #if defined(GSCAN_SUPPORT) && 0
1288                 { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
1289                 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT }
1290 #endif /* GSCAN_SUPPORT */
1291 };
1292
1293 int rtw_cfgvendor_attach(struct wiphy *wiphy)
1294 {
1295
1296         DBG_871X("Register RTW cfg80211 vendor cmd(0x%x) interface \n", NL80211_CMD_VENDOR);
1297
1298         wiphy->vendor_commands  = rtw_vendor_cmds;
1299         wiphy->n_vendor_commands = ARRAY_SIZE(rtw_vendor_cmds);
1300         wiphy->vendor_events    = rtw_vendor_events;
1301         wiphy->n_vendor_events  = ARRAY_SIZE(rtw_vendor_events);
1302
1303         return 0;
1304 }
1305
1306 int rtw_cfgvendor_detach(struct wiphy *wiphy)
1307 {
1308         DBG_871X("Vendor: Unregister RTW cfg80211 vendor interface \n");
1309
1310         wiphy->vendor_commands  = NULL;
1311         wiphy->vendor_events    = NULL;
1312         wiphy->n_vendor_commands = 0;
1313         wiphy->n_vendor_events  = 0;
1314
1315         return 0;
1316 }
1317 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT) */
1318
1319 #endif /* CONFIG_IOCTL_CFG80211 */
1320