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