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