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