aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/net/wireless/bcmdhd/wl_cfgp2p.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/net/wireless/bcmdhd/wl_cfgp2p.c')
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c1469
1 files changed, 1469 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
new file mode 100644
index 00000000000..4ee6557e17d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -0,0 +1,1469 @@
1/*
2 * Linux cfgp2p driver
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_cfgp2p.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
25 *
26 */
27#include <typedefs.h>
28#include <linuxver.h>
29#include <osl.h>
30#include <linux/kernel.h>
31#include <linux/kthread.h>
32#include <linux/netdevice.h>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/timer.h>
36#include <linux/if_arp.h>
37#include <asm/uaccess.h>
38
39#include <bcmutils.h>
40#include <bcmendian.h>
41#include <proto/ethernet.h>
42#include <dngl_stats.h>
43#include <dhd.h>
44#include <dhdioctl.h>
45#include <wlioctl.h>
46
47#include <wl_cfg80211.h>
48#include <wl_cfgp2p.h>
49#include <wldev_common.h>
50
51
52static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
53static s8 scanparambuf[WLC_IOCTL_SMLEN];
54static s8 *smbuf = ioctlbuf;
55
56static bool
57wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
58
59static s32
60wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
61 s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete);
62/*
63 * Initialize variables related to P2P
64 *
65 */
66s32
67wl_cfgp2p_init_priv(struct wl_priv *wl)
68{
69 if (!(wl->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) {
70 CFGP2P_ERR(("struct p2p_info allocation failed\n"));
71 return -ENOMEM;
72 }
73#define INIT_IE(IE_TYPE, BSS_TYPE) \
74 do { \
75 memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
76 sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
77 wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
78 } while (0);
79
80 INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY);
81 INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY);
82 INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY);
83 INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY);
84 INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY);
85 INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE);
86 INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE);
87 INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE);
88 INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE);
89 INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE);
90 INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION);
91 INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION);
92 INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION);
93 INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION);
94 INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION);
95#undef INIT_IE
96 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY) = wl_to_prmry_ndev(wl);
97 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY) = 0;
98 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
99 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
100 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL;
101 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0;
102 spin_lock_init(&wl->p2p->timer_lock);
103 return BCME_OK;
104
105}
106/*
107 * Deinitialize variables related to P2P
108 *
109 */
110void
111wl_cfgp2p_deinit_priv(struct wl_priv *wl)
112{
113 if (wl->p2p) {
114 kfree(wl->p2p);
115 wl->p2p = NULL;
116 }
117 wl->p2p_supported = 0;
118}
119/*
120 * Set P2P functions into firmware
121 */
122s32
123wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
124{
125 struct net_device *ndev = wl_to_prmry_ndev(wl);
126 struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } };
127 s32 ret = BCME_OK;
128 s32 val = 0;
129 /* Do we have to check whether APSTA is enabled or not ? */
130 wldev_iovar_getint(ndev, "apsta", &val);
131 if (val == 0) {
132 val = 1;
133 wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true);
134 wldev_iovar_setint(ndev, "apsta", val);
135 wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true);
136 }
137 val = 1;
138 /* Disable firmware roaming for P2P */
139 wldev_iovar_setint(ndev, "roam_off", val);
140 /* In case of COB type, firmware has default mac address
141 * After Initializing firmware, we have to set current mac address to
142 * firmware for P2P device address
143 */
144 ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
145 sizeof(null_eth_addr), ioctlbuf, sizeof(ioctlbuf), 0);
146 if (ret && ret != BCME_UNSUPPORTED) {
147 CFGP2P_ERR(("failed to update device address\n"));
148 }
149 return ret;
150}
151
152/* Create a new P2P BSS.
153 * Parameters:
154 * @mac : MAC address of the BSS to create
155 * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT
156 * @chspec : chspec to use if creating a GO BSS.
157 * Returns 0 if success.
158 */
159s32
160wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
161 chanspec_t chspec)
162{
163 wl_p2p_if_t ifreq;
164 s32 err;
165 struct net_device *ndev = wl_to_prmry_ndev(wl);
166
167 ifreq.type = if_type;
168 ifreq.chspec = chspec;
169 memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
170
171 CFGP2P_INFO(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
172 ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
173 ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
174 (if_type == WL_P2P_IF_GO) ? "go" : "client",
175 (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
176
177 err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
178 ioctlbuf, sizeof(ioctlbuf));
179 return err;
180}
181
182/* Delete a P2P BSS.
183 * Parameters:
184 * @mac : MAC address of the BSS to create
185 * Returns 0 if success.
186 */
187s32
188wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac)
189{
190 s32 ret;
191 struct net_device *netdev = wl_to_prmry_ndev(wl);
192
193 CFGP2P_INFO(("------primary idx %d : wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n",
194 netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2],
195 mac->octet[3], mac->octet[4], mac->octet[5]));
196 ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
197 ioctlbuf, sizeof(ioctlbuf));
198 if (unlikely(ret < 0)) {
199 printk("'wl p2p_ifdel' error %d\n", ret);
200 }
201 return ret;
202}
203
204/* Change a P2P Role.
205 * Parameters:
206 * @mac : MAC address of the BSS to change a role
207 * Returns 0 if success.
208 */
209s32
210wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
211 chanspec_t chspec)
212{
213 wl_p2p_if_t ifreq;
214 s32 err;
215 struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
216
217 ifreq.type = if_type;
218 ifreq.chspec = chspec;
219 memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
220
221 CFGP2P_INFO(("---wl p2p_ifchange %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
222 ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
223 ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
224 (if_type == WL_P2P_IF_GO) ? "go" : "client",
225 (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
226
227 err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
228 ioctlbuf, sizeof(ioctlbuf));
229
230 if (unlikely(err < 0)) {
231 printk("'wl p2p_ifupd' error %d\n", err);
232 }
233 return err;
234}
235
236
237/* Get the index of a created P2P BSS.
238 * Parameters:
239 * @mac : MAC address of the created BSS
240 * @index : output: index of created BSS
241 * Returns 0 if success.
242 */
243s32
244wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index)
245{
246 s32 ret;
247 u8 getbuf[64];
248 struct net_device *dev = wl_to_prmry_ndev(wl);
249
250 CFGP2P_INFO(("---wl p2p_if %02x:%02x:%02x:%02x:%02x:%02x\n",
251 mac->octet[0], mac->octet[1], mac->octet[2],
252 mac->octet[3], mac->octet[4], mac->octet[5]));
253
254 ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac),
255 getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY));
256
257 if (ret == 0) {
258 memcpy(index, getbuf, sizeof(index));
259 CFGP2P_INFO(("---wl p2p_if ==> %d\n", *index));
260 }
261
262 return ret;
263}
264
265s32
266wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on)
267{
268 s32 ret = BCME_OK;
269 struct net_device *ndev = wl_to_prmry_ndev(wl);
270 CFGP2P_DBG(("enter\n"));
271
272 ret = wldev_iovar_setint(ndev, "p2p_disc", on);
273
274 if (unlikely(ret < 0)) {
275 CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret));
276 }
277
278 return ret;
279}
280
281/* Set the WL driver's P2P mode.
282 * Parameters :
283 * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}.
284 * @channel : the channel to listen
285 * @listen_ms : the time (milli seconds) to wait
286 * @bssidx : bss index for BSSCFG
287 * Returns 0 if success
288 */
289
290s32
291wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, int bssidx)
292{
293 wl_p2p_disc_st_t discovery_mode;
294 s32 ret;
295 struct net_device *dev;
296 CFGP2P_DBG(("enter\n"));
297
298 if (unlikely(bssidx >= P2PAPI_BSSCFG_MAX)) {
299 CFGP2P_ERR((" %d index out of range\n", bssidx));
300 return -1;
301 }
302
303 dev = wl_to_p2p_bss_ndev(wl, bssidx);
304 if (unlikely(dev == NULL)) {
305 CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx));
306 return BCME_NOTFOUND;
307 }
308
309 /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */
310 discovery_mode.state = mode;
311 discovery_mode.chspec = CH20MHZ_CHSPEC(channel);
312 discovery_mode.dwell = listen_ms;
313 ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
314 sizeof(discovery_mode), ioctlbuf, sizeof(ioctlbuf), bssidx);
315
316 return ret;
317}
318
319/* Get the index of the P2P Discovery BSS */
320s32
321wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index)
322{
323 s32 ret;
324 struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
325
326 ret = wldev_iovar_getint(dev, "p2p_dev", index);
327 CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret));
328
329 if (unlikely(ret < 0)) {
330 CFGP2P_ERR(("'p2p_dev' error %d\n", ret));
331 return ret;
332 }
333 return ret;
334}
335
336s32
337wl_cfgp2p_init_discovery(struct wl_priv *wl)
338{
339
340 s32 index = 0;
341 s32 ret = BCME_OK;
342
343 CFGP2P_DBG(("enter\n"));
344
345 if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) != 0) {
346 CFGP2P_ERR(("do nothing, already initialized\n"));
347 return ret;
348 }
349
350 ret = wl_cfgp2p_set_discovery(wl, 1);
351 if (ret < 0) {
352 CFGP2P_ERR(("set discover error\n"));
353 return ret;
354 }
355 /* Enable P2P Discovery in the WL Driver */
356 ret = wl_cfgp2p_get_disc_idx(wl, &index);
357
358 if (ret < 0) {
359 return ret;
360 }
361 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) =
362 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
363 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = index;
364
365 /* Set the initial discovery state to SCAN */
366 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
367 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
368
369 if (unlikely(ret != 0)) {
370 CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
371 wl_cfgp2p_set_discovery(wl, 0);
372 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
373 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
374 return 0;
375 }
376 return ret;
377}
378
379/* Deinitialize P2P Discovery
380 * Parameters :
381 * @wl : wl_private data
382 * Returns 0 if succes
383 */
384s32
385wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
386{
387 s32 ret = BCME_OK;
388 CFGP2P_DBG(("enter\n"));
389
390 if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) {
391 CFGP2P_ERR(("do nothing, not initialized\n"));
392 return -1;
393 }
394 /* Set the discovery state to SCAN */
395 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
396 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
397 /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
398 ret = wl_cfgp2p_set_discovery(wl, 0);
399
400 /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver
401 * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery
402 * BSS.
403 */
404
405 /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we
406 * have no discovery BSS.
407 */
408 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
409 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
410
411 return ret;
412
413}
414/* Enable P2P Discovery
415 * Parameters:
416 * @wl : wl_private data
417 * @ie : probe request ie (WPS IE + P2P IE)
418 * @ie_len : probe request ie length
419 * Returns 0 if success.
420 */
421s32
422wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len)
423{
424 s32 ret = BCME_OK;
425 if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
426 CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
427 goto set_ie;
428 }
429
430 wl_set_p2p_status(wl, DISCOVERY_ON);
431
432 CFGP2P_DBG(("enter\n"));
433
434 ret = wl_cfgp2p_init_discovery(wl);
435 if (unlikely(ret < 0)) {
436 CFGP2P_ERR((" init discovery error %d\n", ret));
437 goto exit;
438 }
439 /* Set wsec to any non-zero value in the discovery bsscfg to ensure our
440 * P2P probe responses have the privacy bit set in the 802.11 WPA IE.
441 * Some peer devices may not initiate WPS with us if this bit is not set.
442 */
443 ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE),
444 "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
445 if (unlikely(ret < 0)) {
446 CFGP2P_ERR((" wsec error %d\n", ret));
447 }
448set_ie:
449 ret = wl_cfgp2p_set_management_ie(wl, dev,
450 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE),
451 VNDR_IE_PRBREQ_FLAG, ie, ie_len);
452
453 if (unlikely(ret < 0)) {
454 CFGP2P_ERR(("set probreq ie occurs error %d\n", ret));
455 goto exit;
456 }
457exit:
458 return ret;
459}
460
461/* Disable P2P Discovery
462 * Parameters:
463 * @wl : wl_private_data
464 * Returns 0 if success.
465 */
466s32
467wl_cfgp2p_disable_discovery(struct wl_priv *wl)
468{
469 s32 ret = BCME_OK;
470 CFGP2P_DBG((" enter\n"));
471 wl_clr_p2p_status(wl, DISCOVERY_ON);
472
473 if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) {
474 CFGP2P_ERR((" do nothing, not initialized\n"));
475 goto exit;
476 }
477
478 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
479 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
480
481 if (unlikely(ret < 0)) {
482
483 CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
484 }
485 /* Do a scan abort to stop the driver's scan engine in case it is still
486 * waiting out an action frame tx dwell time.
487 */
488#ifdef NOT_YET
489 if (wl_get_p2p_status(wl, SCANNING)) {
490 p2pwlu_scan_abort(hdl, FALSE);
491 }
492#endif
493 wl_clr_p2p_status(wl, DISCOVERY_ON);
494 ret = wl_cfgp2p_deinit_discovery(wl);
495
496exit:
497 return ret;
498}
499
500s32
501wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
502 u32 num_chans, u16 *channels,
503 s32 search_state, u16 action, u32 bssidx)
504{
505 s32 ret = BCME_OK;
506 s32 memsize;
507 s32 eparams_size;
508 u32 i;
509 s8 *memblk;
510 wl_p2p_scan_t *p2p_params;
511 wl_escan_params_t *eparams;
512 wlc_ssid_t ssid;
513 /* Scan parameters */
514#define P2PAPI_SCAN_NPROBES 4
515#define P2PAPI_SCAN_DWELL_TIME_MS 80
516#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 100
517#define P2PAPI_SCAN_HOME_TIME_MS 10
518 struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
519 wl_set_p2p_status(wl, SCANNING);
520 /* Allocate scan params which need space for 3 channels and 0 ssids */
521 eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE +
522 OFFSETOF(wl_escan_params_t, params)) +
523 num_chans * sizeof(eparams->params.channel_list[0]);
524
525 memsize = sizeof(wl_p2p_scan_t) + eparams_size;
526 memblk = scanparambuf;
527 if (memsize > sizeof(scanparambuf)) {
528 CFGP2P_ERR((" scanpar buf too small (%u > %u)\n",
529 memsize, sizeof(scanparambuf)));
530 return -1;
531 }
532 memset(memblk, 0, memsize);
533 memset(ioctlbuf, 0, sizeof(ioctlbuf));
534 if (search_state == WL_P2P_DISC_ST_SEARCH) {
535 /*
536 * If we in SEARCH STATE, we don't need to set SSID explictly
537 * because dongle use P2P WILDCARD internally by default
538 */
539 wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx);
540 ssid.SSID_len = htod32(0);
541
542 } else if (search_state == WL_P2P_DISC_ST_SCAN) {
543 /* SCAN STATE 802.11 SCAN
544 * WFD Supplicant has p2p_find command with (type=progressive, type= full)
545 * So if P2P_find command with type=progressive,
546 * we have to set ssid to P2P WILDCARD because
547 * we just do broadcast scan unless setting SSID
548 */
549 strcpy(ssid.SSID, WL_P2P_WILDCARD_SSID);
550 ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN);
551 wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
552 }
553
554
555 /* Fill in the P2P scan structure at the start of the iovar param block */
556 p2p_params = (wl_p2p_scan_t*) memblk;
557 p2p_params->type = 'E';
558 /* Fill in the Scan structure that follows the P2P scan structure */
559 eparams = (wl_escan_params_t*) (p2p_params + 1);
560 eparams->params.bss_type = DOT11_BSSTYPE_ANY;
561 if (active)
562 eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE;
563 else
564 eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE;
565
566 memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
567 if (ssid.SSID_len)
568 memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t));
569
570 eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES);
571 eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
572 if (wl_get_drv_status(wl, CONNECTED))
573 eparams->params.active_time = htod32(-1);
574 else if (num_chans == 3)
575 eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
576 else
577 eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS);
578 eparams->params.passive_time = htod32(-1);
579 eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
580 (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
581
582 for (i = 0; i < num_chans; i++) {
583 eparams->params.channel_list[i] = htodchanspec(channels[i]);
584 }
585 eparams->version = htod32(ESCAN_REQ_VERSION);
586 eparams->action = htod16(action);
587 eparams->sync_id = htod16(0x1234);
588 CFGP2P_INFO(("SCAN CHANNELS : "));
589
590 for (i = 0; i < num_chans; i++) {
591 if (i == 0) CFGP2P_INFO(("%d", channels[i]));
592 else CFGP2P_INFO((",%d", channels[i]));
593 }
594
595 CFGP2P_INFO(("\n"));
596
597 ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
598 memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx);
599 return ret;
600}
601/* Check whether pointed-to IE looks like WPA. */
602#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
603 (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
604/* Check whether pointed-to IE looks like WPS. */
605#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
606 (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE)
607/* Check whether the given IE looks like WFA P2P IE. */
608#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
609 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
610/* Delete and Set a management vndr ie to firmware
611 * Parameters:
612 * @wl : wl_private data
613 * @ndev : net device for bssidx
614 * @bssidx : bssidx for BSS
615 * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
616 * VNDR_IE_ASSOCREQ_FLAG)
617 * @ie : VNDR IE (such as P2P IE , WPS IE)
618 * @ie_len : VNDR IE Length
619 * Returns 0 if success.
620 */
621
622s32
623wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
624 s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
625{
626 /* Vendor-specific Information Element ID */
627#define VNDR_SPEC_ELEMENT_ID 0xdd
628 s32 ret = BCME_OK;
629 u32 pos;
630 u8 *ie_buf;
631 u8 *mgmt_ie_buf = NULL;
632 u32 mgmt_ie_buf_len = 0;
633 u32 *mgmt_ie_len = 0;
634 u8 ie_id, ie_len;
635 u8 delete = 0;
636#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
637#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
638 if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) {
639 if (bssidx == P2PAPI_BSSCFG_PRIMARY)
640 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
641 switch (pktflag) {
642 case VNDR_IE_PRBREQ_FLAG :
643 mgmt_ie_buf = IE_TYPE(probe_req, bssidx);
644 mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx);
645 mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx));
646 break;
647 case VNDR_IE_PRBRSP_FLAG :
648 mgmt_ie_buf = IE_TYPE(probe_res, bssidx);
649 mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx);
650 mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx));
651 break;
652 case VNDR_IE_ASSOCREQ_FLAG :
653 mgmt_ie_buf = IE_TYPE(assoc_req, bssidx);
654 mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx);
655 mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx));
656 break;
657 case VNDR_IE_ASSOCRSP_FLAG :
658 mgmt_ie_buf = IE_TYPE(assoc_res, bssidx);
659 mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx);
660 mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx));
661 break;
662 case VNDR_IE_BEACON_FLAG :
663 mgmt_ie_buf = IE_TYPE(beacon, bssidx);
664 mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx);
665 mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx));
666 break;
667 default:
668 mgmt_ie_buf = NULL;
669 mgmt_ie_len = NULL;
670 CFGP2P_ERR(("not suitable type\n"));
671 return -1;
672 }
673 } else if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
674 switch (pktflag) {
675 case VNDR_IE_PRBRSP_FLAG :
676 mgmt_ie_buf = wl->ap_info->probe_res_ie;
677 mgmt_ie_len = &wl->ap_info->probe_res_ie_len;
678 mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie);
679 break;
680 case VNDR_IE_BEACON_FLAG :
681 mgmt_ie_buf = wl->ap_info->beacon_ie;
682 mgmt_ie_len = &wl->ap_info->beacon_ie_len;
683 mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie);
684 break;
685 default:
686 mgmt_ie_buf = NULL;
687 mgmt_ie_len = NULL;
688 CFGP2P_ERR(("not suitable type\n"));
689 return -1;
690 }
691 bssidx = 0;
692 } else if (bssidx == -1 && get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
693 switch (pktflag) {
694 case VNDR_IE_PRBREQ_FLAG :
695 mgmt_ie_buf = wl->sta_info->probe_req_ie;
696 mgmt_ie_len = &wl->sta_info->probe_req_ie_len;
697 mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie);
698 break;
699 case VNDR_IE_ASSOCREQ_FLAG :
700 mgmt_ie_buf = wl->sta_info->assoc_req_ie;
701 mgmt_ie_len = &wl->sta_info->assoc_req_ie_len;
702 mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie);
703 break;
704 default:
705 mgmt_ie_buf = NULL;
706 mgmt_ie_len = NULL;
707 CFGP2P_ERR(("not suitable type\n"));
708 return -1;
709 }
710 bssidx = 0;
711 } else {
712 CFGP2P_ERR(("not suitable type\n"));
713 return -1;
714 }
715
716 if (vndr_ie_len > mgmt_ie_buf_len) {
717 CFGP2P_ERR(("extra IE size too big\n"));
718 ret = -ENOMEM;
719 } else {
720 if (mgmt_ie_buf != NULL) {
721 if (vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) &&
722 (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
723 CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
724 goto exit;
725 }
726 pos = 0;
727 delete = 1;
728 ie_buf = (u8 *) mgmt_ie_buf;
729 while (pos < *mgmt_ie_len) {
730 ie_id = ie_buf[pos++];
731 ie_len = ie_buf[pos++];
732 if ((ie_id == DOT11_MNG_VS_ID) &&
733 (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
734 wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
735 CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
736 "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
737 ie_buf[pos+1], ie_buf[pos+2]));
738 ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
739 VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
740 }
741 pos += ie_len;
742 }
743
744 }
745 *mgmt_ie_len = 0;
746 /* Add if there is any extra IE */
747 if (vndr_ie && vndr_ie_len) {
748 /* save the current IE in wl struct */
749 memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len);
750 *mgmt_ie_len = vndr_ie_len;
751 pos = 0;
752 ie_buf = (u8 *) vndr_ie;
753 delete = 0;
754 while (pos < vndr_ie_len) {
755 ie_id = ie_buf[pos++];
756 ie_len = ie_buf[pos++];
757 if ((ie_id == DOT11_MNG_VS_ID) &&
758 (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
759 wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
760 CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :"
761 "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
762 ie_buf[pos+1], ie_buf[pos+2]));
763 ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
764 VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
765 }
766 pos += ie_len;
767 }
768 }
769 }
770#undef IE_TYPE
771#undef IE_TYPE_LEN
772exit:
773 return ret;
774}
775
776/* Clear the manament IE buffer of BSSCFG
777 * Parameters:
778 * @wl : wl_private data
779 * @bssidx : bssidx for BSS
780 *
781 * Returns 0 if success.
782 */
783s32
784wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx)
785{
786#define INIT_IE(IE_TYPE, BSS_TYPE) \
787 do { \
788 memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
789 sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
790 wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
791 } while (0);
792 if (bssidx < 0) {
793 CFGP2P_ERR(("invalid bssidx\n"));
794 return BCME_BADARG;
795 }
796 INIT_IE(probe_req, bssidx);
797 INIT_IE(probe_res, bssidx);
798 INIT_IE(assoc_req, bssidx);
799 INIT_IE(assoc_res, bssidx);
800 INIT_IE(beacon, bssidx);
801 return BCME_OK;
802}
803
804
805/* Is any of the tlvs the expected entry? If
806 * not update the tlvs buffer pointer/length.
807 */
808static bool
809wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
810{
811 /* If the contents match the OUI and the type */
812 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
813 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
814 type == ie[TLV_BODY_OFF + oui_len]) {
815 return TRUE;
816 }
817
818 if (tlvs == NULL)
819 return FALSE;
820 /* point to the next ie */
821 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
822 /* calculate the length of the rest of the buffer */
823 *tlvs_len -= (int)(ie - *tlvs);
824 /* update the pointer to the start of the buffer */
825 *tlvs = ie;
826
827 return FALSE;
828}
829
830wpa_ie_fixed_t *
831wl_cfgp2p_find_wpaie(u8 *parse, u32 len)
832{
833 bcm_tlv_t *ie;
834
835 while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
836 if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) {
837 return (wpa_ie_fixed_t *)ie;
838 }
839 }
840 return NULL;
841}
842
843wpa_ie_fixed_t *
844wl_cfgp2p_find_wpsie(u8 *parse, u32 len)
845{
846 bcm_tlv_t *ie;
847
848 while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
849 if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) {
850 return (wpa_ie_fixed_t *)ie;
851 }
852 }
853 return NULL;
854}
855
856wifi_p2p_ie_t *
857wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
858{
859 bcm_tlv_t *ie;
860
861 while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
862 if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) {
863 return (wifi_p2p_ie_t *)ie;
864 }
865 }
866 return NULL;
867}
868
869static s32
870wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
871 s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete)
872{
873 s32 err = BCME_OK;
874 s32 buf_len;
875 s32 iecount;
876
877 vndr_ie_setbuf_t *ie_setbuf;
878
879 /* Validate the pktflag parameter */
880 if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
881 VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
882 VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) {
883 CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag));
884 return -1;
885 }
886
887 buf_len = sizeof(vndr_ie_setbuf_t) + data_len - 1;
888 ie_setbuf = (vndr_ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
889
890 CFGP2P_INFO((" ie_id : %02x, data length : %d\n", ie_id, data_len));
891 if (!ie_setbuf) {
892
893 CFGP2P_ERR(("Error allocating buffer for IE\n"));
894 return -ENOMEM;
895 }
896 if (delete)
897 strcpy(ie_setbuf->cmd, "del");
898 else
899 strcpy(ie_setbuf->cmd, "add");
900 /* Buffer contains only 1 IE */
901 iecount = htod32(1);
902 memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
903 pktflag = htod32(pktflag);
904 memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
905 &pktflag, sizeof(uint32));
906 ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id;
907 ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len
908 = (uchar)(data_len + VNDR_IE_MIN_LEN);
909 memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3);
910 memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len);
911 err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len,
912 ioctlbuf, sizeof(ioctlbuf), bssidx);
913
914 CFGP2P_INFO(("vndr_ie iovar returns %d\n", err));
915 kfree(ie_setbuf);
916 return err;
917}
918
919/*
920 * Search the bssidx based on dev argument
921 * Parameters:
922 * @wl : wl_private data
923 * @ndev : net device to search bssidx
924 * Returns bssidx for ndev
925 */
926s32
927wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev)
928{
929 u32 i;
930 s32 index = -1;
931
932 if (ndev == NULL) {
933 CFGP2P_ERR((" ndev is NULL\n"));
934 goto exit;
935 }
936 if (!wl->p2p_supported) {
937 return P2PAPI_BSSCFG_PRIMARY;
938 }
939 for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
940 if (ndev == wl_to_p2p_bss_ndev(wl, i)) {
941 index = wl_to_p2p_bss_bssidx(wl, i);
942 break;
943 }
944 }
945 if (index == -1)
946 return P2PAPI_BSSCFG_PRIMARY;
947exit:
948 return index;
949}
950/*
951 * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
952 */
953s32
954wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev,
955 const wl_event_msg_t *e, void *data)
956{
957 s32 ret = BCME_OK;
958
959 CFGP2P_DBG((" Enter\n"));
960 if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) {
961 wl_set_p2p_status(wl, LISTEN_EXPIRED);
962 if (timer_pending(&wl->p2p->listen_timer)) {
963 spin_lock_bh(&wl->p2p->timer_lock);
964 del_timer_sync(&wl->p2p->listen_timer);
965 spin_unlock_bh(&wl->p2p->timer_lock);
966 }
967 cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan,
968 wl->remain_on_chan_type, GFP_KERNEL);
969 } else
970 wl_clr_p2p_status(wl, LISTEN_EXPIRED);
971
972 return ret;
973
974}
975
976/*
977 * Timer expire callback function for LISTEN
978 * We can't report cfg80211_remain_on_channel_expired from Timer ISR context,
979 * so lets do it from thread context.
980 */
981static void
982wl_cfgp2p_listen_expired(unsigned long data)
983{
984 wl_event_msg_t msg;
985 struct wl_priv *wl = (struct wl_priv *) data;
986
987 CFGP2P_DBG((" Enter\n"));
988 msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE);
989 wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL);
990}
991
992/*
993 * Do a P2P Listen on the given channel for the given duration.
994 * A listen consists of sitting idle and responding to P2P probe requests
995 * with a P2P probe response.
996 *
997 * This fn assumes dongle p2p device discovery is already enabled.
998 * Parameters :
999 * @wl : wl_private data
1000 * @channel : channel to listen
1001 * @duration_ms : the time (milli seconds) to wait
1002 */
1003s32
1004wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms)
1005{
1006#define INIT_TIMER(timer, func, duration, extra_delay) \
1007 do { \
1008 init_timer(timer); \
1009 timer->function = func; \
1010 timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \
1011 timer->data = (unsigned long) wl; \
1012 add_timer(timer); \
1013 } while (0);
1014
1015 s32 ret = BCME_OK;
1016 struct timer_list *_timer;
1017 CFGP2P_DBG((" Enter Channel : %d, Duration : %d\n", channel, duration_ms));
1018 if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) {
1019
1020 CFGP2P_ERR((" Discovery is not set, so we have noting to do\n"));
1021
1022 ret = BCME_NOTREADY;
1023 goto exit;
1024 }
1025 if (timer_pending(&wl->p2p->listen_timer)) {
1026 CFGP2P_DBG(("previous LISTEN is not completed yet\n"));
1027 goto exit;
1028
1029 } else
1030 wl_clr_p2p_status(wl, LISTEN_EXPIRED);
1031
1032 wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
1033 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
1034 _timer = &wl->p2p->listen_timer;
1035
1036 /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
1037 * otherwise we will wait up to duration_ms + 200ms
1038 */
1039 INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, 200);
1040
1041#undef INIT_TIMER
1042exit:
1043 return ret;
1044}
1045
1046
1047s32
1048wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable)
1049{
1050 s32 ret = BCME_OK;
1051 CFGP2P_DBG((" Enter\n"));
1052 if (!wl_get_p2p_status(wl, DISCOVERY_ON)) {
1053
1054 CFGP2P_DBG((" do nothing, discovery is off\n"));
1055 return ret;
1056 }
1057 if (wl_get_p2p_status(wl, SEARCH_ENABLED) == enable) {
1058 CFGP2P_DBG(("already : %d\n", enable));
1059 return ret;
1060 }
1061
1062 wl_chg_p2p_status(wl, SEARCH_ENABLED);
1063 /* When disabling Search, reset the WL driver's p2p discovery state to
1064 * WL_P2P_DISC_ST_SCAN.
1065 */
1066 if (!enable) {
1067 wl_clr_p2p_status(wl, SCANNING);
1068 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
1069 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
1070 }
1071
1072 return ret;
1073}
1074
1075/*
1076 * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
1077 */
1078s32
1079wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev,
1080 const wl_event_msg_t *e, void *data)
1081{
1082 s32 ret = BCME_OK;
1083 u32 event_type = ntoh32(e->event_type);
1084 u32 status = ntoh32(e->status);
1085 CFGP2P_DBG((" Enter\n"));
1086 if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
1087
1088 CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
1089 if (status == WLC_E_STATUS_SUCCESS) {
1090 wl_set_p2p_status(wl, ACTION_TX_COMPLETED);
1091 }
1092 else {
1093 wl_set_p2p_status(wl, ACTION_TX_NOACK);
1094 CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
1095 }
1096 wake_up_interruptible(&wl->dongle_event_wait);
1097 } else {
1098 CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
1099 "status : %d\n", status));
1100 }
1101 return ret;
1102}
1103/* Send an action frame immediately without doing channel synchronization.
1104 *
1105 * This function does not wait for a completion event before returning.
1106 * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
1107 * frame is transmitted.
1108 * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an
1109 * 802.11 ack has been received for the sent action frame.
1110 */
1111s32
1112wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
1113 wl_af_params_t *af_params, s32 bssidx)
1114{
1115 s32 ret = BCME_OK;
1116 s32 timeout = 0;
1117
1118
1119 CFGP2P_INFO(("\n"));
1120 CFGP2P_INFO(("channel : %u , dwell time : %u\n",
1121 af_params->channel, af_params->dwell_time));
1122
1123 wl_clr_p2p_status(wl, ACTION_TX_COMPLETED);
1124 wl_clr_p2p_status(wl, ACTION_TX_NOACK);
1125#define MAX_WAIT_TIME 2000
1126 if (bssidx == P2PAPI_BSSCFG_PRIMARY)
1127 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
1128
1129 ret = wldev_iovar_setbuf_bsscfg(dev, "actframe",
1130 af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf), bssidx);
1131
1132 if (ret < 0) {
1133
1134 CFGP2P_ERR((" sending action frame is failed\n"));
1135 goto exit;
1136 }
1137 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
1138 (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)),
1139 msecs_to_jiffies(MAX_WAIT_TIME));
1140
1141 if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) {
1142 CFGP2P_INFO(("tx action frame operation is completed\n"));
1143 ret = BCME_OK;
1144 } else {
1145 ret = BCME_ERROR;
1146 CFGP2P_INFO(("tx action frame operation is failed\n"));
1147 }
1148exit:
1149 CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
1150#undef MAX_WAIT_TIME
1151 return ret;
1152}
1153
1154/* Generate our P2P Device Address and P2P Interface Address from our primary
1155 * MAC address.
1156 */
1157void
1158wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr,
1159 struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr)
1160{
1161 memset(out_dev_addr, 0, sizeof(*out_dev_addr));
1162 memset(out_int_addr, 0, sizeof(*out_int_addr));
1163
1164 /* Generate the P2P Device Address. This consists of the device's
1165 * primary MAC address with the locally administered bit set.
1166 */
1167 memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr));
1168 out_dev_addr->octet[0] |= 0x02;
1169
1170 /* Generate the P2P Interface Address. If the discovery and connection
1171 * BSSCFGs need to simultaneously co-exist, then this address must be
1172 * different from the P2P Device Address.
1173 */
1174 memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr));
1175 out_int_addr->octet[4] ^= 0x80;
1176
1177}
1178
1179/* P2P IF Address change to Virtual Interface MAC Address */
1180void
1181wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id)
1182{
1183 wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf;
1184 u16 len = ie->len;
1185 u8 *subel;
1186 u8 subelt_id;
1187 u16 subelt_len;
1188 CFGP2P_DBG((" Enter\n"));
1189
1190 /* Point subel to the P2P IE's subelt field.
1191 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
1192 */
1193 subel = ie->subelts;
1194 len -= 4; /* exclude OUI + OUI_TYPE */
1195
1196 while (len >= 3) {
1197 /* attribute id */
1198 subelt_id = *subel;
1199 subel += 1;
1200 len -= 1;
1201
1202 /* 2-byte little endian */
1203 subelt_len = *subel++;
1204 subelt_len |= *subel++ << 8;
1205
1206 len -= 2;
1207 len -= subelt_len; /* for the remaining subelt fields */
1208
1209 if (subelt_id == element_id) {
1210 if (subelt_id == P2P_SEID_INTINTADDR) {
1211 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1212 CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n"));
1213 } else if (subelt_id == P2P_SEID_DEV_ID) {
1214 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1215 CFGP2P_INFO(("Device ID ATTR FOUND\n"));
1216 } else if (subelt_id == P2P_SEID_DEV_INFO) {
1217 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1218 CFGP2P_INFO(("Device INFO ATTR FOUND\n"));
1219 } else if (subelt_id == P2P_SEID_GROUP_ID) {
1220 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1221 CFGP2P_INFO(("GROUP ID ATTR FOUND\n"));
1222 } return;
1223 } else {
1224 CFGP2P_DBG(("OTHER id : %d\n", subelt_id));
1225 }
1226 subel += subelt_len;
1227 }
1228}
1229/*
1230 * Check if a BSS is up.
1231 * This is a common implementation called by most OSL implementations of
1232 * p2posl_bss_isup(). DO NOT call this function directly from the
1233 * common code -- call p2posl_bss_isup() instead to allow the OSL to
1234 * override the common implementation if necessary.
1235 */
1236bool
1237wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
1238{
1239 s32 result, val;
1240 bool isup = false;
1241 s8 getbuf[64];
1242
1243 /* Check if the BSS is up */
1244 *(int*)getbuf = -1;
1245 result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
1246 sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0);
1247 if (result != 0) {
1248 CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result));
1249 CFGP2P_ERR(("NOTE: this ioctl error is normal "
1250 "when the BSS has not been created yet.\n"));
1251 } else {
1252 val = *(int*)getbuf;
1253 val = dtoh32(val);
1254 CFGP2P_INFO(("---wl bss -C %d ==> %d\n", bsscfg_idx, val));
1255 isup = (val ? TRUE : FALSE);
1256 }
1257 return isup;
1258}
1259
1260
1261/* Bring up or down a BSS */
1262s32
1263wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up)
1264{
1265 s32 ret = BCME_OK;
1266 s32 val = up ? 1 : 0;
1267
1268 struct {
1269 s32 cfg;
1270 s32 val;
1271 } bss_setbuf;
1272
1273 bss_setbuf.cfg = htod32(bsscfg_idx);
1274 bss_setbuf.val = htod32(val);
1275 CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"));
1276 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
1277 ioctlbuf, sizeof(ioctlbuf));
1278
1279 if (ret != 0) {
1280 CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret));
1281 }
1282
1283 return ret;
1284}
1285
1286/* Check if 'p2p' is supported in the driver */
1287s32
1288wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
1289{
1290 s32 ret = BCME_OK;
1291 s32 p2p_supported = 0;
1292 ret = wldev_iovar_getint(ndev, "p2p",
1293 &p2p_supported);
1294 if (ret < 0) {
1295 CFGP2P_ERR(("wl p2p error %d\n", ret));
1296 return 0;
1297 }
1298 if (p2p_supported == 1) {
1299 CFGP2P_INFO(("p2p is supported\n"));
1300 } else {
1301 CFGP2P_INFO(("p2p is unsupported\n"));
1302 p2p_supported = 0;
1303 }
1304 return p2p_supported;
1305}
1306
1307/* Cleanup P2P resources */
1308s32
1309wl_cfgp2p_down(struct wl_priv *wl)
1310{
1311 if (timer_pending(&wl->p2p->listen_timer))
1312 del_timer_sync(&wl->p2p->listen_timer);
1313 wl_cfgp2p_deinit_priv(wl);
1314 return 0;
1315}
1316
1317s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
1318{
1319 s32 ret = -1;
1320 int count, start, duration;
1321 wl_p2p_sched_t dongle_noa;
1322
1323 CFGP2P_DBG((" Enter\n"));
1324
1325 memset(&dongle_noa, 0, sizeof(dongle_noa));
1326
1327 if (wl->p2p && wl->p2p->vif_created) {
1328
1329 wl->p2p->noa.desc[0].start = 0;
1330
1331 sscanf(buf, "%d %d %d", &count, &start, &duration);
1332 CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
1333 count, start, duration));
1334 if (count != -1)
1335 wl->p2p->noa.desc[0].count = count;
1336
1337 /* supplicant gives interval as start */
1338 if (start != -1)
1339 wl->p2p->noa.desc[0].interval = start;
1340
1341 if (duration != -1)
1342 wl->p2p->noa.desc[0].duration = duration;
1343
1344 if (wl->p2p->noa.desc[0].count != 255) {
1345 wl->p2p->noa.desc[0].start = 200;
1346 dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS;
1347 dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF;
1348 dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS;
1349 }
1350 else {
1351 /* Continuous NoA interval. */
1352 dongle_noa.action = WL_P2P_SCHED_ACTION_NONE;
1353 dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
1354 if ((wl->p2p->noa.desc[0].interval == 102) ||
1355 (wl->p2p->noa.desc[0].interval == 100)) {
1356 wl->p2p->noa.desc[0].start = 100 -
1357 wl->p2p->noa.desc[0].duration;
1358 dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT;
1359 }
1360 else {
1361 dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
1362 }
1363 }
1364 /* Put the noa descriptor in dongle format for dongle */
1365 dongle_noa.desc[0].count = htod32(wl->p2p->noa.desc[0].count);
1366 if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) {
1367 dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start);
1368 dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration);
1369 }
1370 else {
1371 dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start*1000);
1372 dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration*1000);
1373 }
1374 dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000);
1375
1376 ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
1377 "p2p_noa", &dongle_noa, sizeof(dongle_noa), ioctlbuf, sizeof(ioctlbuf));
1378
1379 if (ret < 0) {
1380 CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
1381 }
1382 }
1383 else {
1384 CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n"));
1385 }
1386 return ret;
1387}
1388
1389s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len)
1390{
1391 wifi_p2p_noa_desc_t *noa_desc;
1392 int len = 0, i;
1393 char _buf[200];
1394
1395 CFGP2P_DBG((" Enter\n"));
1396 buf[0] = '\0';
1397 if (wl->p2p && wl->p2p->vif_created) {
1398 if (wl->p2p->noa.desc[0].count || wl->p2p->ops.ops) {
1399 _buf[0] = 1; /* noa index */
1400 _buf[1] = (wl->p2p->ops.ops ? 0x80: 0) |
1401 (wl->p2p->ops.ctw & 0x7f); /* ops + ctw */
1402 len += 2;
1403 if (wl->p2p->noa.desc[0].count) {
1404 noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len];
1405 noa_desc->cnt_type = wl->p2p->noa.desc[0].count;
1406 noa_desc->duration = wl->p2p->noa.desc[0].duration;
1407 noa_desc->interval = wl->p2p->noa.desc[0].interval;
1408 noa_desc->start = wl->p2p->noa.desc[0].start;
1409 len += sizeof(wifi_p2p_noa_desc_t);
1410 }
1411 if (buf_len <= len * 2) {
1412 CFGP2P_ERR(("ERROR: buf_len %d in not enough for"
1413 "returning noa in string format\n", buf_len));
1414 return -1;
1415 }
1416 /* We have to convert the buffer data into ASCII strings */
1417 for (i = 0; i < len; i++) {
1418 sprintf(buf, "%02x", _buf[i]);
1419 buf += 2;
1420 }
1421 buf[i*2] = '\0';
1422 }
1423 }
1424 else {
1425 CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n"));
1426 return -1;
1427 }
1428 return len * 2;
1429}
1430
1431s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
1432{
1433 int ps, ctw;
1434 int ret = -1;
1435 s32 legacy_ps;
1436
1437 CFGP2P_DBG((" Enter\n"));
1438 if (wl->p2p && wl->p2p->vif_created) {
1439 sscanf(buf, "%d %d %d", &legacy_ps, &ps, &ctw);
1440 CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw));
1441 if (ctw != -1) {
1442 wl->p2p->ops.ctw = ctw;
1443 ret = 0;
1444 }
1445 if (ps != -1) {
1446 wl->p2p->ops.ops = ps;
1447 ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
1448 "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops),
1449 ioctlbuf, sizeof(ioctlbuf));
1450 if (ret < 0) {
1451 CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
1452 }
1453 }
1454
1455 if (legacy_ps != -1) {
1456 s32 pm = legacy_ps ? PM_MAX : PM_OFF;
1457 ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
1458 WLC_SET_PM, &pm, sizeof(pm), true);
1459 if (unlikely(ret)) {
1460 CFGP2P_ERR(("error (%d)\n", ret));
1461 }
1462 }
1463 }
1464 else {
1465 CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n"));
1466 ret = -1;
1467 }
1468 return ret;
1469}