bcmdhd_1_77: Import A320F (A320FLXXU2CRE3) Oreo driver
[GitHub/LineageOS/android_kernel_samsung_universal7580.git] / drivers / net / wireless / bcmdhd_1_77 / wl_cfgp2p.c
CommitLineData
3c2a0909
S
1/*
2 * Linux cfgp2p driver
3 *
4c205efb 4 * Copyright (C) 1999-2018, Broadcom Corporation
3c2a0909
S
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 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
4c205efb 27 * $Id: wl_cfgp2p.c 699163 2017-05-12 05:18:23Z $
3c2a0909
S
28 *
29 */
30#include <typedefs.h>
31#include <linuxver.h>
32#include <osl.h>
33#include <linux/kernel.h>
34#include <linux/kthread.h>
35#include <linux/netdevice.h>
36#include <linux/etherdevice.h>
37#include <linux/types.h>
38#include <linux/string.h>
39#include <linux/timer.h>
40#include <linux/if_arp.h>
41#include <asm/uaccess.h>
42
43#include <bcmutils.h>
44#include <bcmendian.h>
45#include <ethernet.h>
46#include <802.11.h>
47#include <net/rtnetlink.h>
48
49#include <wl_cfg80211.h>
50#include <wl_cfgp2p.h>
51#include <wldev_common.h>
52#include <wl_android.h>
53#include <dngl_stats.h>
54#include <dhd.h>
55#include <dhd_linux.h>
56#include <dhdioctl.h>
57#include <wlioctl.h>
58#include <dhd_cfg80211.h>
59
60#if defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
61extern int dhd_bus_mem_dump(dhd_pub_t *dhd);
62#endif /* BCMPCIE && DHD_FW_COREDUMP */
63
64static s8 scanparambuf[WLC_IOCTL_SMLEN];
65static bool
66wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
67
68static s32 wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev,
69 struct wireless_dev *wdev, bool notify);
70
71#if defined(WL_ENABLE_P2P_IF)
72static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
73static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
74static int wl_cfgp2p_if_open(struct net_device *net);
75static int wl_cfgp2p_if_stop(struct net_device *net);
76
77static const struct net_device_ops wl_cfgp2p_if_ops = {
78 .ndo_open = wl_cfgp2p_if_open,
79 .ndo_stop = wl_cfgp2p_if_stop,
80 .ndo_do_ioctl = wl_cfgp2p_do_ioctl,
81 .ndo_start_xmit = wl_cfgp2p_start_xmit,
82};
83#endif /* WL_ENABLE_P2P_IF */
84
85#if defined(WL_NEWCFG_PRIVCMD_SUPPORT)
86static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev);
87static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd);
88
89static int wl_cfgp2p_if_dummy(struct net_device *net)
90{
91 return 0;
92}
93
94static const struct net_device_ops wl_cfgp2p_if_ops = {
95 .ndo_open = wl_cfgp2p_if_dummy,
96 .ndo_stop = wl_cfgp2p_if_dummy,
97 .ndo_do_ioctl = wl_cfgp2p_do_ioctl,
98 .ndo_start_xmit = wl_cfgp2p_start_xmit,
99};
100#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
101
102bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len)
103{
104 wifi_p2p_pub_act_frame_t *pact_frm;
105
106 if (frame == NULL)
107 return false;
108 pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
109 if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1)
110 return false;
111
112 if (pact_frm->category == P2P_PUB_AF_CATEGORY &&
113 pact_frm->action == P2P_PUB_AF_ACTION &&
114 pact_frm->oui_type == P2P_VER &&
115 memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) {
116 return true;
117 }
118
119 return false;
120}
121
122bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len)
123{
124 wifi_p2p_action_frame_t *act_frm;
125
126 if (frame == NULL)
127 return false;
128 act_frm = (wifi_p2p_action_frame_t *)frame;
129 if (frame_len < sizeof(wifi_p2p_action_frame_t) -1)
130 return false;
131
132 if (act_frm->category == P2P_AF_CATEGORY &&
133 act_frm->type == P2P_VER &&
134 memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) {
135 return true;
136 }
137
138 return false;
139}
140
141#define GAS_RESP_LEN 2
142#define DOUBLE_TLV_BODY_OFF 4
143#define GAS_RESP_OFFSET 4
144#define GAS_CRESP_OFFSET 5
145
146bool wl_cfgp2p_find_gas_subtype(u8 subtype, u8* data, u32 len)
147{
148 bcm_tlv_t *ie = (bcm_tlv_t *)data;
149 u8 *frame = NULL;
150 u16 id, flen;
151
152 /* Skipped first ANQP Element, if frame has anqp elemnt */
153 ie = bcm_parse_tlvs(ie, (int)len, DOT11_MNG_ADVERTISEMENT_ID);
154
155 if (ie == NULL)
156 return false;
157
158 frame = (uint8 *)ie + ie->len + TLV_HDR_LEN + GAS_RESP_LEN;
159 id = ((u16) (((frame)[1] << 8) | (frame)[0]));
160 flen = ((u16) (((frame)[3] << 8) | (frame)[2]));
161
162 /* If the contents match the OUI and the type */
163 if (flen >= WFA_OUI_LEN + 1 &&
164 id == P2PSD_GAS_NQP_INFOID &&
165 !bcmp(&frame[DOUBLE_TLV_BODY_OFF], (const uint8*)WFA_OUI, WFA_OUI_LEN) &&
166 subtype == frame[DOUBLE_TLV_BODY_OFF+WFA_OUI_LEN]) {
167 return true;
168 }
169
170 return false;
171}
172
173bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
174{
175
176 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
177
178 if (frame == NULL)
179 return false;
180
181 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
182 if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1))
183 return false;
184 if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
185 return false;
186
187#ifdef WL11U
188 if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP)
189 return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
190 (u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET,
191 frame_len);
192
193 else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
194 return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
195 (u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET,
196 frame_len);
197 else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
198 sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ)
199 return true;
200 else
201 return false;
202#else
203 if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
204 sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
205 sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
206 sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
207 return true;
208 else
209 return false;
210#endif /* WL11U */
211}
212
213bool wl_cfgp2p_is_p2p_gas_action(void *frame, u32 frame_len)
214{
215
216 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
217
218 if (frame == NULL)
219 return false;
220
221 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
222 if (frame_len < (sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1))
223 return false;
224 if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
225 return false;
226
227 if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ)
228 return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
229 (u8 *)sd_act_frm->query_data,
230 frame_len);
231 else
232 return false;
233}
234
235void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel)
236{
237 wifi_p2p_pub_act_frame_t *pact_frm;
238 wifi_p2p_action_frame_t *act_frm;
239 wifi_p2psd_gas_pub_act_frame_t *sd_act_frm;
240 if (!frame || frame_len <= 2)
241 return;
242
243 if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
244 pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
245 switch (pact_frm->subtype) {
246 case P2P_PAF_GON_REQ:
247 CFGP2P_ACTION(("%s P2P Group Owner Negotiation Req Frame,"
248 " channel=%d\n", (tx)? "TX": "RX", channel));
249 break;
250 case P2P_PAF_GON_RSP:
251 CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame,"
252 " channel=%d\n", (tx)? "TX": "RX", channel));
253 break;
254 case P2P_PAF_GON_CONF:
255 CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame,"
256 " channel=%d\n", (tx)? "TX": "RX", channel));
257 break;
258 case P2P_PAF_INVITE_REQ:
259 CFGP2P_ACTION(("%s P2P Invitation Request Frame,"
260 " channel=%d\n", (tx)? "TX": "RX", channel));
261 break;
262 case P2P_PAF_INVITE_RSP:
263 CFGP2P_ACTION(("%s P2P Invitation Response Frame,"
264 " channel=%d\n", (tx)? "TX": "RX", channel));
265 break;
266 case P2P_PAF_DEVDIS_REQ:
267 CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame,"
268 " channel=%d\n", (tx)? "TX": "RX", channel));
269 break;
270 case P2P_PAF_DEVDIS_RSP:
271 CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame,"
272 " channel=%d\n", (tx)? "TX": "RX", channel));
273 break;
274 case P2P_PAF_PROVDIS_REQ:
275 CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame,"
276 " channel=%d\n", (tx)? "TX": "RX", channel));
277 break;
278 case P2P_PAF_PROVDIS_RSP:
279 CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame,"
280 " channel=%d\n", (tx)? "TX": "RX", channel));
281 break;
282 default:
283 CFGP2P_ACTION(("%s Unknown Public Action Frame,"
284 " channel=%d\n", (tx)? "TX": "RX", channel));
285
286 }
287
288 } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) {
289 act_frm = (wifi_p2p_action_frame_t *)frame;
290 switch (act_frm->subtype) {
291 case P2P_AF_NOTICE_OF_ABSENCE:
292 CFGP2P_ACTION(("%s P2P Notice of Absence Frame,"
293 " channel=%d\n", (tx)? "TX": "RX", channel));
294 break;
295 case P2P_AF_PRESENCE_REQ:
296 CFGP2P_ACTION(("%s P2P Presence Request Frame,"
297 " channel=%d\n", (tx)? "TX": "RX", channel));
298 break;
299 case P2P_AF_PRESENCE_RSP:
300 CFGP2P_ACTION(("%s P2P Presence Response Frame,"
301 " channel=%d\n", (tx)? "TX": "RX", channel));
302 break;
303 case P2P_AF_GO_DISC_REQ:
304 CFGP2P_ACTION(("%s P2P Discoverability Request Frame,"
305 " channel=%d\n", (tx)? "TX": "RX", channel));
306 break;
307 default:
308 CFGP2P_ACTION(("%s Unknown P2P Action Frame,"
309 " channel=%d\n", (tx)? "TX": "RX", channel));
310 }
311
312 } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) {
313 sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame;
314 switch (sd_act_frm->action) {
315 case P2PSD_ACTION_ID_GAS_IREQ:
316 CFGP2P_ACTION(("%s GAS Initial Request,"
317 " channel=%d\n", (tx)? "TX" : "RX", channel));
318 break;
319 case P2PSD_ACTION_ID_GAS_IRESP:
320 CFGP2P_ACTION(("%s GAS Initial Response,"
321 " channel=%d\n", (tx)? "TX" : "RX", channel));
322 break;
323 case P2PSD_ACTION_ID_GAS_CREQ:
324 CFGP2P_ACTION(("%s GAS Comback Request,"
325 " channel=%d\n", (tx)? "TX" : "RX", channel));
326 break;
327 case P2PSD_ACTION_ID_GAS_CRESP:
328 CFGP2P_ACTION(("%s GAS Comback Response,"
329 " channel=%d\n", (tx)? "TX" : "RX", channel));
330 break;
331 default:
332 CFGP2P_ACTION(("%s Unknown GAS Frame,"
333 " channel=%d\n", (tx)? "TX" : "RX", channel));
334 }
335
336
337 }
338}
339
340/*
341 * Initialize variables related to P2P
342 *
343 */
344s32
345wl_cfgp2p_init_priv(struct bcm_cfg80211 *cfg)
346{
347 if (!(cfg->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) {
348 CFGP2P_ERR(("struct p2p_info allocation failed\n"));
349 return -ENOMEM;
350 }
351
352 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY) = bcmcfg_to_prmry_ndev(cfg);
353 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY) = 0;
354 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
355 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
356 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION1) = NULL;
357 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) = -1;
358 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_CONNECTION2) = NULL;
359 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2) = -1;
360 return BCME_OK;
361
362}
363/*
364 * Deinitialize variables related to P2P
365 *
366 */
367void
368wl_cfgp2p_deinit_priv(struct bcm_cfg80211 *cfg)
369{
370 CFGP2P_ERR(("In\n"));
371 if (cfg->p2p) {
372 kfree(cfg->p2p);
373 cfg->p2p = NULL;
374 }
375 cfg->p2p_supported = 0;
376}
377/*
378 * Set P2P functions into firmware
379 */
380s32
381wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211 *cfg)
382{
383 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
384 struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } };
385 s32 ret = BCME_OK;
386 s32 val = 0;
387 /* Do we have to check whether APSTA is enabled or not ? */
388 ret = wldev_iovar_getint(ndev, "apsta", &val);
389 if (ret < 0) {
390 CFGP2P_ERR(("get apsta error %d\n", ret));
391 return ret;
392 }
393 if (val == 0) {
394 val = 1;
4c205efb 395 ret = wldev_ioctl_set(ndev, WLC_DOWN, &val, sizeof(s32));
3c2a0909
S
396 if (ret < 0) {
397 CFGP2P_ERR(("WLC_DOWN error %d\n", ret));
398 return ret;
399 }
400
401 ret = wldev_iovar_setint(ndev, "apsta", val);
402 if (ret < 0) {
403 /* return error and fail the initialization */
404 CFGP2P_ERR(("wl apsta %d set error. ret: %d\n", val, ret));
405 return ret;
406 }
407
4c205efb 408 ret = wldev_ioctl_set(ndev, WLC_UP, &val, sizeof(s32));
3c2a0909
S
409 if (ret < 0) {
410 CFGP2P_ERR(("WLC_UP error %d\n", ret));
411 return ret;
412 }
413 }
414
415 /* In case of COB type, firmware has default mac address
416 * After Initializing firmware, we have to set current mac address to
417 * firmware for P2P device address
418 */
419 ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
420 sizeof(null_eth_addr), cfg->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &cfg->ioctl_buf_sync);
421 if (ret && ret != BCME_UNSUPPORTED) {
422 CFGP2P_ERR(("failed to update device address ret %d\n", ret));
423 }
424 return ret;
425}
426
427int wl_cfg_multip2p_operational(struct bcm_cfg80211 *cfg)
428{
429 if (!cfg->p2p) {
430 CFGP2P_DBG(("p2p not enabled! \n"));
431 return false;
432 }
433
434 if ((wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) != -1) &&
435 (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2) != -1))
436 return true;
437 else
438 return false;
439}
440
441/* Create a new P2P BSS.
442 * Parameters:
443 * @mac : MAC address of the BSS to create
444 * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT
445 * @chspec : chspec to use if creating a GO BSS.
446 * Returns 0 if success.
447 */
448s32
449wl_cfgp2p_ifadd(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
450 chanspec_t chspec)
451{
452 wl_p2p_if_t ifreq;
453 s32 err;
454 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
455
456 ifreq.type = if_type;
457 ifreq.chspec = chspec;
458 memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
459
460 CFGP2P_ERR(("---cfg p2p_ifadd "MACDBG" %s %u\n",
461 MAC2STRDBG(ifreq.addr.octet),
462 (if_type == WL_P2P_IF_GO) ? "go" : "client",
463 (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
464
465 err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
466 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
467 if (unlikely(err < 0)) {
468 printk("'cfg p2p_ifadd' error %d\n", err);
469 return err;
470 }
471
472 return err;
473}
474
475/* Disable a P2P BSS.
476 * Parameters:
477 * @mac : MAC address of the BSS to disable
478 * Returns 0 if success.
479 */
480s32
481wl_cfgp2p_ifdisable(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
482{
483 s32 ret;
484 struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
485
486 CFGP2P_INFO(("------primary idx %d : cfg p2p_ifdis "MACDBG"\n",
487 netdev->ifindex, MAC2STRDBG(mac->octet)));
488 ret = wldev_iovar_setbuf(netdev, "p2p_ifdis", mac, sizeof(*mac),
489 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
490 if (unlikely(ret < 0)) {
491 printk("'cfg p2p_ifdis' error %d\n", ret);
492 }
493 return ret;
494}
495
496/* Delete a P2P BSS.
497 * Parameters:
498 * @mac : MAC address of the BSS to delete
499 * Returns 0 if success.
500 */
501s32
502wl_cfgp2p_ifdel(struct bcm_cfg80211 *cfg, struct ether_addr *mac)
503{
504 s32 ret;
505 struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
506
507 CFGP2P_ERR(("------primary idx %d : cfg p2p_ifdel "MACDBG"\n",
508 netdev->ifindex, MAC2STRDBG(mac->octet)));
509 ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
510 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
511 if (unlikely(ret < 0)) {
512 printk("'cfg p2p_ifdel' error %d\n", ret);
513 }
514 return ret;
515}
516
517/* Change a P2P Role.
518 * Parameters:
519 * @mac : MAC address of the BSS to change a role
520 * Returns 0 if success.
521 */
522s32
523wl_cfgp2p_ifchange(struct bcm_cfg80211 *cfg, struct ether_addr *mac, u8 if_type,
524 chanspec_t chspec, s32 conn_idx)
525{
526 wl_p2p_if_t ifreq;
527 s32 err;
528
529 struct net_device *netdev = wl_to_p2p_bss_ndev(cfg, conn_idx);
530
531 ifreq.type = if_type;
532 ifreq.chspec = chspec;
533 memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
534
535 CFGP2P_INFO(("---cfg p2p_ifchange "MACDBG" %s %u"
536 " chanspec 0x%04x\n", MAC2STRDBG(ifreq.addr.octet),
537 (if_type == WL_P2P_IF_GO) ? "go" : "client",
538 (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT,
539 ifreq.chspec));
540
541 err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
542 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
543 if (unlikely(err < 0)) {
544 printk("'cfg p2p_ifupd' error %d\n", err);
545 } else if (if_type == WL_P2P_IF_GO) {
546 cfg->p2p->p2p_go_count++;
547 }
548 return err;
549}
550
551
552/* Get the index of a created P2P BSS.
553 * Parameters:
554 * @mac : MAC address of the created BSS
555 * @index : output: index of created BSS
556 * Returns 0 if success.
557 */
558s32
559wl_cfgp2p_ifidx(struct bcm_cfg80211 *cfg, struct ether_addr *mac, s32 *index)
560{
561 s32 ret;
562 u8 getbuf[64];
563 struct net_device *dev = bcmcfg_to_prmry_ndev(cfg);
564
565 CFGP2P_INFO(("---cfg p2p_if "MACDBG"\n", MAC2STRDBG(mac->octet)));
566
567 ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf,
568 sizeof(getbuf), wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY), NULL);
569
570 if (ret == 0) {
571 memcpy(index, getbuf, sizeof(s32));
572 CFGP2P_INFO(("---cfg p2p_if ==> %d\n", *index));
573 }
574
575 return ret;
576}
577
578static s32
579wl_cfgp2p_set_discovery(struct bcm_cfg80211 *cfg, s32 on)
580{
581 s32 ret = BCME_OK;
582 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
583 CFGP2P_DBG(("enter\n"));
584
585 ret = wldev_iovar_setint(ndev, "p2p_disc", on);
586
587 if (unlikely(ret < 0)) {
588 CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret));
589 }
590
591 return ret;
592}
593
594/* Set the WL driver's P2P mode.
595 * Parameters :
596 * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}.
597 * @channel : the channel to listen
598 * @listen_ms : the time (milli seconds) to wait
599 * @bssidx : bss index for BSSCFG
600 * Returns 0 if success
601 */
602
603s32
604wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211 *cfg, u8 mode, u32 channel, u16 listen_ms, int bssidx)
605{
606 wl_p2p_disc_st_t discovery_mode;
607 s32 ret;
608 struct net_device *dev;
609 CFGP2P_DBG(("enter\n"));
610
611 if (unlikely(bssidx == WL_INVALID)) {
612 CFGP2P_ERR((" %d index out of range\n", bssidx));
613 return -1;
614 }
615
616 dev = wl_cfgp2p_find_ndev(cfg, bssidx);
617 if (unlikely(dev == NULL)) {
618 CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx));
619 return BCME_NOTFOUND;
620 }
621
622#ifdef P2PLISTEN_AP_SAMECHN
623 CFGP2P_DBG(("p2p0 listen channel %d AP connection chan %d \n",
624 channel, cfg->channel));
625 if ((mode == WL_P2P_DISC_ST_LISTEN) && (cfg->channel == channel)) {
626 struct net_device *primary_ndev = bcmcfg_to_prmry_ndev(cfg);
627
628 if (cfg->p2p_resp_apchn_status) {
629 CFGP2P_DBG(("p2p_resp_apchn_status already ON \n"));
630 return BCME_OK;
631 }
632
633 if (wl_get_drv_status(cfg, CONNECTED, primary_ndev)) {
634 ret = wl_cfg80211_set_p2p_resp_ap_chn(primary_ndev, 1);
635 cfg->p2p_resp_apchn_status = true;
636 CFGP2P_DBG(("p2p_resp_apchn_status ON \n"));
637 return ret;
638 }
639 }
640#endif /* P2PLISTEN_AP_SAMECHN */
641
642 /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */
643 discovery_mode.state = mode;
644 discovery_mode.chspec = wl_ch_host_to_driver(cfg, bssidx, channel);
645 discovery_mode.dwell = listen_ms;
646 ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
647 sizeof(discovery_mode), cfg->ioctl_buf, WLC_IOCTL_MAXLEN,
648 bssidx, &cfg->ioctl_buf_sync);
649
650 return ret;
651}
652
653/* Get the index of the P2P Discovery BSS */
654static s32
655wl_cfgp2p_get_disc_idx(struct bcm_cfg80211 *cfg, s32 *index)
656{
657 s32 ret;
658 struct net_device *dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
659
660 ret = wldev_iovar_getint(dev, "p2p_dev", index);
661 CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret));
662
663 if (unlikely(ret < 0)) {
664 CFGP2P_ERR(("'p2p_dev' error %d\n", ret));
665 return ret;
666 }
667 return ret;
668}
669
670int wl_cfgp2p_get_conn_idx(struct bcm_cfg80211 *cfg)
671{
672 int i;
673 s32 connected_cnt;
674 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
675 if (!dhd)
676 return (-ENODEV);
677 for (i = P2PAPI_BSSCFG_CONNECTION1; i < P2PAPI_BSSCFG_MAX; i++) {
678 if (wl_to_p2p_bss_bssidx(cfg, i) == -1) {
679 if (i == P2PAPI_BSSCFG_CONNECTION2) {
680 if (!(dhd->op_mode & DHD_FLAG_MP2P_MODE)) {
681 CFGP2P_ERR(("Multi p2p not supported"));
682 return BCME_ERROR;
683 }
684 if ((connected_cnt = wl_get_drv_status_all(cfg, CONNECTED)) > 1) {
685 CFGP2P_ERR(("Failed to create second p2p interface"
686 "Already one connection exists"));
687 return BCME_ERROR;
688 }
689 }
690 return i;
691 }
692 }
693 return BCME_ERROR;
694}
695
696s32
697wl_cfgp2p_init_discovery(struct bcm_cfg80211 *cfg)
698{
699
700 s32 bssidx = 0;
701 s32 ret = BCME_OK;
702
703 CFGP2P_DBG(("enter\n"));
704
705 if (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) > 0) {
706 CFGP2P_ERR(("do nothing, already initialized\n"));
707 return ret;
708 }
709
710 ret = wl_cfgp2p_set_discovery(cfg, 1);
711 if (ret < 0) {
712 CFGP2P_ERR(("set discover error\n"));
713 return ret;
714 }
715 /* Enable P2P Discovery in the WL Driver */
716 ret = wl_cfgp2p_get_disc_idx(cfg, &bssidx);
717
718 if (ret < 0) {
719 return ret;
720 }
721 /* In case of CFG80211 case, check if p2p_discovery interface has allocated p2p_wdev */
722 if (!cfg->p2p_wdev) {
723 CFGP2P_ERR(("p2p_wdev is NULL.\n"));
724 return BCME_NODEVICE;
725 }
726 /* Make an entry in the netinfo */
727 ret = wl_alloc_netinfo(cfg, NULL, cfg->p2p_wdev, WL_MODE_BSS, 0, bssidx);
728 if (unlikely(ret)) {
729 return ret;
730 }
731
732 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) =
733 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
734 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = bssidx;
735
736 /* Set the initial discovery state to SCAN */
737 ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
738 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
739
740 if (unlikely(ret != 0)) {
741 CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
742 wl_cfgp2p_set_discovery(cfg, 0);
743 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = 0;
744 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
745 return 0;
746 }
747 return ret;
748}
749
750/* Deinitialize P2P Discovery
751 * Parameters :
752 * @cfg : wl_private data
753 * Returns 0 if succes
754 */
755static s32
756wl_cfgp2p_deinit_discovery(struct bcm_cfg80211 *cfg)
757{
758 s32 ret = BCME_OK;
759 s32 bssidx;
760
761 CFGP2P_DBG(("enter\n"));
762 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
763 if (bssidx <= 0) {
764 CFGP2P_ERR(("do nothing, not initialized\n"));
765 return -1;
766 }
767
768 /* Clear our saved WPS and P2P IEs for the discovery BSS */
769 wl_cfg80211_clear_per_bss_ies(cfg, bssidx);
770
771 /* Set the discovery state to SCAN */
772 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
773 bssidx);
774 /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
775 ret = wl_cfgp2p_set_discovery(cfg, 0);
776
777 /* Remove the p2p disc entry in the netinfo */
778 wl_dealloc_netinfo_by_wdev(cfg, cfg->p2p_wdev);
779
780 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE) = WL_INVALID;
781 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE) = NULL;
782
783 return ret;
784
785}
786/* Enable P2P Discovery
787 * Parameters:
788 * @cfg : wl_private data
789 * @ie : probe request ie (WPS IE + P2P IE)
790 * @ie_len : probe request ie length
791 * Returns 0 if success.
792 */
793s32
794wl_cfgp2p_enable_discovery(struct bcm_cfg80211 *cfg, struct net_device *dev,
795 const u8 *ie, u32 ie_len)
796{
797 s32 ret = BCME_OK;
798 s32 bssidx;
799
800 CFGP2P_DBG(("enter\n"));
801 if (wl_get_p2p_status(cfg, DISCOVERY_ON)) {
802 CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
803 goto set_ie;
804 }
805
806 ret = wl_cfgp2p_init_discovery(cfg);
807 if (unlikely(ret < 0)) {
808 CFGP2P_ERR((" init discovery error %d\n", ret));
809 goto exit;
810 }
811
812 wl_set_p2p_status(cfg, DISCOVERY_ON);
813 /* Set wsec to any non-zero value in the discovery bsscfg to ensure our
814 * P2P probe responses have the privacy bit set in the 802.11 WPA IE.
815 * Some peer devices may not initiate WPS with us if this bit is not set.
816 */
817 ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE),
818 "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
819 if (unlikely(ret < 0)) {
820 CFGP2P_ERR((" wsec error %d\n", ret));
821 }
822set_ie:
823 if (ie_len) {
824
825 if (bcmcfg_to_prmry_ndev(cfg) == dev) {
826 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
827 } else if ((bssidx = wl_get_bssidx_by_wdev(cfg, cfg->p2p_wdev)) < 0) {
828 WL_ERR(("Find p2p index from wdev(%p) failed\n", cfg->p2p_wdev));
829 return BCME_ERROR;
830 }
831
832 ret = wl_cfg80211_set_mgmt_vndr_ies(cfg, ndev_to_cfgdev(dev),
833 bssidx,
834 VNDR_IE_PRBREQ_FLAG, ie, ie_len);
835
836 if (unlikely(ret < 0)) {
837 CFGP2P_ERR(("set probreq ie occurs error %d\n", ret));
838 goto exit;
839 }
840 }
841exit:
842 return ret;
843}
844
845/* Disable P2P Discovery
846 * Parameters:
847 * @cfg : wl_private_data
848 * Returns 0 if success.
849 */
850s32
851wl_cfgp2p_disable_discovery(struct bcm_cfg80211 *cfg)
852{
853 s32 ret = BCME_OK;
854 s32 bssidx;
855
856 CFGP2P_DBG((" enter\n"));
857 wl_clr_p2p_status(cfg, DISCOVERY_ON);
858#ifdef DHD_IFDEBUG
859 WL_ERR(("%s: (cfg)->p2p->bss[type].bssidx: %d\n",
860 __FUNCTION__, (cfg)->p2p->bss[P2PAPI_BSSCFG_DEVICE].bssidx));
861#endif
862 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
863 if (bssidx <= 0) {
864 CFGP2P_ERR((" do nothing, not initialized\n"));
865 return 0;
866 }
867
868 ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
869 if (unlikely(ret < 0)) {
870 CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
871 }
872 /* Do a scan abort to stop the driver's scan engine in case it is still
873 * waiting out an action frame tx dwell time.
874 */
875#ifdef NOT_YET
876 if (wl_get_p2p_status(cfg, SCANNING)) {
877 p2pwlu_scan_abort(hdl, FALSE);
878 }
879#endif
880 wl_clr_p2p_status(cfg, DISCOVERY_ON);
881 ret = wl_cfgp2p_deinit_discovery(cfg);
882
883 return ret;
884}
885
886s32
887wl_cfgp2p_escan(struct bcm_cfg80211 *cfg, struct net_device *dev, u16 active,
888 u32 num_chans, u16 *channels,
889 s32 search_state, u16 action, u32 bssidx, struct ether_addr *tx_dst_addr,
890 p2p_scan_purpose_t p2p_scan_purpose)
891{
892 s32 ret = BCME_OK;
893 s32 memsize;
894 s32 eparams_size;
895 u32 i;
896 s8 *memblk;
897 wl_p2p_scan_t *p2p_params;
898 wl_escan_params_t *eparams;
899 wlc_ssid_t ssid;
900 /* Scan parameters */
901#define P2PAPI_SCAN_NPROBES 1
902#define P2PAPI_SCAN_DWELL_TIME_MS 80
903#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
904#define P2PAPI_SCAN_HOME_TIME_MS 60
905#define P2PAPI_SCAN_NPROBS_TIME_MS 30
906#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100
907
908 struct net_device *pri_dev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_PRIMARY);
909 /* Allocate scan params which need space for 3 channels and 0 ssids */
910 eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE +
911 OFFSETOF(wl_escan_params_t, params)) +
912 num_chans * sizeof(eparams->params.channel_list[0]);
913
914 memsize = sizeof(wl_p2p_scan_t) + eparams_size;
915 memblk = scanparambuf;
916 if (memsize > sizeof(scanparambuf)) {
917 CFGP2P_ERR((" scanpar buf too small (%u > %zu)\n",
918 memsize, sizeof(scanparambuf)));
919 return -1;
920 }
921 memset(memblk, 0, memsize);
922 memset(cfg->ioctl_buf, 0, WLC_IOCTL_MAXLEN);
923 if (search_state == WL_P2P_DISC_ST_SEARCH) {
924 /*
925 * If we in SEARCH STATE, we don't need to set SSID explictly
926 * because dongle use P2P WILDCARD internally by default
927 */
928 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx);
929 /* use null ssid */
930 ssid.SSID_len = 0;
931 memset(&ssid.SSID, 0, sizeof(ssid.SSID));
932 } else if (search_state == WL_P2P_DISC_ST_SCAN) {
933 /* SCAN STATE 802.11 SCAN
934 * WFD Supplicant has p2p_find command with (type=progressive, type= full)
935 * So if P2P_find command with type=progressive,
936 * we have to set ssid to P2P WILDCARD because
937 * we just do broadcast scan unless setting SSID
938 */
939 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
940 /* use wild card ssid */
941 ssid.SSID_len = WL_P2P_WILDCARD_SSID_LEN;
942 memset(&ssid.SSID, 0, sizeof(ssid.SSID));
943 memcpy(&ssid.SSID, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN);
944 } else {
945 CFGP2P_ERR((" invalid search state %d\n", search_state));
946 return -1;
947 }
948
949
950 /* Fill in the P2P scan structure at the start of the iovar param block */
951 p2p_params = (wl_p2p_scan_t*) memblk;
952 p2p_params->type = 'E';
953 /* Fill in the Scan structure that follows the P2P scan structure */
954 eparams = (wl_escan_params_t*) (p2p_params + 1);
955 eparams->params.bss_type = DOT11_BSSTYPE_ANY;
956 if (active)
957 eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE;
958 else
959 eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE;
960
961 if (tx_dst_addr == NULL)
962 memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
963 else
964 memcpy(&eparams->params.bssid, tx_dst_addr, ETHER_ADDR_LEN);
965
966 if (ssid.SSID_len)
967 memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t));
968
969 eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
970
971 switch (p2p_scan_purpose) {
972 case P2P_SCAN_SOCIAL_CHANNEL:
973 eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
974 break;
975 case P2P_SCAN_AFX_PEER_NORMAL:
976 case P2P_SCAN_AFX_PEER_REDUCED:
977 eparams->params.active_time = htod32(P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS);
978 break;
979 case P2P_SCAN_CONNECT_TRY:
980 eparams->params.active_time = htod32(WL_SCAN_CONNECT_DWELL_TIME_MS);
981 break;
982 default :
983 if (wl_get_drv_status_all(cfg, CONNECTED))
984 eparams->params.active_time = -1;
985 else
986 eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS);
987 break;
988 }
989
990 if (p2p_scan_purpose == P2P_SCAN_CONNECT_TRY)
991 eparams->params.nprobes = htod32(eparams->params.active_time /
992 WL_SCAN_JOIN_PROBE_INTERVAL_MS);
993 else
994 eparams->params.nprobes = htod32((eparams->params.active_time /
995 P2PAPI_SCAN_NPROBS_TIME_MS));
996
997
998 if (eparams->params.nprobes <= 0)
999 eparams->params.nprobes = 1;
1000 CFGP2P_DBG(("nprobes # %d, active_time %d\n",
1001 eparams->params.nprobes, eparams->params.active_time));
1002 eparams->params.passive_time = htod32(-1);
1003 eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
1004 (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
1005
1006 for (i = 0; i < num_chans; i++) {
1007 eparams->params.channel_list[i] = wl_ch_host_to_driver(cfg, bssidx, channels[i]);
1008 }
1009 eparams->version = htod32(ESCAN_REQ_VERSION);
1010 eparams->action = htod16(action);
1011 wl_escan_set_sync_id(eparams->sync_id, cfg);
1012 wl_escan_set_type(cfg, WL_SCANTYPE_P2P);
1013 CFGP2P_INFO(("SCAN CHANNELS : "));
1014
1015 for (i = 0; i < num_chans; i++) {
1016 if (i == 0) CFGP2P_INFO(("%d", channels[i]));
1017 else CFGP2P_INFO((",%d", channels[i]));
1018 }
1019
1020 CFGP2P_INFO(("\n"));
1021
1022 ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
1023 memblk, memsize, cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
1024 WL_ERR(("P2P_SEARCH sync ID: %d, bssidx: %d\n", eparams->sync_id, bssidx));
1025 if (ret == BCME_OK)
1026 wl_set_p2p_status(cfg, SCANNING);
1027 return ret;
1028}
1029
1030/* search function to reach at common channel to send action frame
1031 * Parameters:
1032 * @cfg : wl_private data
1033 * @ndev : net device for bssidx
1034 * @bssidx : bssidx for BSS
1035 * Returns 0 if success.
1036 */
1037s32
1038wl_cfgp2p_act_frm_search(struct bcm_cfg80211 *cfg, struct net_device *ndev,
1039 s32 bssidx, s32 channel, struct ether_addr *tx_dst_addr)
1040{
1041 s32 ret = 0;
1042 u32 chan_cnt = 0;
1043 u16 *default_chan_list = NULL;
1044 p2p_scan_purpose_t p2p_scan_purpose = P2P_SCAN_AFX_PEER_NORMAL;
1045 if (!p2p_is_on(cfg) || ndev == NULL || bssidx == WL_INVALID)
1046 return -EINVAL;
1047 WL_TRACE_HW4((" Enter\n"));
1048 if (bssidx == wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_PRIMARY))
1049 bssidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
1050 if (channel)
1051 chan_cnt = AF_PEER_SEARCH_CNT;
1052 else
1053 chan_cnt = SOCIAL_CHAN_CNT;
1054
1055 if (cfg->afx_hdl->pending_tx_act_frm && cfg->afx_hdl->is_active) {
1056 wl_action_frame_t *action_frame;
1057 action_frame = &(cfg->afx_hdl->pending_tx_act_frm->action_frame);
1058 if (wl_cfgp2p_is_p2p_gas_action(action_frame->data, action_frame->len)) {
1059 chan_cnt = 1;
1060 p2p_scan_purpose = P2P_SCAN_AFX_PEER_REDUCED;
1061 }
1062 }
1063
1064 default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL);
1065 if (default_chan_list == NULL) {
1066 CFGP2P_ERR(("channel list allocation failed \n"));
1067 ret = -ENOMEM;
1068 goto exit;
1069 }
1070 if (channel) {
1071 u32 i;
1072 /* insert same channel to the chan_list */
1073 for (i = 0; i < chan_cnt; i++) {
1074 default_chan_list[i] = channel;
1075 }
1076 } else {
1077 default_chan_list[0] = SOCIAL_CHAN_1;
1078 default_chan_list[1] = SOCIAL_CHAN_2;
1079 default_chan_list[2] = SOCIAL_CHAN_3;
1080 }
1081 ret = wl_cfgp2p_escan(cfg, ndev, true, chan_cnt,
1082 default_chan_list, WL_P2P_DISC_ST_SEARCH,
1083 WL_SCAN_ACTION_START, bssidx, NULL, p2p_scan_purpose);
1084 kfree(default_chan_list);
1085exit:
1086 return ret;
1087}
1088
1089/* Check whether pointed-to IE looks like WPA. */
1090#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
1091 (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
1092/* Check whether pointed-to IE looks like WPS. */
1093#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
1094 (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE)
1095/* Check whether the given IE looks like WFA P2P IE. */
1096#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
1097 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
1098/* Check whether the given IE looks like WFA WFDisplay IE. */
1099#ifndef WFA_OUI_TYPE_WFD
1100#define WFA_OUI_TYPE_WFD 0x0a /* WiFi Display OUI TYPE */
1101#endif
1102#define wl_cfgp2p_is_wfd_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
1103 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_WFD)
1104
1105
1106/* Is any of the tlvs the expected entry? If
1107 * not update the tlvs buffer pointer/length.
1108 */
1109static bool
1110wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
1111{
1112 /* If the contents match the OUI and the type */
1113 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
1114 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
1115 type == ie[TLV_BODY_OFF + oui_len]) {
1116 return TRUE;
1117 }
1118
1119 if (tlvs == NULL)
1120 return FALSE;
1121 /* point to the next ie */
1122 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
1123 /* calculate the length of the rest of the buffer */
1124 *tlvs_len -= (int)(ie - *tlvs);
1125 /* update the pointer to the start of the buffer */
1126 *tlvs = ie;
1127
1128 return FALSE;
1129}
1130
1131wpa_ie_fixed_t *
1132wl_cfgp2p_find_wpaie(u8 *parse, u32 len)
1133{
1134 bcm_tlv_t *ie;
1135
1136 while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
1137 if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) {
1138 return (wpa_ie_fixed_t *)ie;
1139 }
1140 }
1141 return NULL;
1142}
1143
1144wpa_ie_fixed_t *
1145wl_cfgp2p_find_wpsie(u8 *parse, u32 len)
1146{
1147 bcm_tlv_t *ie;
1148
1149 while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
1150 if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) {
1151 return (wpa_ie_fixed_t *)ie;
1152 }
1153 }
1154 return NULL;
1155}
1156
1157wifi_p2p_ie_t *
1158wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
1159{
1160 bcm_tlv_t *ie;
1161
1162 while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
1163 if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) {
1164 return (wifi_p2p_ie_t *)ie;
1165 }
1166 }
1167 return NULL;
1168}
1169
1170wifi_wfd_ie_t *
1171wl_cfgp2p_find_wfdie(u8 *parse, u32 len)
1172{
1173 bcm_tlv_t *ie;
1174
1175 while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
1176 if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) {
1177 return (wifi_wfd_ie_t *)ie;
1178 }
1179 }
1180 return NULL;
1181}
1182u32
1183wl_cfgp2p_vndr_ie(struct bcm_cfg80211 *cfg, u8 *iebuf, s32 pktflag,
1184 s8 *oui, s32 ie_id, s8 *data, s32 datalen, const s8* add_del_cmd)
1185{
1186 vndr_ie_setbuf_t hdr; /* aligned temporary vndr_ie buffer header */
1187 s32 iecount;
1188 u32 data_offset;
1189
1190 /* Validate the pktflag parameter */
1191 if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
1192 VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
1193 VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) {
1194 CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag));
1195 return -1;
1196 }
1197
1198 /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1199 strncpy(hdr.cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1);
1200 hdr.cmd[VNDR_IE_CMD_LEN - 1] = '\0';
1201
1202 /* Set the IE count - the buffer contains only 1 IE */
1203 iecount = htod32(1);
1204 memcpy((void *)&hdr.vndr_ie_buffer.iecount, &iecount, sizeof(s32));
1205
1206 /* Copy packet flags that indicate which packets will contain this IE */
1207 pktflag = htod32(pktflag);
1208 memcpy((void *)&hdr.vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
1209 sizeof(u32));
1210
1211 /* Add the IE ID to the buffer */
1212 hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id;
1213
1214 /* Add the IE length to the buffer */
1215 hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len =
1216 (uint8) VNDR_IE_MIN_LEN + datalen;
1217
1218 /* Add the IE OUI to the buffer */
1219 hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[0] = oui[0];
1220 hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[1] = oui[1];
1221 hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui[2] = oui[2];
1222
1223 /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */
1224 memcpy(iebuf, &hdr, sizeof(hdr) - 1);
1225
1226 /* Copy the IE data to the IE buffer */
1227 data_offset =
1228 (u8*)&hdr.vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data[0] -
1229 (u8*)&hdr;
1230 memcpy(iebuf + data_offset, data, datalen);
1231 return data_offset + datalen;
1232
1233}
1234
1235struct net_device *
1236wl_cfgp2p_find_ndev(struct bcm_cfg80211 *cfg, s32 bssidx)
1237{
1238 u32 i;
1239 struct net_device *ndev = NULL;
1240 if (bssidx < 0) {
1241 CFGP2P_ERR((" bsscfg idx is invalid\n"));
1242 goto exit;
1243 }
1244
1245 for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
1246 if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) {
1247 ndev = wl_to_p2p_bss_ndev(cfg, i);
1248 break;
1249 }
1250 }
1251
1252exit:
1253 return ndev;
1254}
1255/*
1256 * Search the driver array idx based on bssidx argument
1257 * Parameters: Note that this idx is applicable only
1258 * for primary and P2P interfaces. The virtual AP/STA is not
1259 * covered here.
1260 * @cfg : wl_private data
1261 * @bssidx : bssidx which indicate bsscfg->idx of firmware.
1262 * @type : output arg to store array idx of p2p->bss.
1263 * Returns error
1264 */
1265
1266s32
1267wl_cfgp2p_find_type(struct bcm_cfg80211 *cfg, s32 bssidx, s32 *type)
1268{
1269 u32 i;
1270 if (bssidx < 0 || type == NULL) {
1271 CFGP2P_ERR((" argument is invalid\n"));
1272 goto exit;
1273 }
1274
1275 for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
1276 if (bssidx == wl_to_p2p_bss_bssidx(cfg, i)) {
1277 *type = i;
1278 return BCME_OK;
1279 }
1280 }
1281
1282exit:
1283 return BCME_BADARG;
1284}
1285
1286/*
1287 * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
1288 */
1289s32
1290wl_cfgp2p_listen_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1291 const wl_event_msg_t *e, void *data)
1292{
1293 s32 ret = BCME_OK;
1294 struct net_device *ndev = NULL;
1295
1296 if (!cfg || !cfg->p2p || !cfgdev)
1297 return BCME_ERROR;
1298
1299 CFGP2P_DBG((" Enter\n"));
1300#ifdef DHD_IFDEBUG
1301 PRINT_WDEV_INFO(cfgdev);
1302#endif /* DHD_IFDEBUG */
1303
1304 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
1305
1306#ifdef P2P_LISTEN_OFFLOADING
1307 if (wl_get_p2p_status(cfg, DISC_IN_PROGRESS)) {
1308 wl_clr_p2p_status(cfg, DISC_IN_PROGRESS);
1309 CFGP2P_ERR(("DISC_IN_PROGRESS cleared\n"));
1310 if (ndev && (ndev->ieee80211_ptr != NULL)) {
1311#if defined(WL_CFG80211_P2P_DEV_IF)
1312 if (cfgdev && ((struct wireless_dev *)cfgdev)->wiphy) {
1313 cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id,
1314 &cfg->remain_on_chan, GFP_KERNEL);
1315 } else {
1316 CFGP2P_ERR(("Invalid cfgdev. Dropping the"
1317 "remain_on_channel_expired event.\n"));
1318 }
1319#else
1320 cfg80211_remain_on_channel_expired(cfgdev, cfg->last_roc_id,
1321 &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
1322#endif /* WL_CFG80211_P2P_DEV_IF */
1323 }
1324 }
1325#endif /* P2P_LISTEN_OFFLOADING */
1326
1327 if (wl_get_p2p_status(cfg, LISTEN_EXPIRED) == 0) {
1328 wl_set_p2p_status(cfg, LISTEN_EXPIRED);
1329 if (timer_pending(&cfg->p2p->listen_timer)) {
1330 del_timer_sync(&cfg->p2p->listen_timer);
1331 }
1332
1333 if (cfg->afx_hdl->is_listen == TRUE &&
1334 wl_get_drv_status_all(cfg, FINDING_COMMON_CHANNEL)) {
1335 WL_DBG(("Listen DONE for action frame\n"));
1336 complete(&cfg->act_frm_scan);
1337 }
1338#ifdef WL_CFG80211_SYNC_GON
1339 else if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM_LISTEN)) {
1340 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM_LISTEN, ndev);
1341 WL_DBG(("Listen DONE and wake up wait_next_af !!(%d)\n",
1342 jiffies_to_msecs(jiffies - cfg->af_tx_sent_jiffies)));
1343
1344 if (wl_get_drv_status_all(cfg, WAITING_NEXT_ACT_FRM))
1345 wl_clr_drv_status(cfg, WAITING_NEXT_ACT_FRM, ndev);
1346
1347 complete(&cfg->wait_next_af);
1348 }
1349#endif /* WL_CFG80211_SYNC_GON */
1350
1351#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
1352 if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL)) {
1353#else
1354 if (wl_get_drv_status_all(cfg, REMAINING_ON_CHANNEL) ||
1355 wl_get_drv_status_all(cfg, FAKE_REMAINING_ON_CHANNEL)) {
1356#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
1357 WL_DBG(("Listen DONE for remain on channel expired\n"));
1358 wl_clr_drv_status(cfg, REMAINING_ON_CHANNEL, ndev);
1359#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
1360 wl_clr_drv_status(cfg, FAKE_REMAINING_ON_CHANNEL, ndev);
1361#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
1362 if (ndev && (ndev->ieee80211_ptr != NULL)) {
1363#if defined(WL_CFG80211_P2P_DEV_IF)
1364 if (cfgdev && ((struct wireless_dev *)cfgdev)->wiphy &&
1365 bcmcfg_to_p2p_wdev(cfg)) {
1366 /*
1367 * To prevent kernel panic,
1368 * if cfgdev->wiphy may be invalid, adding explicit check
1369 */
1370 cfg80211_remain_on_channel_expired(bcmcfg_to_p2p_wdev(cfg),
1371 cfg->last_roc_id, &cfg->remain_on_chan, GFP_KERNEL);
1372 } else
1373 CFGP2P_ERR(("Invalid cfgdev. Dropping the"
1374 "remain_on_channel_expired event.\n"));
1375#else
1376 if (cfgdev && ((struct wireless_dev *)cfgdev)->wiphy)
1377 cfg80211_remain_on_channel_expired(cfgdev,
1378 cfg->last_roc_id, &cfg->remain_on_chan,
1379 cfg->remain_on_chan_type, GFP_KERNEL);
1380#endif /* WL_CFG80211_P2P_DEV_IF */
1381 }
1382 }
1383 if (wl_add_remove_eventmsg(bcmcfg_to_prmry_ndev(cfg),
1384 WLC_E_P2P_PROBREQ_MSG, false) != BCME_OK) {
1385 CFGP2P_ERR((" failed to unset WLC_E_P2P_PROPREQ_MSG\n"));
1386 }
1387 } else
1388 wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
1389
1390 return ret;
1391
1392}
1393
1394/*
1395 * Timer expire callback function for LISTEN
1396 * We can't report cfg80211_remain_on_channel_expired from Timer ISR context,
1397 * so lets do it from thread context.
1398 */
1399void
1400wl_cfgp2p_listen_expired(unsigned long data)
1401{
1402 wl_event_msg_t msg;
1403 struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *) data;
1404 struct net_device *ndev;
1405 CFGP2P_DBG((" Enter\n"));
1406
1407 if (!cfg) {
1408 CFGP2P_ERR((" No cfg\n"));
1409 return;
1410 }
1411 bzero(&msg, sizeof(wl_event_msg_t));
1412 msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE);
1413 msg.bsscfgidx = wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE);
1414#if defined(WL_ENABLE_P2P_IF)
1415 ndev = cfg->p2p_net ? cfg->p2p_net :
1416 wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE);
1417#else
1418 ndev = wl_to_p2p_bss_ndev(cfg, P2PAPI_BSSCFG_DEVICE);
1419#endif /* WL_ENABLE_P2P_IF */
1420 if (!ndev) {
1421 CFGP2P_ERR((" No ndev\n"));
1422 return;
1423 }
1424 wl_cfg80211_event(ndev, &msg, NULL);
1425}
1426/*
1427 * Routine for cancelling the P2P LISTEN
1428 */
1429static s32
1430wl_cfgp2p_cancel_listen(struct bcm_cfg80211 *cfg, struct net_device *ndev,
1431 struct wireless_dev *wdev, bool notify)
1432{
1433 WL_DBG(("Enter \n"));
1434 /* Irrespective of whether timer is running or not, reset
1435 * the LISTEN state.
1436 */
1437#ifdef NOT_YET
1438 wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
1439 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
1440#endif /* NOT_YET */
1441 if (timer_pending(&cfg->p2p->listen_timer)) {
1442 del_timer_sync(&cfg->p2p->listen_timer);
1443 if (notify) {
1444#if defined(WL_CFG80211_P2P_DEV_IF)
1445 if (bcmcfg_to_p2p_wdev(cfg))
1446 cfg80211_remain_on_channel_expired(wdev, cfg->last_roc_id,
1447 &cfg->remain_on_chan, GFP_KERNEL);
1448#else
1449 if (ndev && ndev->ieee80211_ptr)
1450 cfg80211_remain_on_channel_expired(ndev, cfg->last_roc_id,
1451 &cfg->remain_on_chan, cfg->remain_on_chan_type, GFP_KERNEL);
1452#endif /* WL_CFG80211_P2P_DEV_IF */
1453 }
1454 }
1455 return 0;
1456}
1457/*
1458 * Do a P2P Listen on the given channel for the given duration.
1459 * A listen consists of sitting idle and responding to P2P probe requests
1460 * with a P2P probe response.
1461 *
1462 * This fn assumes dongle p2p device discovery is already enabled.
1463 * Parameters :
1464 * @cfg : wl_private data
1465 * @channel : channel to listen
1466 * @duration_ms : the time (milli seconds) to wait
1467 */
1468s32
1469wl_cfgp2p_discover_listen(struct bcm_cfg80211 *cfg, s32 channel, u32 duration_ms)
1470{
1471#define EXTRA_DELAY_TIME 100
1472 s32 ret = BCME_OK;
1473 struct timer_list *_timer;
1474 s32 extra_delay;
1475 struct net_device *netdev = bcmcfg_to_prmry_ndev(cfg);
1476
1477 CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel, duration_ms));
1478 if (unlikely(wl_get_p2p_status(cfg, DISCOVERY_ON) == 0)) {
1479
1480 CFGP2P_ERR((" Discovery is not set, so we have noting to do\n"));
1481
1482 ret = BCME_NOTREADY;
1483 goto exit;
1484 }
1485 if (timer_pending(&cfg->p2p->listen_timer)) {
1486 CFGP2P_DBG(("previous LISTEN is not completed yet\n"));
1487 goto exit;
1488
1489 }
1490#ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
1491 else
1492 wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
1493#endif /* not WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
1494 if (wl_add_remove_eventmsg(netdev, WLC_E_P2P_PROBREQ_MSG, true) != BCME_OK) {
1495 CFGP2P_ERR((" failed to set WLC_E_P2P_PROPREQ_MSG\n"));
1496 }
1497
1498 ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
1499 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
1500 _timer = &cfg->p2p->listen_timer;
1501
1502 /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
1503 * otherwise we will wait up to duration_ms + 100ms + duration / 10
1504 */
1505 if (ret == BCME_OK) {
1506 extra_delay = EXTRA_DELAY_TIME + (duration_ms / 10);
1507 } else {
1508 /* if failed to set listen, it doesn't need to wait whole duration. */
1509 duration_ms = 100 + duration_ms / 20;
1510 extra_delay = 0;
1511 }
1512
1513 INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, extra_delay);
1514#ifdef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
1515 wl_clr_p2p_status(cfg, LISTEN_EXPIRED);
1516#endif /* WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST */
1517
1518#undef EXTRA_DELAY_TIME
1519exit:
1520 return ret;
1521}
1522
1523
1524s32
1525wl_cfgp2p_discover_enable_search(struct bcm_cfg80211 *cfg, u8 enable)
1526{
1527 s32 ret = BCME_OK;
1528 CFGP2P_DBG((" Enter\n"));
1529 if (!wl_get_p2p_status(cfg, DISCOVERY_ON)) {
1530
1531 CFGP2P_DBG((" do nothing, discovery is off\n"));
1532 return ret;
1533 }
1534 if (wl_get_p2p_status(cfg, SEARCH_ENABLED) == enable) {
1535 CFGP2P_DBG(("already : %d\n", enable));
1536 return ret;
1537 }
1538
1539 wl_chg_p2p_status(cfg, SEARCH_ENABLED);
1540 /* When disabling Search, reset the WL driver's p2p discovery state to
1541 * WL_P2P_DISC_ST_SCAN.
1542 */
1543 if (!enable) {
1544 wl_clr_p2p_status(cfg, SCANNING);
1545 ret = wl_cfgp2p_set_p2p_mode(cfg, WL_P2P_DISC_ST_SCAN, 0, 0,
1546 wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_DEVICE));
1547 }
1548
1549 return ret;
1550}
1551
1552/*
1553 * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
1554 */
1555s32
1556wl_cfgp2p_action_tx_complete(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
1557 const wl_event_msg_t *e, void *data)
1558{
1559 s32 ret = BCME_OK;
1560 u32 event_type = ntoh32(e->event_type);
1561 u32 status = ntoh32(e->status);
1562 struct net_device *ndev = NULL;
1563 u8 bsscfgidx = e->bsscfgidx;
1564
1565 CFGP2P_DBG((" Enter\n"));
1566
1567 ndev = cfgdev_to_wlc_ndev(cfgdev, cfg);
1568
1569 if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM)) {
1570 if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
1571
1572 CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
1573 if (status == WLC_E_STATUS_SUCCESS) {
1574 wl_set_p2p_status(cfg, ACTION_TX_COMPLETED);
1575 CFGP2P_DBG(("WLC_E_ACTION_FRAME_COMPLETE : ACK\n"));
1576 if (!cfg->need_wait_afrx && cfg->af_sent_channel) {
1577 CFGP2P_DBG(("no need to wait next AF.\n"));
1578 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
1579 }
1580 }
1581 else if (!wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) {
1582 wl_set_p2p_status(cfg, ACTION_TX_NOACK);
1583 CFGP2P_INFO(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
1584 wl_stop_wait_next_action_frame(cfg, ndev, bsscfgidx);
1585 }
1586 } else {
1587 CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
1588 "status : %d\n", status));
1589
1590 if (wl_get_drv_status_all(cfg, SENDING_ACT_FRM))
1591 complete(&cfg->send_af_done);
1592 }
1593 }
1594 return ret;
1595}
1596/* Send an action frame immediately without doing channel synchronization.
1597 *
1598 * This function does not wait for a completion event before returning.
1599 * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
1600 * frame is transmitted.
1601 * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an
1602 * 802.11 ack has been received for the sent action frame.
1603 */
1604s32
1605wl_cfgp2p_tx_action_frame(struct bcm_cfg80211 *cfg, struct net_device *dev,
1606 wl_af_params_t *af_params, s32 bssidx)
1607{
1608 s32 ret = BCME_OK;
1609 s32 evt_ret = BCME_OK;
1610 s32 timeout = 0;
1611 wl_eventmsg_buf_t buf;
1612
1613
1614 CFGP2P_INFO(("\n"));
1615 CFGP2P_INFO(("channel : %u , dwell time : %u\n",
1616 af_params->channel, af_params->dwell_time));
1617
1618 wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED);
1619 wl_clr_p2p_status(cfg, ACTION_TX_NOACK);
1620
1621 bzero(&buf, sizeof(wl_eventmsg_buf_t));
1622 wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, true);
1623 wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, true);
1624 if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0)
1625 return evt_ret;
1626
1627 cfg->af_sent_channel = af_params->channel;
1628#ifdef WL_CFG80211_SYNC_GON
1629 cfg->af_tx_sent_jiffies = jiffies;
1630#endif /* WL_CFG80211_SYNC_GON */
1631
1632 ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params),
1633 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync);
1634
1635 if (ret < 0) {
1636 CFGP2P_ERR((" sending action frame is failed\n"));
1637 goto exit;
1638 }
1639
1640 timeout = wait_for_completion_timeout(&cfg->send_af_done,
1641 msecs_to_jiffies(af_params->dwell_time + WL_AF_TX_EXTRA_TIME_MAX));
1642
1643 if (timeout >= 0 && wl_get_p2p_status(cfg, ACTION_TX_COMPLETED)) {
1644 CFGP2P_INFO(("tx action frame operation is completed\n"));
1645 ret = BCME_OK;
1646 } else if (ETHER_ISBCAST(&cfg->afx_hdl->tx_dst_addr)) {
1647 CFGP2P_INFO(("bcast tx action frame operation is completed\n"));
1648 ret = BCME_OK;
1649 } else {
1650 ret = BCME_ERROR;
1651 CFGP2P_INFO(("tx action frame operation is failed\n"));
1652 }
1653 /* clear status bit for action tx */
1654 wl_clr_p2p_status(cfg, ACTION_TX_COMPLETED);
1655 wl_clr_p2p_status(cfg, ACTION_TX_NOACK);
1656
1657exit:
1658 CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
1659
1660 bzero(&buf, sizeof(wl_eventmsg_buf_t));
1661 wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, false);
1662 wl_cfg80211_add_to_eventbuffer(&buf, WLC_E_ACTION_FRAME_COMPLETE, false);
1663 if ((evt_ret = wl_cfg80211_apply_eventbuffer(bcmcfg_to_prmry_ndev(cfg), cfg, &buf)) < 0) {
1664 WL_ERR(("TX frame events revert back failed \n"));
1665 return evt_ret;
1666 }
1667
1668 return ret;
1669}
1670
1671/* Generate our P2P Device Address and P2P Interface Address from our primary
1672 * MAC address.
1673 */
1674void
1675wl_cfgp2p_generate_bss_mac(struct bcm_cfg80211 *cfg, struct ether_addr *primary_addr)
1676{
1677 struct ether_addr *mac_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE);
1678 struct ether_addr *int_addr;
1679
1680 memcpy(mac_addr, primary_addr, sizeof(struct ether_addr));
1681 mac_addr->octet[0] |= 0x02;
1682 WL_DBG(("P2P Discovery address:"MACDBG "\n", MAC2STRDBG(mac_addr->octet)));
1683
1684 int_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_CONNECTION1);
1685 memcpy(int_addr, mac_addr, sizeof(struct ether_addr));
1686 int_addr->octet[4] ^= 0x80;
1687 WL_DBG(("Primary P2P Interface address:"MACDBG "\n", MAC2STRDBG(int_addr->octet)));
1688
1689 int_addr = wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_CONNECTION2);
1690 memcpy(int_addr, mac_addr, sizeof(struct ether_addr));
1691 int_addr->octet[4] ^= 0x90;
1692}
1693
1694/* P2P IF Address change to Virtual Interface MAC Address */
1695void
1696wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id)
1697{
1698 wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf;
1699 u16 len = ie->len;
1700 u8 *subel;
1701 u8 subelt_id;
1702 u16 subelt_len;
1703 CFGP2P_DBG((" Enter\n"));
1704
1705 /* Point subel to the P2P IE's subelt field.
1706 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
1707 */
1708 subel = ie->subelts;
1709 len -= 4; /* exclude OUI + OUI_TYPE */
1710
1711 while (len >= 3) {
1712 /* attribute id */
1713 subelt_id = *subel;
1714 subel += 1;
1715 len -= 1;
1716
1717 /* 2-byte little endian */
1718 subelt_len = *subel++;
1719 subelt_len |= *subel++ << 8;
1720
1721 len -= 2;
1722 len -= subelt_len; /* for the remaining subelt fields */
1723
1724 if (subelt_id == element_id) {
1725 if (subelt_id == P2P_SEID_INTINTADDR) {
1726 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1727 CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n"));
1728 } else if (subelt_id == P2P_SEID_DEV_ID) {
1729 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1730 CFGP2P_INFO(("Device ID ATTR FOUND\n"));
1731 } else if (subelt_id == P2P_SEID_DEV_INFO) {
1732 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1733 CFGP2P_INFO(("Device INFO ATTR FOUND\n"));
1734 } else if (subelt_id == P2P_SEID_GROUP_ID) {
1735 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1736 CFGP2P_INFO(("GROUP ID ATTR FOUND\n"));
1737 } return;
1738 } else {
1739 CFGP2P_DBG(("OTHER id : %d\n", subelt_id));
1740 }
1741 subel += subelt_len;
1742 }
1743}
1744
1745s32
1746wl_cfgp2p_supported(struct bcm_cfg80211 *cfg, struct net_device *ndev)
1747{
1748 s32 ret = BCME_OK;
1749 s32 p2p_supported = 0;
1750 ret = wldev_iovar_getint(ndev, "p2p",
1751 &p2p_supported);
1752 if (ret < 0) {
1753 if (ret == BCME_UNSUPPORTED) {
1754 CFGP2P_INFO(("p2p is unsupported\n"));
1755 return 0;
1756 } else {
1757 CFGP2P_ERR(("cfg p2p error %d\n", ret));
1758 return ret;
1759 }
1760 }
1761 if (p2p_supported == 1) {
1762 CFGP2P_INFO(("p2p is supported\n"));
1763 } else {
1764 CFGP2P_INFO(("p2p is unsupported\n"));
1765 p2p_supported = 0;
1766 }
1767 return p2p_supported;
1768}
1769/* Cleanup P2P resources */
1770s32
1771wl_cfgp2p_down(struct bcm_cfg80211 *cfg)
1772{
1773 struct net_device *ndev = NULL;
1774 struct wireless_dev *wdev = NULL;
1775 s32 i = 0, index = -1;
1776
1777#if defined(WL_CFG80211_P2P_DEV_IF)
1778 ndev = bcmcfg_to_prmry_ndev(cfg);
1779 wdev = bcmcfg_to_p2p_wdev(cfg);
1780#elif defined(WL_ENABLE_P2P_IF)
1781 ndev = cfg->p2p_net ? cfg->p2p_net : bcmcfg_to_prmry_ndev(cfg);
1782 wdev = ndev_to_wdev(ndev);
1783#endif /* WL_CFG80211_P2P_DEV_IF */
1784
1785 wl_cfgp2p_cancel_listen(cfg, ndev, wdev, TRUE);
1786 wl_cfgp2p_disable_discovery(cfg);
1787
1788#if defined(WL_CFG80211_P2P_DEV_IF) && !defined(KEEP_WIFION_OPTION)
1789/*
1790 * In CUSTOMER_HW4 implementation "ifconfig wlan0 down" can get
1791 * called during phone suspend and customer requires the p2p
1792 * discovery interface to be left untouched so that the user
1793 * space can resume without any problem.
1794 */
1795 if (cfg->p2p_wdev) {
1796 /* If p2p wdev is left out, clean it up */
1797 WL_ERR(("Clean up the p2p discovery IF\n"));
1798 wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
1799 }
1800#endif /* WL_CFG80211_P2P_DEV_IF !defined(KEEP_WIFION_OPTION) */
1801
1802 for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
1803 index = wl_to_p2p_bss_bssidx(cfg, i);
1804 if (index != WL_INVALID)
1805 wl_cfg80211_clear_per_bss_ies(cfg, index);
1806 }
1807 wl_cfgp2p_deinit_priv(cfg);
1808 return 0;
1809}
1810
1811int wl_cfgp2p_vif_created(struct bcm_cfg80211 *cfg)
1812{
1813 if (cfg->p2p && ((wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION1) != -1) ||
1814 (wl_to_p2p_bss_bssidx(cfg, P2PAPI_BSSCFG_CONNECTION2) != -1)))
1815 return true;
1816 else
1817 return false;
1818
1819}
1820
1821s32
1822wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
1823{
1824 s32 ret = -1;
1825 int count, start, duration;
1826 wl_p2p_sched_t dongle_noa;
1827 s32 bssidx, type;
1828 int iovar_len = sizeof(dongle_noa);
1829 CFGP2P_DBG((" Enter\n"));
1830
1831 memset(&dongle_noa, 0, sizeof(dongle_noa));
1832
1833 if (wl_cfgp2p_vif_created(cfg)) {
1834 cfg->p2p->noa.desc[0].start = 0;
1835
1836 sscanf(buf, "%10d %10d %10d", &count, &start, &duration);
1837 CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
1838 count, start, duration));
1839 if (count != -1)
1840 cfg->p2p->noa.desc[0].count = count;
1841
1842 /* supplicant gives interval as start */
1843 if (start != -1)
1844 cfg->p2p->noa.desc[0].interval = start;
1845
1846 if (duration != -1)
1847 cfg->p2p->noa.desc[0].duration = duration;
1848
1849 if (cfg->p2p->noa.desc[0].count != 255 && cfg->p2p->noa.desc[0].count != 0) {
1850 cfg->p2p->noa.desc[0].start = 200;
1851 dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS;
1852 dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF;
1853 dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS;
1854 }
1855 else if (cfg->p2p->noa.desc[0].count == 0) {
1856 cfg->p2p->noa.desc[0].start = 0;
1857 dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
1858 dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
1859 dongle_noa.action = WL_P2P_SCHED_ACTION_RESET;
1860 }
1861 else {
1862 /* Continuous NoA interval. */
1863 dongle_noa.action = WL_P2P_SCHED_ACTION_DOZE;
1864 dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
1865 if ((cfg->p2p->noa.desc[0].interval == 102) ||
1866 (cfg->p2p->noa.desc[0].interval == 100)) {
1867 cfg->p2p->noa.desc[0].start = 100 -
1868 cfg->p2p->noa.desc[0].duration;
1869 dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT;
1870 }
1871 else {
1872 dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
1873 }
1874 }
1875 /* Put the noa descriptor in dongle format for dongle */
1876 dongle_noa.desc[0].count = htod32(cfg->p2p->noa.desc[0].count);
1877 if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) {
1878 dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start);
1879 dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration);
1880 }
1881 else {
1882 dongle_noa.desc[0].start = htod32(cfg->p2p->noa.desc[0].start*1000);
1883 dongle_noa.desc[0].duration = htod32(cfg->p2p->noa.desc[0].duration*1000);
1884 }
1885 dongle_noa.desc[0].interval = htod32(cfg->p2p->noa.desc[0].interval*1000);
1886 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
1887 if (wl_cfgp2p_find_type(cfg, bssidx, &type) != BCME_OK)
1888 return BCME_ERROR;
1889
1890 if (dongle_noa.action == WL_P2P_SCHED_ACTION_RESET) {
1891 iovar_len -= sizeof(wl_p2p_sched_desc_t);
1892 }
1893
1894 ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(cfg, type),
1895 "p2p_noa", &dongle_noa, iovar_len, cfg->ioctl_buf,
1896 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
1897
1898 if (ret < 0) {
1899 CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
1900 }
1901 }
1902 else {
1903 CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n"));
1904 }
1905 return ret;
1906}
1907s32
1908wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int buf_len)
1909{
1910
1911 wifi_p2p_noa_desc_t *noa_desc;
1912 int len = 0, i;
1913 char _buf[200];
1914
1915 CFGP2P_DBG((" Enter\n"));
1916 buf[0] = '\0';
1917 if (wl_cfgp2p_vif_created(cfg)) {
1918 if (cfg->p2p->noa.desc[0].count || cfg->p2p->ops.ops) {
1919 _buf[0] = 1; /* noa index */
1920 _buf[1] = (cfg->p2p->ops.ops ? 0x80: 0) |
1921 (cfg->p2p->ops.ctw & 0x7f); /* ops + ctw */
1922 len += 2;
1923 if (cfg->p2p->noa.desc[0].count) {
1924 noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len];
1925 noa_desc->cnt_type = cfg->p2p->noa.desc[0].count;
1926 noa_desc->duration = cfg->p2p->noa.desc[0].duration;
1927 noa_desc->interval = cfg->p2p->noa.desc[0].interval;
1928 noa_desc->start = cfg->p2p->noa.desc[0].start;
1929 len += sizeof(wifi_p2p_noa_desc_t);
1930 }
1931 if (buf_len <= len * 2) {
1932 CFGP2P_ERR(("ERROR: buf_len %d in not enough for"
1933 "returning noa in string format\n", buf_len));
1934 return -1;
1935 }
1936 /* We have to convert the buffer data into ASCII strings */
1937 for (i = 0; i < len; i++) {
1938 snprintf(buf, 3, "%02x", _buf[i]);
1939 buf += 2;
1940 }
1941 buf[i*2] = '\0';
1942 }
1943 }
1944 else {
1945 CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n"));
1946 return -1;
1947 }
1948 return len * 2;
1949}
1950s32
1951wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
1952{
1953 int ps, ctw;
1954 int ret = -1;
1955 s32 legacy_ps;
1956 s32 conn_idx;
1957 s32 bssidx;
1958 struct net_device *dev;
1959
1960 CFGP2P_DBG((" Enter\n"));
1961 if (wl_cfgp2p_vif_created(cfg)) {
1962 sscanf(buf, "%10d %10d %10d", &legacy_ps, &ps, &ctw);
1963 CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw));
1964
1965 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
1966 if (wl_cfgp2p_find_type(cfg, bssidx, &conn_idx) != BCME_OK)
1967 return BCME_ERROR;
1968 dev = wl_to_p2p_bss_ndev(cfg, conn_idx);
1969 if (ctw != -1) {
1970 cfg->p2p->ops.ctw = ctw;
1971 ret = 0;
1972 }
1973 if (ps != -1) {
1974 cfg->p2p->ops.ops = ps;
1975 ret = wldev_iovar_setbuf(dev,
1976 "p2p_ops", &cfg->p2p->ops, sizeof(cfg->p2p->ops),
1977 cfg->ioctl_buf, WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
1978 if (ret < 0) {
1979 CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
1980 }
1981 }
1982
1983 if ((legacy_ps != -1) && ((legacy_ps == PM_MAX) || (legacy_ps == PM_OFF))) {
4c205efb
DW
1984 ret = wldev_ioctl_set(dev,
1985 WLC_SET_PM, &legacy_ps, sizeof(legacy_ps));
3c2a0909
S
1986 if (unlikely(ret))
1987 CFGP2P_ERR(("error (%d)\n", ret));
1988 wl_cfg80211_update_power_mode(dev);
1989 }
1990 else
1991 CFGP2P_ERR(("ilegal setting\n"));
1992 }
1993 else {
1994 CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n"));
1995 ret = -1;
1996 }
1997 return ret;
1998}
1999
2000s32
2001wl_cfgp2p_set_p2p_ecsa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
2002{
2003 int ch, bw;
2004 s32 conn_idx;
2005 s32 bssidx;
2006 struct net_device *dev;
2007 char smbuf[WLC_IOCTL_SMLEN];
2008 wl_chan_switch_t csa_arg;
2009 u32 chnsp = 0;
2010 int err = 0;
2011
2012 CFGP2P_DBG((" Enter\n"));
2013 if (wl_cfgp2p_vif_created(cfg)) {
2014 sscanf(buf, "%10d %10d", &ch, &bw);
2015 CFGP2P_DBG(("Enter ch %d bw %d\n", ch, bw));
2016
2017 bssidx = wl_get_bssidx_by_wdev(cfg, ndev->ieee80211_ptr);
2018 if (wl_cfgp2p_find_type(cfg, bssidx, &conn_idx) != BCME_OK) {
2019 return BCME_ERROR;
2020 }
2021 dev = wl_to_p2p_bss_ndev(cfg, conn_idx);
2022 if (ch <= 0 || bw <= 0) {
2023 CFGP2P_ERR(("Negative value not permitted!\n"));
2024 return BCME_ERROR;
2025 }
2026
2027 csa_arg.mode = DOT11_CSA_MODE_ADVISORY;
2028 csa_arg.count = P2P_ECSA_CNT;
2029 csa_arg.reg = 0;
2030
2031 snprintf(buf, len, "%d/%d", ch, bw);
2032 chnsp = wf_chspec_aton(buf);
2033 if (chnsp == 0) {
2034 CFGP2P_ERR(("%s:chsp is not correct\n", __FUNCTION__));
2035 return BCME_ERROR;
2036 }
2037 chnsp = wl_chspec_host_to_driver(chnsp);
2038 csa_arg.chspec = chnsp;
2039
2040 err = wldev_iovar_setbuf(dev, "csa", &csa_arg, sizeof(csa_arg),
2041 smbuf, sizeof(smbuf), NULL);
2042 if (err) {
2043 CFGP2P_ERR(("%s:set p2p_ecsa failed:%d\n", __FUNCTION__, err));
2044 return BCME_ERROR;
2045 }
2046 } else {
2047 CFGP2P_ERR(("ERROR: set_p2p_ecsa in non-p2p mode\n"));
2048 return BCME_ERROR;
2049 }
2050 return BCME_OK;
2051}
2052
2053s32
2054wl_cfgp2p_increase_p2p_bw(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* buf, int len)
2055{
2056 int algo;
2057 int bw;
2058 int ret = BCME_OK;
2059
2060
2061 sscanf(buf, "%3d", &bw);
2062 if (bw == 0) {
2063 algo = 0;
2064 ret = wldev_iovar_setbuf(ndev, "mchan_algo", &algo, sizeof(algo), cfg->ioctl_buf,
2065 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
2066 if (ret < 0) {
2067 CFGP2P_ERR(("fw set mchan_algo failed %d\n", ret));
2068 return BCME_ERROR;
2069 }
2070 } else {
2071 algo = 1;
2072 ret = wldev_iovar_setbuf(ndev, "mchan_algo", &algo, sizeof(algo), cfg->ioctl_buf,
2073 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
2074 if (ret < 0) {
2075 CFGP2P_ERR(("fw set mchan_algo failed %d\n", ret));
2076 return BCME_ERROR;
2077 }
2078 ret = wldev_iovar_setbuf(ndev, "mchan_bw", &bw, sizeof(algo), cfg->ioctl_buf,
2079 WLC_IOCTL_MAXLEN, &cfg->ioctl_buf_sync);
2080 if (ret < 0) {
2081 CFGP2P_ERR(("fw set mchan_bw failed %d\n", ret));
2082 return BCME_ERROR;
2083 }
2084 }
2085 return BCME_OK;
2086}
2087
2088u8 *
2089wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id)
2090{
2091 wifi_p2p_ie_t *ie = NULL;
2092 u16 len = 0;
2093 u8 *subel;
2094 u8 subelt_id;
2095 u16 subelt_len;
2096
2097 if (!buf) {
2098 WL_ERR(("P2P IE not present"));
2099 return 0;
2100 }
2101
2102 ie = (wifi_p2p_ie_t*) buf;
2103 len = ie->len;
2104
2105 /* Point subel to the P2P IE's subelt field.
2106 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
2107 */
2108 subel = ie->subelts;
2109 len -= 4; /* exclude OUI + OUI_TYPE */
2110
2111 while (len >= 3) {
2112 /* attribute id */
2113 subelt_id = *subel;
2114 subel += 1;
2115 len -= 1;
2116
2117 /* 2-byte little endian */
2118 subelt_len = *subel++;
2119 subelt_len |= *subel++ << 8;
2120
2121 len -= 2;
2122 len -= subelt_len; /* for the remaining subelt fields */
2123
2124 if (subelt_id == element_id) {
2125 /* This will point to start of subelement attrib after
2126 * attribute id & len
2127 */
2128 return subel;
2129 }
2130
2131 /* Go to next subelement */
2132 subel += subelt_len;
2133 }
2134
2135 /* Not Found */
2136 return NULL;
2137}
2138
2139#define P2P_GROUP_CAPAB_GO_BIT 0x01
2140
2141u8*
2142wl_cfgp2p_find_attrib_in_all_p2p_Ies(u8 *parse, u32 len, u32 attrib)
2143{
2144 bcm_tlv_t *ie;
2145 u8* pAttrib;
2146
2147 CFGP2P_INFO(("Starting parsing parse %p attrib %d remaining len %d ", parse, attrib, len));
2148 while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
2149 if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len) == TRUE) {
2150 /* Have the P2p ie. Now check for attribute */
2151 if ((pAttrib = wl_cfgp2p_retreive_p2pattrib(parse, attrib)) != NULL) {
2152 CFGP2P_INFO(("P2P attribute %d was found at parse %p",
2153 attrib, parse));
2154 return pAttrib;
2155 }
2156 else {
2157 parse += (ie->len + TLV_HDR_LEN);
2158 len -= (ie->len + TLV_HDR_LEN);
2159 CFGP2P_INFO(("P2P Attribute %d not found Moving parse"
2160 " to %p len to %d", attrib, parse, len));
2161 }
2162 }
2163 else {
2164 /* It was not p2p IE. parse will get updated automatically to next TLV */
2165 CFGP2P_INFO(("IT was NOT P2P IE parse %p len %d", parse, len));
2166 }
2167 }
2168 CFGP2P_ERR(("P2P attribute %d was NOT found", attrib));
2169 return NULL;
2170}
2171
2172u8 *
2173wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length)
2174{
2175 u8 *capability = NULL;
2176 bool p2p_go = 0;
2177 u8 *ptr = NULL;
2178
2179 if ((capability = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
2180 bi->ie_length, P2P_SEID_P2P_INFO)) == NULL) {
2181 WL_ERR(("P2P Capability attribute not found"));
2182 return NULL;
2183 }
2184
2185 /* Check Group capability for Group Owner bit */
2186 p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT;
2187 if (!p2p_go) {
2188 return bi->BSSID.octet;
2189 }
2190
2191 /* In probe responses, DEVICE INFO attribute will be present */
2192 if (!(ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
2193 bi->ie_length, P2P_SEID_DEV_INFO))) {
2194 /* If DEVICE_INFO is not found, this might be a beacon frame.
2195 * check for DEVICE_ID in the beacon frame.
2196 */
2197 ptr = wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8 *) bi) + bi->ie_offset,
2198 bi->ie_length, P2P_SEID_DEV_ID);
2199 }
2200
2201 if (!ptr)
2202 WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "));
2203
2204 return ptr;
2205}
2206
2207#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2208static void
2209wl_cfgp2p_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
2210{
2211 snprintf(info->driver, sizeof(info->driver), "p2p");
2212 snprintf(info->version, sizeof(info->version), "%lu", (unsigned long)(0));
2213}
2214
2215struct ethtool_ops cfgp2p_ethtool_ops = {
2216 .get_drvinfo = wl_cfgp2p_ethtool_get_drvinfo
2217};
2218#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
2219
2220#if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
2221s32
2222wl_cfgp2p_register_ndev(struct bcm_cfg80211 *cfg)
2223{
2224 int ret = 0;
2225 struct net_device* net = NULL;
2226#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2227 struct wireless_dev *wdev = NULL;
2228#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2229 uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 };
2230
2231 if (cfg->p2p_net) {
2232 CFGP2P_ERR(("p2p_net defined already.\n"));
2233 return -EINVAL;
2234 }
2235
2236 /* Allocate etherdev, including space for private structure */
2237 if (!(net = alloc_etherdev(sizeof(struct bcm_cfg80211 *)))) {
2238 CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
2239 return -ENODEV;
2240 }
2241
2242#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2243 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2244 if (unlikely(!wdev)) {
2245 WL_ERR(("Could not allocate wireless device\n"));
2246 free_netdev(net);
2247 return -ENOMEM;
2248 }
2249#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2250
2251 strncpy(net->name, "p2p%d", sizeof(net->name) - 1);
2252 net->name[IFNAMSIZ - 1] = '\0';
2253
2254 /* Copy the reference to bcm_cfg80211 */
2255 memcpy((void *)netdev_priv(net), &cfg, sizeof(struct bcm_cfg80211 *));
2256
2257#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
2258 ASSERT(!net->open);
2259 net->do_ioctl = wl_cfgp2p_do_ioctl;
2260 net->hard_start_xmit = wl_cfgp2p_start_xmit;
2261 net->open = wl_cfgp2p_if_open;
2262 net->stop = wl_cfgp2p_if_stop;
2263#else
2264 ASSERT(!net->netdev_ops);
2265 net->netdev_ops = &wl_cfgp2p_if_ops;
2266#endif
2267
2268 /* Register with a dummy MAC addr */
2269 memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
2270
2271#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2272 wdev->wiphy = cfg->wdev->wiphy;
2273
2274 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
2275
2276 net->ieee80211_ptr = wdev;
2277#else
2278 net->ieee80211_ptr = NULL;
2279#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2280
2281#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2282 net->ethtool_ops = &cfgp2p_ethtool_ops;
2283#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
2284
2285#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2286 SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy));
2287
2288 /* Associate p2p0 network interface with new wdev */
2289 wdev->netdev = net;
2290#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2291
2292 ret = register_netdev(net);
2293 if (ret) {
2294 CFGP2P_ERR((" register_netdevice failed (%d)\n", ret));
2295 free_netdev(net);
2296#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2297 kfree(wdev);
2298#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2299 return -ENODEV;
2300 }
2301
2302 /* store p2p net ptr for further reference. Note that iflist won't have this
2303 * entry as there corresponding firmware interface is a "Hidden" interface.
2304 */
2305#ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2306 cfg->p2p_wdev = wdev;
2307#else
2308 cfg->p2p_wdev = NULL;
2309#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2310 cfg->p2p_net = net;
2311
2312 printk("%s: P2P Interface Registered\n", net->name);
2313
2314 return ret;
2315}
2316
2317s32
2318wl_cfgp2p_unregister_ndev(struct bcm_cfg80211 *cfg)
2319{
2320
2321 if (!cfg || !cfg->p2p_net) {
2322 CFGP2P_ERR(("Invalid Ptr\n"));
2323 return -EINVAL;
2324 }
2325
2326 unregister_netdev(cfg->p2p_net);
2327 free_netdev(cfg->p2p_net);
2328
2329 return 0;
2330}
2331static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev)
2332{
2333
2334 if (skb)
2335 {
2336 CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n",
2337 ndev->name));
2338 dev_kfree_skb_any(skb);
2339 }
2340
2341 return 0;
2342}
2343
2344static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd)
2345{
2346 int ret = 0;
2347 struct bcm_cfg80211 *cfg = *(struct bcm_cfg80211 **)netdev_priv(net);
2348 struct net_device *ndev = bcmcfg_to_prmry_ndev(cfg);
2349
2350 /* There is no ifidx corresponding to p2p0 in our firmware. So we should
2351 * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs.
2352 * For Android PRIV CMD handling map it to primary I/F
2353 */
2354 if (cmd == SIOCDEVPRIVATE+1) {
2355 ret = wl_android_priv_cmd(ndev, ifr, cmd);
2356
2357 } else {
2358 CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n",
2359 __FUNCTION__, cmd));
2360 return -1;
2361 }
2362
2363 return ret;
2364}
2365#endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
2366
2367#if defined(WL_ENABLE_P2P_IF)
2368static int wl_cfgp2p_if_open(struct net_device *net)
2369{
2370 struct wireless_dev *wdev = net->ieee80211_ptr;
2371
2372 if (!wdev || !wl_cfg80211_is_p2p_active(net))
2373 return -EINVAL;
2374 WL_TRACE(("Enter\n"));
2375#if !defined(WL_IFACE_COMB_NUM_CHANNELS)
2376 /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now,
2377 * do it here. This will make sure that in concurrent mode, supplicant
2378 * is not dependent on a particular order of interface initialization.
2379 * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N
2380 * -iwlan0.
2381 */
2382 wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)
2383 | BIT(NL80211_IFTYPE_P2P_GO));
2384#endif /* !WL_IFACE_COMB_NUM_CHANNELS */
2385 wl_cfg80211_do_driver_init(net);
2386
2387 return 0;
2388}
2389
2390static int wl_cfgp2p_if_stop(struct net_device *net)
2391{
2392 struct wireless_dev *wdev = net->ieee80211_ptr;
2393 struct bcm_cfg80211 *cfg = wl_get_cfg(net);
2394
2395 if (!wdev)
2396 return -EINVAL;
2397
2398 wl_cfg80211_scan_stop(cfg, net);
2399
2400#if !defined(WL_IFACE_COMB_NUM_CHANNELS)
2401 wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes)
2402 & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)|
2403 BIT(NL80211_IFTYPE_P2P_GO)));
2404#endif /* !WL_IFACE_COMB_NUM_CHANNELS */
2405 return 0;
2406}
2407
2408bool wl_cfgp2p_is_ifops(const struct net_device_ops *if_ops)
2409{
2410 return (if_ops == &wl_cfgp2p_if_ops);
2411}
2412#endif /* WL_ENABLE_P2P_IF */
2413
2414#if defined(WL_CFG80211_P2P_DEV_IF)
2415struct wireless_dev *
2416wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211 *cfg)
2417{
2418 struct wireless_dev *wdev = NULL;
2419 struct ether_addr primary_mac;
2420
2421 if (!cfg || !cfg->p2p_supported)
2422 return ERR_PTR(-EINVAL);
2423
2424 WL_TRACE(("Enter\n"));
2425
2426 if (cfg->p2p_wdev) {
2427#ifndef EXPLICIT_DISCIF_CLEANUP
2428 dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
2429#endif /* EXPLICIT_DISCIF_CLEANUP */
2430 /*
2431 * This is not expected. This can happen due to
2432 * supplicant crash/unclean de-initialization which
2433 * didn't free the p2p discovery interface. Indicate
2434 * driver hang to user space so that the framework
2435 * can rei-init the Wi-Fi.
2436 */
2437 CFGP2P_ERR(("p2p_wdev defined already.\n"));
2438 wl_probe_wdev_all(cfg);
2439#ifdef EXPLICIT_DISCIF_CLEANUP
2440 /*
2441 * CUSTOMER_HW4 design doesn't delete the p2p discovery
2442 * interface on ifconfig wlan0 down context which comes
2443 * without a preceeding NL80211_CMD_DEL_INTERFACE for p2p
2444 * discovery. But during supplicant crash the DEL_IFACE
2445 * command will not happen and will cause a left over iface
2446 * even after ifconfig wlan0 down. So delete the iface
2447 * first and then indicate the HANG event
2448 */
2449 wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg);
2450#else
2451 dhd->hang_reason = HANG_REASON_IFACE_OP_FAILURE;
2452#if defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
2453 if (dhd->memdump_enabled) {
2454 /* Load the dongle side dump to host
2455 * memory and then BUG_ON()
2456 */
2457 dhd->memdump_type = DUMP_TYPE_HANG_ON_IFACE_OP_FAIL;
2458 dhd_bus_mem_dump(dhd);
2459 }
2460#endif /* BCMPCIE && DHD_FW_COREDUMP */
2461 net_os_send_hang_message(bcmcfg_to_prmry_ndev(cfg));
2462 return ERR_PTR(-ENODEV);
2463#endif /* EXPLICIT_DISCIF_CLEANUP */
2464 }
2465
2466 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
2467 if (unlikely(!wdev)) {
2468 WL_ERR(("Could not allocate wireless device\n"));
2469 return ERR_PTR(-ENOMEM);
2470 }
2471
2472 memset(&primary_mac, 0, sizeof(primary_mac));
2473 get_primary_mac(cfg, &primary_mac);
2474 wl_cfgp2p_generate_bss_mac(cfg, &primary_mac);
2475
2476 wdev->wiphy = cfg->wdev->wiphy;
2477 wdev->iftype = NL80211_IFTYPE_P2P_DEVICE;
2478 memcpy(wdev->address, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE), ETHER_ADDR_LEN);
2479
2480#if defined(WL_NEWCFG_PRIVCMD_SUPPORT)
2481 if (cfg->p2p_net)
2482 memcpy(cfg->p2p_net->dev_addr, wl_to_p2p_bss_macaddr(cfg, P2PAPI_BSSCFG_DEVICE),
2483 ETHER_ADDR_LEN);
2484#endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2485
2486 /* store p2p wdev ptr for further reference. */
2487 cfg->p2p_wdev = wdev;
2488
2489 CFGP2P_ERR(("P2P interface registered\n"));
2490
2491 return wdev;
2492}
2493
2494int
2495wl_cfgp2p_start_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
2496{
2497 int ret = 0;
2498 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2499
2500 if (!cfg)
2501 return -EINVAL;
2502
2503 WL_TRACE(("Enter\n"));
2504
2505 ret = wl_cfgp2p_set_firm_p2p(cfg);
2506 if (unlikely(ret < 0)) {
2507 CFGP2P_ERR(("Set P2P in firmware failed, ret=%d\n", ret));
2508 goto exit;
2509 }
2510
2511 ret = wl_cfgp2p_enable_discovery(cfg, bcmcfg_to_prmry_ndev(cfg), NULL, 0);
2512 if (unlikely(ret < 0)) {
2513 CFGP2P_ERR(("P2P enable discovery failed, ret=%d\n", ret));
2514 goto exit;
2515 }
2516
2517 p2p_on(cfg) = true;
2518#if defined(P2P_IE_MISSING_FIX)
2519 cfg->p2p_prb_noti = false;
2520#endif
2521
2522 CFGP2P_DBG(("P2P interface started\n"));
2523
2524exit:
2525 return ret;
2526}
2527
2528void
2529wl_cfgp2p_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev)
2530{
2531 int ret = 0;
2532 struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
2533
2534 if (!cfg)
2535 return;
2536
2537 CFGP2P_DBG(("Enter\n"));
2538
2539 ret = wl_cfg80211_scan_stop(cfg, wdev);
2540 if (unlikely(ret < 0)) {
2541 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret));
2542 }
2543
2544 if (!cfg->p2p)
2545 return;
2546
2547 /* Cancel any on-going listen */
2548 wl_cfgp2p_cancel_listen(cfg, bcmcfg_to_prmry_ndev(cfg), wdev, TRUE);
2549
2550 ret = wl_cfgp2p_disable_discovery(cfg);
2551 if (unlikely(ret < 0)) {
2552 CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret));
2553 }
2554
2555 p2p_on(cfg) = false;
2556
2557 CFGP2P_DBG(("Exit. P2P interface stopped\n"));
2558
2559 return;
2560}
2561
2562int
2563wl_cfgp2p_del_p2p_disc_if(struct wireless_dev *wdev, struct bcm_cfg80211 *cfg)
2564{
2565 bool rollback_lock = false;
2566
2567 if (!wdev)
2568 return -EINVAL;
2569
2570 WL_TRACE(("Enter\n"));
2571
2572 if (!rtnl_is_locked()) {
2573 rtnl_lock();
2574 rollback_lock = true;
2575 }
2576
2577 cfg80211_unregister_wdev(wdev);
2578
2579 if (rollback_lock)
2580 rtnl_unlock();
2581
2582 synchronize_rcu();
2583
2584 kfree(wdev);
2585
2586 if (cfg)
2587 cfg->p2p_wdev = NULL;
2588
2589 CFGP2P_ERR(("P2P interface unregistered\n"));
2590
2591 return 0;
2592}
2593#endif /* WL_CFG80211_P2P_DEV_IF */
2594
2595void
2596wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211 *cfg, void *frame, u32 frame_len, bool tx)
2597{
2598 wifi_p2p_pub_act_frame_t *pact_frm;
2599 int status = 0;
2600
2601 if (!frame || (frame_len < (sizeof(*pact_frm) + WL_P2P_AF_STATUS_OFFSET - 1))) {
2602 return;
2603 }
2604
2605 if (wl_cfgp2p_is_pub_action(frame, frame_len)) {
2606 pact_frm = (wifi_p2p_pub_act_frame_t *)frame;
2607 if (pact_frm->subtype == P2P_PAF_GON_RSP && tx) {
2608 CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n"));
2609 status = pact_frm->elts[WL_P2P_AF_STATUS_OFFSET];
2610 if (status) {
2611 cfg->need_wait_afrx = false;
2612 return;
2613 }
2614 }
2615 }
2616
2617 cfg->need_wait_afrx = true;
2618 return;
2619}
2620
2621int
2622wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request *request)
2623{
2624 if (request && (request->n_ssids == 1) &&
2625 (request->n_channels == 1) &&
2626 IS_P2P_SSID(request->ssids[0].ssid, WL_P2P_WILDCARD_SSID_LEN) &&
2627 (request->ssids[0].ssid_len > WL_P2P_WILDCARD_SSID_LEN)) {
2628 return true;
2629 }
2630 return false;
2631}