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