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