4 * Copyright (C) 1999-2019, Broadcom.
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:
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.
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.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: wl_cfgp2p.c 783638 2018-10-08 02:24:49Z $
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>
44 #include <bcmendian.h>
47 #include <net/rtnetlink.h>
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>
55 #include <dhd_linux.h>
58 #include <dhd_cfg80211.h>
60 #if defined(BCMPCIE) && defined(DHD_FW_COREDUMP)
61 extern int dhd_bus_mem_dump(dhd_pub_t
*dhd
);
62 #endif /* BCMPCIE && DHD_FW_COREDUMP */
63 static s8 scanparambuf
[WLC_IOCTL_SMLEN
];
65 wl_cfgp2p_has_ie(const u8
*ie
, const u8
**tlvs
, u32
*tlvs_len
, const u8
*oui
, u32 oui_len
, u8 type
);
67 static s32
wl_cfgp2p_cancel_listen(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
68 struct wireless_dev
*wdev
, bool notify
);
70 #if defined(WL_ENABLE_P2P_IF)
71 static int wl_cfgp2p_start_xmit(struct sk_buff
*skb
, struct net_device
*ndev
);
72 static int wl_cfgp2p_do_ioctl(struct net_device
*net
, struct ifreq
*ifr
, int cmd
);
73 static int wl_cfgp2p_if_open(struct net_device
*net
);
74 static int wl_cfgp2p_if_stop(struct net_device
*net
);
76 static 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
,
82 #endif /* WL_ENABLE_P2P_IF */
84 #if defined(WL_NEWCFG_PRIVCMD_SUPPORT)
85 static int wl_cfgp2p_start_xmit(struct sk_buff
*skb
, struct net_device
*ndev
);
86 static int wl_cfgp2p_do_ioctl(struct net_device
*net
, struct ifreq
*ifr
, int cmd
);
88 static int wl_cfgp2p_if_dummy(struct net_device
*net
)
93 static 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
,
99 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
101 bool wl_cfgp2p_is_pub_action(void *frame
, u32 frame_len
)
103 wifi_p2p_pub_act_frame_t
*pact_frm
;
107 pact_frm
= (wifi_p2p_pub_act_frame_t
*)frame
;
108 if (frame_len
< sizeof(wifi_p2p_pub_act_frame_t
) -1)
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) {
121 bool wl_cfgp2p_is_p2p_action(void *frame
, u32 frame_len
)
123 wifi_p2p_action_frame_t
*act_frm
;
127 act_frm
= (wifi_p2p_action_frame_t
*)frame
;
128 if (frame_len
< sizeof(wifi_p2p_action_frame_t
) -1)
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) {
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
145 bool wl_cfgp2p_find_gas_subtype(u8 subtype
, u8
* data
, u32 len
)
147 const bcm_tlv_t
*ie
= (bcm_tlv_t
*)data
;
148 const u8
*frame
= NULL
;
151 /* Skipped first ANQP Element, if frame has anqp elemnt */
152 ie
= bcm_parse_tlvs(ie
, len
, DOT11_MNG_ADVERTISEMENT_ID
);
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]));
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
]) {
172 bool wl_cfgp2p_is_gas_action(void *frame
, u32 frame_len
)
175 wifi_p2psd_gas_pub_act_frame_t
*sd_act_frm
;
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))
183 if (sd_act_frm
->category
!= P2PSD_ACTION_CATEGORY
)
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
,
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
,
196 else if (sd_act_frm
->action
== P2PSD_ACTION_ID_GAS_IREQ
||
197 sd_act_frm
->action
== P2PSD_ACTION_ID_GAS_CREQ
)
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
)
212 bool wl_cfgp2p_is_p2p_gas_action(void *frame
, u32 frame_len
)
215 wifi_p2psd_gas_pub_act_frame_t
*sd_act_frm
;
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))
223 if (sd_act_frm
->category
!= P2PSD_ACTION_CATEGORY
)
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
,
234 void wl_cfgp2p_print_actframe(bool tx
, void *frame
, u32 frame_len
, u32 channel
)
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)
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
));
249 case P2P_PAF_GON_RSP
:
250 CFGP2P_ACTION(("%s P2P Group Owner Negotiation Rsp Frame,"
251 " channel=%d\n", (tx
)? "TX": "RX", channel
));
253 case P2P_PAF_GON_CONF
:
254 CFGP2P_ACTION(("%s P2P Group Owner Negotiation Confirm Frame,"
255 " channel=%d\n", (tx
)? "TX": "RX", channel
));
257 case P2P_PAF_INVITE_REQ
:
258 CFGP2P_ACTION(("%s P2P Invitation Request Frame,"
259 " channel=%d\n", (tx
)? "TX": "RX", channel
));
261 case P2P_PAF_INVITE_RSP
:
262 CFGP2P_ACTION(("%s P2P Invitation Response Frame,"
263 " channel=%d\n", (tx
)? "TX": "RX", channel
));
265 case P2P_PAF_DEVDIS_REQ
:
266 CFGP2P_ACTION(("%s P2P Device Discoverability Request Frame,"
267 " channel=%d\n", (tx
)? "TX": "RX", channel
));
269 case P2P_PAF_DEVDIS_RSP
:
270 CFGP2P_ACTION(("%s P2P Device Discoverability Response Frame,"
271 " channel=%d\n", (tx
)? "TX": "RX", channel
));
273 case P2P_PAF_PROVDIS_REQ
:
274 CFGP2P_ACTION(("%s P2P Provision Discovery Request Frame,"
275 " channel=%d\n", (tx
)? "TX": "RX", channel
));
277 case P2P_PAF_PROVDIS_RSP
:
278 CFGP2P_ACTION(("%s P2P Provision Discovery Response Frame,"
279 " channel=%d\n", (tx
)? "TX": "RX", channel
));
282 CFGP2P_ACTION(("%s Unknown Public Action Frame,"
283 " channel=%d\n", (tx
)? "TX": "RX", channel
));
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
));
294 case P2P_AF_PRESENCE_REQ
:
295 CFGP2P_ACTION(("%s P2P Presence Request Frame,"
296 " channel=%d\n", (tx
)? "TX": "RX", channel
));
298 case P2P_AF_PRESENCE_RSP
:
299 CFGP2P_ACTION(("%s P2P Presence Response Frame,"
300 " channel=%d\n", (tx
)? "TX": "RX", channel
));
302 case P2P_AF_GO_DISC_REQ
:
303 CFGP2P_ACTION(("%s P2P Discoverability Request Frame,"
304 " channel=%d\n", (tx
)? "TX": "RX", channel
));
307 CFGP2P_ACTION(("%s Unknown P2P Action Frame,"
308 " channel=%d\n", (tx
)? "TX": "RX", channel
));
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
));
318 case P2PSD_ACTION_ID_GAS_IRESP
:
319 CFGP2P_ACTION(("%s GAS Initial Response,"
320 " channel=%d\n", (tx
)? "TX" : "RX", channel
));
322 case P2PSD_ACTION_ID_GAS_CREQ
:
323 CFGP2P_ACTION(("%s GAS Comback Request,"
324 " channel=%d\n", (tx
)? "TX" : "RX", channel
));
326 case P2PSD_ACTION_ID_GAS_CRESP
:
327 CFGP2P_ACTION(("%s GAS Comback Response,"
328 " channel=%d\n", (tx
)? "TX" : "RX", channel
));
331 CFGP2P_ACTION(("%s Unknown GAS Frame,"
332 " channel=%d\n", (tx
)? "TX" : "RX", channel
));
339 * Initialize variables related to P2P
343 wl_cfgp2p_init_priv(struct bcm_cfg80211
*cfg
)
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"));
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;
364 * Deinitialize variables related to P2P
368 wl_cfgp2p_deinit_priv(struct bcm_cfg80211
*cfg
)
370 CFGP2P_INFO(("In\n"));
372 MFREE(cfg
->osh
, cfg
->p2p
, sizeof(struct p2p_info
));
375 cfg
->p2p_supported
= 0;
378 * Set P2P functions into firmware
381 wl_cfgp2p_set_firm_p2p(struct bcm_cfg80211
*cfg
)
383 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
384 struct ether_addr null_eth_addr
= { { 0, 0, 0, 0, 0, 0 } };
387 /* Do we have to check whether APSTA is enabled or not ? */
388 ret
= wldev_iovar_getint(ndev
, "apsta", &val
);
390 CFGP2P_ERR(("get apsta error %d\n", ret
));
395 ret
= wldev_ioctl_set(ndev
, WLC_DOWN
, &val
, sizeof(s32
));
397 CFGP2P_ERR(("WLC_DOWN error %d\n", ret
));
401 ret
= wldev_iovar_setint(ndev
, "apsta", val
);
403 /* return error and fail the initialization */
404 CFGP2P_ERR(("wl apsta %d set error. ret: %d\n", val
, ret
));
408 ret
= wldev_ioctl_set(ndev
, WLC_UP
, &val
, sizeof(s32
));
410 CFGP2P_ERR(("WLC_UP error %d\n", ret
));
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
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
));
427 int wl_cfg_multip2p_operational(struct bcm_cfg80211
*cfg
)
430 CFGP2P_DBG(("p2p not enabled! \n"));
434 if ((wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_CONNECTION1
) != -1) &&
435 (wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_CONNECTION2
) != -1))
441 /* Create a new P2P BSS.
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.
449 wl_cfgp2p_ifadd(struct bcm_cfg80211
*cfg
, struct ether_addr
*mac
, u8 if_type
,
454 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
456 ifreq
.type
= if_type
;
457 ifreq
.chspec
= chspec
;
458 memcpy(ifreq
.addr
.octet
, mac
->octet
, sizeof(ifreq
.addr
.octet
));
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
));
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
);
475 /* Disable a P2P BSS.
477 * @mac : MAC address of the BSS to disable
478 * Returns 0 if success.
481 wl_cfgp2p_ifdisable(struct bcm_cfg80211
*cfg
, struct ether_addr
*mac
)
484 struct net_device
*netdev
= bcmcfg_to_prmry_ndev(cfg
);
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
);
498 * @mac : MAC address of the BSS to delete
499 * Returns 0 if success.
502 wl_cfgp2p_ifdel(struct bcm_cfg80211
*cfg
, struct ether_addr
*mac
)
505 struct net_device
*netdev
= bcmcfg_to_prmry_ndev(cfg
);
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
);
517 /* Change a P2P Role.
519 * @mac : MAC address of the BSS to change a role
520 * Returns 0 if success.
523 wl_cfgp2p_ifchange(struct bcm_cfg80211
*cfg
, struct ether_addr
*mac
, u8 if_type
,
524 chanspec_t chspec
, s32 conn_idx
)
529 struct net_device
*netdev
= wl_to_p2p_bss_ndev(cfg
, conn_idx
);
531 ifreq
.type
= if_type
;
532 ifreq
.chspec
= chspec
;
533 memcpy(ifreq
.addr
.octet
, mac
->octet
, sizeof(ifreq
.addr
.octet
));
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
,
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
++;
551 /* Get the index of a created P2P BSS.
553 * @mac : MAC address of the created BSS
554 * @index : output: index of created BSS
555 * Returns 0 if success.
558 wl_cfgp2p_ifidx(struct bcm_cfg80211
*cfg
, struct ether_addr
*mac
, s32
*index
)
562 struct net_device
*dev
= bcmcfg_to_prmry_ndev(cfg
);
564 CFGP2P_INFO(("---cfg p2p_if "MACDBG
"\n", MAC2STRDBG(mac
->octet
)));
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
);
570 memcpy(index
, getbuf
, sizeof(s32
));
571 CFGP2P_DBG(("---cfg p2p_if ==> %d\n", *index
));
578 wl_cfgp2p_set_discovery(struct bcm_cfg80211
*cfg
, s32 on
)
581 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
582 CFGP2P_DBG(("enter\n"));
584 ret
= wldev_iovar_setint(ndev
, "p2p_disc", on
);
586 if (unlikely(ret
< 0)) {
587 CFGP2P_ERR(("p2p_disc %d error %d\n", on
, ret
));
593 /* Set the WL driver's P2P mode.
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
603 wl_cfgp2p_set_p2p_mode(struct bcm_cfg80211
*cfg
, u8 mode
, u32 channel
, u16 listen_ms
, int bssidx
)
605 wl_p2p_disc_st_t discovery_mode
;
607 struct net_device
*dev
;
608 CFGP2P_DBG(("enter\n"));
610 if (unlikely(bssidx
== WL_INVALID
)) {
611 CFGP2P_ERR((" %d index out of range\n", bssidx
));
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
;
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
);
627 if (cfg
->p2p_resp_apchn_status
) {
628 CFGP2P_DBG(("p2p_resp_apchn_status already ON \n"));
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"));
639 #endif /* P2PLISTEN_AP_SAMECHN */
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
);
652 /* Get the index of the P2P Discovery BSS */
654 wl_cfgp2p_get_disc_idx(struct bcm_cfg80211
*cfg
, s32
*index
)
657 struct net_device
*dev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_PRIMARY
);
659 ret
= wldev_iovar_getint(dev
, "p2p_dev", index
);
660 CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index
, ret
));
662 if (unlikely(ret
< 0)) {
663 CFGP2P_ERR(("'p2p_dev' error %d\n", ret
));
669 int wl_cfgp2p_get_conn_idx(struct bcm_cfg80211
*cfg
)
673 dhd_pub_t
*dhd
= (dhd_pub_t
*)(cfg
->pub
);
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"));
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"));
696 wl_cfgp2p_init_discovery(struct bcm_cfg80211
*cfg
)
701 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
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"));
710 ret
= wl_cfgp2p_set_discovery(cfg
, 1);
712 CFGP2P_ERR(("set discover error\n"));
715 /* Enable P2P Discovery in the WL Driver */
716 ret
= wl_cfgp2p_get_disc_idx(cfg
, &bssidx
);
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"));
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
732 ret
= wl_alloc_netinfo(cfg
, NULL
, cfg
->p2p_wdev
, WL_MODE_BSS
, 0, bssidx
, 0);
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
;
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
;
752 /* Clear our saved WPS and P2P IEs for the discovery BSS */
753 wl_cfg80211_clear_p2p_disc_ies(cfg
);
756 wl_flush_fw_log_buffer(ndev
, FW_LOGSET_MASK_ALL
);
761 /* Deinitialize P2P Discovery
763 * @cfg : wl_private data
764 * Returns 0 if succes
767 wl_cfgp2p_deinit_discovery(struct bcm_cfg80211
*cfg
)
772 CFGP2P_DBG(("enter\n"));
773 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
775 CFGP2P_ERR(("do nothing, not initialized\n"));
779 /* Clear our saved WPS and P2P IEs for the discovery BSS */
780 wl_cfg80211_clear_p2p_disc_ies(cfg
);
782 /* Set the discovery state to SCAN */
783 wl_cfgp2p_set_p2p_mode(cfg
, WL_P2P_DISC_ST_SCAN
, 0, 0,
785 /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
786 ret
= wl_cfgp2p_set_discovery(cfg
, 0);
788 /* Remove the p2p disc entry in the netinfo */
789 wl_dealloc_netinfo_by_wdev(cfg
, cfg
->p2p_wdev
);
791 wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
) = WL_INVALID
;
792 wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_DEVICE
) = NULL
;
797 /* Enable P2P Discovery
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.
805 wl_cfgp2p_enable_discovery(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
806 const u8
*ie
, u32 ie_len
)
810 bcm_struct_cfgdev
*cfgdev
;
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"));
818 ret
= wl_cfgp2p_init_discovery(cfg
);
819 if (unlikely(ret
< 0)) {
820 CFGP2P_ERR((" init discovery error %d\n", ret
));
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.
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
));
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
));
844 #if defined(WL_CFG80211_P2P_DEV_IF)
845 /* For 3.8+ kernels, pass p2p discovery wdev */
846 cfgdev
= cfg
->p2p_wdev
;
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
));
860 wl_flush_fw_log_buffer(dev
, FW_LOGSET_MASK_ALL
);
865 /* Disable P2P Discovery
867 * @cfg : wl_private_data
868 * Returns 0 if success.
871 wl_cfgp2p_disable_discovery(struct bcm_cfg80211
*cfg
)
876 CFGP2P_DBG((" enter\n"));
877 wl_clr_p2p_status(cfg
, DISCOVERY_ON
);
879 WL_ERR(("%s: bssidx: %d\n",
880 __FUNCTION__
, (cfg
)->p2p
->bss
[P2PAPI_BSSCFG_DEVICE
].bssidx
));
882 bssidx
= wl_to_p2p_bss_bssidx(cfg
, P2PAPI_BSSCFG_DEVICE
);
884 CFGP2P_ERR((" do nothing, not initialized\n"));
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"));
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.
896 if (wl_get_p2p_status(cfg
, SCANNING
)) {
897 p2pwlu_scan_abort(hdl
, FALSE
);
900 wl_clr_p2p_status(cfg
, DISCOVERY_ON
);
901 ret
= wl_cfgp2p_deinit_discovery(cfg
);
907 wl_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
)
917 wl_p2p_scan_t
*p2p_params
;
918 wl_escan_params_t
*eparams
;
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
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]);
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
)));
941 memset(memblk
, 0, memsize
);
942 memset(cfg
->ioctl_buf
, 0, WLC_IOCTL_MAXLEN
);
943 if (search_state
== WL_P2P_DISC_ST_SEARCH
) {
945 * If we in SEARCH STATE, we don't need to set SSID explictly
946 * because dongle use P2P WILDCARD internally by default
948 wl_cfgp2p_set_p2p_mode(cfg
, WL_P2P_DISC_ST_SEARCH
, 0, 0, bssidx
);
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
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
);
965 CFGP2P_ERR((" invalid search state %d\n", search_state
));
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
;
976 eparams
->params
.scan_type
= DOT11_SCANTYPE_ACTIVE
;
978 eparams
->params
.scan_type
= DOT11_SCANTYPE_PASSIVE
;
980 if (tx_dst_addr
== NULL
)
981 memcpy(&eparams
->params
.bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
983 memcpy(&eparams
->params
.bssid
, tx_dst_addr
, ETHER_ADDR_LEN
);
986 memcpy(&eparams
->params
.ssid
, &ssid
, sizeof(wlc_ssid_t
));
988 eparams
->params
.home_time
= htod32(P2PAPI_SCAN_HOME_TIME_MS
);
990 switch (p2p_scan_purpose
) {
991 case P2P_SCAN_SOCIAL_CHANNEL
:
992 eparams
->params
.active_time
= htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS
);
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
);
998 case P2P_SCAN_CONNECT_TRY
:
999 eparams
->params
.active_time
= htod32(WL_SCAN_CONNECT_DWELL_TIME_MS
);
1002 if (wl_get_drv_status_all(cfg
, CONNECTED
))
1003 eparams
->params
.active_time
= -1;
1005 eparams
->params
.active_time
= htod32(P2PAPI_SCAN_DWELL_TIME_MS
);
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
);
1013 eparams
->params
.nprobes
= htod32((eparams
->params
.active_time
/
1014 P2PAPI_SCAN_NPROBS_TIME_MS
));
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
));
1024 for (i
= 0; i
< num_chans
; i
++) {
1025 eparams
->params
.channel_list
[i
] =
1026 wl_ch_host_to_driver(channels
[i
]);
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 : "));
1034 CFGP2P_DBG(("%d", channels
[0]));
1035 for (i
= 1; i
< num_chans
; i
++) {
1036 CFGP2P_DBG((",%d", channels
[i
]));
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
));
1044 wl_set_p2p_status(cfg
, SCANNING
);
1048 /* search function to reach at common channel to send action frame
1050 * @cfg : wl_private data
1051 * @ndev : net device for bssidx
1052 * @bssidx : bssidx for BSS
1053 * Returns 0 if success.
1056 wl_cfgp2p_act_frm_search(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
1057 s32 bssidx
, s32 channel
, struct ether_addr
*tx_dst_addr
)
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
)
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
);
1069 chan_cnt
= AF_PEER_SEARCH_CNT
;
1071 chan_cnt
= SOCIAL_CHAN_CNT
;
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
)) {
1078 p2p_scan_purpose
= P2P_SCAN_AFX_PEER_REDUCED
;
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"));
1090 /* insert same channel to the chan_list */
1091 for (i
= 0; i
< chan_cnt
; i
++) {
1092 default_chan_list
[i
] = channel
;
1095 default_chan_list
[0] = SOCIAL_CHAN_1
;
1096 default_chan_list
[1] = SOCIAL_CHAN_2
;
1097 default_chan_list
[2] = SOCIAL_CHAN_3
;
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
));
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 */
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)
1123 /* Is any of the tlvs the expected entry? If
1124 * not update the tlvs buffer pointer/length.
1127 wl_cfgp2p_has_ie(const u8
*ie
, const u8
**tlvs
, u32
*tlvs_len
, const u8
*oui
, u32 oui_len
, u8 type
)
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
]) {
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 */
1148 const wpa_ie_fixed_t
*
1149 wl_cfgp2p_find_wpaie(const u8
*parse
, u32 len
)
1151 const bcm_tlv_t
*ie
;
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
;
1161 const wpa_ie_fixed_t
*
1162 wl_cfgp2p_find_wpsie(const u8
*parse
, u32 len
)
1164 const bcm_tlv_t
*ie
;
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
;
1175 wl_cfgp2p_find_p2pie(const u8
*parse
, u32 len
)
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
;
1187 const wifi_wfd_ie_t
*
1188 wl_cfgp2p_find_wfdie(const u8
*parse
, u32 len
)
1190 const bcm_tlv_t
*ie
;
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
;
1201 wl_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
)
1204 vndr_ie_setbuf_t hdr
; /* aligned temporary vndr_ie buffer header */
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
));
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';
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
));
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
,
1229 /* Add the IE ID to the buffer */
1230 hdr
.vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.id
= ie_id
;
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
;
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];
1241 /* Copy the aligned temporary vndr_ie buffer header to the IE buffer */
1242 memcpy(iebuf
, &hdr
, sizeof(hdr
) - 1);
1244 /* Copy the IE data to the IE buffer */
1246 (u8
*)&hdr
.vndr_ie_buffer
.vndr_ie_list
[0].vndr_ie_data
.data
[0] -
1248 memcpy(iebuf
+ data_offset
, data
, datalen
);
1249 return data_offset
+ datalen
;
1254 wl_cfgp2p_find_ndev(struct bcm_cfg80211
*cfg
, s32 bssidx
)
1257 struct net_device
*ndev
= NULL
;
1259 CFGP2P_ERR((" bsscfg idx is invalid\n"));
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
);
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
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.
1285 wl_cfgp2p_find_type(struct bcm_cfg80211
*cfg
, s32 bssidx
, s32
*type
)
1288 if (bssidx
< 0 || type
== NULL
) {
1289 CFGP2P_ERR((" argument is invalid\n"));
1294 CFGP2P_ERR(("p2p if does not exist\n"));
1298 for (i
= 0; i
< P2PAPI_BSSCFG_MAX
; i
++) {
1299 if (bssidx
== wl_to_p2p_bss_bssidx(cfg
, i
)) {
1310 * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
1313 wl_cfgp2p_listen_complete(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
1314 const wl_event_msg_t
*e
, void *data
)
1317 struct net_device
*ndev
= NULL
;
1319 if (!cfg
|| !cfg
->p2p
|| !cfgdev
)
1322 CFGP2P_DBG((" Enter\n"));
1324 PRINT_WDEV_INFO(cfgdev
);
1325 #endif /* DHD_IFDEBUG */
1327 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
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
);
1339 CFGP2P_ERR(("Invalid cfgdev. Dropping the"
1340 "remain_on_channel_expired event.\n"));
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 */
1348 #endif /* P2P_LISTEN_OFFLOADING */
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
);
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
);
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
)));
1367 if (wl_get_drv_status_all(cfg
, WAITING_NEXT_ACT_FRM
))
1368 wl_clr_drv_status(cfg
, WAITING_NEXT_ACT_FRM
, ndev
);
1370 complete(&cfg
->wait_next_af
);
1372 #endif /* WL_CFG80211_SYNC_GON */
1374 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
1375 if (wl_get_drv_status_all(cfg
, REMAINING_ON_CHANNEL
)) {
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
)) {
1390 * To prevent kernel panic,
1391 * if cfgdev->wiphy may be invalid, adding explicit check
1393 cfg80211_remain_on_channel_expired(bcmcfg_to_p2p_wdev(cfg
),
1394 cfg
->last_roc_id
, &cfg
->remain_on_chan
, GFP_KERNEL
);
1396 CFGP2P_ERR(("Invalid cfgdev. Dropping the"
1397 "remain_on_channel_expired event.\n"));
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 */
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"));
1411 wl_clr_p2p_status(cfg
, LISTEN_EXPIRED
);
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.
1423 wl_cfgp2p_listen_expired(unsigned long data
)
1426 struct bcm_cfg80211
*cfg
= (struct bcm_cfg80211
*) data
;
1427 struct net_device
*ndev
;
1428 CFGP2P_DBG((" Enter\n"));
1431 CFGP2P_ERR((" No cfg\n"));
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
);
1441 ndev
= wl_to_p2p_bss_ndev(cfg
, P2PAPI_BSSCFG_DEVICE
);
1442 #endif /* WL_ENABLE_P2P_IF */
1444 CFGP2P_ERR((" No ndev\n"));
1447 wl_cfg80211_event(ndev
, &msg
, NULL
);
1450 * Routine for cancelling the P2P LISTEN
1453 wl_cfgp2p_cancel_listen(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
,
1454 struct wireless_dev
*wdev
, bool notify
)
1456 WL_DBG(("Enter \n"));
1457 /* Irrespective of whether timer is running or not, reset
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
);
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
);
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 */
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.
1485 * This fn assumes dongle p2p device discovery is already enabled.
1487 * @cfg : wl_private data
1488 * @channel : channel to listen
1489 * @duration_ms : the time (milli seconds) to wait
1492 wl_cfgp2p_discover_listen(struct bcm_cfg80211
*cfg
, s32 channel
, u32 duration_ms
)
1494 #define EXTRA_DELAY_TIME 100
1496 struct timer_list
*_timer
;
1498 struct net_device
*netdev
= bcmcfg_to_prmry_ndev(cfg
);
1500 CFGP2P_DBG((" Enter Listen Channel : %d, Duration : %d\n", channel
, duration_ms
));
1501 if (unlikely(wl_get_p2p_status(cfg
, DISCOVERY_ON
) == 0)) {
1503 CFGP2P_ERR((" Discovery is not set, so we have noting to do\n"));
1505 ret
= BCME_NOTREADY
;
1508 if (timer_pending(&cfg
->p2p
->listen_timer
)) {
1509 CFGP2P_DBG(("previous LISTEN is not completed yet\n"));
1513 #ifndef WL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
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"));
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
;
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
1528 if (ret
== BCME_OK
) {
1529 extra_delay
= EXTRA_DELAY_TIME
+ (duration_ms
/ 10);
1531 /* if failed to set listen, it doesn't need to wait whole duration. */
1532 duration_ms
= 100 + duration_ms
/ 20;
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 */
1541 #undef EXTRA_DELAY_TIME
1547 wl_cfgp2p_discover_enable_search(struct bcm_cfg80211
*cfg
, u8 enable
)
1550 CFGP2P_DBG((" Enter\n"));
1551 if (!wl_get_p2p_status(cfg
, DISCOVERY_ON
)) {
1553 CFGP2P_DBG((" do nothing, discovery is off\n"));
1556 if (wl_get_p2p_status(cfg
, SEARCH_ENABLED
) == enable
) {
1557 CFGP2P_DBG(("already : %d\n", enable
));
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.
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
));
1575 * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
1578 wl_cfgp2p_action_tx_complete(struct bcm_cfg80211
*cfg
, bcm_struct_cfgdev
*cfgdev
,
1579 const wl_event_msg_t
*e
, void *data
)
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
;
1587 CFGP2P_DBG((" Enter\n"));
1589 ndev
= cfgdev_to_wlc_ndev(cfgdev
, cfg
);
1591 if (wl_get_drv_status_all(cfg
, SENDING_ACT_FRM
)) {
1592 if (event_type
== WLC_E_ACTION_FRAME_COMPLETE
) {
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
);
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
);
1609 CFGP2P_DBG((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
1610 "status : %d\n", status
));
1612 if (wl_get_drv_status_all(cfg
, SENDING_ACT_FRM
))
1613 complete(&cfg
->send_af_done
);
1618 /* Send an action frame immediately without doing channel synchronization.
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.
1627 wl_cfgp2p_tx_action_frame(struct bcm_cfg80211
*cfg
, struct net_device
*dev
,
1628 wl_af_params_t
*af_params
, s32 bssidx
)
1631 s32 evt_ret
= BCME_OK
;
1633 wl_eventmsg_buf_t buf
;
1636 CFGP2P_DBG(("channel : %u , dwell time : %u\n",
1637 af_params
->channel
, af_params
->dwell_time
));
1639 wl_clr_p2p_status(cfg
, ACTION_TX_COMPLETED
);
1640 wl_clr_p2p_status(cfg
, ACTION_TX_NOACK
);
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)
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 */
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
);
1657 CFGP2P_ERR((" sending action frame is failed\n"));
1661 timeout
= wait_for_completion_timeout(&cfg
->send_af_done
,
1662 msecs_to_jiffies(af_params
->dwell_time
+ WL_AF_TX_EXTRA_TIME_MAX
));
1664 if (timeout
>= 0 && wl_get_p2p_status(cfg
, ACTION_TX_COMPLETED
)) {
1665 CFGP2P_DBG(("tx action frame operation is completed\n"));
1667 } else if (ETHER_ISBCAST(&cfg
->afx_hdl
->tx_dst_addr
)) {
1668 CFGP2P_DBG(("bcast tx action frame operation is completed\n"));
1672 CFGP2P_DBG(("tx action frame operation is failed\n"));
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
);
1679 CFGP2P_DBG((" via act frame iovar : status = %d\n", ret
));
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"));
1692 /* Generate our P2P Device Address and P2P Interface Address from our primary
1696 wl_cfgp2p_generate_bss_mac(struct bcm_cfg80211
*cfg
, struct ether_addr
*primary_addr
)
1698 struct ether_addr
*mac_addr
= wl_to_p2p_bss_macaddr(cfg
, P2PAPI_BSSCFG_DEVICE
);
1699 struct ether_addr
*int_addr
;
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
)));
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
)));
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;
1715 /* P2P IF Address change to Virtual Interface MAC Address */
1717 wl_cfg80211_change_ifaddr(u8
* buf
, struct ether_addr
*p2p_int_addr
, u8 element_id
)
1719 wifi_p2p_ie_t
*ie
= (wifi_p2p_ie_t
*) buf
;
1724 CFGP2P_DBG((" Enter\n"));
1726 /* Point subel to the P2P IE's subelt field.
1727 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
1729 subel
= ie
->subelts
;
1730 len
-= 4; /* exclude OUI + OUI_TYPE */
1738 /* 2-byte little endian */
1739 subelt_len
= *subel
++;
1740 subelt_len
|= *subel
++ << 8;
1743 len
-= subelt_len
; /* for the remaining subelt fields */
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"));
1760 CFGP2P_DBG(("OTHER id : %d\n", subelt_id
));
1762 subel
+= subelt_len
;
1767 wl_cfgp2p_supported(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
)
1770 s32 p2p_supported
= 0;
1771 ret
= wldev_iovar_getint(ndev
, "p2p",
1774 if (ret
== BCME_UNSUPPORTED
) {
1775 CFGP2P_INFO(("p2p is unsupported\n"));
1778 CFGP2P_ERR(("cfg p2p error %d\n", ret
));
1782 if (p2p_supported
== 1) {
1783 CFGP2P_INFO(("p2p is supported\n"));
1785 CFGP2P_INFO(("p2p is unsupported\n"));
1788 return p2p_supported
;
1790 /* Cleanup P2P resources */
1792 wl_cfgp2p_down(struct bcm_cfg80211
*cfg
)
1794 struct net_device
*ndev
= NULL
;
1795 struct wireless_dev
*wdev
= NULL
;
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 */
1805 wl_cfgp2p_cancel_listen(cfg
, ndev
, wdev
, TRUE
);
1806 wl_cfgp2p_disable_discovery(cfg
);
1808 #if defined(WL_CFG80211_P2P_DEV_IF) && !defined(KEEP_WIFION_OPTION)
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.
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
);
1820 #endif /* WL_CFG80211_P2P_DEV_IF !defined(KEEP_WIFION_OPTION) */
1822 wl_cfgp2p_deinit_priv(cfg
);
1826 int wl_cfgp2p_vif_created(struct bcm_cfg80211
*cfg
)
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)))
1837 wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, char* buf
, int len
)
1840 int count
, start
, duration
;
1841 wl_p2p_sched_t dongle_noa
;
1843 int iovar_len
= sizeof(dongle_noa
);
1844 CFGP2P_DBG((" Enter\n"));
1846 memset(&dongle_noa
, 0, sizeof(dongle_noa
));
1848 if (wl_cfgp2p_vif_created(cfg
)) {
1849 cfg
->p2p
->noa
.desc
[0].start
= 0;
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
));
1855 cfg
->p2p
->noa
.desc
[0].count
= count
;
1857 /* supplicant gives interval as start */
1859 cfg
->p2p
->noa
.desc
[0].interval
= start
;
1862 cfg
->p2p
->noa
.desc
[0].duration
= duration
;
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
;
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
;
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
;
1887 dongle_noa
.option
= WL_P2P_SCHED_OPTION_NORMAL
;
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
);
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);
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
)
1905 if (dongle_noa
.action
== WL_P2P_SCHED_ACTION_RESET
) {
1906 iovar_len
-= sizeof(wl_p2p_sched_desc_t
);
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
);
1914 CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret
));
1918 CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n"));
1923 wl_cfgp2p_get_p2p_noa(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, char* buf
, int buf_len
)
1926 wifi_p2p_noa_desc_t
*noa_desc
;
1930 CFGP2P_DBG((" Enter\n"));
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 */
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
);
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
));
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
]);
1960 CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n"));
1966 wl_cfgp2p_set_p2p_ps(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, char* buf
, int len
)
1973 struct net_device
*dev
;
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
));
1980 bssidx
= wl_get_bssidx_by_wdev(cfg
, ndev
->ieee80211_ptr
);
1981 if (wl_cfgp2p_find_type(cfg
, bssidx
, &conn_idx
) != BCME_OK
)
1983 dev
= wl_to_p2p_bss_ndev(cfg
, conn_idx
);
1985 cfg
->p2p
->ops
.ctw
= ctw
;
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
);
1994 CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret
));
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
));
2002 CFGP2P_ERR(("error (%d)\n", ret
));
2003 wl_cfg80211_update_power_mode(dev
);
2006 CFGP2P_ERR(("ilegal setting\n"));
2009 CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n"));
2016 wl_cfgp2p_set_p2p_ecsa(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, char* buf
, int len
)
2021 struct net_device
*dev
;
2022 char smbuf
[WLC_IOCTL_SMLEN
];
2023 wl_chan_switch_t csa_arg
;
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
));
2032 bssidx
= wl_get_bssidx_by_wdev(cfg
, ndev
->ieee80211_ptr
);
2033 if (wl_cfgp2p_find_type(cfg
, bssidx
, &conn_idx
) != BCME_OK
) {
2036 dev
= wl_to_p2p_bss_ndev(cfg
, conn_idx
);
2037 if (ch
<= 0 || bw
<= 0) {
2038 CFGP2P_ERR(("Negative value not permitted!\n"));
2042 csa_arg
.mode
= DOT11_CSA_MODE_ADVISORY
;
2043 csa_arg
.count
= P2P_ECSA_CNT
;
2046 snprintf(buf
, len
, "%d/%d", ch
, bw
);
2047 chnsp
= wf_chspec_aton(buf
);
2049 CFGP2P_ERR(("%s:chsp is not correct\n", __FUNCTION__
));
2052 chnsp
= wl_chspec_host_to_driver(chnsp
);
2053 csa_arg
.chspec
= chnsp
;
2055 err
= wldev_iovar_setbuf(dev
, "csa", &csa_arg
, sizeof(csa_arg
),
2056 smbuf
, sizeof(smbuf
), NULL
);
2058 CFGP2P_ERR(("%s:set p2p_ecsa failed:%d\n", __FUNCTION__
, err
));
2062 CFGP2P_ERR(("ERROR: set_p2p_ecsa in non-p2p mode\n"));
2069 wl_cfgp2p_increase_p2p_bw(struct bcm_cfg80211
*cfg
, struct net_device
*ndev
, char* buf
, int len
)
2075 sscanf(buf
, "%3d", &bw
);
2078 ret
= wldev_iovar_setbuf(ndev
, "mchan_algo", &algo
, sizeof(algo
), cfg
->ioctl_buf
,
2079 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
2081 CFGP2P_ERR(("fw set mchan_algo failed %d\n", ret
));
2086 ret
= wldev_iovar_setbuf(ndev
, "mchan_algo", &algo
, sizeof(algo
), cfg
->ioctl_buf
,
2087 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
2089 CFGP2P_ERR(("fw set mchan_algo failed %d\n", ret
));
2092 ret
= wldev_iovar_setbuf(ndev
, "mchan_bw", &bw
, sizeof(algo
), cfg
->ioctl_buf
,
2093 WLC_IOCTL_MAXLEN
, &cfg
->ioctl_buf_sync
);
2095 CFGP2P_ERR(("fw set mchan_bw failed %d\n", ret
));
2103 wl_cfgp2p_retreive_p2pattrib(const void *buf
, u8 element_id
)
2105 const wifi_p2p_ie_t
*ie
= NULL
;
2112 WL_ERR(("P2P IE not present"));
2116 ie
= (const wifi_p2p_ie_t
*) buf
;
2119 /* Point subel to the P2P IE's subelt field.
2120 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
2122 subel
= ie
->subelts
;
2123 len
-= 4; /* exclude OUI + OUI_TYPE */
2131 /* 2-byte little endian */
2132 subelt_len
= *subel
++;
2133 subelt_len
|= *subel
++ << 8;
2136 len
-= subelt_len
; /* for the remaining subelt fields */
2138 if (subelt_id
== element_id
) {
2139 /* This will point to start of subelement attrib after
2140 * attribute id & len
2145 /* Go to next subelement */
2146 subel
+= subelt_len
;
2153 #define P2P_GROUP_CAPAB_GO_BIT 0x01
2156 wl_cfgp2p_find_attrib_in_all_p2p_Ies(const u8
*parse
, u32 len
, u32 attrib
)
2158 const bcm_tlv_t
*ie
;
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",
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
));
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
));
2182 CFGP2P_ERR(("P2P attribute %d was NOT found", attrib
));
2187 wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t
*bi
, u32 bi_length
)
2189 const u8
*capability
= NULL
;
2191 const u8
*ptr
= NULL
;
2193 if (bi
->length
!= bi
->ie_offset
+ bi
->ie_length
) {
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"));
2203 /* Check Group capability for Group Owner bit */
2204 p2p_go
= capability
[1] & P2P_GROUP_CAPAB_GO_BIT
;
2206 return bi
->BSSID
.octet
;
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.
2215 ptr
= wl_cfgp2p_find_attrib_in_all_p2p_Ies(((u8
*) bi
) + bi
->ie_offset
,
2216 bi
->ie_length
, P2P_SEID_DEV_ID
);
2220 WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE "));
2225 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2227 wl_cfgp2p_ethtool_get_drvinfo(struct net_device
*net
, struct ethtool_drvinfo
*info
)
2229 snprintf(info
->driver
, sizeof(info
->driver
), "p2p");
2230 snprintf(info
->version
, sizeof(info
->version
), "%lu", (unsigned long)(0));
2233 struct ethtool_ops cfgp2p_ethtool_ops
= {
2234 .get_drvinfo
= wl_cfgp2p_ethtool_get_drvinfo
2236 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
2238 #if defined(WL_ENABLE_P2P_IF) || defined(WL_NEWCFG_PRIVCMD_SUPPORT)
2240 wl_cfgp2p_register_ndev(struct bcm_cfg80211
*cfg
)
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 };
2250 CFGP2P_ERR(("p2p_net defined already.\n"));
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__
));
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"));
2267 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2269 strncpy(net
->name
, "p2p%d", sizeof(net
->name
) - 1);
2270 net
->name
[IFNAMSIZ
- 1] = '\0';
2272 /* Copy the reference to bcm_cfg80211 */
2273 memcpy((void *)netdev_priv(net
), &cfg
, sizeof(struct bcm_cfg80211
*));
2275 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
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
;
2282 ASSERT(!net
->netdev_ops
);
2283 net
->netdev_ops
= &wl_cfgp2p_if_ops
;
2286 /* Register with a dummy MAC addr */
2287 memcpy(net
->dev_addr
, temp_addr
, ETHER_ADDR_LEN
);
2289 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2290 wdev
->wiphy
= cfg
->wdev
->wiphy
;
2292 wdev
->iftype
= wl_mode_to_nl80211_iftype(WL_MODE_BSS
);
2294 net
->ieee80211_ptr
= wdev
;
2296 net
->ieee80211_ptr
= NULL
;
2297 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
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) */
2303 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2304 SET_NETDEV_DEV(net
, wiphy_dev(wdev
->wiphy
));
2306 /* Associate p2p0 network interface with new wdev */
2308 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2310 ret
= register_netdev(net
);
2312 CFGP2P_ERR((" register_netdevice failed (%d)\n", ret
));
2314 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2315 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
2316 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
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.
2323 #ifndef WL_NEWCFG_PRIVCMD_SUPPORT
2324 cfg
->p2p_wdev
= wdev
;
2326 cfg
->p2p_wdev
= NULL
;
2327 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2330 printk("%s: P2P Interface Registered\n", net
->name
);
2336 wl_cfgp2p_unregister_ndev(struct bcm_cfg80211
*cfg
)
2339 if (!cfg
|| !cfg
->p2p_net
) {
2340 CFGP2P_ERR(("Invalid Ptr\n"));
2344 unregister_netdev(cfg
->p2p_net
);
2345 free_netdev(cfg
->p2p_net
);
2349 static int wl_cfgp2p_start_xmit(struct sk_buff
*skb
, struct net_device
*ndev
)
2354 CFGP2P_DBG(("(%s) is not used for data operations.Droping the packet.\n",
2356 dev_kfree_skb_any(skb
);
2362 static int wl_cfgp2p_do_ioctl(struct net_device
*net
, struct ifreq
*ifr
, int cmd
)
2365 struct bcm_cfg80211
*cfg
= *(struct bcm_cfg80211
**)netdev_priv(net
);
2366 struct net_device
*ndev
= bcmcfg_to_prmry_ndev(cfg
);
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
2372 if (cmd
== SIOCDEVPRIVATE
+1) {
2373 ret
= wl_android_priv_cmd(ndev
, ifr
);
2376 CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n",
2377 __FUNCTION__
, cmd
));
2383 #endif /* WL_ENABLE_P2P_IF || WL_NEWCFG_PRIVCMD_SUPPORT */
2385 #if defined(WL_ENABLE_P2P_IF)
2386 static int wl_cfgp2p_if_open(struct net_device
*net
)
2388 struct wireless_dev
*wdev
= net
->ieee80211_ptr
;
2390 if (!wdev
|| !wl_cfg80211_is_p2p_active(net
))
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
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
);
2408 static int wl_cfgp2p_if_stop(struct net_device
*net
)
2410 struct wireless_dev
*wdev
= net
->ieee80211_ptr
;
2411 struct bcm_cfg80211
*cfg
= wl_get_cfg(net
);
2416 wl_cfg80211_scan_stop(cfg
, net
);
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 */
2426 bool wl_cfgp2p_is_ifops(const struct net_device_ops
*if_ops
)
2428 return (if_ops
== &wl_cfgp2p_if_ops
);
2430 #endif /* WL_ENABLE_P2P_IF */
2432 #if defined(WL_CFG80211_P2P_DEV_IF)
2433 struct wireless_dev
*
2434 wl_cfgp2p_add_p2p_disc_if(struct bcm_cfg80211
*cfg
)
2436 struct wireless_dev
*wdev
= NULL
;
2437 struct ether_addr primary_mac
;
2439 if (!cfg
|| !cfg
->p2p_supported
)
2440 return ERR_PTR(-EINVAL
);
2442 WL_TRACE(("Enter\n"));
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 */
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.
2455 CFGP2P_ERR(("p2p_wdev defined already.\n"));
2456 wl_probe_wdev_all(cfg
);
2457 #ifdef EXPLICIT_DISCIF_CLEANUP
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
2467 wl_cfgp2p_del_p2p_disc_if(cfg
->p2p_wdev
, cfg
);
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()
2475 dhd
->memdump_type
= DUMP_TYPE_IFACE_OP_FAILURE
;
2476 dhd_bus_mem_dump(dhd
);
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 */
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
);
2490 memset(&primary_mac
, 0, sizeof(primary_mac
));
2491 get_primary_mac(cfg
, &primary_mac
);
2492 wl_cfgp2p_generate_bss_mac(cfg
, &primary_mac
);
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
);
2498 #if defined(WL_NEWCFG_PRIVCMD_SUPPORT)
2500 memcpy(cfg
->p2p_net
->dev_addr
, wl_to_p2p_bss_macaddr(cfg
, P2PAPI_BSSCFG_DEVICE
),
2502 #endif /* WL_NEWCFG_PRIVCMD_SUPPORT */
2504 /* store p2p wdev ptr for further reference. */
2505 cfg
->p2p_wdev
= wdev
;
2507 CFGP2P_ERR(("P2P interface registered\n"));
2512 wl_cfgp2p_start_p2p_device(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
2515 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2520 WL_TRACE(("Enter\n"));
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
));
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
));
2535 #if defined(P2P_IE_MISSING_FIX)
2536 cfg
->p2p_prb_noti
= false;
2539 CFGP2P_DBG(("P2P interface started\n"));
2546 wl_cfgp2p_stop_p2p_device(struct wiphy
*wiphy
, struct wireless_dev
*wdev
)
2549 struct bcm_cfg80211
*cfg
= wiphy_priv(wiphy
);
2554 CFGP2P_DBG(("Enter\n"));
2556 ret
= wl_cfg80211_scan_stop(cfg
, wdev
);
2557 if (unlikely(ret
< 0)) {
2558 CFGP2P_ERR(("P2P scan stop failed, ret=%d\n", ret
));
2564 /* Cancel any on-going listen */
2565 wl_cfgp2p_cancel_listen(cfg
, bcmcfg_to_prmry_ndev(cfg
), wdev
, TRUE
);
2567 ret
= wl_cfgp2p_disable_discovery(cfg
);
2568 if (unlikely(ret
< 0)) {
2569 CFGP2P_ERR(("P2P disable discovery failed, ret=%d\n", ret
));
2572 p2p_on(cfg
) = false;
2574 CFGP2P_DBG(("Exit. P2P interface stopped\n"));
2580 wl_cfgp2p_del_p2p_disc_if(struct wireless_dev
*wdev
, struct bcm_cfg80211
*cfg
)
2582 bool rollback_lock
= false;
2584 if (!wdev
|| !cfg
) {
2585 WL_ERR(("null ptr. wdev:%p cfg:%p\n", wdev
, cfg
));
2589 WL_INFORM(("Enter\n"));
2591 if (!rtnl_is_locked()) {
2593 rollback_lock
= true;
2596 cfg80211_unregister_wdev(wdev
);
2603 MFREE(cfg
->osh
, wdev
, sizeof(*wdev
));
2605 cfg
->p2p_wdev
= NULL
;
2607 CFGP2P_ERR(("P2P interface unregistered\n"));
2611 #endif /* WL_CFG80211_P2P_DEV_IF */
2614 wl_cfgp2p_need_wait_actfrmae(struct bcm_cfg80211
*cfg
, void *frame
, u32 frame_len
, bool tx
)
2616 wifi_p2p_pub_act_frame_t
*pact_frm
;
2619 if (!frame
|| (frame_len
< (sizeof(*pact_frm
) + WL_P2P_AF_STATUS_OFFSET
- 1))) {
2623 if (wl_cfgp2p_is_pub_action(frame
, frame_len
)) {
2624 pact_frm
= (wifi_p2p_pub_act_frame_t
*)frame
;
2625 if (pact_frm
->subtype
== P2P_PAF_GON_RSP
&& tx
) {
2626 CFGP2P_ACTION(("Check TX P2P Group Owner Negotiation Rsp Frame status\n"));
2627 status
= pact_frm
->elts
[WL_P2P_AF_STATUS_OFFSET
];
2629 cfg
->need_wait_afrx
= false;
2635 cfg
->need_wait_afrx
= true;
2640 wl_cfgp2p_is_p2p_specific_scan(struct cfg80211_scan_request
*request
)
2642 if (request
&& (request
->n_ssids
== 1) &&
2643 (request
->n_channels
== 1) &&
2644 IS_P2P_SSID(request
->ssids
[0].ssid
, WL_P2P_WILDCARD_SSID_LEN
) &&
2645 (request
->ssids
[0].ssid_len
> WL_P2P_WILDCARD_SSID_LEN
)) {