~ubuntu-branches/ubuntu/wily/rtl8812au/wily

« back to all changes in this revision

Viewing changes to .pc/0001-Making-it-compatible-with-kernel-4.2.patch/os_dep/linux/rtw_cfgvendor.c

  • Committer: Package Import Robot
  • Author(s): Ricardo Salveti de Araujo
  • Date: 2015-10-19 15:17:22 UTC
  • Revision ID: package-import@ubuntu.com-20151019151722-1x5ku8h9t573wmll
Tags: 4.3.8.12175.20140902+dfsg-0ubuntu1
* New dsfg orig tarball
  - Removing files without a proper copyright/license

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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