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, ðer_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