update 8723bu wifi driver
[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 /*
24 #include <linux/kernel.h>
25 #include <linux/if_arp.h>
26 #include <asm/uaccess.h>
27
28 #include <linux/kernel.h>
29 #include <linux/kthread.h>
30 #include <linux/netdevice.h>
31 #include <linux/sched.h>
32 #include <linux/etherdevice.h>
33 #include <linux/wireless.h>
34 #include <linux/ieee80211.h>
35 #include <linux/wait.h>
36 #include <net/cfg80211.h>
37 */
38
39 #include <net/rtnetlink.h>
40
41 #ifdef CONFIG_IOCTL_CFG80211
42
43 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT)
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_92D(*hal_ver) || IS_8812_SERIES(*hal_ver) || IS_8821_SERIES(*hal_ver))
233                 feature_set |= WIFI_FEATURE_INFRA_5G;
234
235         feature_set |= WIFI_FEATURE_P2P;
236         feature_set |= WIFI_FEATURE_SOFT_AP;
237
238         feature_set |= WIFI_FEATURE_ADDITIONAL_STA;
239
240         return feature_set;
241 }
242
243 int *rtw_dev_get_feature_set_matrix(struct net_device *dev, int *num)
244 {
245         int feature_set_full, mem_needed;
246         int *ret;
247
248         *num = 0;
249         mem_needed = sizeof(int) * MAX_FEATURE_SET_CONCURRRENT_GROUPS;
250         ret = (int *)rtw_malloc(mem_needed);
251
252         if (!ret) {
253                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" failed to allocate %d bytes\n"
254                         , FUNC_NDEV_ARG(dev), mem_needed);
255                 return ret;
256         }
257
258         feature_set_full = rtw_dev_get_feature_set(dev);
259
260         ret[0] = (feature_set_full & WIFI_FEATURE_INFRA) |
261                  (feature_set_full & WIFI_FEATURE_INFRA_5G) |
262                  (feature_set_full & WIFI_FEATURE_NAN) |
263                  (feature_set_full & WIFI_FEATURE_D2D_RTT) |
264                  (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
265                  (feature_set_full & WIFI_FEATURE_PNO) |
266                  (feature_set_full & WIFI_FEATURE_BATCH_SCAN) |
267                  (feature_set_full & WIFI_FEATURE_GSCAN) |
268                  (feature_set_full & WIFI_FEATURE_HOTSPOT) |
269                  (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA) |
270                  (feature_set_full & WIFI_FEATURE_EPR);
271
272         ret[1] = (feature_set_full & WIFI_FEATURE_INFRA) |
273                  (feature_set_full & WIFI_FEATURE_INFRA_5G) |
274                  /* Not yet verified NAN with P2P */
275                  /* (feature_set_full & WIFI_FEATURE_NAN) | */
276                  (feature_set_full & WIFI_FEATURE_P2P) |
277                  (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
278                  (feature_set_full & WIFI_FEATURE_D2D_RTT) |
279                  (feature_set_full & WIFI_FEATURE_EPR);
280
281         ret[2] = (feature_set_full & WIFI_FEATURE_INFRA) |
282                  (feature_set_full & WIFI_FEATURE_INFRA_5G) |
283                  (feature_set_full & WIFI_FEATURE_NAN) |
284                  (feature_set_full & WIFI_FEATURE_D2D_RTT) |
285                  (feature_set_full & WIFI_FEATURE_D2AP_RTT) |
286                  (feature_set_full & WIFI_FEATURE_TDLS) |
287                  (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL) |
288                  (feature_set_full & WIFI_FEATURE_EPR);
289         *num = MAX_FEATURE_SET_CONCURRRENT_GROUPS;
290
291         return ret;
292 }
293
294 static int rtw_cfgvendor_get_feature_set(struct wiphy *wiphy,
295         struct wireless_dev *wdev, const void  *data, int len)
296 {
297         int err = 0;
298         int reply;
299
300         reply = rtw_dev_get_feature_set(wdev_to_ndev(wdev));
301
302         err =  rtw_cfgvendor_send_cmd_reply(wiphy, wdev_to_ndev(wdev), &reply, sizeof(int));
303
304         if (unlikely(err))
305                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" Vendor Command reply failed ret:%d \n"
306                         , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
307
308         return err;
309 }
310
311 static int rtw_cfgvendor_get_feature_set_matrix(struct wiphy *wiphy,
312         struct wireless_dev *wdev, const void  *data, int len)
313 {
314         int err = 0;
315         struct sk_buff *skb;
316         int *reply;
317         int num, mem_needed, i;
318
319         reply = rtw_dev_get_feature_set_matrix(wdev_to_ndev(wdev), &num);
320
321         if (!reply) {
322                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" Could not get feature list matrix\n"
323                         , FUNC_NDEV_ARG(wdev_to_ndev(wdev)));
324                 err = -EINVAL;
325                 return err;
326         }
327
328         mem_needed = VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * num) +
329                      ATTRIBUTE_U32_LEN;
330
331         /* Alloc the SKB for vendor_event */
332         skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
333         if (unlikely(!skb)) {
334                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" skb alloc failed", FUNC_NDEV_ARG(wdev_to_ndev(wdev)));
335                 err = -ENOMEM;
336                 goto exit;
337         }
338
339         nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, num);
340         for (i = 0; i < num; i++) {
341                 nla_put_u32(skb, ANDR_WIFI_ATTRIBUTE_FEATURE_SET, reply[i]);
342         }
343
344         err =  rtw_cfg80211_vendor_cmd_reply(skb);
345
346         if (unlikely(err))
347                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT" Vendor Command reply failed ret:%d \n"
348                         , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
349 exit:
350         rtw_mfree((u8*)reply, sizeof(int)*num);
351         return err;
352 }
353
354 #if defined(GSCAN_SUPPORT) && 0
355 int wl_cfgvendor_send_hotlist_event(struct wiphy *wiphy,
356         struct net_device *dev, void  *data, int len, wl_vendor_event_t event)
357 {
358         u16 kflags;
359         const void *ptr;
360         struct sk_buff *skb;
361         int malloc_len, total, iter_cnt_to_send, cnt;
362         gscan_results_cache_t *cache = (gscan_results_cache_t *)data;
363
364         total = len/sizeof(wifi_gscan_result_t);
365         while (total > 0) {
366                 malloc_len = (total * sizeof(wifi_gscan_result_t)) + VENDOR_DATA_OVERHEAD;
367                 if (malloc_len > NLMSG_DEFAULT_SIZE) {
368                         malloc_len = NLMSG_DEFAULT_SIZE;
369                 }
370                 iter_cnt_to_send =
371                    (malloc_len - VENDOR_DATA_OVERHEAD)/sizeof(wifi_gscan_result_t);
372                 total = total - iter_cnt_to_send;
373
374                 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
375
376                 /* Alloc the SKB for vendor_event */
377                 skb = rtw_cfg80211_vendor_event_alloc(wiphy, malloc_len, event, kflags);
378                 if (!skb) {
379                         WL_ERR(("skb alloc failed"));
380                         return -ENOMEM;
381                 }
382
383                 while (cache && iter_cnt_to_send) {
384                         ptr = (const void *) &cache->results[cache->tot_consumed];
385
386                         if (iter_cnt_to_send < (cache->tot_count - cache->tot_consumed))
387                                 cnt = iter_cnt_to_send;
388                         else
389                                 cnt = (cache->tot_count - cache->tot_consumed);
390
391                         iter_cnt_to_send -= cnt;
392                         cache->tot_consumed += cnt;
393                         /* Push the data to the skb */
394                         nla_append(skb, cnt * sizeof(wifi_gscan_result_t), ptr);
395                         if (cache->tot_consumed == cache->tot_count)
396                                 cache = cache->next;
397
398                 }
399
400                 rtw_cfg80211_vendor_event(skb, kflags);
401         }
402
403         return 0;
404 }
405
406
407 static int wl_cfgvendor_gscan_get_capabilities(struct wiphy *wiphy,
408         struct wireless_dev *wdev, const void  *data, int len)
409 {
410         int err = 0;
411         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
412         dhd_pno_gscan_capabilities_t *reply = NULL;
413         uint32 reply_len = 0;
414
415
416         reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
417            DHD_PNO_GET_CAPABILITIES, NULL, &reply_len);
418         if (!reply) {
419                 WL_ERR(("Could not get capabilities\n"));
420                 err = -EINVAL;
421                 return err;
422         }
423
424         err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
425                 reply, reply_len);
426
427         if (unlikely(err))
428                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
429
430         kfree(reply);
431         return err;
432 }
433
434 static int wl_cfgvendor_gscan_get_channel_list(struct wiphy *wiphy,
435         struct wireless_dev *wdev, const void  *data, int len)
436 {
437         int err = 0, type, band;
438         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
439         uint16 *reply = NULL;
440         uint32 reply_len = 0, num_channels, mem_needed;
441         struct sk_buff *skb;
442
443         type = nla_type(data);
444
445         if (type == GSCAN_ATTRIBUTE_BAND) {
446                 band = nla_get_u32(data);
447         } else {
448                 return -1;
449         }
450
451         reply = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
452            DHD_PNO_GET_CHANNEL_LIST, &band, &reply_len);
453
454         if (!reply) {
455                 WL_ERR(("Could not get channel list\n"));
456                 err = -EINVAL;
457                 return err;
458         }
459         num_channels =  reply_len/ sizeof(uint32);
460         mem_needed = reply_len + VENDOR_REPLY_OVERHEAD + (ATTRIBUTE_U32_LEN * 2);
461
462         /* Alloc the SKB for vendor_event */
463         skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
464         if (unlikely(!skb)) {
465                 WL_ERR(("skb alloc failed"));
466                 err = -ENOMEM;
467                 goto exit;
468         }
469
470         nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels);
471         nla_put(skb, GSCAN_ATTRIBUTE_CHANNEL_LIST, reply_len, reply);
472
473         err =  rtw_cfg80211_vendor_cmd_reply(skb);
474
475         if (unlikely(err))
476                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
477 exit:
478         kfree(reply);
479         return err;
480 }
481
482 static int wl_cfgvendor_gscan_get_batch_results(struct wiphy *wiphy,
483         struct wireless_dev *wdev, const void  *data, int len)
484 {
485         int err = 0;
486         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
487         gscan_results_cache_t *results, *iter;
488         uint32 reply_len, complete = 0, num_results_iter;
489         int32 mem_needed;
490         wifi_gscan_result_t *ptr;
491         uint16 num_scan_ids, num_results;
492         struct sk_buff *skb;
493         struct nlattr *scan_hdr;
494
495         dhd_dev_wait_batch_results_complete(bcmcfg_to_prmry_ndev(cfg));
496         dhd_dev_pno_lock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
497         results = dhd_dev_pno_get_gscan(bcmcfg_to_prmry_ndev(cfg),
498                      DHD_PNO_GET_BATCH_RESULTS, NULL, &reply_len);
499
500         if (!results) {
501                 WL_ERR(("No results to send %d\n", err));
502                 err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
503                         results, 0);
504
505                 if (unlikely(err))
506                         WL_ERR(("Vendor Command reply failed ret:%d \n", err));
507                 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
508                 return err;
509         }
510         num_scan_ids = reply_len & 0xFFFF;
511         num_results = (reply_len & 0xFFFF0000) >> 16;
512         mem_needed = (num_results * sizeof(wifi_gscan_result_t)) +
513                      (num_scan_ids * GSCAN_BATCH_RESULT_HDR_LEN) +
514                      VENDOR_REPLY_OVERHEAD + SCAN_RESULTS_COMPLETE_FLAG_LEN;
515
516         if (mem_needed > (int32)NLMSG_DEFAULT_SIZE) {
517                 mem_needed = (int32)NLMSG_DEFAULT_SIZE;
518                 complete = 0;
519         } else {
520                 complete = 1;
521         }
522
523         WL_TRACE(("complete %d mem_needed %d max_mem %d\n", complete, mem_needed,
524                 (int)NLMSG_DEFAULT_SIZE));
525         /* Alloc the SKB for vendor_event */
526         skb = rtw_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, mem_needed);
527         if (unlikely(!skb)) {
528                 WL_ERR(("skb alloc failed"));
529                 dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
530                 return -ENOMEM;
531         }
532         iter = results;
533
534         nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, complete);
535
536         mem_needed = mem_needed - (SCAN_RESULTS_COMPLETE_FLAG_LEN + VENDOR_REPLY_OVERHEAD);
537
538         while (iter && ((mem_needed - GSCAN_BATCH_RESULT_HDR_LEN)  > 0)) {
539                 scan_hdr = nla_nest_start(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS);
540                 nla_put_u32(skb, GSCAN_ATTRIBUTE_SCAN_ID, iter->scan_id);
541                 nla_put_u8(skb, GSCAN_ATTRIBUTE_SCAN_FLAGS, iter->flag);
542                 num_results_iter =
543                     (mem_needed - GSCAN_BATCH_RESULT_HDR_LEN)/sizeof(wifi_gscan_result_t);
544
545                 if ((iter->tot_count - iter->tot_consumed) < num_results_iter)
546                         num_results_iter = iter->tot_count - iter->tot_consumed;
547
548                 nla_put_u32(skb, GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num_results_iter);
549                 if (num_results_iter) {
550                         ptr = &iter->results[iter->tot_consumed];
551                         iter->tot_consumed += num_results_iter;
552                         nla_put(skb, GSCAN_ATTRIBUTE_SCAN_RESULTS,
553                          num_results_iter * sizeof(wifi_gscan_result_t), ptr);
554                 }
555                 nla_nest_end(skb, scan_hdr);
556                 mem_needed -= GSCAN_BATCH_RESULT_HDR_LEN +
557                     (num_results_iter * sizeof(wifi_gscan_result_t));
558                 iter = iter->next;
559         }
560
561         dhd_dev_gscan_batch_cache_cleanup(bcmcfg_to_prmry_ndev(cfg));
562         dhd_dev_pno_unlock_access_batch_results(bcmcfg_to_prmry_ndev(cfg));
563
564         return rtw_cfg80211_vendor_cmd_reply(skb);
565 }
566
567 static int wl_cfgvendor_initiate_gscan(struct wiphy *wiphy,
568         struct wireless_dev *wdev, const void  *data, int len)
569 {
570         int err = 0;
571         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
572         int type, tmp = len;
573         int run = 0xFF;
574         int flush = 0;
575         const struct nlattr *iter;
576
577         nla_for_each_attr(iter, data, len, tmp) {
578                 type = nla_type(iter);
579                 if (type == GSCAN_ATTRIBUTE_ENABLE_FEATURE)
580                         run = nla_get_u32(iter);
581                 else if (type == GSCAN_ATTRIBUTE_FLUSH_FEATURE)
582                         flush = nla_get_u32(iter);
583         }
584
585         if (run != 0xFF) {
586                 err = dhd_dev_pno_run_gscan(bcmcfg_to_prmry_ndev(cfg), run, flush);
587
588                 if (unlikely(err))
589                         WL_ERR(("Could not run gscan:%d \n", err));
590                 return err;
591         } else {
592                 return -1;
593         }
594
595
596 }
597
598 static int wl_cfgvendor_enable_full_scan_result(struct wiphy *wiphy,
599         struct wireless_dev *wdev, const void  *data, int len)
600 {
601         int err = 0;
602         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
603         int type;
604         bool real_time = FALSE;
605
606         type = nla_type(data);
607
608         if (type == GSCAN_ATTRIBUTE_ENABLE_FULL_SCAN_RESULTS) {
609                 real_time = nla_get_u32(data);
610
611                 err = dhd_dev_pno_enable_full_scan_result(bcmcfg_to_prmry_ndev(cfg), real_time);
612
613                 if (unlikely(err))
614                         WL_ERR(("Could not run gscan:%d \n", err));
615
616         } else {
617                 err = -1;
618         }
619
620         return err;
621 }
622
623 static int wl_cfgvendor_set_scan_cfg(struct wiphy *wiphy,
624         struct wireless_dev *wdev, const void  *data, int len)
625 {
626         int err = 0;
627         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
628         gscan_scan_params_t *scan_param;
629         int j = 0;
630         int type, tmp, tmp1, tmp2, k = 0;
631         const struct nlattr *iter, *iter1, *iter2;
632         struct dhd_pno_gscan_channel_bucket  *ch_bucket;
633
634         scan_param = kzalloc(sizeof(gscan_scan_params_t), GFP_KERNEL);
635         if (!scan_param) {
636                 WL_ERR(("Could not set GSCAN scan cfg, mem alloc failure\n"));
637                 err = -EINVAL;
638                 return err;
639
640         }
641
642         scan_param->scan_fr = PNO_SCAN_MIN_FW_SEC;
643         nla_for_each_attr(iter, data, len, tmp) {
644                 type = nla_type(iter);
645
646                 if (j >= GSCAN_MAX_CH_BUCKETS)
647                         break;
648
649                 switch (type) {
650                         case GSCAN_ATTRIBUTE_BASE_PERIOD:
651                                 scan_param->scan_fr = nla_get_u32(iter)/1000;
652                                 break;
653                         case GSCAN_ATTRIBUTE_NUM_BUCKETS:
654                                 scan_param->nchannel_buckets = nla_get_u32(iter);
655                                 break;
656                         case GSCAN_ATTRIBUTE_CH_BUCKET_1:
657                         case GSCAN_ATTRIBUTE_CH_BUCKET_2:
658                         case GSCAN_ATTRIBUTE_CH_BUCKET_3:
659                         case GSCAN_ATTRIBUTE_CH_BUCKET_4:
660                         case GSCAN_ATTRIBUTE_CH_BUCKET_5:
661                         case GSCAN_ATTRIBUTE_CH_BUCKET_6:
662                         case GSCAN_ATTRIBUTE_CH_BUCKET_7:
663                                 nla_for_each_nested(iter1, iter, tmp1) {
664                                         type = nla_type(iter1);
665                                         ch_bucket =
666                                         scan_param->channel_bucket;
667
668                                         switch (type) {
669                                                 case GSCAN_ATTRIBUTE_BUCKET_ID:
670                                                 break;
671                                                 case GSCAN_ATTRIBUTE_BUCKET_PERIOD:
672                                                         ch_bucket[j].bucket_freq_multiple =
673                                                             nla_get_u32(iter1)/1000;
674                                                         break;
675                                                 case GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS:
676                                                         ch_bucket[j].num_channels =
677                                                              nla_get_u32(iter1);
678                                                         break;
679                                                 case GSCAN_ATTRIBUTE_BUCKET_CHANNELS:
680                                                         nla_for_each_nested(iter2, iter1, tmp2) {
681                                                                 if (k >= PFN_SWC_RSSI_WINDOW_MAX)
682                                                                         break;
683                                                                 ch_bucket[j].chan_list[k] =
684                                                                      nla_get_u32(iter2);
685                                                                 k++;
686                                                         }
687                                                         k = 0;
688                                                         break;
689                                                 case GSCAN_ATTRIBUTE_BUCKETS_BAND:
690                                                         ch_bucket[j].band = (uint16)
691                                                              nla_get_u32(iter1);
692                                                         break;
693                                                 case GSCAN_ATTRIBUTE_REPORT_EVENTS:
694                                                         ch_bucket[j].report_flag = (uint8)
695                                                              nla_get_u32(iter1);
696                                                         break;
697                                         }
698                                 }
699                                 j++;
700                                 break;
701                 }
702         }
703
704         if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
705              DHD_PNO_SCAN_CFG_ID, scan_param, 0) < 0) {
706                 WL_ERR(("Could not set GSCAN scan cfg\n"));
707                 err = -EINVAL;
708         }
709
710         kfree(scan_param);
711         return err;
712
713 }
714
715 static int wl_cfgvendor_hotlist_cfg(struct wiphy *wiphy,
716         struct wireless_dev *wdev, const void  *data, int len)
717 {
718         int err = 0;
719         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
720         gscan_hotlist_scan_params_t *hotlist_params;
721         int tmp, tmp1, tmp2, type, j = 0, dummy;
722         const struct nlattr *outer, *inner, *iter;
723         uint8 flush = 0;
724         struct bssid_t *pbssid;
725
726         hotlist_params = (gscan_hotlist_scan_params_t *)kzalloc(len, GFP_KERNEL);
727         if (!hotlist_params) {
728                 WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes \n", len));
729                 return -1;
730         }
731
732         hotlist_params->lost_ap_window = GSCAN_LOST_AP_WINDOW_DEFAULT;
733
734         nla_for_each_attr(iter, data, len, tmp2) {
735                 type = nla_type(iter);
736                 switch (type) {
737                         case GSCAN_ATTRIBUTE_HOTLIST_BSSIDS:
738                                 pbssid = hotlist_params->bssid;
739                                 nla_for_each_nested(outer, iter, tmp) {
740                                         nla_for_each_nested(inner, outer, tmp1) {
741                                                 type = nla_type(inner);
742
743                                                 switch (type) {
744                                                         case GSCAN_ATTRIBUTE_BSSID:
745                                                                 memcpy(&(pbssid[j].macaddr),
746                                                                   nla_data(inner), ETHER_ADDR_LEN);
747                                                                 break;
748                                                         case GSCAN_ATTRIBUTE_RSSI_LOW:
749                                                                 pbssid[j].rssi_reporting_threshold =
750                                                                          (int8) nla_get_u8(inner);
751                                                                 break;
752                                                         case GSCAN_ATTRIBUTE_RSSI_HIGH:
753                                                                 dummy = (int8) nla_get_u8(inner);
754                                                                 break;
755                                                 }
756                                         }
757                                         j++;
758                                 }
759                                 hotlist_params->nbssid = j;
760                                 break;
761                         case GSCAN_ATTRIBUTE_HOTLIST_FLUSH:
762                                 flush = nla_get_u8(iter);
763                                 break;
764                         case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
765                                 hotlist_params->lost_ap_window = nla_get_u32(iter);
766                                 break;
767                         }
768
769         }
770
771         if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
772               DHD_PNO_GEOFENCE_SCAN_CFG_ID, hotlist_params, flush) < 0) {
773                 WL_ERR(("Could not set GSCAN HOTLIST cfg\n"));
774                 err = -EINVAL;
775                 goto exit;
776         }
777 exit:
778         kfree(hotlist_params);
779         return err;
780 }
781 static int wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
782         struct wireless_dev *wdev, const void  *data, int len)
783 {
784         int err = 0, tmp, type;
785         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
786         gscan_batch_params_t batch_param;
787         const struct nlattr *iter;
788
789         batch_param.mscan = batch_param.bestn = 0;
790         batch_param.buffer_threshold = GSCAN_BATCH_NO_THR_SET;
791
792         nla_for_each_attr(iter, data, len, tmp) {
793                 type = nla_type(iter);
794
795                 switch (type) {
796                         case GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN:
797                                 batch_param.bestn = nla_get_u32(iter);
798                                 break;
799                         case GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE:
800                                 batch_param.mscan = nla_get_u32(iter);
801                                 break;
802                         case GSCAN_ATTRIBUTE_REPORT_THRESHOLD:
803                                 batch_param.buffer_threshold = nla_get_u32(iter);
804                                 break;
805                 }
806         }
807
808         if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
809                DHD_PNO_BATCH_SCAN_CFG_ID, &batch_param, 0) < 0) {
810                 WL_ERR(("Could not set batch cfg\n"));
811                 err = -EINVAL;
812                 return err;
813         }
814
815         return err;
816 }
817
818 static int wl_cfgvendor_significant_change_cfg(struct wiphy *wiphy,
819         struct wireless_dev *wdev, const void  *data, int len)
820 {
821         int err = 0;
822         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
823         gscan_swc_params_t *significant_params;
824         int tmp, tmp1, tmp2, type, j = 0;
825         const struct nlattr *outer, *inner, *iter;
826         uint8 flush = 0;
827         wl_pfn_significant_bssid_t *pbssid;
828
829         significant_params = (gscan_swc_params_t *) kzalloc(len, GFP_KERNEL);
830         if (!significant_params) {
831                 WL_ERR(("Cannot Malloc mem to parse config commands size - %d bytes \n", len));
832                 return -1;
833         }
834
835
836         nla_for_each_attr(iter, data, len, tmp2) {
837                 type = nla_type(iter);
838
839                 switch (type) {
840                         case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_FLUSH:
841                         flush = nla_get_u8(iter);
842                         break;
843                         case GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE:
844                                 significant_params->rssi_window = nla_get_u16(iter);
845                                 break;
846                         case GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE:
847                                 significant_params->lost_ap_window = nla_get_u16(iter);
848                                 break;
849                         case GSCAN_ATTRIBUTE_MIN_BREACHING:
850                                 significant_params->swc_threshold = nla_get_u16(iter);
851                                 break;
852                         case GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS:
853                                 pbssid = significant_params->bssid_elem_list;
854                                 nla_for_each_nested(outer, iter, tmp) {
855                                         nla_for_each_nested(inner, outer, tmp1) {
856                                                         switch (nla_type(inner)) {
857                                                                 case GSCAN_ATTRIBUTE_BSSID:
858                                                                 memcpy(&(pbssid[j].macaddr),
859                                                                      nla_data(inner),
860                                                                      ETHER_ADDR_LEN);
861                                                                 break;
862                                                                 case GSCAN_ATTRIBUTE_RSSI_HIGH:
863                                                                 pbssid[j].rssi_high_threshold =
864                                                                        (int8) nla_get_u8(inner);
865                                                                 break;
866                                                                 case GSCAN_ATTRIBUTE_RSSI_LOW:
867                                                                 pbssid[j].rssi_low_threshold =
868                                                                       (int8) nla_get_u8(inner);
869                                                                 break;
870                                                         }
871                                                 }
872                                         j++;
873                                 }
874                                 break;
875                 }
876         }
877         significant_params->nbssid = j;
878
879         if (dhd_dev_pno_set_cfg_gscan(bcmcfg_to_prmry_ndev(cfg),
880             DHD_PNO_SIGNIFICANT_SCAN_CFG_ID, significant_params, flush) < 0) {
881                 WL_ERR(("Could not set GSCAN significant cfg\n"));
882                 err = -EINVAL;
883                 goto exit;
884         }
885 exit:
886         kfree(significant_params);
887         return err;
888 }
889 #endif /* GSCAN_SUPPORT */
890
891 #if defined(RTT_SUPPORT) && 0
892 void wl_cfgvendor_rtt_evt(void *ctx, void *rtt_data)
893 {
894         struct wireless_dev *wdev = (struct wireless_dev *)ctx;
895         struct wiphy *wiphy;
896         struct sk_buff *skb;
897         uint32 tot_len = NLMSG_DEFAULT_SIZE, entry_len = 0;
898         gfp_t kflags;
899         rtt_report_t *rtt_report = NULL;
900         rtt_result_t *rtt_result = NULL;
901         struct list_head *rtt_list;
902         wiphy = wdev->wiphy;
903
904         WL_DBG(("In\n"));
905         /* Push the data to the skb */
906         if (!rtt_data) {
907                 WL_ERR(("rtt_data is NULL\n"));
908                 goto exit;
909         }
910         rtt_list = (struct list_head *)rtt_data;
911         kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
912         /* Alloc the SKB for vendor_event */
913         skb = rtw_cfg80211_vendor_event_alloc(wiphy, tot_len, GOOGLE_RTT_COMPLETE_EVENT, kflags);
914         if (!skb) {
915                 WL_ERR(("skb alloc failed"));
916                 goto exit;
917         }
918         /* fill in the rtt results on each entry */
919         list_for_each_entry(rtt_result, rtt_list, list) {
920                 entry_len = 0;
921                 if (rtt_result->TOF_type == TOF_TYPE_ONE_WAY) {
922                         entry_len = sizeof(rtt_report_t);
923                         rtt_report = kzalloc(entry_len, kflags);
924                         if (!rtt_report) {
925                                 WL_ERR(("rtt_report alloc failed"));
926                                 goto exit;
927                         }
928                         rtt_report->addr = rtt_result->peer_mac;
929                         rtt_report->num_measurement = 1; /* ONE SHOT */
930                         rtt_report->status = rtt_result->err_code;
931                         rtt_report->type = (rtt_result->TOF_type == TOF_TYPE_ONE_WAY) ? RTT_ONE_WAY: RTT_TWO_WAY;
932                         rtt_report->peer = rtt_result->target_info->peer;
933                         rtt_report->channel = rtt_result->target_info->channel;
934                         rtt_report->rssi = rtt_result->avg_rssi;
935                         /* tx_rate */
936                         rtt_report->tx_rate = rtt_result->tx_rate;
937                         /* RTT */
938                         rtt_report->rtt = rtt_result->meanrtt;
939                         rtt_report->rtt_sd = rtt_result->sdrtt;
940                         /* convert to centi meter */
941                         if (rtt_result->distance != 0xffffffff)
942                                 rtt_report->distance = (rtt_result->distance >> 2) * 25;
943                         else /* invalid distance */
944                                 rtt_report->distance = -1;
945
946                         rtt_report->ts = rtt_result->ts;
947                         nla_append(skb, entry_len, rtt_report);
948                         kfree(rtt_report);
949                 }
950         }
951         rtw_cfg80211_vendor_event(skb, kflags);
952 exit:
953         return;
954 }
955
956 static int wl_cfgvendor_rtt_set_config(struct wiphy *wiphy, struct wireless_dev *wdev,
957                                         const void *data, int len) {
958         int err = 0, rem, rem1, rem2, type;
959         rtt_config_params_t rtt_param;
960         rtt_target_info_t* rtt_target = NULL;
961         const struct nlattr *iter, *iter1, *iter2;
962         int8 eabuf[ETHER_ADDR_STR_LEN];
963         int8 chanbuf[CHANSPEC_STR_LEN];
964         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
965
966         WL_DBG(("In\n"));
967         err = dhd_dev_rtt_register_noti_callback(wdev->netdev, wdev, wl_cfgvendor_rtt_evt);
968         if (err < 0) {
969                 WL_ERR(("failed to register rtt_noti_callback\n"));
970                 goto exit;
971         }
972         memset(&rtt_param, 0, sizeof(rtt_param));
973         nla_for_each_attr(iter, data, len, rem) {
974                 type = nla_type(iter);
975                 switch (type) {
976                 case RTT_ATTRIBUTE_TARGET_CNT:
977                         rtt_param.rtt_target_cnt = nla_get_u8(iter);
978                         if (rtt_param.rtt_target_cnt > RTT_MAX_TARGET_CNT) {
979                                 WL_ERR(("exceed max target count : %d\n",
980                                         rtt_param.rtt_target_cnt));
981                                 err = BCME_RANGE;
982                         }
983                         break;
984                 case RTT_ATTRIBUTE_TARGET_INFO:
985                         rtt_target = rtt_param.target_info;
986                         nla_for_each_nested(iter1, iter, rem1) {
987                                 nla_for_each_nested(iter2, iter1, rem2) {
988                                         type = nla_type(iter2);
989                                         switch (type) {
990                                         case RTT_ATTRIBUTE_TARGET_MAC:
991                                                 memcpy(&rtt_target->addr, nla_data(iter2), ETHER_ADDR_LEN);
992                                                 break;
993                                         case RTT_ATTRIBUTE_TARGET_TYPE:
994                                                 rtt_target->type = nla_get_u8(iter2);
995                                                 break;
996                                         case RTT_ATTRIBUTE_TARGET_PEER:
997                                                 rtt_target->peer= nla_get_u8(iter2);
998                                                 break;
999                                         case RTT_ATTRIBUTE_TARGET_CHAN:
1000                                                 memcpy(&rtt_target->channel, nla_data(iter2),
1001                                                         sizeof(rtt_target->channel));
1002                                                 break;
1003                                         case RTT_ATTRIBUTE_TARGET_MODE:
1004                                                 rtt_target->continuous = nla_get_u8(iter2);
1005                                                 break;
1006                                         case RTT_ATTRIBUTE_TARGET_INTERVAL:
1007                                                 rtt_target->interval = nla_get_u32(iter2);
1008                                                 break;
1009                                         case RTT_ATTRIBUTE_TARGET_NUM_MEASUREMENT:
1010                                                 rtt_target->measure_cnt = nla_get_u32(iter2);
1011                                                 break;
1012                                         case RTT_ATTRIBUTE_TARGET_NUM_PKT:
1013                                                 rtt_target->ftm_cnt = nla_get_u32(iter2);
1014                                                 break;
1015                                         case RTT_ATTRIBUTE_TARGET_NUM_RETRY:
1016                                                 rtt_target->retry_cnt = nla_get_u32(iter2);
1017                                         }
1018                                 }
1019                                 /* convert to chanspec value */
1020                                 rtt_target->chanspec = dhd_rtt_convert_to_chspec(rtt_target->channel);
1021                                 if (rtt_target->chanspec == 0) {
1022                                         WL_ERR(("Channel is not valid \n"));
1023                                         goto exit;
1024                                 }
1025                                 WL_INFORM(("Target addr %s, Channel : %s for RTT \n",
1026                                         bcm_ether_ntoa((const struct ether_addr *)&rtt_target->addr, eabuf),
1027                                         wf_chspec_ntoa(rtt_target->chanspec, chanbuf)));
1028                                 rtt_target++;
1029                         }
1030                         break;
1031                 }
1032         }
1033         WL_DBG(("leave :target_cnt : %d\n", rtt_param.rtt_target_cnt));
1034         if (dhd_dev_rtt_set_cfg(bcmcfg_to_prmry_ndev(cfg), &rtt_param) < 0) {
1035                 WL_ERR(("Could not set RTT configuration\n"));
1036                 err = -EINVAL;
1037         }
1038 exit:
1039         return err;
1040 }
1041
1042 static int wl_cfgvendor_rtt_cancel_config(struct wiphy *wiphy, struct wireless_dev *wdev,
1043                                         const void *data, int len)
1044 {
1045         int err = 0, rem, type, target_cnt = 0;
1046         const struct nlattr *iter;
1047         struct ether_addr *mac_list = NULL, *mac_addr = NULL;
1048         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1049
1050         nla_for_each_attr(iter, data, len, rem) {
1051                 type = nla_type(iter);
1052                 switch (type) {
1053                 case RTT_ATTRIBUTE_TARGET_CNT:
1054                         target_cnt = nla_get_u8(iter);
1055                         mac_list = (struct ether_addr *)kzalloc(target_cnt * ETHER_ADDR_LEN , GFP_KERNEL);
1056                         if (mac_list == NULL) {
1057                                 WL_ERR(("failed to allocate mem for mac list\n"));
1058                                 goto exit;
1059                         }
1060                         mac_addr = &mac_list[0];
1061                         break;
1062                 case RTT_ATTRIBUTE_TARGET_MAC:
1063                         if (mac_addr)
1064                                 memcpy(mac_addr++, nla_data(iter), ETHER_ADDR_LEN);
1065                         else {
1066                                 WL_ERR(("mac_list is NULL\n"));
1067                                 goto exit;
1068                         }
1069                         break;
1070                 }
1071                 if (dhd_dev_rtt_cancel_cfg(bcmcfg_to_prmry_ndev(cfg), mac_list, target_cnt) < 0) {
1072                         WL_ERR(("Could not cancel RTT configuration\n"));
1073                         err = -EINVAL;
1074                         goto exit;
1075                 }
1076         }
1077 exit:
1078         if (mac_list)
1079                 kfree(mac_list);
1080         return err;
1081 }
1082 static int wl_cfgvendor_rtt_get_capability(struct wiphy *wiphy, struct wireless_dev *wdev,
1083                                         const void *data, int len)
1084 {
1085         int err = 0;
1086         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1087         rtt_capabilities_t capability;
1088
1089         err = dhd_dev_rtt_capability(bcmcfg_to_prmry_ndev(cfg), &capability);
1090         if (unlikely(err)) {
1091                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1092                 goto exit;
1093         }
1094         err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
1095                 &capability, sizeof(capability));
1096
1097         if (unlikely(err)) {
1098                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1099         }
1100 exit:
1101         return err;
1102 }
1103
1104 #endif /* RTT_SUPPORT */
1105 static int wl_cfgvendor_priv_string_handler(struct wiphy *wiphy,
1106         struct wireless_dev *wdev, const void  *data, int len)
1107 {
1108         int err = 0;
1109         u8 resp[1] = {'\0'};
1110
1111         DBG_871X_LEVEL(_drv_always_, FUNC_NDEV_FMT" %s\n", FUNC_NDEV_ARG(wdev_to_ndev(wdev)), (char*)data);
1112         err =  rtw_cfgvendor_send_cmd_reply(wiphy, wdev_to_ndev(wdev), resp, 1);
1113         if (unlikely(err))
1114                 DBG_871X_LEVEL(_drv_err_, FUNC_NDEV_FMT"Vendor Command reply failed ret:%d \n"
1115                         , FUNC_NDEV_ARG(wdev_to_ndev(wdev)), err);
1116
1117         return err;
1118 #if 0
1119         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
1120         int err = 0;
1121         int data_len = 0;
1122
1123         bzero(cfg->ioctl_buf, WLC_IOCTL_MAXLEN);
1124
1125         if (strncmp((char *)data, BRCM_VENDOR_SCMD_CAPA, strlen(BRCM_VENDOR_SCMD_CAPA)) == 0) {
1126                 err = wldev_iovar_getbuf(bcmcfg_to_prmry_ndev(cfg), "cap", NULL, 0,
1127                         cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
1128                 if (unlikely(err)) {
1129                         WL_ERR(("error (%d)\n", err));
1130                         return err;
1131                 }
1132                 data_len = strlen(cfg->ioctl_buf);
1133                 cfg->ioctl_buf[data_len] = '\0';
1134         }
1135
1136         err =  rtw_cfgvendor_send_cmd_reply(wiphy, bcmcfg_to_prmry_ndev(cfg),
1137                 cfg->ioctl_buf, data_len+1);
1138         if (unlikely(err))
1139                 WL_ERR(("Vendor Command reply failed ret:%d \n", err));
1140         else
1141                 WL_INFORM(("Vendor Command reply sent successfully!\n"));
1142
1143         return err;
1144 #endif
1145 }
1146
1147 static const struct wiphy_vendor_command rtw_vendor_cmds [] = {
1148         {
1149                 {
1150                         .vendor_id = OUI_BRCM,
1151                         .subcmd = BRCM_VENDOR_SCMD_PRIV_STR
1152                 },
1153                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1154                 .doit = wl_cfgvendor_priv_string_handler
1155         },
1156 #if defined(GSCAN_SUPPORT) && 0
1157         {
1158                 {
1159                         .vendor_id = OUI_GOOGLE,
1160                         .subcmd = GSCAN_SUBCMD_GET_CAPABILITIES
1161                 },
1162                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1163                 .doit = wl_cfgvendor_gscan_get_capabilities
1164         },
1165         {
1166                 {
1167                         .vendor_id = OUI_GOOGLE,
1168                         .subcmd = GSCAN_SUBCMD_SET_CONFIG
1169                 },
1170                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1171                 .doit = wl_cfgvendor_set_scan_cfg
1172         },
1173         {
1174                 {
1175                         .vendor_id = OUI_GOOGLE,
1176                         .subcmd = GSCAN_SUBCMD_SET_SCAN_CONFIG
1177                 },
1178                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1179                 .doit = wl_cfgvendor_set_batch_scan_cfg
1180         },
1181         {
1182                 {
1183                         .vendor_id = OUI_GOOGLE,
1184                         .subcmd = GSCAN_SUBCMD_ENABLE_GSCAN
1185                 },
1186                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1187                 .doit = wl_cfgvendor_initiate_gscan
1188         },
1189         {
1190                 {
1191                         .vendor_id = OUI_GOOGLE,
1192                         .subcmd = GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS
1193                 },
1194                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1195                 .doit = wl_cfgvendor_enable_full_scan_result
1196         },
1197         {
1198                 {
1199                         .vendor_id = OUI_GOOGLE,
1200                         .subcmd = GSCAN_SUBCMD_SET_HOTLIST
1201                 },
1202                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1203                 .doit = wl_cfgvendor_hotlist_cfg
1204         },
1205         {
1206                 {
1207                         .vendor_id = OUI_GOOGLE,
1208                         .subcmd = GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG
1209                 },
1210                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1211                 .doit = wl_cfgvendor_significant_change_cfg
1212         },
1213         {
1214                 {
1215                         .vendor_id = OUI_GOOGLE,
1216                         .subcmd = GSCAN_SUBCMD_GET_SCAN_RESULTS
1217                 },
1218                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1219                 .doit = wl_cfgvendor_gscan_get_batch_results
1220         },
1221         {
1222                 {
1223                         .vendor_id = OUI_GOOGLE,
1224                         .subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
1225                 },
1226                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1227                 .doit = wl_cfgvendor_gscan_get_channel_list
1228         },
1229 #endif /* GSCAN_SUPPORT */
1230 #if defined(RTT_SUPPORT) && 0
1231         {
1232                 {
1233                         .vendor_id = OUI_GOOGLE,
1234                         .subcmd = RTT_SUBCMD_SET_CONFIG
1235                 },
1236                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1237                 .doit = wl_cfgvendor_rtt_set_config
1238         },
1239         {
1240                 {
1241                         .vendor_id = OUI_GOOGLE,
1242                         .subcmd = RTT_SUBCMD_CANCEL_CONFIG
1243                 },
1244                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1245                 .doit = wl_cfgvendor_rtt_cancel_config
1246         },
1247         {
1248                 {
1249                         .vendor_id = OUI_GOOGLE,
1250                         .subcmd = RTT_SUBCMD_GETCAPABILITY
1251                 },
1252                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1253                 .doit = wl_cfgvendor_rtt_get_capability
1254         },
1255 #endif /* RTT_SUPPORT */
1256         {
1257                 {
1258                         .vendor_id = OUI_GOOGLE,
1259                         .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET
1260                 },
1261                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1262                 .doit = rtw_cfgvendor_get_feature_set
1263         },
1264         {
1265                 {
1266                         .vendor_id = OUI_GOOGLE,
1267                         .subcmd = ANDR_WIFI_SUBCMD_GET_FEATURE_SET_MATRIX
1268                 },
1269                 .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
1270                 .doit = rtw_cfgvendor_get_feature_set_matrix
1271         }
1272 };
1273
1274 static const struct  nl80211_vendor_cmd_info rtw_vendor_events [] = {
1275                 { OUI_BRCM, BRCM_VENDOR_EVENT_UNSPEC },
1276                 { OUI_BRCM, BRCM_VENDOR_EVENT_PRIV_STR },
1277 #if defined(GSCAN_SUPPORT) && 0
1278                 { OUI_GOOGLE, GOOGLE_GSCAN_SIGNIFICANT_EVENT },
1279                 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT },
1280                 { OUI_GOOGLE, GOOGLE_GSCAN_BATCH_SCAN_EVENT },
1281                 { OUI_GOOGLE, GOOGLE_SCAN_FULL_RESULTS_EVENT },
1282 #endif /* GSCAN_SUPPORT */
1283 #if defined(RTT_SUPPORT) && 0
1284                 { OUI_GOOGLE, GOOGLE_RTT_COMPLETE_EVENT },
1285 #endif /* RTT_SUPPORT */
1286 #if defined(GSCAN_SUPPORT) && 0
1287                 { OUI_GOOGLE, GOOGLE_SCAN_COMPLETE_EVENT },
1288                 { OUI_GOOGLE, GOOGLE_GSCAN_GEOFENCE_LOST_EVENT }
1289 #endif /* GSCAN_SUPPORT */
1290 };
1291
1292 int rtw_cfgvendor_attach(struct wiphy *wiphy)
1293 {
1294
1295         DBG_871X("Register RTW cfg80211 vendor cmd(0x%x) interface \n", NL80211_CMD_VENDOR);
1296
1297         wiphy->vendor_commands  = rtw_vendor_cmds;
1298         wiphy->n_vendor_commands = ARRAY_SIZE(rtw_vendor_cmds);
1299         wiphy->vendor_events    = rtw_vendor_events;
1300         wiphy->n_vendor_events  = ARRAY_SIZE(rtw_vendor_events);
1301
1302         return 0;
1303 }
1304
1305 int rtw_cfgvendor_detach(struct wiphy *wiphy)
1306 {
1307         DBG_871X("Vendor: Unregister RTW cfg80211 vendor interface \n");
1308
1309         wiphy->vendor_commands  = NULL;
1310         wiphy->vendor_events    = NULL;
1311         wiphy->n_vendor_commands = 0;
1312         wiphy->n_vendor_events  = 0;
1313
1314         return 0;
1315 }
1316 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(RTW_VENDOR_EXT_SUPPORT) */
1317
1318 #endif /* CONFIG_IOCTL_CFG80211 */
1319