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