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