3d7b54841529a28bf5ef9b28a068a6eff5c5de7e
[linux-2.6.git] / drivers / net / wireless / bcmdhd / wl_cfgp2p.c
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 Exp $
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
52 static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
53 static s8 scanparambuf[WLC_IOCTL_SMLEN];
54 static s8 *smbuf = ioctlbuf;
55
56 static bool
57 wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
58
59 static s32
60 wl_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  */
66 s32
67 wl_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
103         return BCME_OK;
104
105 }
106 /*
107  *  Deinitialize variables related to P2P
108  *
109  */
110 void
111 wl_cfgp2p_deinit_priv(struct wl_priv *wl)
112 {
113         if (wl->p2p) {
114                 kfree(wl->p2p);
115         }
116         wl->p2p_supported = 0;
117 }
118 /*
119  * Set P2P functions into firmware
120  */
121 s32
122 wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
123 {
124         struct net_device *ndev = wl_to_prmry_ndev(wl);
125         s32 ret = BCME_OK;
126         s32 val = 0;
127         /* Do we have to check whether APSTA is enabled or not ? */
128         wldev_iovar_getint(ndev, "apsta", &val);
129         if (val == 0) {
130                 val = 1;
131                 wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), false);
132                 wldev_iovar_setint(ndev, "apsta", val);
133                 wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), false);
134         }
135         return ret;
136 }
137
138 /* Create a new P2P BSS.
139  * Parameters:
140  * @mac      : MAC address of the BSS to create
141  * @if_type  : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT
142  * @chspec   : chspec to use if creating a GO BSS.
143  * Returns 0 if success.
144  */
145 s32
146 wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
147             chanspec_t chspec)
148 {
149         wl_p2p_if_t ifreq;
150         s32 err;
151         struct net_device *ndev = wl_to_prmry_ndev(wl);
152
153         ifreq.type = if_type;
154         ifreq.chspec = chspec;
155         memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
156
157         CFGP2P_INFO(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
158             ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
159                 ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
160                 (if_type == WL_P2P_IF_GO) ? "go" : "client",
161                 (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
162
163         err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
164                 ioctlbuf, sizeof(ioctlbuf));
165         return err;
166 }
167
168 /* Delete a P2P BSS.
169  * Parameters:
170  * @mac      : MAC address of the BSS to create
171  * Returns 0 if success.
172  */
173 s32
174 wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac)
175 {
176         s32 ret;
177         struct net_device *netdev = wl_to_prmry_ndev(wl);
178
179         CFGP2P_INFO(("---wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n",
180             mac->octet[0], mac->octet[1], mac->octet[2],
181             mac->octet[3], mac->octet[4], mac->octet[5]));
182
183         ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
184                 ioctlbuf, sizeof(ioctlbuf));
185
186         if (unlikely(ret < 0)) {
187                 printk("'wl p2p_ifdel' error %d\n", ret);
188         }
189         return ret;
190 }
191
192 /* Change a P2P Role.
193  * Parameters:
194  * @mac      : MAC address of the BSS to change a role
195  * Returns 0 if success.
196  */
197 s32
198 wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
199             chanspec_t chspec)
200 {
201         wl_p2p_if_t ifreq;
202         s32 err;
203         struct net_device *netdev =  wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
204
205         ifreq.type = if_type;
206         ifreq.chspec = chspec;
207         memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
208
209         CFGP2P_INFO(("---wl p2p_ifchange %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
210             ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
211             ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
212             (if_type == WL_P2P_IF_GO) ? "go" : "client",
213                 (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
214
215         err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
216                 ioctlbuf, sizeof(ioctlbuf));
217
218         if (unlikely(err < 0)) {
219                 printk("'wl p2p_ifupd' error %d\n", err);
220         }
221         return err;
222 }
223
224
225 /* Get the index of a created P2P BSS.
226  * Parameters:
227  * @mac      : MAC address of the created BSS
228  * @index    : output: index of created BSS
229  * Returns 0 if success.
230  */
231 s32
232 wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index)
233 {
234         s32 ret;
235         u8 getbuf[64];
236         struct net_device *dev = wl_to_prmry_ndev(wl);
237
238         CFGP2P_INFO(("---wl p2p_if %02x:%02x:%02x:%02x:%02x:%02x\n",
239             mac->octet[0], mac->octet[1], mac->octet[2],
240             mac->octet[3], mac->octet[4], mac->octet[5]));
241
242         ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac),
243                     getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY));
244
245         if (ret == 0) {
246                 memcpy(index, getbuf, sizeof(index));
247                 CFGP2P_INFO(("---wl p2p_if   ==> %d\n", *index));
248         }
249
250         return ret;
251 }
252
253 s32
254 wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on)
255 {
256         s32 ret = BCME_OK;
257         struct net_device *ndev = wl_to_prmry_ndev(wl);
258         CFGP2P_DBG(("enter\n"));
259
260         ret = wldev_iovar_setint(ndev, "p2p_disc", on);
261
262         if (unlikely(ret < 0)) {
263                 CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret));
264         }
265
266         return ret;
267 }
268
269 /* Set the WL driver's P2P mode.
270  * Parameters :
271  * @mode      : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}.
272  * @channel   : the channel to listen
273  * @listen_ms : the time (milli seconds) to wait
274  * @bssidx    : bss index for BSSCFG
275  * Returns 0 if success
276  */
277
278 s32
279 wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, int bssidx)
280 {
281         wl_p2p_disc_st_t discovery_mode;
282         s32 ret;
283         struct net_device *dev;
284         CFGP2P_DBG(("enter\n"));
285
286         if (unlikely(bssidx >= P2PAPI_BSSCFG_MAX)) {
287                 CFGP2P_ERR((" %d index out of range\n", bssidx));
288                 return -1;
289         }
290
291         dev = wl_to_p2p_bss_ndev(wl, bssidx);
292         if (unlikely(dev == NULL)) {
293                 CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx));
294                 return BCME_NOTFOUND;
295         }
296
297         /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */
298         discovery_mode.state = mode;
299         discovery_mode.chspec = CH20MHZ_CHSPEC(channel);
300         discovery_mode.dwell = listen_ms;
301         ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
302                     sizeof(discovery_mode), ioctlbuf, sizeof(ioctlbuf), bssidx);
303
304         return ret;
305 }
306
307 /* Get the index of the P2P Discovery BSS */
308 s32
309 wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index)
310 {
311         s32 ret;
312         struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
313
314         ret = wldev_iovar_getint(dev, "p2p_dev", index);
315         CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret));
316
317         if (unlikely(ret <  0)) {
318             CFGP2P_ERR(("'p2p_dev' error %d\n", ret));
319                 return ret;
320         }
321         return ret;
322 }
323
324 s32
325 wl_cfgp2p_init_discovery(struct wl_priv *wl)
326 {
327
328         s32 index = 0;
329         s32 ret = BCME_OK;
330
331         CFGP2P_DBG(("enter\n"));
332
333         if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) != 0) {
334                 CFGP2P_ERR(("do nothing, already initialized\n"));
335                 return ret;
336         }
337
338         ret = wl_cfgp2p_set_discovery(wl, 1);
339         if (ret < 0) {
340                 CFGP2P_ERR(("set discover error\n"));
341                 return ret;
342         }
343         /* Enable P2P Discovery in the WL Driver */
344         ret = wl_cfgp2p_get_disc_idx(wl, &index);
345
346         if (ret < 0) {
347                 return ret;
348         }
349         wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) =
350             wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
351         wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = index;
352
353         /* Set the initial discovery state to SCAN */
354         ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
355                 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
356
357         if (unlikely(ret != 0)) {
358                 CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
359                 wl_cfgp2p_set_discovery(wl, 0);
360                 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
361                 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
362                 return 0;
363         }
364         return ret;
365 }
366
367 /* Deinitialize P2P Discovery
368  * Parameters :
369  * @wl        : wl_private data
370  * Returns 0 if succes
371  */
372 s32
373 wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
374 {
375         s32 ret = BCME_OK;
376         CFGP2P_DBG(("enter\n"));
377
378         if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) {
379                 CFGP2P_ERR(("do nothing, not initialized\n"));
380                 return -1;
381         }
382         /* Set the discovery state to SCAN */
383         ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
384                     wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
385         /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
386         ret = wl_cfgp2p_set_discovery(wl, 0);
387
388         /* Clear our saved WPS and P2P IEs for the discovery BSS.  The driver
389          * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery
390          * BSS.
391          */
392
393         /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we
394          * have no discovery BSS.
395          */
396         wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
397         wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
398
399         return ret;
400
401 }
402 /* Enable P2P Discovery
403  * Parameters:
404  * @wl  : wl_private data
405  * @ie  : probe request ie (WPS IE + P2P IE)
406  * @ie_len   : probe request ie length
407  * Returns 0 if success.
408  */
409 s32
410 wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len)
411 {
412         s32 ret = BCME_OK;
413         if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
414                 CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
415                 goto set_ie;
416         }
417
418         wl_set_p2p_status(wl, DISCOVERY_ON);
419
420         CFGP2P_DBG(("enter\n"));
421
422         ret = wl_cfgp2p_init_discovery(wl);
423         if (unlikely(ret < 0)) {
424                 CFGP2P_ERR((" init discovery error %d\n", ret));
425                 goto exit;
426         }
427         /* Set wsec to any non-zero value in the discovery bsscfg to ensure our
428          * P2P probe responses have the privacy bit set in the 802.11 WPA IE.
429          * Some peer devices may not initiate WPS with us if this bit is not set.
430          */
431         ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE),
432                         "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
433         if (unlikely(ret < 0)) {
434                 CFGP2P_ERR((" wsec error %d\n", ret));
435         }
436 set_ie:
437         ret = wl_cfgp2p_set_management_ie(wl, dev,
438                     wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE),
439                     VNDR_IE_PRBREQ_FLAG, ie, ie_len);
440
441         if (unlikely(ret < 0)) {
442                 CFGP2P_ERR(("set probreq ie occurs error %d\n", ret));
443                 goto exit;
444         }
445 exit:
446         return ret;
447 }
448
449 /* Disable P2P Discovery
450  * Parameters:
451  * @wl       : wl_private_data
452  * Returns 0 if success.
453  */
454 s32
455 wl_cfgp2p_disable_discovery(struct wl_priv *wl)
456 {
457         s32 ret = BCME_OK;
458         CFGP2P_DBG((" enter\n"));
459         wl_clr_p2p_status(wl, DISCOVERY_ON);
460
461         if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) {
462                 CFGP2P_ERR((" do nothing, not initialized\n"));
463                 goto exit;
464         }
465
466         ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
467                     wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
468
469         if (unlikely(ret < 0)) {
470
471                 CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
472         }
473         /* Do a scan abort to stop the driver's scan engine in case it is still
474          * waiting out an action frame tx dwell time.
475          */
476 #ifdef NOT_YET
477         if (wl_get_p2p_status(wl, SCANNING)) {
478                 p2pwlu_scan_abort(hdl, FALSE);
479         }
480 #endif
481         wl_clr_p2p_status(wl, DISCOVERY_ON);
482         ret = wl_cfgp2p_deinit_discovery(wl);
483
484 exit:
485         return ret;
486 }
487
488 s32
489 wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
490         u32 num_chans, u16 *channels,
491         s32 search_state, u16 action, u32 bssidx)
492 {
493         s32 ret = BCME_OK;
494         s32 memsize;
495         s32 eparams_size;
496         u32 i;
497         s8 *memblk;
498         wl_p2p_scan_t *p2p_params;
499         wl_escan_params_t *eparams;
500         wlc_ssid_t ssid;
501         /* Scan parameters */
502 #define P2PAPI_SCAN_NPROBES 1
503 #define P2PAPI_SCAN_DWELL_TIME_MS 40
504 #define P2PAPI_SCAN_HOME_TIME_MS 10
505
506         wl_set_p2p_status(wl, SCANNING);
507         /* Allocate scan params which need space for 3 channels and 0 ssids */
508         eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE +
509             OFFSETOF(wl_escan_params_t, params)) +
510                 num_chans * sizeof(eparams->params.channel_list[0]);
511
512         memsize = sizeof(wl_p2p_scan_t) + eparams_size;
513         memblk = scanparambuf;
514         if (memsize > sizeof(scanparambuf)) {
515                 CFGP2P_ERR((" scanpar buf too small (%u > %u)\n",
516                     memsize, sizeof(scanparambuf)));
517                 return -1;
518         }
519         memset(memblk, 0, memsize);
520         memset(ioctlbuf, 0, sizeof(ioctlbuf));
521         if (search_state == WL_P2P_DISC_ST_SEARCH) {
522                 /*
523                  * If we in SEARCH STATE, we don't need to set SSID explictly
524                  * because dongle use P2P WILDCARD internally by default
525                  */
526                 wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx);
527                 ssid.SSID_len = htod32(0);
528
529         } else if (search_state == WL_P2P_DISC_ST_SCAN) {
530                 /* SCAN STATE 802.11 SCAN
531                  * WFD Supplicant has p2p_find command with (type=progressive, type= full)
532                  * So if P2P_find command with type=progressive,
533                  * we have to set ssid to P2P WILDCARD because
534                  * we just do broadcast scan unless setting SSID
535                  */
536                 strcpy(ssid.SSID, WL_P2P_WILDCARD_SSID);
537                 ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN);
538                 wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
539         }
540
541
542         /* Fill in the P2P scan structure at the start of the iovar param block */
543         p2p_params = (wl_p2p_scan_t*) memblk;
544         p2p_params->type = 'E';
545         /* Fill in the Scan structure that follows the P2P scan structure */
546         eparams = (wl_escan_params_t*) (p2p_params + 1);
547         eparams->params.bss_type = DOT11_BSSTYPE_ANY;
548         if (active)
549                 eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE;
550         else
551                 eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE;
552
553         memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
554         if (ssid.SSID_len)
555                 memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t));
556
557         eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES);
558         eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
559         eparams->params.active_time = htod32(-1);
560         eparams->params.passive_time = htod32(-1);
561         eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
562             (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
563
564         for (i = 0; i < num_chans; i++) {
565                 eparams->params.channel_list[i] = htodchanspec(channels[i]);
566         }
567         eparams->version = htod32(ESCAN_REQ_VERSION);
568         eparams->action =  htod16(action);
569         eparams->sync_id = htod16(0x1234);
570         CFGP2P_INFO(("SCAN CHANNELS : "));
571
572         for (i = 0; i < num_chans; i++) {
573                 if (i == 0) CFGP2P_INFO(("%d", channels[i]));
574                 else CFGP2P_INFO((",%d", channels[i]));
575         }
576
577         CFGP2P_INFO(("\n"));
578
579         ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_scan",
580                     memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx);
581         return ret;
582 }
583 /* Check whether pointed-to IE looks like WPA. */
584 #define wl_cfgp2p_is_wpa_ie(ie, tlvs, len)      wl_cfgp2p_has_ie(ie, tlvs, len, \
585                 (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
586 /* Check whether pointed-to IE looks like WPS. */
587 #define wl_cfgp2p_is_wps_ie(ie, tlvs, len)      wl_cfgp2p_has_ie(ie, tlvs, len, \
588                 (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE)
589 /* Check whether the given IE looks like WFA P2P IE. */
590 #define wl_cfgp2p_is_p2p_ie(ie, tlvs, len)      wl_cfgp2p_has_ie(ie, tlvs, len, \
591                 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
592 /* Delete and Set a management vndr ie to firmware
593  * Parameters:
594  * @wl       : wl_private data
595  * @ndev     : net device for bssidx
596  * @bssidx   : bssidx for BSS
597  * @pktflag  : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
598  *                                 VNDR_IE_ASSOCREQ_FLAG)
599  * @ie       :  VNDR IE (such as P2P IE , WPS IE)
600  * @ie_len   : VNDR IE Length
601  * Returns 0 if success.
602  */
603
604 s32
605 wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
606     s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
607 {
608         /* Vendor-specific Information Element ID */
609 #define VNDR_SPEC_ELEMENT_ID 0xdd
610         s32 ret = BCME_OK;
611         u32 pos;
612         u8  *ie_buf;
613         u8  *mgmt_ie_buf;
614         u32 mgmt_ie_buf_len;
615         u32 *mgmt_ie_len;
616         u8 ie_id, ie_len;
617         u8 delete = 0;
618 #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
619 #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
620         if (bssidx == -1)
621                 return BCME_BADARG;
622         if (wl->p2p_supported && p2p_on(wl)) {
623                 if (bssidx == P2PAPI_BSSCFG_PRIMARY)
624                         bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
625                 switch (pktflag) {
626                         case VNDR_IE_PRBREQ_FLAG :
627                                 mgmt_ie_buf = IE_TYPE(probe_req, bssidx);
628                                 mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx);
629                                 mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx));
630                                 break;
631                         case VNDR_IE_PRBRSP_FLAG :
632                                 mgmt_ie_buf = IE_TYPE(probe_res, bssidx);
633                                 mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx);
634                                 mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx));
635                                 break;
636                         case VNDR_IE_ASSOCREQ_FLAG :
637                                 mgmt_ie_buf = IE_TYPE(assoc_req, bssidx);
638                                 mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx);
639                                 mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx));
640                                 break;
641                         case VNDR_IE_ASSOCRSP_FLAG :
642                                 mgmt_ie_buf = IE_TYPE(assoc_res, bssidx);
643                                 mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx);
644                                 mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx));
645                                 break;
646                         case VNDR_IE_BEACON_FLAG :
647                                 mgmt_ie_buf = IE_TYPE(beacon, bssidx);
648                                 mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx);
649                                 mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx));
650                                 break;
651                         default:
652                                 mgmt_ie_buf = NULL;
653                                 mgmt_ie_len = NULL;
654                                 CFGP2P_ERR(("not suitable type\n"));
655                                 return -1;
656                 }
657         } else {
658                 switch (pktflag) {
659                         case VNDR_IE_PRBRSP_FLAG :
660                                 mgmt_ie_buf = wl->ap_info->probe_res_ie;
661                                 mgmt_ie_len = &wl->ap_info->probe_res_ie_len;
662                                 mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie);
663                                 break;
664                         case VNDR_IE_BEACON_FLAG :
665                                 mgmt_ie_buf = wl->ap_info->beacon_ie;
666                                 mgmt_ie_len = &wl->ap_info->beacon_ie_len;
667                                 mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie);
668                                 break;
669                         default:
670                                 mgmt_ie_buf = NULL;
671                                 mgmt_ie_len = NULL;
672                                 CFGP2P_ERR(("not suitable type\n"));
673                                 return -1;
674                 }
675         }
676         /* Add if there is any extra IE */
677         if (vndr_ie && vndr_ie_len) {
678                 CFGP2P_INFO(("Request has extra IE"));
679                 if (vndr_ie_len > mgmt_ie_buf_len) {
680                         CFGP2P_ERR(("extra IE size too big\n"));
681                         ret = -ENOMEM;
682                 } else {
683                         if (mgmt_ie_buf != NULL) {
684                                 if ((vndr_ie_len == *mgmt_ie_len) &&
685                                      (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
686                                         CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
687                                         goto exit;
688                                 }
689                                 pos = 0;
690                                 delete = 1;
691                                 ie_buf = (u8 *) mgmt_ie_buf;
692                                 while (pos < *mgmt_ie_len) {
693                                         ie_id = ie_buf[pos++];
694                                         ie_len = ie_buf[pos++];
695                                         CFGP2P_INFO(("DELELED ID(%d), Len(%d),"
696                                                 "OUI(%02x:%02x:%02x)\n",
697                                                 ie_id, ie_len, ie_buf[pos],
698                                                 ie_buf[pos+1], ie_buf[pos+2]));
699                                         ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag,
700                                             ie_buf+pos, VNDR_SPEC_ELEMENT_ID,
701                                                 ie_buf+pos+3, ie_len-3, delete);
702                                         pos += ie_len;
703                                 }
704
705                         }
706                         /* save the current IE in wl struct */
707                         memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len);
708                         *mgmt_ie_len = vndr_ie_len;
709                         pos = 0;
710                         ie_buf = (u8 *) vndr_ie;
711                         delete = 0;
712                         while (pos < vndr_ie_len) {
713                                 ie_id = ie_buf[pos++];
714                                 ie_len = ie_buf[pos++];
715                                 if ((ie_id == DOT11_MNG_VS_ID) &&
716                                    (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
717                                         wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
718                                         CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :"
719                                                 "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
720                                                 ie_buf[pos+1], ie_buf[pos+2]));
721                                         ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
722                                             VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
723                                 }
724                                 pos += ie_len;
725                         }
726                 }
727
728         }
729 #undef IE_TYPE
730 #undef IE_TYPE_LEN
731 exit:
732         return ret;
733 }
734
735 /* Clear the manament IE buffer of BSSCFG
736  * Parameters:
737  * @wl       : wl_private data
738  * @bssidx   : bssidx for BSS
739  *
740  * Returns 0 if success.
741  */
742 s32
743 wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx)
744 {
745 #define INIT_IE(IE_TYPE, BSS_TYPE)              \
746         do {                                                    \
747                 memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
748                    sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
749                 wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
750         } while (0);
751         if (bssidx < 0) {
752                 CFGP2P_ERR(("invalid bssidx\n"));
753                 return BCME_BADARG;
754         }
755         INIT_IE(probe_req, bssidx);
756         INIT_IE(probe_res, bssidx);
757         INIT_IE(assoc_req, bssidx);
758         INIT_IE(assoc_res, bssidx);
759         INIT_IE(beacon, bssidx);
760         return BCME_OK;
761 }
762
763
764 /* Is any of the tlvs the expected entry? If
765  * not update the tlvs buffer pointer/length.
766  */
767 static bool
768 wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
769 {
770         /* If the contents match the OUI and the type */
771         if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
772                 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
773                 type == ie[TLV_BODY_OFF + oui_len]) {
774                 return TRUE;
775         }
776
777         if (tlvs == NULL)
778                 return FALSE;
779         /* point to the next ie */
780         ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
781         /* calculate the length of the rest of the buffer */
782         *tlvs_len -= (int)(ie - *tlvs);
783         /* update the pointer to the start of the buffer */
784         *tlvs = ie;
785
786         return FALSE;
787 }
788
789 wpa_ie_fixed_t *
790 wl_cfgp2p_find_wpaie(u8 *parse, u32 len)
791 {
792         bcm_tlv_t *ie;
793
794         while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
795                 if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) {
796                         return (wpa_ie_fixed_t *)ie;
797                 }
798         }
799         return NULL;
800 }
801
802 wpa_ie_fixed_t *
803 wl_cfgp2p_find_wpsie(u8 *parse, u32 len)
804 {
805         bcm_tlv_t *ie;
806
807         while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
808                 if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) {
809                         return (wpa_ie_fixed_t *)ie;
810                 }
811         }
812         return NULL;
813 }
814
815 wifi_p2p_ie_t *
816 wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
817 {
818         bcm_tlv_t *ie;
819
820         while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
821                 if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) {
822                         return (wifi_p2p_ie_t *)ie;
823                 }
824         }
825         return NULL;
826 }
827
828 static s32
829 wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
830             s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete)
831 {
832         s32 err = BCME_OK;
833         s32 buf_len;
834         s32 iecount;
835
836         vndr_ie_setbuf_t *ie_setbuf;
837
838         /* Validate the pktflag parameter */
839         if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
840                     VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
841                     VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) {
842                 CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag));
843                 return -1;
844         }
845
846         buf_len = sizeof(vndr_ie_setbuf_t) + data_len - 1;
847         ie_setbuf = (vndr_ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
848
849         CFGP2P_INFO((" ie_id : %02x, data length : %d\n", ie_id, data_len));
850         if (!ie_setbuf) {
851
852                 CFGP2P_ERR(("Error allocating buffer for IE\n"));
853                 return -ENOMEM;
854         }
855         if (delete)
856                 strcpy(ie_setbuf->cmd, "del");
857         else
858                 strcpy(ie_setbuf->cmd, "add");
859         /* Buffer contains only 1 IE */
860         iecount = htod32(1);
861         memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
862         pktflag = htod32(pktflag);
863         memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
864             &pktflag, sizeof(uint32));
865         ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id;
866         ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len
867                 = (uchar)(data_len + VNDR_IE_MIN_LEN);
868         memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3);
869         memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len);
870         err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len,
871                 ioctlbuf, sizeof(ioctlbuf), bssidx);
872
873         CFGP2P_INFO(("vndr_ie iovar returns %d\n", err));
874         kfree(ie_setbuf);
875         return err;
876 }
877
878 /*
879  * Search the bssidx based on dev argument
880  * Parameters:
881  * @wl       : wl_private data
882  * @ndev     : net device to search bssidx
883  *  Returns bssidx for ndev
884  */
885 s32
886 wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev)
887 {
888         u32 i;
889         s32 index = -1;
890
891         if (ndev == NULL) {
892                 CFGP2P_ERR((" ndev is NULL\n"));
893                 goto exit;
894         }
895         if (!wl->p2p_supported) {
896                 return P2PAPI_BSSCFG_PRIMARY;
897         }
898         for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
899                 if (ndev == wl_to_p2p_bss_ndev(wl, i)) {
900                         index = wl_to_p2p_bss_bssidx(wl, i);
901                         break;
902                 }
903         }
904         if (index == -1)
905                 return P2PAPI_BSSCFG_PRIMARY;
906 exit:
907         return index;
908 }
909 /*
910  * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
911  */
912 s32
913 wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev,
914             const wl_event_msg_t *e, void *data)
915 {
916         s32 ret = BCME_OK;
917
918         CFGP2P_DBG((" Enter\n"));
919         if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) {
920                 wl_set_p2p_status(wl, LISTEN_EXPIRED);
921
922                 if (wl->p2p->listen_timer)
923                         del_timer_sync(wl->p2p->listen_timer);
924
925                 cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan,
926                     wl->remain_on_chan_type, GFP_KERNEL);
927         }
928
929         return ret;
930
931 }
932
933 /*
934  *  Timer expire callback function for LISTEN
935  *  We can't report cfg80211_remain_on_channel_expired from Timer ISR context, 
936  *  so lets do it from thread context.
937  */
938 static void
939 wl_cfgp2p_listen_expired(unsigned long data)
940 {
941         wl_event_msg_t msg;
942         struct wl_priv *wl = (struct wl_priv *) data;
943
944         CFGP2P_DBG((" Enter\n"));
945         msg.event_type =  hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE);
946         wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL);
947 }
948
949 /* 
950  * Do a P2P Listen on the given channel for the given duration.
951  * A listen consists of sitting idle and responding to P2P probe requests
952  * with a P2P probe response.
953  *
954  * This fn assumes dongle p2p device discovery is already enabled.
955  * Parameters   :
956  * @wl          : wl_private data
957  * @channel     : channel to listen
958  * @duration_ms : the time (milli seconds) to wait
959  */
960 s32
961 wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms)
962 {
963 #define INIT_TIMER(timer, func, duration, extra_delay)  \
964         do {                   \
965                 init_timer(timer); \
966                 timer->function = func; \
967                 timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \
968                 timer->data = (unsigned long) wl; \
969                 add_timer(timer); \
970         } while (0);
971
972         s32 ret = BCME_OK;
973         CFGP2P_DBG((" Enter Channel : %d, Duration : %d\n", channel, duration_ms));
974         if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) {
975
976                 CFGP2P_ERR((" Discovery is not set, so we have noting to do\n"));
977
978                 ret = BCME_NOTREADY;
979                 goto exit;
980         }
981
982         wl_clr_p2p_status(wl, LISTEN_EXPIRED);
983
984         wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
985                     wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
986
987         if (wl->p2p->listen_timer)
988                 del_timer_sync(wl->p2p->listen_timer);
989
990         wl->p2p->listen_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
991
992         if (wl->p2p->listen_timer == NULL) {
993                 CFGP2P_ERR(("listen_timer allocation failed\n"));
994                 return -ENOMEM;
995         }
996
997         /*  We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle , 
998          *  otherwise we will wait up to duration_ms + 200ms
999          */
1000         INIT_TIMER(wl->p2p->listen_timer, wl_cfgp2p_listen_expired, duration_ms, 200);
1001
1002 #undef INIT_TIMER
1003 exit:
1004         return ret;
1005 }
1006
1007
1008 s32
1009 wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable)
1010 {
1011         s32 ret = BCME_OK;
1012         CFGP2P_DBG((" Enter\n"));
1013         if (!wl_get_p2p_status(wl, DISCOVERY_ON)) {
1014
1015                 CFGP2P_DBG((" do nothing, discovery is off\n"));
1016                 return ret;
1017         }
1018         if (wl_get_p2p_status(wl, SEARCH_ENABLED) == enable) {
1019                 CFGP2P_DBG(("already : %d\n", enable));
1020                 return ret;
1021         }
1022
1023         wl_chg_p2p_status(wl, SEARCH_ENABLED);
1024         /* When disabling Search, reset the WL driver's p2p discovery state to
1025          * WL_P2P_DISC_ST_SCAN.
1026          */
1027         if (!enable) {
1028                 wl_clr_p2p_status(wl, SCANNING);
1029                 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
1030                             wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
1031         }
1032
1033         return ret;
1034 }
1035
1036 /*
1037  * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
1038  */
1039 s32
1040 wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev,
1041             const wl_event_msg_t *e, void *data)
1042 {
1043         s32 ret = BCME_OK;
1044         u32 event_type = ntoh32(e->event_type);
1045         u32 status = ntoh32(e->status);
1046         CFGP2P_DBG((" Enter\n"));
1047         if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
1048
1049                 CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
1050                 if (status == WLC_E_STATUS_SUCCESS)
1051                         wl_set_p2p_status(wl, ACTION_TX_COMPLETED);
1052                 else
1053                         CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
1054                 wake_up_interruptible(&wl->dongle_event_wait);
1055         } else {
1056                 CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
1057                                         "status : %d\n", status));
1058
1059         }
1060
1061         return ret;
1062 }
1063 /* Send an action frame immediately without doing channel synchronization.
1064  *
1065  * This function does not wait for a completion event before returning.
1066  * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
1067  * frame is transmitted.
1068  * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an
1069  * 802.11 ack has been received for the sent action frame.
1070  */
1071 s32
1072 wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
1073         wl_af_params_t *af_params, s32 bssidx)
1074 {
1075         s32 ret = BCME_OK;
1076         s32 timeout = 0;
1077
1078
1079         CFGP2P_INFO(("\n"));
1080         CFGP2P_INFO(("channel : %u , dwell time : %u\n",
1081             af_params->channel, af_params->dwell_time));
1082
1083         wl_clr_p2p_status(wl, ACTION_TX_COMPLETED);
1084 #define MAX_WAIT_TIME 2000
1085         if (bssidx == P2PAPI_BSSCFG_PRIMARY)
1086                 bssidx =  wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
1087
1088         ret = wldev_iovar_setbuf_bsscfg(dev, "actframe",
1089                    af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf), bssidx);
1090
1091         if (ret < 0) {
1092
1093                 CFGP2P_ERR((" sending action frame is failed\n"));
1094                 goto exit;
1095         }
1096         timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
1097                         (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) == TRUE),
1098                             msecs_to_jiffies(MAX_WAIT_TIME));
1099
1100         if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) {
1101                 CFGP2P_INFO(("tx action frame operation is completed\n"));
1102                 ret = BCME_OK;
1103         } else {
1104                 ret = BCME_ERROR;
1105                 CFGP2P_INFO(("tx action frame operation is failed\n"));
1106         }
1107 exit:
1108         CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
1109 #undef MAX_WAIT_TIME
1110         return ret;
1111 }
1112
1113 /* Generate our P2P Device Address and P2P Interface Address from our primary
1114  * MAC address.
1115  */
1116 void
1117 wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr,
1118             struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr)
1119 {
1120         memset(out_dev_addr, 0, sizeof(*out_dev_addr));
1121         memset(out_int_addr, 0, sizeof(*out_int_addr));
1122
1123         /* Generate the P2P Device Address.  This consists of the device's
1124          * primary MAC address with the locally administered bit set.
1125          */
1126         memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr));
1127         out_dev_addr->octet[0] |= 0x02;
1128
1129         /* Generate the P2P Interface Address.  If the discovery and connection
1130          * BSSCFGs need to simultaneously co-exist, then this address must be
1131          * different from the P2P Device Address.
1132          */
1133         memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr));
1134         out_int_addr->octet[4] ^= 0x80;
1135
1136 }
1137
1138 /* P2P IF Address change to Virtual Interface MAC Address */
1139 void
1140 wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id)
1141 {
1142         wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf;
1143         u16 len = ie->len;
1144         u8 *subel;
1145         u8 subelt_id;
1146         u16 subelt_len;
1147         CFGP2P_DBG((" Enter\n"));
1148
1149         /* Point subel to the P2P IE's subelt field.
1150          * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
1151          */
1152         subel = ie->subelts;
1153         len -= 4;       /* exclude OUI + OUI_TYPE */
1154
1155         while (len >= 3) {
1156         /* attribute id */
1157                 subelt_id = *subel;
1158                 subel += 1;
1159                 len -= 1;
1160
1161                 /* 2-byte little endian */
1162                 subelt_len = *subel++;
1163                 subelt_len |= *subel++ << 8;
1164
1165                 len -= 2;
1166                 len -= subelt_len;      /* for the remaining subelt fields */
1167
1168                 if (subelt_id == element_id) {
1169                         if (subelt_id == P2P_SEID_INTINTADDR) {
1170                                 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1171                                 CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n"));
1172                         } else if (subelt_id == P2P_SEID_DEV_ID) {
1173                                 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1174                                 CFGP2P_INFO(("Device ID ATTR FOUND\n"));
1175                         } else if (subelt_id == P2P_SEID_DEV_INFO) {
1176                                 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1177                                 CFGP2P_INFO(("Device INFO ATTR FOUND\n"));
1178                         } else if (subelt_id == P2P_SEID_GROUP_ID) {
1179                                 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1180                                 CFGP2P_INFO(("GROUP ID ATTR FOUND\n"));
1181                         }                       return;
1182                 } else {
1183                         CFGP2P_DBG(("OTHER id : %d\n", subelt_id));
1184                 }
1185                 subel += subelt_len;
1186         }
1187 }
1188 /*
1189  * Check if a BSS is up.
1190  * This is a common implementation called by most OSL implementations of
1191  * p2posl_bss_isup().  DO NOT call this function directly from the
1192  * common code -- call p2posl_bss_isup() instead to allow the OSL to
1193  * override the common implementation if necessary.
1194  */
1195 bool
1196 wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
1197 {
1198         s32 result, val;
1199         bool isup = false;
1200         s8 getbuf[64];
1201
1202         /* Check if the BSS is up */
1203         *(int*)getbuf = -1;
1204         result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
1205                             sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0);
1206         if (result != 0) {
1207                 CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result));
1208                 CFGP2P_ERR(("NOTE: this ioctl error is normal "
1209                                         "when the BSS has not been created yet.\n"));
1210         } else {
1211                 val = *(int*)getbuf;
1212                 val = dtoh32(val);
1213                 CFGP2P_INFO(("---wl bss -C %d   ==> %d\n", bsscfg_idx, val));
1214                 isup = (val ? TRUE : FALSE);
1215         }
1216         return isup;
1217 }
1218
1219
1220 /* Bring up or down a BSS */
1221 s32
1222 wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up)
1223 {
1224         s32 ret = BCME_OK;
1225         s32 val = up ? 1 : 0;
1226
1227         struct {
1228                 s32 cfg;
1229                 s32 val;
1230         } bss_setbuf;
1231
1232         bss_setbuf.cfg = htod32(bsscfg_idx);
1233         bss_setbuf.val = htod32(val);
1234         CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"));
1235         ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
1236                 ioctlbuf, sizeof(ioctlbuf));
1237
1238         if (ret != 0) {
1239                 CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret));
1240         }
1241
1242         return ret;
1243 }
1244
1245 /* Check if 'p2p' is supported in the driver */
1246 s32
1247 wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
1248 {
1249         s32 ret = BCME_OK;
1250         s32 p2p_supported = 0;
1251         ret = wldev_iovar_getint(ndev, "p2p",
1252                        &p2p_supported);
1253         if (ret < 0) {
1254                 CFGP2P_ERR(("wl p2p error %d\n", ret));
1255                 return 0;
1256         }
1257         if (p2p_supported == 1) {
1258                 CFGP2P_INFO(("p2p is supported\n"));
1259         } else {
1260                 CFGP2P_INFO(("p2p is unsupported\n"));
1261                 p2p_supported = 0;
1262         }
1263         return p2p_supported;
1264 }
1265 /* Cleanup P2P resources */
1266 s32
1267 wl_cfgp2p_down(struct wl_priv *wl)
1268 {
1269         if (wl->p2p->listen_timer)
1270                 del_timer_sync(wl->p2p->listen_timer);
1271         return 0;
1272 }