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