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