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