staging: brcm80211: removed unused stuff from proto/802.11.h
[deliverable/linux.git] / drivers / staging / brcm80211 / brcmfmac / dhd_common.c
CommitLineData
cf2b4488
HP
1/*
2 * Copyright (c) 2010 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 */
d5642d3b
AS
16#include <linux/kernel.h>
17#include <linux/string.h>
a1c16ed2 18#include <bcmdefs.h>
c6ac24e9 19#include <linux/netdevice.h>
cf2b4488 20#include <bcmutils.h>
cf2b4488
HP
21#include <dngl_stats.h>
22#include <dhd.h>
23#include <dhd_bus.h>
24#include <dhd_proto.h>
25#include <dhd_dbg.h>
26#include <msgtrace.h>
cf2b4488
HP
27
28int dhd_msg_level;
29char fw_path[MOD_PARAM_PATHLEN];
30char nv_path[MOD_PARAM_PATHLEN];
31
32/* Last connection success/failure status */
66cbd3ab
GKH
33u32 dhd_conn_event;
34u32 dhd_conn_status;
35u32 dhd_conn_reason;
cf2b4488 36
cf2b4488
HP
37extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf,
38 uint len);
39extern void dhd_ind_scan_confirm(void *h, bool status);
40extern int dhd_wl_ioctl(dhd_pub_t *dhd, uint cmd, char *buf, uint buflen);
41void dhd_iscan_lock(void);
42void dhd_iscan_unlock(void);
43
44/* Packet alignment for most efficient SDIO (can change based on platform) */
45#ifndef DHD_SDALIGN
46#define DHD_SDALIGN 32
47#endif
48#if !ISPOWEROF2(DHD_SDALIGN)
49#error DHD_SDALIGN is not a power of 2!
50#endif
51
cf2b4488 52#define EPI_VERSION_STR "4.218.248.5"
26e80554 53#ifdef DHD_DEBUG
cf2b4488
HP
54const char dhd_version[] =
55"Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " __DATE__
56" at " __TIME__;
57#else
58const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
59#endif
60
61void dhd_set_timer(void *bus, uint wdtick);
62
63/* IOVar table */
64enum {
65 IOV_VERSION = 1,
66 IOV_MSGLEVEL,
67 IOV_BCMERRORSTR,
68 IOV_BCMERROR,
69 IOV_WDTICK,
70 IOV_DUMP,
71#ifdef DHD_DEBUG
72 IOV_CONS,
73 IOV_DCONSOLE_POLL,
74#endif
75 IOV_CLEARCOUNTS,
76 IOV_LOGDUMP,
77 IOV_LOGCAL,
78 IOV_LOGSTAMP,
79 IOV_GPIOOB,
80 IOV_IOCTLTIMEOUT,
81 IOV_LAST
82};
83
84const bcm_iovar_t dhd_iovars[] = {
85 {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version)}
86 ,
87#ifdef DHD_DEBUG
88 {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0}
89 ,
90#endif /* DHD_DEBUG */
91 {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN}
92 ,
93 {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0}
94 ,
95 {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0}
96 ,
97 {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN}
98 ,
99#ifdef DHD_DEBUG
100 {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0}
101 ,
102 {"cons", IOV_CONS, 0, IOVT_BUFFER, 0}
103 ,
104#endif
105 {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0}
106 ,
107 {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0}
108 ,
109 {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0}
110 ,
111 {NULL, 0, 0, 0, 0}
112};
113
114void dhd_common_init(void)
115{
116 /* Init global variables at run-time, not as part of the declaration.
117 * This is required to support init/de-init of the driver.
118 * Initialization
119 * of globals as part of the declaration results in non-deterministic
120 * behaviour since the value of the globals may be different on the
121 * first time that the driver is initialized vs subsequent
122 * initializations.
123 */
124 dhd_msg_level = DHD_ERROR_VAL;
125#ifdef CONFIG_BCM4329_FW_PATH
126 strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN - 1);
127#else
128 fw_path[0] = '\0';
129#endif
130#ifdef CONFIG_BCM4329_NVRAM_PATH
131 strncpy(nv_path, CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN - 1);
132#else
133 nv_path[0] = '\0';
134#endif
135}
136
137static int dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
138{
cf2b4488
HP
139 struct bcmstrbuf b;
140 struct bcmstrbuf *strbuf = &b;
141
142 bcm_binit(strbuf, buf, buflen);
143
144 /* Base DHD info */
145 bcm_bprintf(strbuf, "%s\n", dhd_version);
146 bcm_bprintf(strbuf, "\n");
147 bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
148 dhdp->up, dhdp->txoff, dhdp->busstate);
149 bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
150 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
ba07d0cb
AS
151 bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %pM\n",
152 dhdp->iswl, dhdp->drv_version, &dhdp->mac);
cf2b4488
HP
153 bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror,
154 dhdp->tickcnt);
155
156 bcm_bprintf(strbuf, "dongle stats:\n");
157 bcm_bprintf(strbuf,
158 "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
159 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
160 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
161 bcm_bprintf(strbuf,
162 "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
163 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
164 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
165 bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast);
166
167 bcm_bprintf(strbuf, "bus stats:\n");
168 bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
169 dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors);
170 bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
171 dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
172 bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld\n",
173 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
174 bcm_bprintf(strbuf,
175 "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n",
176 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped,
177 dhdp->rx_flushed);
178 bcm_bprintf(strbuf,
179 "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n",
180 dhdp->rx_readahead_cnt, dhdp->tx_realloc, dhdp->fc_packets);
181 bcm_bprintf(strbuf, "wd_dpc_sched %ld\n", dhdp->wd_dpc_sched);
182 bcm_bprintf(strbuf, "\n");
183
184 /* Add any prot info */
185 dhd_prot_dump(dhdp, strbuf);
186 bcm_bprintf(strbuf, "\n");
187
188 /* Add any bus info */
189 dhd_bus_dump(dhdp, strbuf);
190
e10d82d4 191 return !strbuf->size ? -EOVERFLOW : 0;
cf2b4488
HP
192}
193
194static int
66cbd3ab 195dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, u32 actionid,
cf2b4488
HP
196 const char *name, void *params, int plen, void *arg, int len,
197 int val_size)
198{
199 int bcmerror = 0;
3e26416e 200 s32 int_val = 0;
cf2b4488
HP
201
202 DHD_TRACE(("%s: Enter\n", __func__));
203
b229fad2
JC
204 bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid));
205 if (bcmerror != 0)
cf2b4488
HP
206 goto exit;
207
208 if (plen >= (int)sizeof(int_val))
02160695 209 memcpy(&int_val, params, sizeof(int_val));
cf2b4488
HP
210
211 switch (actionid) {
212 case IOV_GVAL(IOV_VERSION):
213 /* Need to have checked buffer length */
214 strncpy((char *)arg, dhd_version, len);
215 break;
216
217 case IOV_GVAL(IOV_MSGLEVEL):
3e26416e 218 int_val = (s32) dhd_msg_level;
02160695 219 memcpy(arg, &int_val, val_size);
cf2b4488
HP
220 break;
221
222 case IOV_SVAL(IOV_MSGLEVEL):
223 dhd_msg_level = int_val;
224 break;
225
226 case IOV_GVAL(IOV_BCMERRORSTR):
c2be548d 227 strncpy((char *)arg, "bcm_error",
cf2b4488
HP
228 BCME_STRLEN);
229 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
230 break;
231
232 case IOV_GVAL(IOV_BCMERROR):
3e26416e 233 int_val = (s32) dhd_pub->bcmerror;
02160695 234 memcpy(arg, &int_val, val_size);
cf2b4488
HP
235 break;
236
237 case IOV_GVAL(IOV_WDTICK):
3e26416e 238 int_val = (s32) dhd_watchdog_ms;
02160695 239 memcpy(arg, &int_val, val_size);
cf2b4488
HP
240 break;
241
242 case IOV_SVAL(IOV_WDTICK):
243 if (!dhd_pub->up) {
e10d82d4 244 bcmerror = -ENOLINK;
cf2b4488
HP
245 break;
246 }
247 dhd_os_wd_timer(dhd_pub, (uint) int_val);
248 break;
249
250 case IOV_GVAL(IOV_DUMP):
251 bcmerror = dhd_dump(dhd_pub, arg, len);
252 break;
253
254#ifdef DHD_DEBUG
255 case IOV_GVAL(IOV_DCONSOLE_POLL):
3e26416e 256 int_val = (s32) dhd_console_ms;
02160695 257 memcpy(arg, &int_val, val_size);
cf2b4488
HP
258 break;
259
260 case IOV_SVAL(IOV_DCONSOLE_POLL):
261 dhd_console_ms = (uint) int_val;
262 break;
263
264 case IOV_SVAL(IOV_CONS):
265 if (len > 0)
266 bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
267 break;
268#endif
269
270 case IOV_SVAL(IOV_CLEARCOUNTS):
271 dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
272 dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
273 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
274 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
275 dhd_pub->rx_dropped = 0;
276 dhd_pub->rx_readahead_cnt = 0;
277 dhd_pub->tx_realloc = 0;
278 dhd_pub->wd_dpc_sched = 0;
279 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
280 dhd_bus_clearcounts(dhd_pub);
281 break;
282
283 case IOV_GVAL(IOV_IOCTLTIMEOUT):{
3e26416e 284 int_val = (s32) dhd_os_get_ioctl_resp_timeout();
02160695 285 memcpy(arg, &int_val, sizeof(int_val));
cf2b4488
HP
286 break;
287 }
288
289 case IOV_SVAL(IOV_IOCTLTIMEOUT):{
290 if (int_val <= 0)
e10d82d4 291 bcmerror = -EINVAL;
cf2b4488
HP
292 else
293 dhd_os_set_ioctl_resp_timeout((unsigned int)
294 int_val);
295 break;
296 }
297
298 default:
e10d82d4 299 bcmerror = -ENOTSUPP;
cf2b4488
HP
300 break;
301 }
302
303exit:
304 return bcmerror;
305}
306
c26b1378
AS
307bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, struct sk_buff *pkt,
308 int prec)
cf2b4488 309{
c26b1378 310 struct sk_buff *p;
cf2b4488
HP
311 int eprec = -1; /* precedence to evict from */
312 bool discard_oldest;
313
314 /* Fast case, precedence queue is not full and we are also not
315 * exceeding total queue length
316 */
317 if (!pktq_pfull(q, prec) && !pktq_full(q)) {
b33f0e28 318 bcm_pktq_penq(q, prec, pkt);
0f0881b0 319 return true;
cf2b4488
HP
320 }
321
322 /* Determine precedence from which to evict packet, if any */
323 if (pktq_pfull(q, prec))
324 eprec = prec;
325 else if (pktq_full(q)) {
b33f0e28 326 p = bcm_pktq_peek_tail(q, &eprec);
cf2b4488
HP
327 ASSERT(p);
328 if (eprec > prec)
0965ae88 329 return false;
cf2b4488
HP
330 }
331
332 /* Evict if needed */
333 if (eprec >= 0) {
334 /* Detect queueing to unconfigured precedence */
335 ASSERT(!pktq_pempty(q, eprec));
336 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
337 if (eprec == prec && !discard_oldest)
0965ae88 338 return false; /* refuse newer (incoming) packet */
cf2b4488 339 /* Evict packet according to discard policy */
b33f0e28
HP
340 p = discard_oldest ? bcm_pktq_pdeq(q, eprec) :
341 bcm_pktq_pdeq_tail(q, eprec);
cf2b4488 342 if (p == NULL) {
b33f0e28 343 DHD_ERROR(("%s: bcm_pktq_penq() failed, oldest %d.",
cf2b4488
HP
344 __func__, discard_oldest));
345 ASSERT(p);
346 }
347
b33f0e28 348 bcm_pkt_buf_free_skb(p);
cf2b4488
HP
349 }
350
351 /* Enqueue */
b33f0e28 352 p = bcm_pktq_penq(q, prec, pkt);
cf2b4488 353 if (p == NULL) {
b33f0e28 354 DHD_ERROR(("%s: bcm_pktq_penq() failed.", __func__));
cf2b4488
HP
355 ASSERT(p);
356 }
357
0f0881b0 358 return true;
cf2b4488
HP
359}
360
361static int
362dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
363 void *params, int plen, void *arg, int len, bool set)
364{
365 int bcmerror = 0;
366 int val_size;
367 const bcm_iovar_t *vi = NULL;
66cbd3ab 368 u32 actionid;
cf2b4488
HP
369
370 DHD_TRACE(("%s: Enter\n", __func__));
371
372 ASSERT(name);
373 ASSERT(len >= 0);
374
375 /* Get MUST have return space */
376 ASSERT(set || (arg && len));
377
378 /* Set does NOT take qualifiers */
379 ASSERT(!set || (!params && !plen));
380
b229fad2
JC
381 vi = bcm_iovar_lookup(dhd_iovars, name);
382 if (vi == NULL) {
e10d82d4 383 bcmerror = -ENOTSUPP;
cf2b4488
HP
384 goto exit;
385 }
386
387 DHD_CTL(("%s: %s %s, len %d plen %d\n", __func__,
388 name, (set ? "set" : "get"), len, plen));
389
390 /* set up 'params' pointer in case this is a set command so that
391 * the convenience int and bool code can be common to set and get
392 */
393 if (params == NULL) {
394 params = arg;
395 plen = len;
396 }
397
398 if (vi->type == IOVT_VOID)
399 val_size = 0;
400 else if (vi->type == IOVT_BUFFER)
401 val_size = len;
402 else
403 /* all other types are integer sized */
404 val_size = sizeof(int);
405
406 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
407 bcmerror =
408 dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len,
409 val_size);
410
411exit:
412 return bcmerror;
413}
414
415int dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen)
416{
417 int bcmerror = 0;
418
419 DHD_TRACE(("%s: Enter\n", __func__));
420
421 if (!buf)
e10d82d4 422 return -EINVAL;
cf2b4488
HP
423
424 switch (ioc->cmd) {
425 case DHD_GET_MAGIC:
426 if (buflen < sizeof(int))
e10d82d4 427 bcmerror = -EOVERFLOW;
cf2b4488
HP
428 else
429 *(int *)buf = DHD_IOCTL_MAGIC;
430 break;
431
432 case DHD_GET_VERSION:
433 if (buflen < sizeof(int))
e10d82d4 434 bcmerror = -EOVERFLOW;
cf2b4488
HP
435 else
436 *(int *)buf = DHD_IOCTL_VERSION;
437 break;
438
439 case DHD_GET_VAR:
440 case DHD_SET_VAR:{
441 char *arg;
442 uint arglen;
443
444 /* scan past the name to any arguments */
445 for (arg = buf, arglen = buflen; *arg && arglen;
446 arg++, arglen--)
447 ;
448
449 if (*arg) {
e10d82d4 450 bcmerror = -EOVERFLOW;
cf2b4488
HP
451 break;
452 }
453
454 /* account for the NUL terminator */
455 arg++, arglen--;
456
457 /* call with the appropriate arguments */
458 if (ioc->cmd == DHD_GET_VAR)
459 bcmerror =
460 dhd_iovar_op(dhd_pub, buf, arg, arglen, buf,
461 buflen, IOV_GET);
462 else
463 bcmerror =
464 dhd_iovar_op(dhd_pub, buf, NULL, 0, arg,
465 arglen, IOV_SET);
e10d82d4 466 if (bcmerror != -ENOTSUPP)
cf2b4488
HP
467 break;
468
469 /* not in generic table, try protocol module */
470 if (ioc->cmd == DHD_GET_VAR)
471 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
472 arglen, buf,
473 buflen, IOV_GET);
474 else
475 bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
476 NULL, 0, arg,
477 arglen, IOV_SET);
e10d82d4 478 if (bcmerror != -ENOTSUPP)
cf2b4488
HP
479 break;
480
481 /* if still not found, try bus module */
482 if (ioc->cmd == DHD_GET_VAR)
483 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
484 arg, arglen, buf,
485 buflen, IOV_GET);
486 else
487 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
488 NULL, 0, arg,
489 arglen, IOV_SET);
490
491 break;
492 }
493
494 default:
e10d82d4 495 bcmerror = -ENOTSUPP;
cf2b4488
HP
496 }
497
498 return bcmerror;
499}
500
501#ifdef SHOW_EVENTS
502static void wl_show_host_event(wl_event_msg_t *event, void *event_data)
503{
504 uint i, status, reason;
0965ae88 505 bool group = false, flush_txq = false, link = false;
cf2b4488 506 char *auth_str, *event_name;
580a0bd9 507 unsigned char *buf;
cf2b4488
HP
508 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
509 static struct {
510 uint event;
511 char *event_name;
512 } event_names[] = {
513 {
514 WLC_E_SET_SSID, "SET_SSID"}, {
515 WLC_E_JOIN, "JOIN"}, {
516 WLC_E_START, "START"}, {
517 WLC_E_AUTH, "AUTH"}, {
518 WLC_E_AUTH_IND, "AUTH_IND"}, {
519 WLC_E_DEAUTH, "DEAUTH"}, {
520 WLC_E_DEAUTH_IND, "DEAUTH_IND"}, {
521 WLC_E_ASSOC, "ASSOC"}, {
522 WLC_E_ASSOC_IND, "ASSOC_IND"}, {
523 WLC_E_REASSOC, "REASSOC"}, {
524 WLC_E_REASSOC_IND, "REASSOC_IND"}, {
525 WLC_E_DISASSOC, "DISASSOC"}, {
526 WLC_E_DISASSOC_IND, "DISASSOC_IND"}, {
527 WLC_E_QUIET_START, "START_QUIET"}, {
528 WLC_E_QUIET_END, "END_QUIET"}, {
529 WLC_E_BEACON_RX, "BEACON_RX"}, {
530 WLC_E_LINK, "LINK"}, {
531 WLC_E_MIC_ERROR, "MIC_ERROR"}, {
532 WLC_E_NDIS_LINK, "NDIS_LINK"}, {
533 WLC_E_ROAM, "ROAM"}, {
534 WLC_E_TXFAIL, "TXFAIL"}, {
535 WLC_E_PMKID_CACHE, "PMKID_CACHE"}, {
536 WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, {
537 WLC_E_PRUNE, "PRUNE"}, {
538 WLC_E_AUTOAUTH, "AUTOAUTH"}, {
539 WLC_E_EAPOL_MSG, "EAPOL_MSG"}, {
540 WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
541 WLC_E_ADDTS_IND, "ADDTS_IND"}, {
542 WLC_E_DELTS_IND, "DELTS_IND"}, {
543 WLC_E_BCNSENT_IND, "BCNSENT_IND"}, {
544 WLC_E_BCNRX_MSG, "BCNRX_MSG"}, {
545 WLC_E_BCNLOST_MSG, "BCNLOST_MSG"}, {
546 WLC_E_ROAM_PREP, "ROAM_PREP"}, {
547 WLC_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, {
548 WLC_E_PFN_NET_LOST, "PNO_NET_LOST"}, {
549 WLC_E_RESET_COMPLETE, "RESET_COMPLETE"}, {
550 WLC_E_JOIN_START, "JOIN_START"}, {
551 WLC_E_ROAM_START, "ROAM_START"}, {
552 WLC_E_ASSOC_START, "ASSOC_START"}, {
553 WLC_E_IBSS_ASSOC, "IBSS_ASSOC"}, {
554 WLC_E_RADIO, "RADIO"}, {
555 WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, {
556 WLC_E_PROBREQ_MSG, "PROBREQ_MSG"}, {
557 WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, {
558 WLC_E_PSK_SUP, "PSK_SUP"}, {
559 WLC_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, {
560 WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, {
561 WLC_E_ICV_ERROR, "ICV_ERROR"}, {
562 WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, {
563 WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, {
564 WLC_E_TRACE, "TRACE"}, {
565 WLC_E_ACTION_FRAME, "ACTION FRAME"}, {
566 WLC_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
567 WLC_E_IF, "IF"}, {
568 WLC_E_RSSI, "RSSI"}, {
569 WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}
570 };
571 uint event_type, flags, auth_type, datalen;
628f10ba
SF
572 event_type = be32_to_cpu(event->event_type);
573 flags = be16_to_cpu(event->flags);
574 status = be32_to_cpu(event->status);
575 reason = be32_to_cpu(event->reason);
576 auth_type = be32_to_cpu(event->auth_type);
577 datalen = be32_to_cpu(event->datalen);
cf2b4488 578 /* debug dump of event messages */
a44d4236 579 sprintf(eabuf, "%pM", event->addr);
cf2b4488
HP
580
581 event_name = "UNKNOWN";
8d3d6a69 582 for (i = 0; i < ARRAY_SIZE(event_names); i++) {
cf2b4488
HP
583 if (event_names[i].event == event_type)
584 event_name = event_names[i].event_name;
585 }
586
587 DHD_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type));
1ce4784e
SS
588 DHD_EVENT(("flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n",
589 flags, status, reason, auth_type, eabuf));
cf2b4488
HP
590
591 if (flags & WLC_EVENT_MSG_LINK)
0f0881b0 592 link = true;
cf2b4488 593 if (flags & WLC_EVENT_MSG_GROUP)
0f0881b0 594 group = true;
cf2b4488 595 if (flags & WLC_EVENT_MSG_FLUSHTXQ)
0f0881b0 596 flush_txq = true;
cf2b4488
HP
597
598 switch (event_type) {
599 case WLC_E_START:
600 case WLC_E_DEAUTH:
601 case WLC_E_DISASSOC:
602 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
603 break;
604
605 case WLC_E_ASSOC_IND:
606 case WLC_E_REASSOC_IND:
607 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
608 break;
609
610 case WLC_E_ASSOC:
611 case WLC_E_REASSOC:
612 if (status == WLC_E_STATUS_SUCCESS) {
613 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n",
614 event_name, eabuf));
615 } else if (status == WLC_E_STATUS_TIMEOUT) {
616 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n",
617 event_name, eabuf));
618 } else if (status == WLC_E_STATUS_FAIL) {
619 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
620 event_name, eabuf, (int)reason));
621 } else {
622 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status "
623 "%d\n", event_name, eabuf, (int)status));
624 }
625 break;
626
627 case WLC_E_DEAUTH_IND:
628 case WLC_E_DISASSOC_IND:
629 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name,
630 eabuf, (int)reason));
631 break;
632
633 case WLC_E_AUTH:
634 case WLC_E_AUTH_IND:
fd4bd42e 635 if (auth_type == WLAN_AUTH_OPEN)
cf2b4488 636 auth_str = "Open System";
fd4bd42e 637 else if (auth_type == WLAN_AUTH_SHARED_KEY)
cf2b4488
HP
638 auth_str = "Shared Key";
639 else {
640 sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
641 auth_str = err_msg;
642 }
643 if (event_type == WLC_E_AUTH_IND) {
644 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name,
645 eabuf, auth_str));
646 } else if (status == WLC_E_STATUS_SUCCESS) {
647 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
648 event_name, eabuf, auth_str));
649 } else if (status == WLC_E_STATUS_TIMEOUT) {
650 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
651 event_name, eabuf, auth_str));
652 } else if (status == WLC_E_STATUS_FAIL) {
653 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, "
654 "reason %d\n",
655 event_name, eabuf, auth_str, (int)reason));
656 }
657
658 break;
659
660 case WLC_E_JOIN:
661 case WLC_E_ROAM:
662 case WLC_E_SET_SSID:
663 if (status == WLC_E_STATUS_SUCCESS) {
664 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name,
665 eabuf));
666 } else if (status == WLC_E_STATUS_FAIL) {
667 DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
668 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
669 DHD_EVENT(("MACEVENT: %s, no networks found\n",
670 event_name));
671 } else {
672 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
673 event_name, (int)status));
674 }
675 break;
676
677 case WLC_E_BEACON_RX:
678 if (status == WLC_E_STATUS_SUCCESS) {
679 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
680 } else if (status == WLC_E_STATUS_FAIL) {
681 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
682 } else {
683 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name,
684 status));
685 }
686 break;
687
688 case WLC_E_LINK:
689 DHD_EVENT(("MACEVENT: %s %s\n", event_name,
690 link ? "UP" : "DOWN"));
691 break;
692
693 case WLC_E_MIC_ERROR:
694 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
695 event_name, eabuf, group, flush_txq));
696 break;
697
698 case WLC_E_ICV_ERROR:
699 case WLC_E_UNICAST_DECODE_ERROR:
700 case WLC_E_MULTICAST_DECODE_ERROR:
701 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
702 break;
703
704 case WLC_E_TXFAIL:
705 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
706 break;
707
708 case WLC_E_SCAN_COMPLETE:
709 case WLC_E_PMKID_CACHE:
710 DHD_EVENT(("MACEVENT: %s\n", event_name));
711 break;
712
713 case WLC_E_PFN_NET_FOUND:
714 case WLC_E_PFN_NET_LOST:
715 case WLC_E_PFN_SCAN_COMPLETE:
716 DHD_EVENT(("PNOEVENT: %s\n", event_name));
717 break;
718
719 case WLC_E_PSK_SUP:
720 case WLC_E_PRUNE:
721 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
722 event_name, (int)status, (int)reason));
723 break;
724
725 case WLC_E_TRACE:
726 {
66cbd3ab 727 static u32 seqnum_prev;
cf2b4488 728 msgtrace_hdr_t hdr;
66cbd3ab 729 u32 nblost;
cf2b4488
HP
730 char *s, *p;
731
580a0bd9 732 buf = (unsigned char *) event_data;
cf2b4488
HP
733 memcpy(&hdr, buf, MSGTRACE_HDRLEN);
734
735 if (hdr.version != MSGTRACE_VERSION) {
0bef7748 736 DHD_ERROR(
cf2b4488
HP
737 ("\nMACEVENT: %s [unsupported version --> "
738 "dhd version:%d dongle version:%d]\n",
0bef7748
AS
739 event_name, MSGTRACE_VERSION, hdr.version)
740 );
cf2b4488
HP
741 /* Reset datalen to avoid display below */
742 datalen = 0;
743 break;
744 }
745
746 /* There are 2 bytes available at the end of data */
628f10ba 747 buf[MSGTRACE_HDRLEN + be16_to_cpu(hdr.len)] = '\0';
cf2b4488 748
628f10ba
SF
749 if (be32_to_cpu(hdr.discarded_bytes)
750 || be32_to_cpu(hdr.discarded_printf)) {
0bef7748 751 DHD_ERROR(
cf2b4488
HP
752 ("\nWLC_E_TRACE: [Discarded traces in dongle -->"
753 "discarded_bytes %d discarded_printf %d]\n",
628f10ba
SF
754 be32_to_cpu(hdr.discarded_bytes),
755 be32_to_cpu(hdr.discarded_printf)));
cf2b4488
HP
756 }
757
628f10ba 758 nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
cf2b4488 759 if (nblost > 0) {
0bef7748 760 DHD_ERROR(
cf2b4488 761 ("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
628f10ba 762 be32_to_cpu(hdr.seqnum), nblost));
cf2b4488 763 }
628f10ba 764 seqnum_prev = be32_to_cpu(hdr.seqnum);
cf2b4488
HP
765
766 /* Display the trace buffer. Advance from \n to \n to
767 * avoid display big
768 * printf (issue with Linux printk )
769 */
770 p = (char *)&buf[MSGTRACE_HDRLEN];
771 while ((s = strstr(p, "\n")) != NULL) {
772 *s = '\0';
0bef7748 773 printk(KERN_DEBUG"%s\n", p);
cf2b4488
HP
774 p = s + 1;
775 }
0bef7748 776 printk(KERN_DEBUG "%s\n", p);
cf2b4488
HP
777
778 /* Reset datalen to avoid display below */
779 datalen = 0;
780 }
781 break;
782
783 case WLC_E_RSSI:
784 DHD_EVENT(("MACEVENT: %s %d\n", event_name,
628f10ba 785 be32_to_cpu(*((int *)event_data))));
cf2b4488
HP
786 break;
787
788 default:
789 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
790 "auth %d\n", event_name, event_type, eabuf,
791 (int)status, (int)reason, (int)auth_type));
792 break;
793 }
794
795 /* show any appended data */
796 if (datalen) {
580a0bd9 797 buf = (unsigned char *) event_data;
cf2b4488
HP
798 DHD_EVENT((" data (%d) : ", datalen));
799 for (i = 0; i < datalen; i++)
800 DHD_EVENT((" 0x%02x ", *buf++));
801 DHD_EVENT(("\n"));
802 }
803}
804#endif /* SHOW_EVENTS */
805
806int
807wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata,
808 wl_event_msg_t *event, void **data_ptr)
809{
810 /* check whether packet is a BRCM event pkt */
811 bcm_event_t *pvt_data = (bcm_event_t *) pktdata;
812 char *event_data;
66cbd3ab 813 u32 type, status;
7d4df48e 814 u16 flags;
cf2b4488
HP
815 int evlen;
816
a043b266 817 if (memcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
cf2b4488 818 DHD_ERROR(("%s: mismatched OUI, bailing\n", __func__));
b74ac12e 819 return -EBADE;
cf2b4488
HP
820 }
821
822 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
56dfe3c7 823 if (get_unaligned_be16(&pvt_data->bcm_hdr.usr_subtype) !=
cf2b4488
HP
824 BCMILCP_BCM_SUBTYPE_EVENT) {
825 DHD_ERROR(("%s: mismatched subtype, bailing\n", __func__));
b74ac12e 826 return -EBADE;
cf2b4488
HP
827 }
828
829 *data_ptr = &pvt_data[1];
830 event_data = *data_ptr;
831
832 /* memcpy since BRCM event pkt may be unaligned. */
833 memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
834
56dfe3c7
SF
835 type = get_unaligned_be32(&event->event_type);
836 flags = get_unaligned_be16(&event->flags);
837 status = get_unaligned_be32(&event->status);
838 evlen = get_unaligned_be32(&event->datalen) + sizeof(bcm_event_t);
cf2b4488
HP
839
840 switch (type) {
841 case WLC_E_IF:
842 {
843 dhd_if_event_t *ifevent = (dhd_if_event_t *) event_data;
844 DHD_TRACE(("%s: if event\n", __func__));
845
846 if (ifevent->ifidx > 0 &&
847 ifevent->ifidx < DHD_MAX_IFS) {
848 if (ifevent->action == WLC_E_IF_ADD)
849 dhd_add_if(dhd, ifevent->ifidx,
850 NULL, event->ifname,
e2582ad8 851 pvt_data->eth.h_dest,
cf2b4488
HP
852 ifevent->flags,
853 ifevent->bssidx);
854 else
855 dhd_del_if(dhd, ifevent->ifidx);
856 } else {
857 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
858 __func__, ifevent->ifidx,
859 event->ifname));
860 }
861 }
862 /* send up the if event: btamp user needs it */
863 *ifidx = dhd_ifname2idx(dhd, event->ifname);
864 /* push up to external supp/auth */
865 dhd_event(dhd, (char *)pvt_data, evlen, *ifidx);
866 break;
867
868#ifdef P2P
869 case WLC_E_NDIS_LINK:
870 break;
871#endif
872 /* fall through */
873 /* These are what external supplicant/authenticator wants */
874 case WLC_E_LINK:
875 case WLC_E_ASSOC_IND:
876 case WLC_E_REASSOC_IND:
877 case WLC_E_DISASSOC_IND:
878 case WLC_E_MIC_ERROR:
879 default:
880 /* Fall through: this should get _everything_ */
881
882 *ifidx = dhd_ifname2idx(dhd, event->ifname);
883 /* push up to external supp/auth */
884 dhd_event(dhd, (char *)pvt_data, evlen, *ifidx);
885 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
886 __func__, type, flags, status));
887
888 /* put it back to WLC_E_NDIS_LINK */
889 if (type == WLC_E_NDIS_LINK) {
66cbd3ab 890 u32 temp;
cf2b4488 891
56dfe3c7 892 temp = get_unaligned_be32(&event->event_type);
cf2b4488
HP
893 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
894
628f10ba 895 temp = be32_to_cpu(WLC_E_NDIS_LINK);
cf2b4488
HP
896 memcpy((void *)(&pvt_data->event.event_type), &temp,
897 sizeof(pvt_data->event.event_type));
898 }
899 break;
900 }
901
902#ifdef SHOW_EVENTS
903 wl_show_host_event(event, event_data);
904#endif /* SHOW_EVENTS */
905
a1c5ad81 906 return 0;
cf2b4488
HP
907}
908
cf2b4488
HP
909/* Convert user's input in hex pattern to byte-size mask */
910static int wl_pattern_atoh(char *src, char *dst)
911{
912 int i;
913 if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
914 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
915 return -1;
916 }
917 src = src + 2; /* Skip past 0x */
918 if (strlen(src) % 2 != 0) {
919 DHD_ERROR(("Mask invalid format. Length must be even.\n"));
920 return -1;
921 }
922 for (i = 0; *src != '\0'; i++) {
923 char num[3];
924 strncpy(num, src, 2);
925 num[2] = '\0';
d5642d3b 926 dst[i] = (u8) simple_strtoul(num, NULL, 16);
cf2b4488
HP
927 src += 2;
928 }
929 return i;
930}
931
932void
933dhd_pktfilter_offload_enable(dhd_pub_t *dhd, char *arg, int enable,
934 int master_mode)
935{
936 char *argv[8];
937 int i = 0;
938 const char *str;
939 int buf_len;
940 int str_len;
941 char *arg_save = 0, *arg_org = 0;
942 int rc;
943 char buf[128];
944 wl_pkt_filter_enable_t enable_parm;
945 wl_pkt_filter_enable_t *pkt_filterp;
946
5fcc1fcb 947 arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC);
b229fad2 948 if (!arg_save) {
cf2b4488
HP
949 DHD_ERROR(("%s: kmalloc failed\n", __func__));
950 goto fail;
951 }
952 arg_org = arg_save;
953 memcpy(arg_save, arg, strlen(arg) + 1);
954
d5642d3b 955 argv[i] = strsep(&arg_save, " ");
cf2b4488
HP
956
957 i = 0;
958 if (NULL == argv[i]) {
959 DHD_ERROR(("No args provided\n"));
960 goto fail;
961 }
962
963 str = "pkt_filter_enable";
964 str_len = strlen(str);
965 strncpy(buf, str, str_len);
966 buf[str_len] = '\0';
967 buf_len = str_len + 1;
968
969 pkt_filterp = (wl_pkt_filter_enable_t *) (buf + str_len + 1);
970
971 /* Parse packet filter id. */
29750b90 972 enable_parm.id = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
973
974 /* Parse enable/disable value. */
29750b90 975 enable_parm.enable = enable;
cf2b4488
HP
976
977 buf_len += sizeof(enable_parm);
978 memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm));
979
980 /* Enable/disable the specified filter. */
981 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
982 rc = rc >= 0 ? 0 : rc;
983 if (rc)
984 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
985 __func__, arg, rc));
986 else
987 DHD_TRACE(("%s: successfully added pktfilter %s\n",
988 __func__, arg));
989
990 /* Contorl the master mode */
991 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf,
992 sizeof(buf));
993 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
994 rc = rc >= 0 ? 0 : rc;
995 if (rc)
996 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
997 __func__, arg, rc));
998
999fail:
46d994b1 1000 kfree(arg_org);
cf2b4488
HP
1001}
1002
1003void dhd_pktfilter_offload_set(dhd_pub_t *dhd, char *arg)
1004{
1005 const char *str;
1006 wl_pkt_filter_t pkt_filter;
1007 wl_pkt_filter_t *pkt_filterp;
1008 int buf_len;
1009 int str_len;
1010 int rc;
66cbd3ab
GKH
1011 u32 mask_size;
1012 u32 pattern_size;
cf2b4488
HP
1013 char *argv[8], *buf = 0;
1014 int i = 0;
1015 char *arg_save = 0, *arg_org = 0;
1016#define BUF_SIZE 2048
1017
5fcc1fcb 1018 arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC);
81e95f9d 1019 if (!arg_save) {
cf2b4488
HP
1020 DHD_ERROR(("%s: kmalloc failed\n", __func__));
1021 goto fail;
1022 }
1023
1024 arg_org = arg_save;
1025
5fcc1fcb 1026 buf = kmalloc(BUF_SIZE, GFP_ATOMIC);
81e95f9d 1027 if (!buf) {
cf2b4488
HP
1028 DHD_ERROR(("%s: kmalloc failed\n", __func__));
1029 goto fail;
1030 }
1031
1032 memcpy(arg_save, arg, strlen(arg) + 1);
1033
1034 if (strlen(arg) > BUF_SIZE) {
1035 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg),
1036 (int)sizeof(buf)));
1037 goto fail;
1038 }
1039
d5642d3b 1040 argv[i] = strsep(&arg_save, " ");
cf2b4488 1041 while (argv[i++])
d5642d3b 1042 argv[i] = strsep(&arg_save, " ");
cf2b4488
HP
1043
1044 i = 0;
1045 if (NULL == argv[i]) {
1046 DHD_ERROR(("No args provided\n"));
1047 goto fail;
1048 }
1049
1050 str = "pkt_filter_add";
1051 str_len = strlen(str);
1052 strncpy(buf, str, str_len);
1053 buf[str_len] = '\0';
1054 buf_len = str_len + 1;
1055
1056 pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
1057
1058 /* Parse packet filter id. */
29750b90 1059 pkt_filter.id = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
1060
1061 if (NULL == argv[++i]) {
1062 DHD_ERROR(("Polarity not provided\n"));
1063 goto fail;
1064 }
1065
1066 /* Parse filter polarity. */
29750b90 1067 pkt_filter.negate_match = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
1068
1069 if (NULL == argv[++i]) {
1070 DHD_ERROR(("Filter type not provided\n"));
1071 goto fail;
1072 }
1073
1074 /* Parse filter type. */
29750b90 1075 pkt_filter.type = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
1076
1077 if (NULL == argv[++i]) {
1078 DHD_ERROR(("Offset not provided\n"));
1079 goto fail;
1080 }
1081
1082 /* Parse pattern filter offset. */
29750b90 1083 pkt_filter.u.pattern.offset = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
1084
1085 if (NULL == argv[++i]) {
1086 DHD_ERROR(("Bitmask not provided\n"));
1087 goto fail;
1088 }
1089
1090 /* Parse pattern filter mask. */
1091 mask_size =
29750b90
SF
1092 wl_pattern_atoh
1093 (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern);
cf2b4488
HP
1094
1095 if (NULL == argv[++i]) {
1096 DHD_ERROR(("Pattern not provided\n"));
1097 goto fail;
1098 }
1099
1100 /* Parse pattern filter pattern. */
1101 pattern_size =
29750b90 1102 wl_pattern_atoh(argv[i],
cf2b4488 1103 (char *)&pkt_filterp->u.pattern.
29750b90 1104 mask_and_pattern[mask_size]);
cf2b4488
HP
1105
1106 if (mask_size != pattern_size) {
1107 DHD_ERROR(("Mask and pattern not the same size\n"));
1108 goto fail;
1109 }
1110
1111 pkt_filter.u.pattern.size_bytes = mask_size;
1112 buf_len += WL_PKT_FILTER_FIXED_LEN;
1113 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
1114
1115 /* Keep-alive attributes are set in local
1116 * variable (keep_alive_pkt), and
1117 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1118 ** guarantee that the buffer is properly aligned.
1119 */
1120 memcpy((char *)pkt_filterp,
1121 &pkt_filter,
1122 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
1123
1124 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
1125 rc = rc >= 0 ? 0 : rc;
1126
1127 if (rc)
1128 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1129 __func__, arg, rc));
1130 else
1131 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1132 __func__, arg));
1133
1134fail:
46d994b1 1135 kfree(arg_org);
cf2b4488 1136
46d994b1 1137 kfree(buf);
cf2b4488
HP
1138}
1139
1140void dhd_arp_offload_set(dhd_pub_t *dhd, int arp_mode)
1141{
1142 char iovbuf[32];
1143 int retcode;
1144
1145 bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
1146 retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1147 retcode = retcode >= 0 ? 0 : retcode;
1148 if (retcode)
1149 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, "
1150 "retcode = %d\n", __func__, arp_mode, retcode));
1151 else
1152 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1153 __func__, arp_mode));
1154}
1155
1156void dhd_arp_offload_enable(dhd_pub_t *dhd, int arp_enable)
1157{
1158 char iovbuf[32];
1159 int retcode;
1160
1161 bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
1162 retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1163 retcode = retcode >= 0 ? 0 : retcode;
1164 if (retcode)
1165 DHD_TRACE(("%s: failed to enabe ARP offload to %d, "
1166 "retcode = %d\n", __func__, arp_enable, retcode));
1167 else
1168 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1169 __func__, arp_enable));
1170}
1171
1172int dhd_preinit_ioctls(dhd_pub_t *dhd)
1173{
1174 char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for
1175 "event_msgs" + '\0' + bitvec */
1176 uint up = 0;
1177 char buf[128], *ptr;
1178 uint power_mode = PM_FAST;
66cbd3ab
GKH
1179 u32 dongle_align = DHD_SDALIGN;
1180 u32 glom = 0;
cf2b4488
HP
1181 uint bcn_timeout = 3;
1182 int scan_assoc_time = 40;
1183 int scan_unassoc_time = 40;
1184#ifdef GET_CUSTOM_MAC_ENABLE
1185 int ret = 0;
a44d4236 1186 u8 ea_addr[ETH_ALEN];
cf2b4488
HP
1187#endif /* GET_CUSTOM_MAC_ENABLE */
1188
1189 dhd_os_proto_block(dhd);
1190
1191#ifdef GET_CUSTOM_MAC_ENABLE
1192 /* Read MAC address from external customer place
1193 ** NOTE that default mac address has to be present in
1194 ** otp or nvram file to bring up
1195 ** firmware but unique per board mac address maybe provided by
1196 ** customer code
1197 */
a44d4236 1198 ret = dhd_custom_get_mac_address(ea_addr);
cf2b4488 1199 if (!ret) {
a44d4236 1200 bcm_mkiovar("cur_etheraddr", (void *)ea_addr, ETH_ALEN,
cf2b4488
HP
1201 buf, sizeof(buf));
1202 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
1203 if (ret < 0) {
1204 DHD_ERROR(("%s: can't set MAC address , error=%d\n",
1205 __func__, ret));
1206 } else
1207 memcpy(dhd->mac.octet, (void *)&ea_addr,
b8d63078 1208 ETH_ALEN);
cf2b4488
HP
1209 }
1210#endif /* GET_CUSTOM_MAC_ENABLE */
1211
1212 /* Set Country code */
1213 if (dhd->country_code[0] != 0) {
1214 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY,
1215 dhd->country_code,
1216 sizeof(dhd->country_code)) < 0) {
1217 DHD_ERROR(("%s: country code setting failed\n",
1218 __func__));
1219 }
1220 }
1221
1222 /* query for 'ver' to get version info from firmware */
1223 memset(buf, 0, sizeof(buf));
1224 ptr = buf;
1225 bcm_mkiovar("ver", 0, 0, buf, sizeof(buf));
1226 dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
d5642d3b 1227 strsep(&ptr, "\n");
cf2b4488
HP
1228 /* Print fw version info */
1229 DHD_ERROR(("Firmware version = %s\n", buf));
1230
1231 /* Set PowerSave mode */
1232 dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode,
1233 sizeof(power_mode));
1234
1235 /* Match Host and Dongle rx alignment */
1236 bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
1237 sizeof(iovbuf));
1238 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1239
1240 /* disable glom option per default */
1241 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
1242 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1243
1244 /* Setup timeout if Beacons are lost and roam is off to report
1245 link down */
1246 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
1247 sizeof(iovbuf));
1248 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1249
1250 /* Enable/Disable build-in roaming to allowed ext supplicant to take
1251 of romaing */
1252 bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf));
1253 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1254
1255 /* Force STA UP */
1256 if (dhd_radio_up)
1257 dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up));
1258
1259 /* Setup event_msgs */
1260 bcm_mkiovar("event_msgs", dhd->eventmask, WL_EVENTING_MASK_LEN, iovbuf,
1261 sizeof(iovbuf));
1262 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1263
1264 dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_CHANNEL_TIME,
1265 (char *)&scan_assoc_time, sizeof(scan_assoc_time));
1266 dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_UNASSOC_TIME,
1267 (char *)&scan_unassoc_time, sizeof(scan_unassoc_time));
1268
1269#ifdef ARP_OFFLOAD_SUPPORT
1270 /* Set and enable ARP offload feature */
1271 if (dhd_arp_enable)
1272 dhd_arp_offload_set(dhd, dhd_arp_mode);
1273 dhd_arp_offload_enable(dhd, dhd_arp_enable);
1274#endif /* ARP_OFFLOAD_SUPPORT */
1275
1276#ifdef PKT_FILTER_SUPPORT
1277 {
1278 int i;
1279 /* Set up pkt filter */
1280 if (dhd_pkt_filter_enable) {
1281 for (i = 0; i < dhd->pktfilter_count; i++) {
1282 dhd_pktfilter_offload_set(dhd,
1283 dhd->pktfilter[i]);
1284 dhd_pktfilter_offload_enable(dhd,
1285 dhd->pktfilter[i],
1286 dhd_pkt_filter_init,
1287 dhd_master_mode);
1288 }
1289 }
1290 }
1291#endif /* PKT_FILTER_SUPPORT */
1292
1293 dhd_os_proto_unblock(dhd);
1294
1295 return 0;
1296}
1297
1298#ifdef SIMPLE_ISCAN
1299uint iscan_thread_id;
6998d337 1300iscan_buf_t *iscan_chain;
cf2b4488
HP
1301
1302iscan_buf_t *dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
1303{
1304 iscan_buf_t *iscanbuf_alloc = 0;
1305 iscan_buf_t *iscanbuf_head;
1306
1307 dhd_iscan_lock();
1308
5fcc1fcb 1309 iscanbuf_alloc = kmalloc(sizeof(iscan_buf_t), GFP_ATOMIC);
cf2b4488
HP
1310 if (iscanbuf_alloc == NULL)
1311 goto fail;
1312
1313 iscanbuf_alloc->next = NULL;
1314 iscanbuf_head = *iscanbuf;
1315
1316 DHD_ISCAN(("%s: addr of allocated node = 0x%X"
1317 "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
1318 __func__, iscanbuf_alloc, iscanbuf_head, dhd));
1319
1320 if (iscanbuf_head == NULL) {
1321 *iscanbuf = iscanbuf_alloc;
1322 DHD_ISCAN(("%s: Head is allocated\n", __func__));
1323 goto fail;
1324 }
1325
1326 while (iscanbuf_head->next)
1327 iscanbuf_head = iscanbuf_head->next;
1328
1329 iscanbuf_head->next = iscanbuf_alloc;
1330
1331fail:
1332 dhd_iscan_unlock();
1333 return iscanbuf_alloc;
1334}
1335
1336void dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
1337{
1338 iscan_buf_t *iscanbuf_free = 0;
1339 iscan_buf_t *iscanbuf_prv = 0;
1340 iscan_buf_t *iscanbuf_cur = iscan_chain;
1341 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1342
1343 dhd_iscan_lock();
1344 /* If iscan_delete is null then delete the entire
1345 * chain or else delete specific one provided
1346 */
1347 if (!iscan_delete) {
1348 while (iscanbuf_cur) {
1349 iscanbuf_free = iscanbuf_cur;
1350 iscanbuf_cur = iscanbuf_cur->next;
1351 iscanbuf_free->next = 0;
182acb3c 1352 kfree(iscanbuf_free);
cf2b4488
HP
1353 }
1354 iscan_chain = 0;
1355 } else {
1356 while (iscanbuf_cur) {
1357 if (iscanbuf_cur == iscan_delete)
1358 break;
1359 iscanbuf_prv = iscanbuf_cur;
1360 iscanbuf_cur = iscanbuf_cur->next;
1361 }
1362 if (iscanbuf_prv)
1363 iscanbuf_prv->next = iscan_delete->next;
1364
1365 iscan_delete->next = 0;
182acb3c 1366 kfree(iscan_delete);
cf2b4488
HP
1367
1368 if (!iscanbuf_prv)
1369 iscan_chain = 0;
1370 }
1371 dhd_iscan_unlock();
1372}
1373
1374iscan_buf_t *dhd_iscan_result_buf(void)
1375{
1376 return iscan_chain;
1377}
1378
1379/*
1380* print scan cache
1381* print partial iscan_skip list differently
1382*/
1383int dhd_iscan_print_cache(iscan_buf_t *iscan_skip)
1384{
1385 int i = 0, l = 0;
1386 iscan_buf_t *iscan_cur;
1387 wl_iscan_results_t *list;
1388 wl_scan_results_t *results;
1389 wl_bss_info_t UNALIGNED *bi;
1390
1391 dhd_iscan_lock();
1392
1393 iscan_cur = dhd_iscan_result_buf();
1394
1395 while (iscan_cur) {
1396 list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1397 if (!list)
1398 break;
1399
1400 results = (wl_scan_results_t *)&list->results;
1401 if (!results)
1402 break;
1403
1404 if (results->version != WL_BSS_INFO_VERSION) {
1405 DHD_ISCAN(("%s: results->version %d != "
1406 "WL_BSS_INFO_VERSION\n",
1407 __func__, results->version));
1408 goto done;
1409 }
1410
1411 bi = results->bss_info;
1412 for (i = 0; i < results->count; i++) {
1413 if (!bi)
1414 break;
1415
1416 DHD_ISCAN(("%s[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n",
1417 iscan_cur != iscan_skip ? "BSS" : "bss", l,
1418 i, bi->BSSID.octet[0], bi->BSSID.octet[1],
1419 bi->BSSID.octet[2], bi->BSSID.octet[3],
1420 bi->BSSID.octet[4], bi->BSSID.octet[5]));
1421
29750b90 1422 bi = (wl_bss_info_t *)((unsigned long)bi + bi->length);
cf2b4488
HP
1423 }
1424 iscan_cur = iscan_cur->next;
1425 l++;
1426 }
1427
1428done:
1429 dhd_iscan_unlock();
1430 return 0;
1431}
1432
1433/*
1434* delete disappeared AP from specific scan cache but skip partial
1435* list in iscan_skip
1436*/
1437int dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip)
1438{
1439 int i = 0, j = 0, l = 0;
1440 iscan_buf_t *iscan_cur;
1441 wl_iscan_results_t *list;
1442 wl_scan_results_t *results;
1443 wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
1444
580a0bd9 1445 unsigned char *s_addr = addr;
cf2b4488
HP
1446
1447 dhd_iscan_lock();
1448 DHD_ISCAN(("%s: BSS to remove %X:%X:%X:%X:%X:%X\n",
1449 __func__, s_addr[0], s_addr[1], s_addr[2],
1450 s_addr[3], s_addr[4], s_addr[5]));
1451
1452 iscan_cur = dhd_iscan_result_buf();
1453
1454 while (iscan_cur) {
1455 if (iscan_cur != iscan_skip) {
1456 list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1457 if (!list)
1458 break;
1459
1460 results = (wl_scan_results_t *)&list->results;
1461 if (!results)
1462 break;
1463
1464 if (results->version != WL_BSS_INFO_VERSION) {
1465 DHD_ERROR(("%s: results->version %d != "
1466 "WL_BSS_INFO_VERSION\n",
1467 __func__, results->version));
1468 goto done;
1469 }
1470
1471 bi = results->bss_info;
1472 for (i = 0; i < results->count; i++) {
1473 if (!bi)
1474 break;
1475
1476 if (!memcmp
b8d63078 1477 (bi->BSSID.octet, addr, ETH_ALEN)) {
cf2b4488
HP
1478 DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] "
1479 "%X:%X:%X:%X:%X:%X\n",
1480 __func__, l, i, bi->BSSID.octet[0],
1481 bi->BSSID.octet[1], bi->BSSID.octet[2],
1482 bi->BSSID.octet[3], bi->BSSID.octet[4],
1483 bi->BSSID.octet[5]));
1484
1485 bi_new = bi;
29750b90
SF
1486 bi = (wl_bss_info_t *)((unsigned long)
1487 bi + bi->length);
cf2b4488
HP
1488/*
1489 if(bi && bi_new) {
02160695 1490 memcpy(bi_new, bi, results->buflen -
29750b90
SF
1491 bi_new->length);
1492 results->buflen -= bi_new->length;
cf2b4488
HP
1493 }
1494*/
29750b90 1495 results->buflen -= bi_new->length;
cf2b4488
HP
1496 results->count--;
1497
1498 for (j = i; j < results->count; j++) {
1499 if (bi && bi_new) {
1500 DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d]" "%X:%X:%X:%X:%X:%X\n",
1501 __func__, l, j,
1502 bi->BSSID.octet[0],
1503 bi->BSSID.octet[1],
1504 bi->BSSID.octet[2],
1505 bi->BSSID.octet[3],
1506 bi->BSSID.octet[4],
1507 bi->BSSID.octet[5]));
1508
1509 bi_next =
f024c48a 1510 (wl_bss_info_t *)((unsigned long)bi +
29750b90 1511 bi->length);
02160695 1512 memcpy(bi_new, bi,
29750b90 1513 bi->length);
cf2b4488 1514 bi_new =
f024c48a 1515 (wl_bss_info_t *)((unsigned long)bi_new +
29750b90
SF
1516 bi_new->
1517 length);
cf2b4488
HP
1518 bi = bi_next;
1519 }
1520 }
1521
1522 if (results->count == 0) {
1523 /* Prune now empty partial
1524 scan list */
1525 dhd_iscan_free_buf(dhdp,
1526 iscan_cur);
1527 goto done;
1528 }
1529 break;
1530 }
f024c48a 1531 bi = (wl_bss_info_t *)((unsigned long)bi +
29750b90 1532 bi->length);
cf2b4488
HP
1533 }
1534 }
1535 iscan_cur = iscan_cur->next;
1536 l++;
1537 }
1538
1539done:
1540 dhd_iscan_unlock();
1541 return 0;
1542}
1543
1544int dhd_iscan_remove_duplicates(void *dhdp, iscan_buf_t *iscan_cur)
1545{
1546 int i = 0;
1547 wl_iscan_results_t *list;
1548 wl_scan_results_t *results;
1549 wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
1550
1551 dhd_iscan_lock();
1552
1553 DHD_ISCAN(("%s: Scan cache before delete\n", __func__));
1554 dhd_iscan_print_cache(iscan_cur);
1555
1556 if (!iscan_cur)
1557 goto done;
1558
1559 list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1560 if (!list)
1561 goto done;
1562
1563 results = (wl_scan_results_t *)&list->results;
1564 if (!results)
1565 goto done;
1566
1567 if (results->version != WL_BSS_INFO_VERSION) {
1568 DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
1569 __func__, results->version));
1570 goto done;
1571 }
1572
1573 bi = results->bss_info;
1574 for (i = 0; i < results->count; i++) {
1575 if (!bi)
1576 break;
1577
1578 DHD_ISCAN(("%s: Find dups for BSS[%2.2d] %X:%X:%X:%X:%X:%X\n",
1579 __func__, i, bi->BSSID.octet[0],
1580 bi->BSSID.octet[1], bi->BSSID.octet[2],
1581 bi->BSSID.octet[3], bi->BSSID.octet[4],
1582 bi->BSSID.octet[5]));
1583
1584 dhd_iscan_delete_bss(dhdp, bi->BSSID.octet, iscan_cur);
1585
29750b90 1586 bi = (wl_bss_info_t *)((unsigned long)bi + bi->length);
cf2b4488
HP
1587 }
1588
1589done:
1590 DHD_ISCAN(("%s: Scan cache after delete\n", __func__));
1591 dhd_iscan_print_cache(iscan_cur);
1592 dhd_iscan_unlock();
1593 return 0;
1594}
1595
1596void dhd_iscan_ind_scan_confirm(void *dhdp, bool status)
1597{
1598
1599 dhd_ind_scan_confirm(dhdp, status);
1600}
1601
7d4df48e 1602int dhd_iscan_request(void *dhdp, u16 action)
cf2b4488
HP
1603{
1604 int rc;
1605 wl_iscan_params_t params;
1606 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1607 char buf[WLC_IOCTL_SMLEN];
1608
1609 memset(&params, 0, sizeof(wl_iscan_params_t));
b8d63078 1610 memcpy(&params.params.bssid, &ether_bcast, ETH_ALEN);
cf2b4488
HP
1611
1612 params.params.bss_type = DOT11_BSSTYPE_ANY;
1613 params.params.scan_type = DOT11_SCANTYPE_ACTIVE;
1614
29750b90
SF
1615 params.params.nprobes = -1;
1616 params.params.active_time = -1;
1617 params.params.passive_time = -1;
1618 params.params.home_time = -1;
1619 params.params.channel_num = 0;
cf2b4488 1620
29750b90
SF
1621 params.version = ISCAN_REQ_VERSION;
1622 params.action = action;
1623 params.scan_duration = 0;
cf2b4488
HP
1624
1625 bcm_mkiovar("iscan", (char *)&params, sizeof(wl_iscan_params_t), buf,
1626 WLC_IOCTL_SMLEN);
1627 rc = dhd_wl_ioctl(dhdp, WLC_SET_VAR, buf, WLC_IOCTL_SMLEN);
1628
1629 return rc;
1630}
1631
1632static int dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
1633{
1634 wl_iscan_results_t *list_buf;
1635 wl_iscan_results_t list;
1636 wl_scan_results_t *results;
1637 iscan_buf_t *iscan_cur;
1638 int status = -1;
1639 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1640 int rc;
1641
1642 iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
1643 if (!iscan_cur) {
1644 DHD_ERROR(("%s: Failed to allocate node\n", __func__));
1645 dhd_iscan_free_buf(dhdp, 0);
1646 dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
1647 goto fail;
1648 }
1649
1650 dhd_iscan_lock();
1651
1652 memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1653 list_buf = (wl_iscan_results_t *) iscan_cur->iscan_buf;
1654 results = &list_buf->results;
1655 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1656 results->version = 0;
1657 results->count = 0;
1658
1659 memset(&list, 0, sizeof(list));
29750b90 1660 list.results.buflen = WLC_IW_ISCAN_MAXLEN;
cf2b4488
HP
1661 bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
1662 iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1663 rc = dhd_wl_ioctl(dhdp, WLC_GET_VAR, iscan_cur->iscan_buf,
1664 WLC_IW_ISCAN_MAXLEN);
1665
29750b90
SF
1666 results->buflen = results->buflen;
1667 results->version = results->version;
1668 *scan_count = results->count = results->count;
1669 status = list_buf->status;
cf2b4488
HP
1670
1671 dhd_iscan_unlock();
1672
1673 if (!(*scan_count))
1674 dhd_iscan_free_buf(dhdp, iscan_cur);
1675 else
1676 dhd_iscan_remove_duplicates(dhdp, iscan_cur);
1677
1678fail:
1679 return status;
1680}
1681#endif /* SIMPLE_ISCAN */
1682
1683#ifdef PNO_SUPPORT
1684int dhd_pno_clean(dhd_pub_t *dhd)
1685{
1686 char iovbuf[128];
1687 int pfn_enabled = 0;
1688 int iov_len = 0;
1689 int ret;
1690
1691 /* Disable pfn */
1692 iov_len =
1693 bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf));
81e95f9d
JC
1694 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1695 if (ret >= 0) {
cf2b4488
HP
1696 /* clear pfn */
1697 iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf));
1698 if (iov_len) {
81e95f9d
JC
1699 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf,
1700 iov_len);
1701 if (ret < 0) {
cf2b4488
HP
1702 DHD_ERROR(("%s failed code %d\n", __func__,
1703 ret));
1704 }
1705 } else {
1706 ret = -1;
1707 DHD_ERROR(("%s failed code %d\n", __func__, iov_len));
1708 }
1709 } else
1710 DHD_ERROR(("%s failed code %d\n", __func__, ret));
1711
1712 return ret;
1713}
1714
1715int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
1716{
1717 char iovbuf[128];
1718 int ret = -1;
1719
1720 if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
1721 DHD_ERROR(("%s error exit\n", __func__));
1722 return ret;
1723 }
1724
1725 /* Enable/disable PNO */
81e95f9d
JC
1726 ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf,
1727 sizeof(iovbuf));
1728 if (ret > 0) {
1729 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf,
1730 sizeof(iovbuf));
1731 if (ret < 0) {
cf2b4488
HP
1732 DHD_ERROR(("%s failed for error=%d\n", __func__, ret));
1733 return ret;
1734 } else {
1735 dhd->pno_enable = pfn_enabled;
1736 DHD_TRACE(("%s set pno as %d\n", __func__,
1737 dhd->pno_enable));
1738 }
1739 } else
1740 DHD_ERROR(("%s failed err=%d\n", __func__, ret));
1741
1742 return ret;
1743}
1744
1745/* Function to execute combined scan */
1746int
580a0bd9 1747dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t *ssids_local, int nssid, unsigned char scan_fr)
cf2b4488
HP
1748{
1749 int err = -1;
1750 char iovbuf[128];
1751 int k, i;
1752 wl_pfn_param_t pfn_param;
1753 wl_pfn_t pfn_element;
1754
1755 DHD_TRACE(("%s nssid=%d nchan=%d\n", __func__, nssid, scan_fr));
1756
1757 if ((!dhd) && (!ssids_local)) {
1758 DHD_ERROR(("%s error exit\n", __func__));
1759 err = -1;
1760 }
1761
1762 /* Check for broadcast ssid */
1763 for (k = 0; k < nssid; k++) {
1764 if (!ssids_local[k].SSID_len) {
1765 DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO "
1766 "setting\n", k));
1767 return err;
1768 }
1769 }
1770/* #define PNO_DUMP 1 */
1771#ifdef PNO_DUMP
1772 {
1773 int j;
1774 for (j = 0; j < nssid; j++) {
1775 DHD_ERROR(("%d: scan for %s size =%d\n", j,
1776 ssids_local[j].SSID,
1777 ssids_local[j].SSID_len));
1778 }
1779 }
1780#endif /* PNO_DUMP */
1781
1782 /* clean up everything */
81e95f9d
JC
1783 err = dhd_pno_clean(dhd);
1784 if (err < 0) {
cf2b4488
HP
1785 DHD_ERROR(("%s failed error=%d\n", __func__, err));
1786 return err;
1787 }
1788 memset(&pfn_param, 0, sizeof(pfn_param));
1789 memset(&pfn_element, 0, sizeof(pfn_element));
1790
1791 /* set pfn parameters */
29750b90
SF
1792 pfn_param.version = PFN_VERSION;
1793 pfn_param.flags = (PFN_LIST_ORDER << SORT_CRITERIA_BIT);
cf2b4488
HP
1794
1795 /* set up pno scan fr */
1796 if (scan_fr != 0)
29750b90 1797 pfn_param.scan_freq = scan_fr;
cf2b4488
HP
1798
1799 bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf,
1800 sizeof(iovbuf));
1801 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1802
1803 /* set all pfn ssid */
1804 for (i = 0; i < nssid; i++) {
1805
29750b90 1806 pfn_element.bss_type = DOT11_BSSTYPE_INFRASTRUCTURE;
fd4bd42e 1807 pfn_element.auth = WLAN_AUTH_OPEN;
29750b90
SF
1808 pfn_element.wpa_auth = WPA_AUTH_PFN_ANY;
1809 pfn_element.wsec = 0;
1810 pfn_element.infra = 1;
cf2b4488
HP
1811
1812 memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID,
1813 ssids_local[i].SSID_len);
1814 pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;
1815
81e95f9d
JC
1816 err = bcm_mkiovar("pfn_add", (char *)&pfn_element,
1817 sizeof(pfn_element), iovbuf, sizeof(iovbuf));
1818 if (err > 0) {
1819 err = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf,
1820 sizeof(iovbuf));
1821 if (err < 0) {
cf2b4488
HP
1822 DHD_ERROR(("%s failed for i=%d error=%d\n",
1823 __func__, i, err));
1824 return err;
1825 }
1826 } else
1827 DHD_ERROR(("%s failed err=%d\n", __func__, err));
1828 }
1829
1830 /* Enable PNO */
1831 /* dhd_pno_enable(dhd, 1); */
1832 return err;
1833}
1834
1835int dhd_pno_get_status(dhd_pub_t *dhd)
1836{
1837 int ret = -1;
1838
1839 if (!dhd)
1840 return ret;
1841 else
1842 return dhd->pno_enable;
1843}
1844
1845#endif /* PNO_SUPPORT */
1846
1847/* Androd ComboSCAN support */
This page took 0.201069 seconds and 5 git commands to generate.