blob: fff5722d4c0b54de5f75adc76fc8d3841c2f6d74 [file] [log] [blame]
Arend van Spriel9f440b72013-02-08 15:53:36 +01001/*
2 * Copyright (c) 2012 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16#include <linux/slab.h>
17#include <linux/netdevice.h>
18#include <net/cfg80211.h>
19
20#include <brcmu_wifi.h>
21#include <brcmu_utils.h>
22#include <defs.h>
23#include <dhd.h>
24#include <dhd_dbg.h>
25#include "fwil.h"
Arend van Sprield3c0b632013-02-08 15:53:37 +010026#include "fwil_types.h"
Arend van Spriel9f440b72013-02-08 15:53:36 +010027#include "p2p.h"
28#include "wl_cfg80211.h"
29
30/* parameters used for p2p escan */
31#define P2PAPI_SCAN_NPROBES 1
32#define P2PAPI_SCAN_DWELL_TIME_MS 80
33#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40
34#define P2PAPI_SCAN_HOME_TIME_MS 60
35#define P2PAPI_SCAN_NPROBS_TIME_MS 30
36#define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100
37#define WL_SCAN_CONNECT_DWELL_TIME_MS 200
38#define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20
39
40#define BRCMF_P2P_WILDCARD_SSID "DIRECT-"
41#define BRCMF_P2P_WILDCARD_SSID_LEN (sizeof(BRCMF_P2P_WILDCARD_SSID) - 1)
42
43#define SOCIAL_CHAN_1 1
44#define SOCIAL_CHAN_2 6
45#define SOCIAL_CHAN_3 11
46#define SOCIAL_CHAN_CNT 3
47#define AF_PEER_SEARCH_CNT 2
48
Arend van Sprield3c0b632013-02-08 15:53:37 +010049#define BRCMF_SCB_TIMEOUT_VALUE 20
50
Arend van Spriel9f440b72013-02-08 15:53:36 +010051/**
52 * struct brcmf_p2p_disc_st_le - set discovery state in firmware.
53 *
54 * @state: requested discovery state (see enum brcmf_p2p_disc_state).
55 * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state.
56 * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state.
57 */
58struct brcmf_p2p_disc_st_le {
59 u8 state;
60 __le16 chspec;
61 __le16 dwell;
62};
63
64/**
65 * enum brcmf_p2p_disc_state - P2P discovery state values
66 *
67 * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE.
68 * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time.
69 * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE.
70 */
71enum brcmf_p2p_disc_state {
72 WL_P2P_DISC_ST_SCAN,
73 WL_P2P_DISC_ST_LISTEN,
74 WL_P2P_DISC_ST_SEARCH
75};
76
77/**
78 * struct brcmf_p2p_scan_le - P2P specific scan request.
79 *
80 * @type: type of scan method requested (values: 'E' or 'S').
81 * @reserved: reserved (ignored).
82 * @eparams: parameters used for type 'E'.
83 * @sparams: parameters used for type 'S'.
84 */
85struct brcmf_p2p_scan_le {
86 u8 type;
87 u8 reserved[3];
88 union {
89 struct brcmf_escan_params_le eparams;
90 struct brcmf_scan_params_le sparams;
91 };
92};
93
94static struct brcmf_cfg80211_vif *p2p_discover_vif(struct brcmf_p2p_info *p2p)
95{
96 return p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
97}
98
99/**
100 * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation.
101 *
102 * @p2p: P2P specific data.
103 */
104static int brcmf_p2p_set_firmware(struct brcmf_p2p_info *p2p)
105{
106 struct net_device *ndev = cfg_to_ndev(p2p->cfg);
107 u8 null_eth_addr[] = { 0, 0, 0, 0, 0, 0 };
108 s32 ret = 0;
109
110 brcmf_fil_iovar_int_set(netdev_priv(ndev), "apsta", 1);
111
112 /* In case of COB type, firmware has default mac address
113 * After Initializing firmware, we have to set current mac address to
114 * firmware for P2P device address
115 */
116 ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "p2p_da_override",
117 null_eth_addr, sizeof(null_eth_addr));
118 if (ret)
119 brcmf_err("failed to update device address ret %d\n", ret);
120
121 return ret;
122}
123
124/**
125 * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P.
126 *
127 * @p2p: P2P specific data.
128 *
129 * P2P needs mac addresses for P2P device and interface. These are
130 * derived from the primary net device, ie. the permanent ethernet
131 * address of the device.
132 */
133static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p)
134{
Arend van Spriel9f440b72013-02-08 15:53:36 +0100135 /* Generate the P2P Device Address. This consists of the device's
136 * primary MAC address with the locally administered bit set.
137 */
Arend van Sprielde66efc2013-02-08 15:53:40 +0100138 memcpy(p2p->dev_addr, p2p->cfg->pub->mac, ETH_ALEN);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100139 p2p->dev_addr[0] |= 0x02;
140
141 /* Generate the P2P Interface Address. If the discovery and connection
142 * BSSCFGs need to simultaneously co-exist, then this address must be
143 * different from the P2P Device Address, but also locally administered.
144 */
145 memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN);
146 p2p->int_addr[4] ^= 0x80;
147}
148
149/**
150 * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan.
151 *
152 * @request: the scan request as received from cfg80211.
153 *
154 * returns true if one of the ssids in the request matches the
155 * P2P wildcard ssid; otherwise returns false.
156 */
157static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request)
158{
159 struct cfg80211_ssid *ssids = request->ssids;
160 int i;
161
162 for (i = 0; i < request->n_ssids; i++) {
163 if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN)
164 continue;
165
166 brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid);
167 if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid,
168 BRCMF_P2P_WILDCARD_SSID_LEN))
169 return true;
170 }
171 return false;
172}
173
174/**
175 * brcmf_p2p_set_discover_state - set discover state in firmware.
176 *
177 * @ifp: low-level interface object.
178 * @state: discover state to set.
179 * @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only).
180 * @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only).
181 */
182static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state,
183 u16 chanspec, u16 listen_ms)
184{
185 struct brcmf_p2p_disc_st_le discover_state;
186 s32 ret = 0;
187 brcmf_dbg(TRACE, "enter\n");
188
189 discover_state.state = state;
190 discover_state.chspec = cpu_to_le16(chanspec);
191 discover_state.dwell = cpu_to_le16(listen_ms);
192 ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state,
193 sizeof(discover_state));
194 return ret;
195}
196
197/**
198 * brcmf_p2p_discover_disable_search() - reset discover state.
199 *
200 * @p2p: P2P specific data.
201 *
202 * Reset the discover state to @WL_P2P_DISC_ST_SCAN. Returns 0 on success.
203 */
204static s32 brcmf_p2p_discover_disable_search(struct brcmf_p2p_info *p2p)
205{
206 struct brcmf_cfg80211_vif *vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
207 struct brcmf_p2p_disc_st_le discovery_mode;
208 int ret;
209
210 /*
211 * vif presence indicates discovery is initialized.
212 */
213 if (!vif)
214 return -ENODEV;
215
216 ret = brcmf_fil_bsscfg_data_get(vif->ifp, "p2p_state",
217 &discovery_mode,
218 sizeof(discovery_mode));
219 if (!ret && discovery_mode.state != WL_P2P_DISC_ST_SCAN)
220 ret = brcmf_p2p_set_discover_state(vif->ifp,
221 WL_P2P_DISC_ST_SCAN, 0, 0);
222 return ret;
223}
224
225/**
226 * brcmf_p2p_init_discovery() - enable discovery in the firmware.
227 *
228 * @p2p: P2P specific data.
229 *
230 * Configures the firmware to allow P2P peer discovery. Creates the
231 * virtual interface and consequently the P2P device for it.
232 */
233static s32 brcmf_p2p_init_discovery(struct brcmf_p2p_info *p2p)
234{
235 struct net_device *ndev = cfg_to_ndev(p2p->cfg);
236 struct brcmf_cfg80211_vif *vif;
237 struct brcmf_if *ifp;
238 struct p2p_bss *bss_dev;
239 s32 index;
240 s32 ret;
241
242 brcmf_dbg(TRACE, "enter\n");
243
244 bss_dev = &p2p->bss_idx[P2PAPI_BSSCFG_DEVICE];
245 if (bss_dev->vif != NULL) {
246 brcmf_dbg(INFO, "do nothing, already initialized\n");
247 return 0;
248 }
249
250 /* Enable P2P Discovery in the firmware */
251 ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "p2p_disc", 1);
252 if (ret < 0) {
253 brcmf_err("set discover error\n");
254 return ret;
255 }
256
257 /* obtain bsscfg index for P2P discovery */
258 ret = brcmf_fil_iovar_int_get(netdev_priv(ndev), "p2p_dev", &index);
259 if (ret < 0) {
260 brcmf_err("retrieving discover bsscfg index failed\n");
261 return ret;
262 }
263
264 /*
265 * need brcmf_if for setting the discovery state.
266 */
267 ifp = kzalloc(sizeof(*vif->ifp), GFP_KERNEL);
268 if (!ifp) {
269 brcmf_err("could not create discovery if\n");
270 return -ENOMEM;
271 }
272
273 /* set required fields */
274 ifp->drvr = p2p->cfg->pub;
275 ifp->ifidx = 0;
276 ifp->bssidx = index;
277
278 /* Set the initial discovery state to SCAN */
279 ret = brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
280
281 if (ret != 0) {
282 brcmf_err("unable to set WL_P2P_DISC_ST_SCAN\n");
283 (void)brcmf_fil_iovar_int_set(netdev_priv(ndev), "p2p_disc", 0);
284 kfree(ifp);
285 return ret;
286 }
287
288 /* create a vif for it */
Arend van Sprield3c0b632013-02-08 15:53:37 +0100289 vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE, false);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100290 if (IS_ERR(vif)) {
291 brcmf_err("could not create discovery vif\n");
292 kfree(ifp);
293 return PTR_ERR(vif);
294 }
295
296 vif->ifp = ifp;
297 ifp->vif = vif;
298 bss_dev->vif = vif;
299
300 return 0;
301}
302
303/**
304 * brcmf_p2p_deinit_discovery() - disable P2P device discovery.
305 *
306 * @p2p: P2P specific data.
307 *
308 * Resets the discovery state and disables it in firmware. The virtual
309 * interface and P2P device are freed.
310 */
311static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p)
312{
313 struct net_device *ndev = cfg_to_ndev(p2p->cfg);
314 struct brcmf_if *ifp;
315 struct p2p_bss *bss_dev;
316 brcmf_dbg(TRACE, "enter\n");
317
318 bss_dev = &p2p->bss_idx[P2PAPI_BSSCFG_DEVICE];
Arend van Spriel9f440b72013-02-08 15:53:36 +0100319 ifp = bss_dev->vif->ifp;
320
321 /* Set the discovery state to SCAN */
322 (void)brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
323
324 /* Disable P2P discovery in the firmware */
325 (void)brcmf_fil_iovar_int_set(netdev_priv(ndev), "p2p_disc", 0);
326
327 /* remove discovery interface */
328 brcmf_free_vif(bss_dev->vif);
329 bss_dev->vif = NULL;
330 kfree(ifp);
331
332 return 0;
333}
334
335/**
336 * brcmf_p2p_enable_discovery() - initialize and configure discovery.
337 *
338 * @p2p: P2P specific data.
339 * @ie: buffer containing information elements.
340 * @ie_len: length of @ie buffer.
341 *
342 * Initializes the discovery device and configure the virtual interface.
343 */
Hante Meuleman0de8aac2013-02-08 15:53:38 +0100344static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p)
Arend van Spriel9f440b72013-02-08 15:53:36 +0100345{
346 struct brcmf_cfg80211_vif *vif;
347 s32 ret = 0;
348
349 brcmf_dbg(TRACE, "enter\n");
350 vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
351 if (vif) {
Hante Meuleman0de8aac2013-02-08 15:53:38 +0100352 brcmf_dbg(INFO, "DISCOVERY init already done\n");
353 goto exit;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100354 }
355
356 ret = brcmf_p2p_init_discovery(p2p);
357 if (ret < 0) {
358 brcmf_err("init discovery error %d\n", ret);
359 goto exit;
360 }
361
362 vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
363
364 /*
365 * Set wsec to any non-zero value in the discovery bsscfg
366 * to ensure our P2P probe responses have the privacy bit
367 * set in the 802.11 WPA IE. Some peer devices may not
368 * initiate WPS with us if this bit is not set.
369 */
370 ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED);
371 if (ret < 0)
372 brcmf_err("wsec error %d\n", ret);
373
Arend van Spriel9f440b72013-02-08 15:53:36 +0100374exit:
375 return ret;
376}
377
Hante Meuleman0de8aac2013-02-08 15:53:38 +0100378/**
379 * brcmf_p2p_configure_probereq() - Configure probe request data.
380 *
381 * @p2p: P2P specific data.
382 * @ie: buffer containing information elements.
383 * @ie_len: length of @ie buffer.
384 *
385 */
386static int brcmf_p2p_configure_probereq(struct brcmf_p2p_info *p2p,
387 const u8 *ie, u32 ie_len)
388{
389 struct brcmf_cfg80211_vif *vif;
390 s32 err = 0;
391
392 brcmf_dbg(TRACE, "enter\n");
393 vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
394
395 err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG,
396 ie, ie_len);
397
398 if (err < 0)
399 brcmf_err("set probreq ie occurs error %d\n", err);
400
401 return err;
402}
403
Arend van Spriel9f440b72013-02-08 15:53:36 +0100404/*
405 * brcmf_p2p_escan() - initiate a P2P scan.
406 *
407 * @p2p: P2P specific data.
408 * @num_chans: number of channels to scan.
409 * @chanspecs: channel parameters for @num_chans channels.
410 * @search_state: P2P discover state to use.
411 * @action: scan action to pass to firmware.
412 * @bss_type: type of P2P bss.
413 */
414static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans,
415 u16 chanspecs[], s32 search_state, u16 action,
416 enum p2p_bss_type bss_type)
417{
418 s32 ret = 0;
419 s32 memsize = offsetof(struct brcmf_p2p_scan_le,
420 eparams.params_le.channel_list);
421 s32 nprobes;
422 s32 active;
423 u32 i;
424 u8 *memblk;
425 struct brcmf_cfg80211_vif *vif;
426 struct brcmf_p2p_scan_le *p2p_params;
427 struct brcmf_scan_params_le *sparams;
428 struct brcmf_ssid ssid;
429
Arend van Spriel9f440b72013-02-08 15:53:36 +0100430 memsize += num_chans * sizeof(__le16);
431 memblk = kzalloc(memsize, GFP_KERNEL);
432 if (!memblk)
433 return -ENOMEM;
434
435 vif = p2p->bss_idx[bss_type].vif;
436 if (vif == NULL) {
437 brcmf_err("no vif for bss type %d\n", bss_type);
438 ret = -EINVAL;
439 goto exit;
440 }
441
442 switch (search_state) {
443 case WL_P2P_DISC_ST_SEARCH:
444 /*
445 * If we in SEARCH STATE, we don't need to set SSID explictly
446 * because dongle use P2P WILDCARD internally by default
447 */
448 /* use null ssid */
449 ssid.SSID_len = 0;
450 memset(ssid.SSID, 0, sizeof(ssid.SSID));
451 break;
452 case WL_P2P_DISC_ST_SCAN:
453 /*
454 * wpa_supplicant has p2p_find command with type social or
455 * progressive. For progressive, we need to set the ssid to
456 * P2P WILDCARD because we just do broadcast scan unless
457 * setting SSID.
458 */
459 ssid.SSID_len = BRCMF_P2P_WILDCARD_SSID_LEN;
460 memcpy(ssid.SSID, BRCMF_P2P_WILDCARD_SSID, ssid.SSID_len);
461 break;
462 default:
463 brcmf_err(" invalid search state %d\n", search_state);
464 ret = -EINVAL;
465 goto exit;
466 }
467
468 brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0);
469
470 /*
471 * set p2p scan parameters.
472 */
473 p2p_params = (struct brcmf_p2p_scan_le *)memblk;
474 p2p_params->type = 'E';
475
476 /* determine the scan engine parameters */
477 sparams = &p2p_params->eparams.params_le;
478 sparams->bss_type = DOT11_BSSTYPE_ANY;
479 if (p2p->cfg->active_scan)
480 sparams->scan_type = 0;
481 else
482 sparams->scan_type = 1;
483
484 memset(&sparams->bssid, 0xFF, ETH_ALEN);
485 if (ssid.SSID_len)
486 memcpy(sparams->ssid_le.SSID, ssid.SSID, ssid.SSID_len);
487 sparams->ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
488 sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS);
489
490 /*
491 * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan
492 * supported by the supplicant.
493 */
494 if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1))
495 active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS;
496 else if (num_chans == AF_PEER_SEARCH_CNT)
497 active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS;
498 else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED))
499 active = -1;
500 else
501 active = P2PAPI_SCAN_DWELL_TIME_MS;
502
503 /* Override scan params to find a peer for a connection */
504 if (num_chans == 1) {
505 active = WL_SCAN_CONNECT_DWELL_TIME_MS;
506 /* XXX WAR to sync with presence period of VSDB GO.
507 * send probe request more frequently
508 */
509 nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS;
510 } else {
511 nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS;
512 }
513
514 if (nprobes <= 0)
515 nprobes = 1;
516
517 brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active);
518 sparams->active_time = cpu_to_le32(active);
519 sparams->nprobes = cpu_to_le32(nprobes);
520 sparams->passive_time = cpu_to_le32(-1);
521 sparams->channel_num = cpu_to_le32(num_chans &
522 BRCMF_SCAN_PARAMS_COUNT_MASK);
523 for (i = 0; i < num_chans; i++)
524 sparams->channel_list[i] = cpu_to_le16(chanspecs[i]);
525
526 /* set the escan specific parameters */
527 p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION);
528 p2p_params->eparams.action = cpu_to_le16(action);
529 p2p_params->eparams.sync_id = cpu_to_le16(0x1234);
530 /* perform p2p scan on primary device */
531 ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize);
532 if (!ret)
533 set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status);
534exit:
535 kfree(memblk);
536 return ret;
537}
538
539/**
540 * brcmf_p2p_run_escan() - escan callback for peer-to-peer.
541 *
542 * @cfg: driver private data for cfg80211 interface.
543 * @ndev: net device for which scan is requested.
544 * @request: scan request from cfg80211.
545 * @action: scan action.
546 *
547 * Determines the P2P discovery state based to scan request parameters and
548 * validates the channels in the request.
549 */
550static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg,
551 struct net_device *ndev,
552 struct cfg80211_scan_request *request,
553 u16 action)
554{
555 struct brcmf_p2p_info *p2p = &cfg->p2p;
556 s32 err = 0;
557 s32 search_state = WL_P2P_DISC_ST_SCAN;
558 struct brcmf_cfg80211_vif *vif;
559 struct net_device *dev = NULL;
560 int i, num_nodfs = 0;
561 u16 *chanspecs;
562
563 brcmf_dbg(TRACE, "enter\n");
564
565 if (!request) {
566 err = -EINVAL;
567 goto exit;
568 }
569
570 if (request->n_channels) {
571 chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs),
572 GFP_KERNEL);
573 if (!chanspecs) {
574 err = -ENOMEM;
575 goto exit;
576 }
577 vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif;
578 if (vif)
579 dev = vif->wdev.netdev;
580 if (request->n_channels == 3 &&
581 request->channels[0]->hw_value == SOCIAL_CHAN_1 &&
582 request->channels[1]->hw_value == SOCIAL_CHAN_2 &&
583 request->channels[2]->hw_value == SOCIAL_CHAN_3) {
584 /* SOCIAL CHANNELS 1, 6, 11 */
585 search_state = WL_P2P_DISC_ST_SEARCH;
586 brcmf_dbg(INFO, "P2P SEARCH PHASE START\n");
587 } else if (dev != NULL && vif->mode == WL_MODE_AP) {
588 /* If you are already a GO, then do SEARCH only */
589 brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n");
590 search_state = WL_P2P_DISC_ST_SEARCH;
591 } else {
592 brcmf_dbg(INFO, "P2P SCAN STATE START\n");
593 }
594
595 /*
596 * no P2P scanning on passive or DFS channels.
597 */
598 for (i = 0; i < request->n_channels; i++) {
599 struct ieee80211_channel *chan = request->channels[i];
600
601 if (chan->flags & (IEEE80211_CHAN_RADAR |
602 IEEE80211_CHAN_PASSIVE_SCAN))
603 continue;
604
605 chanspecs[i] = channel_to_chanspec(chan);
606 brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n",
607 num_nodfs, chan->hw_value, chanspecs[i]);
608 num_nodfs++;
609 }
610 err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state,
611 action, P2PAPI_BSSCFG_DEVICE);
612 }
613exit:
614 if (err)
615 brcmf_err("error (%d)\n", err);
616 return err;
617}
618
619/**
620 * brcmf_p2p_scan_prep() - prepare scan based on request.
621 *
622 * @wiphy: wiphy device.
623 * @request: scan request from cfg80211.
624 *
625 * Prepare the scan appropriately for type of scan requested. Overrides the
626 * escan .run() callback for peer-to-peer scanning.
627 */
628int brcmf_p2p_scan_prep(struct wiphy *wiphy,
629 struct cfg80211_scan_request *request)
630{
631 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
632 struct brcmf_p2p_info *p2p = &cfg->p2p;
633 int err = 0;
634
635 if (brcmf_p2p_scan_is_p2p_request(request)) {
636 /* find my listen channel */
637 err = cfg80211_get_p2p_attr(request->ie, request->ie_len,
638 IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
639 &p2p->listen_channel, 1);
640 if (err < 0)
641 return err;
642
643 clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status);
644 brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n");
645
Hante Meuleman0de8aac2013-02-08 15:53:38 +0100646 err = brcmf_p2p_enable_discovery(p2p);
647 if (err == 0)
648 err = brcmf_p2p_configure_probereq(p2p, request->ie,
649 request->ie_len);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100650
651 /*
652 * override .run_escan() callback.
653 */
654 cfg->escan_info.run = brcmf_p2p_run_escan;
655 } else {
656 /*
657 * legacy scan trigger
658 * So, we have to disable p2p discovery if p2p discovery is on
659 */
660 (void)brcmf_p2p_discover_disable_search(p2p);
661
662 /*
663 * clear p2p vendor ies for probe request set by
664 * previous p2p related scan(s).
665 */
666 if (p2p_discover_vif(p2p))
667 err = brcmf_vif_set_mgmt_ie(p2p_discover_vif(p2p),
668 BRCMF_VNDR_IE_PRBREQ_FLAG,
669 request->ie,
670 request->ie_len);
671 }
672 return err;
673}
674
Hante Meuleman0de8aac2013-02-08 15:53:38 +0100675
676/**
677 * brcmf_p2p_remain_on_channel() - put device on channel and stay there.
678 *
679 * @wiphy: wiphy device.
680 * @channel: channel to stay on.
681 * @duration: time in ms to remain on channel.
682 *
683 */
684int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
685 struct ieee80211_channel *channel,
686 unsigned int duration, u64 *cookie)
687{
688 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
689 struct brcmf_p2p_info *p2p = &cfg->p2p;
690 struct brcmf_cfg80211_vif *vif;
691 s32 err;
692 u16 chanspec;
693
694 brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n",
695 ieee80211_frequency_to_channel(channel->center_freq),
696 duration);
697
698 *cookie = 0;
699 err = brcmf_p2p_enable_discovery(p2p);
700 if (err)
701 goto exit;
702
703 chanspec = channel_to_chanspec(channel);
704 vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif;
705 err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN,
706 chanspec, (u16)duration);
707 if (err)
708 goto exit;
709
710 memcpy(&p2p->remain_on_channel, channel,
711 sizeof(p2p->remain_on_channel));
712
713 set_bit(BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL, &p2p->status);
714
715exit:
716 cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL);
717 return err;
718}
719
720
721/**
722 * brcmf_p2p_notify_listen_complete() - p2p listen has completed.
723 *
724 * @ifp: interfac control.
725 * @e: event message. Not used, to make it usable for fweh event dispatcher.
726 * @data: payload of message. Not used.
727 *
728 */
729int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp,
730 const struct brcmf_event_msg *e,
731 void *data)
732{
733 struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
734 struct brcmf_p2p_info *p2p = &cfg->p2p;
735
736 brcmf_dbg(TRACE, "Enter\n");
737 if (test_and_clear_bit(BRCMF_P2P_STATUS_REMAIN_ON_CHANNEL,
738 &p2p->status))
739 cfg80211_remain_on_channel_expired(&ifp->vif->wdev, 0,
740 &p2p->remain_on_channel,
741 GFP_KERNEL);
742 return 0;
743}
744
745
746/**
747 * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state.
748 *
749 * @ifp: interfac control.
750 *
751 */
752void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp)
753{
754 if (!ifp)
755 return;
756 brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0);
757 brcmf_p2p_notify_listen_complete(ifp, NULL, NULL);
758}
759
760
Arend van Spriel9f440b72013-02-08 15:53:36 +0100761/**
762 * brcmf_p2p_attach() - attach for P2P.
763 *
764 * @cfg: driver private data for cfg80211 interface.
765 */
766void brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
767{
768 struct brcmf_p2p_info *p2p;
769
770 p2p = &cfg->p2p;
771
772 p2p->cfg = cfg;
773 brcmf_p2p_set_firmware(p2p);
774 brcmf_p2p_generate_bss_mac(p2p);
775}
776
777/**
778 * brcmf_p2p_detach() - detach P2P.
779 *
780 * @p2p: P2P specific data.
781 */
782void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
783{
Hante Meuleman0de8aac2013-02-08 15:53:38 +0100784 if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif != NULL) {
785 brcmf_p2p_cancel_remain_on_channel(
786 p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp);
787 brcmf_p2p_deinit_discovery(p2p);
788 }
Arend van Spriel9f440b72013-02-08 15:53:36 +0100789 /* just set it all to zero */
790 memset(p2p, 0, sizeof(*p2p));
791}
792
Arend van Sprield3c0b632013-02-08 15:53:37 +0100793static int brcmf_p2p_request_p2p_if(struct brcmf_if *ifp, u8 ea[ETH_ALEN],
794 enum brcmf_fil_p2p_if_types iftype)
795{
796 struct brcmf_fil_p2p_if_le if_request;
797 struct brcmf_fil_chan_info_le ci;
798 u16 chanspec = 11 & WL_CHANSPEC_CHAN_MASK;
799 int err;
800
801 /* we need a default channel */
802 err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci));
803 if (!err) {
804 chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK;
805 if (chanspec < CH_MAX_2G_CHANNEL)
806 chanspec |= WL_CHANSPEC_BAND_2G;
807 else
808 chanspec |= WL_CHANSPEC_BAND_5G;
809 }
810 chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
811
812 /* fill the firmware request */
813 memcpy(if_request.addr, ea, ETH_ALEN);
814 if_request.type = iftype;
815 if_request.chspec = cpu_to_le16(chanspec);
816
817 err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request,
818 sizeof(if_request));
819 if (err)
820 return err;
821
822 if (iftype == BRCMF_FIL_P2P_IF_GO) {
823 /* set station timeout for p2p */
824 err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT,
825 BRCMF_SCB_TIMEOUT_VALUE);
826 }
827 return err;
828}
829
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100830static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif)
831{
832 struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
833 struct net_device *pri_ndev = cfg_to_ndev(cfg);
834 struct brcmf_if *ifp = netdev_priv(pri_ndev);
835 u8 *addr = vif->wdev.netdev->dev_addr;
836
837 return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN);
838}
839
840static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif)
841{
842 struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev);
843 struct net_device *pri_ndev = cfg_to_ndev(cfg);
844 struct brcmf_if *ifp = netdev_priv(pri_ndev);
845 u8 *addr = vif->wdev.netdev->dev_addr;
846
847 return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN);
848}
849
Arend van Spriel9f440b72013-02-08 15:53:36 +0100850/**
851 * brcmf_p2p_add_vif() - create a new P2P virtual interface.
852 *
853 * @wiphy: wiphy device of new interface.
854 * @name: name of the new interface.
855 * @type: nl80211 interface type.
856 * @flags: TBD
857 * @params: TBD
Arend van Spriel9f440b72013-02-08 15:53:36 +0100858 */
859struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
860 enum nl80211_iftype type, u32 *flags,
861 struct vif_params *params)
862{
Arend van Sprield3c0b632013-02-08 15:53:37 +0100863 struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
864 struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
865 struct brcmf_cfg80211_vif *vif;
866 enum brcmf_fil_p2p_if_types iftype;
867 enum wl_mode mode;
868 int err;
869
870 if (brcmf_cfg80211_vif_event_armed(cfg))
871 return ERR_PTR(-EBUSY);
872
Arend van Spriel9f440b72013-02-08 15:53:36 +0100873 brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type);
Arend van Sprield3c0b632013-02-08 15:53:37 +0100874
875 switch (type) {
876 case NL80211_IFTYPE_P2P_CLIENT:
877 iftype = BRCMF_FIL_P2P_IF_CLIENT;
878 mode = WL_MODE_BSS;
879 break;
880 case NL80211_IFTYPE_P2P_GO:
881 iftype = BRCMF_FIL_P2P_IF_GO;
882 mode = WL_MODE_AP;
883 break;
884 default:
885 return ERR_PTR(-EOPNOTSUPP);
886 }
887
888 vif = brcmf_alloc_vif(cfg, type, false);
889 brcmf_cfg80211_arm_vif_event(cfg, vif);
890
891 err = brcmf_p2p_request_p2p_if(ifp, cfg->p2p.int_addr, iftype);
892 if (err)
893 goto fail;
894
895 /* wait for firmware event */
896 err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
897 msecs_to_jiffies(1500));
898 brcmf_cfg80211_arm_vif_event(cfg, NULL);
899 if (!err) {
900 brcmf_err("timeout occurred\n");
901 err = -EIO;
902 goto fail;
903 }
904
905 /* interface created in firmware */
906 ifp = vif->ifp;
907 if (!ifp) {
908 brcmf_err("no if pointer provided\n");
909 err = -ENOENT;
910 }
911
912 strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
913 brcmf_cfg80211_vif_complete(cfg);
914 return &ifp->vif->wdev;
915
916fail:
917 brcmf_free_vif(vif);
918 return ERR_PTR(err);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100919}
920
921/**
922 * brcmf_p2p_del_vif() - delete a P2P virtual interface.
923 *
924 * @wiphy: wiphy device of interface.
925 * @wdev: wireless device of interface.
926 *
927 * TODO: not yet supported.
928 */
929int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
930{
Arend van Sprield3c0b632013-02-08 15:53:37 +0100931 struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
Arend van Spriel9f440b72013-02-08 15:53:36 +0100932 struct brcmf_cfg80211_vif *vif;
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100933 unsigned long jiffie_timeout = msecs_to_jiffies(1500);
934 bool wait_for_disable = false;
Arend van Sprield3c0b632013-02-08 15:53:37 +0100935 int err;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100936
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100937 brcmf_dbg(TRACE, "delete P2P vif\n");
Arend van Spriel9f440b72013-02-08 15:53:36 +0100938 vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev);
Arend van Sprield3c0b632013-02-08 15:53:37 +0100939
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100940 switch (vif->wdev.iftype) {
941 case NL80211_IFTYPE_P2P_CLIENT:
942 if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state))
943 wait_for_disable = true;
944 break;
945
946 case NL80211_IFTYPE_P2P_GO:
947 if (!brcmf_p2p_disable_p2p_if(vif))
948 wait_for_disable = true;
949 break;
950
951 case NL80211_IFTYPE_P2P_DEVICE:
952 default:
953 return -ENOTSUPP;
954 break;
955 }
956
957 if (wait_for_disable)
958 wait_for_completion_timeout(&cfg->vif_disabled, 500);
959
960 brcmf_vif_clear_mgmt_ies(vif);
Arend van Sprield3c0b632013-02-08 15:53:37 +0100961
962 brcmf_cfg80211_arm_vif_event(cfg, vif);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100963 err = brcmf_p2p_release_p2p_if(vif);
964 if (!err)
965 /* wait for firmware event */
966 err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
967 jiffie_timeout);
Arend van Sprield3c0b632013-02-08 15:53:37 +0100968 brcmf_cfg80211_arm_vif_event(cfg, NULL);
Arend van Spriel5f4f9f12013-02-08 15:53:41 +0100969 brcmf_free_vif(vif);
970
971 return err;
Arend van Spriel9f440b72013-02-08 15:53:36 +0100972}