staging: brcm80211: removed occurrences of 'dhd'
[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>
7c6100ee 18#include <linux/sched.h>
c6ac24e9 19#include <linux/netdevice.h>
7c6100ee 20#include <asm/unaligned.h>
c4daa849
RV
21#include <defs.h>
22#include <brcmu_wifi.h>
f97e956a 23#include <brcmu_utils.h>
c4daa849
RV
24#include "dngl_stats.h"
25#include "dhd.h"
26#include "dhd_bus.h"
27#include "dhd_proto.h"
28#include "dhd_dbg.h"
cf2b4488 29
8d825a8e 30#define BRCM_OUI "\x00\x10\x18"
9152bf26 31#define DOT11_OUI_LEN 3
8d825a8e
AS
32#define BCMILCP_BCM_SUBTYPE_EVENT 1
33#define PKTFILTER_BUF_SIZE 2048
9152bf26 34
aba5e0ad 35int brcmf_msg_level;
cf2b4488 36
86c01843
FL
37#define MSGTRACE_VERSION 1
38
762c2a36 39#ifdef BCMDBG
aba5e0ad 40const char brcmf_version[] =
c8796cbe 41"Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " __DATE__
cf2b4488
HP
42" at " __TIME__;
43#else
c8796cbe 44const char brcmf_version[] = "Dongle Host Driver, version " BRCMF_VERSION_STR;
cf2b4488
HP
45#endif
46
cf2b4488
HP
47/* IOVar table */
48enum {
49 IOV_VERSION = 1,
50 IOV_MSGLEVEL,
51 IOV_BCMERRORSTR,
52 IOV_BCMERROR,
cf2b4488 53 IOV_DUMP,
cf2b4488
HP
54 IOV_CLEARCOUNTS,
55 IOV_LOGDUMP,
56 IOV_LOGCAL,
57 IOV_LOGSTAMP,
58 IOV_GPIOOB,
59 IOV_IOCTLTIMEOUT,
60 IOV_LAST
61};
62
aba5e0ad
AS
63const struct brcmu_iovar brcmf_iovars[] = {
64 {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(brcmf_version)}
cf2b4488 65 ,
762c2a36 66#ifdef BCMDBG
cf2b4488
HP
67 {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0}
68 ,
762c2a36 69#endif /* BCMDBG */
cf2b4488
HP
70 {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN}
71 ,
72 {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0}
73 ,
40695d1a 74 {"dump", IOV_DUMP, 0, IOVT_BUFFER, BRCMF_IOCTL_MAXLEN}
cf2b4488 75 ,
cf2b4488
HP
76 {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0}
77 ,
78 {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0}
79 ,
80 {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0}
81 ,
82 {NULL, 0, 0, 0, 0}
83};
84
86c01843
FL
85/* Message trace header */
86struct msgtrace_hdr {
87 u8 version;
88 u8 spare;
89 u16 len; /* Len of the trace */
90 u32 seqnum; /* Sequence number of message. Useful
91 * if the messsage has been lost
92 * because of DMA error or a bus reset
93 * (ex: SDIO Func2)
94 */
95 u32 discarded_bytes; /* Number of discarded bytes because of
96 trace overflow */
97 u32 discarded_printf; /* Number of discarded printf
98 because of trace overflow */
99} __packed;
100
aba5e0ad 101void brcmf_c_init(void)
cf2b4488
HP
102{
103 /* Init global variables at run-time, not as part of the declaration.
104 * This is required to support init/de-init of the driver.
105 * Initialization
106 * of globals as part of the declaration results in non-deterministic
107 * behaviour since the value of the globals may be different on the
108 * first time that the driver is initialized vs subsequent
109 * initializations.
110 */
40695d1a 111 brcmf_msg_level = BRCMF_ERROR_VAL;
cf2b4488
HP
112}
113
fb1d0aa2 114static int brcmf_c_dump(struct brcmf_pub *drvr, char *buf, int buflen)
cf2b4488 115{
67ad48bc
RV
116 struct brcmu_strbuf b;
117 struct brcmu_strbuf *strbuf = &b;
cf2b4488 118
67ad48bc 119 brcmu_binit(strbuf, buf, buflen);
cf2b4488 120
1f660b9c 121 /* Base info */
aba5e0ad 122 brcmu_bprintf(strbuf, "%s\n", brcmf_version);
67ad48bc
RV
123 brcmu_bprintf(strbuf, "\n");
124 brcmu_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
56d52fcc 125 drvr->up, drvr->txoff, drvr->busstate);
67ad48bc 126 brcmu_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
56d52fcc 127 drvr->hdrlen, drvr->maxctl, drvr->rxsz);
67ad48bc 128 brcmu_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %pM\n",
56d52fcc
AS
129 drvr->iswl, drvr->drv_version, &drvr->mac);
130 brcmu_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", drvr->bcmerror,
131 drvr->tickcnt);
cf2b4488 132
67ad48bc
RV
133 brcmu_bprintf(strbuf, "dongle stats:\n");
134 brcmu_bprintf(strbuf,
cf2b4488 135 "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
56d52fcc
AS
136 drvr->dstats.tx_packets, drvr->dstats.tx_bytes,
137 drvr->dstats.tx_errors, drvr->dstats.tx_dropped);
67ad48bc 138 brcmu_bprintf(strbuf,
cf2b4488 139 "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
56d52fcc
AS
140 drvr->dstats.rx_packets, drvr->dstats.rx_bytes,
141 drvr->dstats.rx_errors, drvr->dstats.rx_dropped);
142 brcmu_bprintf(strbuf, "multicast %ld\n", drvr->dstats.multicast);
cf2b4488 143
67ad48bc
RV
144 brcmu_bprintf(strbuf, "bus stats:\n");
145 brcmu_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
56d52fcc 146 drvr->tx_packets, drvr->tx_multicast, drvr->tx_errors);
67ad48bc 147 brcmu_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
56d52fcc 148 drvr->tx_ctlpkts, drvr->tx_ctlerrs);
67ad48bc 149 brcmu_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld\n",
56d52fcc 150 drvr->rx_packets, drvr->rx_multicast, drvr->rx_errors);
67ad48bc 151 brcmu_bprintf(strbuf,
cf2b4488 152 "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n",
56d52fcc
AS
153 drvr->rx_ctlpkts, drvr->rx_ctlerrs, drvr->rx_dropped,
154 drvr->rx_flushed);
67ad48bc 155 brcmu_bprintf(strbuf,
cf2b4488 156 "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n",
56d52fcc
AS
157 drvr->rx_readahead_cnt, drvr->tx_realloc, drvr->fc_packets);
158 brcmu_bprintf(strbuf, "wd_dpc_sched %ld\n", drvr->wd_dpc_sched);
67ad48bc 159 brcmu_bprintf(strbuf, "\n");
cf2b4488
HP
160
161 /* Add any prot info */
56d52fcc 162 brcmf_proto_dump(drvr, strbuf);
67ad48bc 163 brcmu_bprintf(strbuf, "\n");
cf2b4488
HP
164
165 /* Add any bus info */
56d52fcc 166 brcmf_sdbrcm_bus_dump(drvr, strbuf);
cf2b4488 167
e10d82d4 168 return !strbuf->size ? -EOVERFLOW : 0;
cf2b4488
HP
169}
170
171static int
fb1d0aa2
AS
172brcmf_c_doiovar(struct brcmf_pub *drvr, const struct brcmu_iovar *vi,
173 u32 actionid, const char *name, void *params, int plen,
174 void *arg, int len, int val_size)
cf2b4488
HP
175{
176 int bcmerror = 0;
3e26416e 177 s32 int_val = 0;
cf2b4488
HP
178
179 DHD_TRACE(("%s: Enter\n", __func__));
180
67ad48bc 181 bcmerror = brcmu_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid));
b229fad2 182 if (bcmerror != 0)
cf2b4488
HP
183 goto exit;
184
185 if (plen >= (int)sizeof(int_val))
02160695 186 memcpy(&int_val, params, sizeof(int_val));
cf2b4488
HP
187
188 switch (actionid) {
189 case IOV_GVAL(IOV_VERSION):
190 /* Need to have checked buffer length */
aba5e0ad 191 strncpy((char *)arg, brcmf_version, len);
cf2b4488
HP
192 break;
193
194 case IOV_GVAL(IOV_MSGLEVEL):
aba5e0ad 195 int_val = (s32) brcmf_msg_level;
02160695 196 memcpy(arg, &int_val, val_size);
cf2b4488
HP
197 break;
198
199 case IOV_SVAL(IOV_MSGLEVEL):
aba5e0ad 200 brcmf_msg_level = int_val;
cf2b4488
HP
201 break;
202
203 case IOV_GVAL(IOV_BCMERRORSTR):
c2be548d 204 strncpy((char *)arg, "bcm_error",
cf2b4488
HP
205 BCME_STRLEN);
206 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
207 break;
208
209 case IOV_GVAL(IOV_BCMERROR):
56d52fcc 210 int_val = (s32) drvr->bcmerror;
02160695 211 memcpy(arg, &int_val, val_size);
cf2b4488
HP
212 break;
213
cf2b4488 214 case IOV_GVAL(IOV_DUMP):
56d52fcc 215 bcmerror = brcmf_c_dump(drvr, arg, len);
cf2b4488
HP
216 break;
217
cf2b4488 218 case IOV_SVAL(IOV_CLEARCOUNTS):
56d52fcc
AS
219 drvr->tx_packets = drvr->rx_packets = 0;
220 drvr->tx_errors = drvr->rx_errors = 0;
221 drvr->tx_ctlpkts = drvr->rx_ctlpkts = 0;
222 drvr->tx_ctlerrs = drvr->rx_ctlerrs = 0;
223 drvr->rx_dropped = 0;
224 drvr->rx_readahead_cnt = 0;
225 drvr->tx_realloc = 0;
226 drvr->wd_dpc_sched = 0;
227 memset(&drvr->dstats, 0, sizeof(drvr->dstats));
46c3db78 228 brcmf_bus_clearcounts(drvr);
cf2b4488
HP
229 break;
230
231 case IOV_GVAL(IOV_IOCTLTIMEOUT):{
a84bac46 232 int_val = (s32) brcmf_os_get_ioctl_resp_timeout();
02160695 233 memcpy(arg, &int_val, sizeof(int_val));
cf2b4488
HP
234 break;
235 }
236
237 case IOV_SVAL(IOV_IOCTLTIMEOUT):{
238 if (int_val <= 0)
e10d82d4 239 bcmerror = -EINVAL;
cf2b4488 240 else
a84bac46 241 brcmf_os_set_ioctl_resp_timeout((unsigned int)
cf2b4488
HP
242 int_val);
243 break;
244 }
245
246 default:
e10d82d4 247 bcmerror = -ENOTSUPP;
cf2b4488
HP
248 break;
249 }
250
251exit:
252 return bcmerror;
253}
254
fb1d0aa2
AS
255bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
256 struct sk_buff *pkt, int prec)
cf2b4488 257{
c26b1378 258 struct sk_buff *p;
cf2b4488
HP
259 int eprec = -1; /* precedence to evict from */
260 bool discard_oldest;
261
262 /* Fast case, precedence queue is not full and we are also not
263 * exceeding total queue length
264 */
265 if (!pktq_pfull(q, prec) && !pktq_full(q)) {
67ad48bc 266 brcmu_pktq_penq(q, prec, pkt);
0f0881b0 267 return true;
cf2b4488
HP
268 }
269
270 /* Determine precedence from which to evict packet, if any */
271 if (pktq_pfull(q, prec))
272 eprec = prec;
273 else if (pktq_full(q)) {
67ad48bc 274 p = brcmu_pktq_peek_tail(q, &eprec);
cf2b4488
HP
275 ASSERT(p);
276 if (eprec > prec)
0965ae88 277 return false;
cf2b4488
HP
278 }
279
280 /* Evict if needed */
281 if (eprec >= 0) {
282 /* Detect queueing to unconfigured precedence */
283 ASSERT(!pktq_pempty(q, eprec));
56d52fcc 284 discard_oldest = AC_BITMAP_TST(drvr->wme_dp, eprec);
cf2b4488 285 if (eprec == prec && !discard_oldest)
0965ae88 286 return false; /* refuse newer (incoming) packet */
cf2b4488 287 /* Evict packet according to discard policy */
67ad48bc
RV
288 p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
289 brcmu_pktq_pdeq_tail(q, eprec);
cf2b4488 290 if (p == NULL) {
67ad48bc 291 DHD_ERROR(("%s: brcmu_pktq_penq() failed, oldest %d.",
cf2b4488
HP
292 __func__, discard_oldest));
293 ASSERT(p);
294 }
295
67ad48bc 296 brcmu_pkt_buf_free_skb(p);
cf2b4488
HP
297 }
298
299 /* Enqueue */
67ad48bc 300 p = brcmu_pktq_penq(q, prec, pkt);
cf2b4488 301 if (p == NULL) {
67ad48bc 302 DHD_ERROR(("%s: brcmu_pktq_penq() failed.", __func__));
cf2b4488
HP
303 ASSERT(p);
304 }
305
0f0881b0 306 return true;
cf2b4488
HP
307}
308
309static int
fb1d0aa2 310brcmf_c_iovar_op(struct brcmf_pub *drvr, const char *name,
cf2b4488
HP
311 void *params, int plen, void *arg, int len, bool set)
312{
313 int bcmerror = 0;
314 int val_size;
67ad48bc 315 const struct brcmu_iovar *vi = NULL;
66cbd3ab 316 u32 actionid;
cf2b4488
HP
317
318 DHD_TRACE(("%s: Enter\n", __func__));
319
320 ASSERT(name);
321 ASSERT(len >= 0);
322
323 /* Get MUST have return space */
324 ASSERT(set || (arg && len));
325
326 /* Set does NOT take qualifiers */
327 ASSERT(!set || (!params && !plen));
328
aba5e0ad 329 vi = brcmu_iovar_lookup(brcmf_iovars, name);
b229fad2 330 if (vi == NULL) {
e10d82d4 331 bcmerror = -ENOTSUPP;
cf2b4488
HP
332 goto exit;
333 }
334
335 DHD_CTL(("%s: %s %s, len %d plen %d\n", __func__,
336 name, (set ? "set" : "get"), len, plen));
337
338 /* set up 'params' pointer in case this is a set command so that
339 * the convenience int and bool code can be common to set and get
340 */
341 if (params == NULL) {
342 params = arg;
343 plen = len;
344 }
345
346 if (vi->type == IOVT_VOID)
347 val_size = 0;
348 else if (vi->type == IOVT_BUFFER)
349 val_size = len;
350 else
351 /* all other types are integer sized */
352 val_size = sizeof(int);
353
354 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
355 bcmerror =
56d52fcc 356 brcmf_c_doiovar(drvr, vi, actionid, name, params, plen, arg, len,
cf2b4488
HP
357 val_size);
358
359exit:
360 return bcmerror;
361}
362
fb1d0aa2 363int brcmf_c_ioctl(struct brcmf_pub *drvr, struct brcmf_c_ioctl *ioc, void *buf,
bb26354a 364 uint buflen)
cf2b4488
HP
365{
366 int bcmerror = 0;
367
368 DHD_TRACE(("%s: Enter\n", __func__));
369
370 if (!buf)
e10d82d4 371 return -EINVAL;
cf2b4488
HP
372
373 switch (ioc->cmd) {
40695d1a 374 case BRCMF_GET_MAGIC:
cf2b4488 375 if (buflen < sizeof(int))
e10d82d4 376 bcmerror = -EOVERFLOW;
cf2b4488 377 else
40695d1a 378 *(int *)buf = BRCMF_IOCTL_MAGIC;
cf2b4488
HP
379 break;
380
40695d1a 381 case BRCMF_GET_VERSION:
cf2b4488 382 if (buflen < sizeof(int))
e10d82d4 383 bcmerror = -EOVERFLOW;
cf2b4488 384 else
40695d1a 385 *(int *)buf = BRCMF_IOCTL_VERSION;
cf2b4488
HP
386 break;
387
40695d1a
AS
388 case BRCMF_GET_VAR:
389 case BRCMF_SET_VAR:{
cf2b4488
HP
390 char *arg;
391 uint arglen;
392
393 /* scan past the name to any arguments */
394 for (arg = buf, arglen = buflen; *arg && arglen;
395 arg++, arglen--)
396 ;
397
398 if (*arg) {
e10d82d4 399 bcmerror = -EOVERFLOW;
cf2b4488
HP
400 break;
401 }
402
403 /* account for the NUL terminator */
404 arg++, arglen--;
405
406 /* call with the appropriate arguments */
40695d1a 407 if (ioc->cmd == BRCMF_GET_VAR)
56d52fcc 408 bcmerror = brcmf_c_iovar_op(drvr, buf, arg,
aba5e0ad 409 arglen, buf, buflen, IOV_GET);
cf2b4488
HP
410 else
411 bcmerror =
56d52fcc 412 brcmf_c_iovar_op(drvr, buf, NULL, 0, arg,
aba5e0ad 413 arglen, IOV_SET);
e10d82d4 414 if (bcmerror != -ENOTSUPP)
cf2b4488
HP
415 break;
416
cf2b4488 417 /* if still not found, try bus module */
40695d1a 418 if (ioc->cmd == BRCMF_GET_VAR)
56d52fcc 419 bcmerror = brcmf_sdbrcm_bus_iovar_op(drvr,
54ca2969
RV
420 buf, arg, arglen, buf, buflen,
421 IOV_GET);
cf2b4488 422 else
56d52fcc 423 bcmerror = brcmf_sdbrcm_bus_iovar_op(drvr,
54ca2969
RV
424 buf, NULL, 0, arg, arglen,
425 IOV_SET);
cf2b4488
HP
426
427 break;
428 }
429
430 default:
e10d82d4 431 bcmerror = -ENOTSUPP;
cf2b4488
HP
432 }
433
434 return bcmerror;
435}
436
437#ifdef SHOW_EVENTS
63bec49e
RV
438static void
439brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
cf2b4488
HP
440{
441 uint i, status, reason;
0965ae88 442 bool group = false, flush_txq = false, link = false;
cf2b4488 443 char *auth_str, *event_name;
580a0bd9 444 unsigned char *buf;
cf2b4488
HP
445 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
446 static struct {
447 uint event;
448 char *event_name;
449 } event_names[] = {
450 {
05dc0f43
AS
451 BRCMF_E_SET_SSID, "SET_SSID"}, {
452 BRCMF_E_JOIN, "JOIN"}, {
453 BRCMF_E_START, "START"}, {
454 BRCMF_E_AUTH, "AUTH"}, {
455 BRCMF_E_AUTH_IND, "AUTH_IND"}, {
456 BRCMF_E_DEAUTH, "DEAUTH"}, {
457 BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, {
458 BRCMF_E_ASSOC, "ASSOC"}, {
459 BRCMF_E_ASSOC_IND, "ASSOC_IND"}, {
460 BRCMF_E_REASSOC, "REASSOC"}, {
461 BRCMF_E_REASSOC_IND, "REASSOC_IND"}, {
462 BRCMF_E_DISASSOC, "DISASSOC"}, {
463 BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, {
464 BRCMF_E_QUIET_START, "START_QUIET"}, {
465 BRCMF_E_QUIET_END, "END_QUIET"}, {
466 BRCMF_E_BEACON_RX, "BEACON_RX"}, {
467 BRCMF_E_LINK, "LINK"}, {
468 BRCMF_E_MIC_ERROR, "MIC_ERROR"}, {
469 BRCMF_E_NDIS_LINK, "NDIS_LINK"}, {
470 BRCMF_E_ROAM, "ROAM"}, {
471 BRCMF_E_TXFAIL, "TXFAIL"}, {
472 BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, {
473 BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, {
474 BRCMF_E_PRUNE, "PRUNE"}, {
475 BRCMF_E_AUTOAUTH, "AUTOAUTH"}, {
476 BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, {
477 BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
478 BRCMF_E_ADDTS_IND, "ADDTS_IND"}, {
479 BRCMF_E_DELTS_IND, "DELTS_IND"}, {
480 BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, {
481 BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, {
482 BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, {
483 BRCMF_E_ROAM_PREP, "ROAM_PREP"}, {
484 BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, {
485 BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, {
486 BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, {
487 BRCMF_E_JOIN_START, "JOIN_START"}, {
488 BRCMF_E_ROAM_START, "ROAM_START"}, {
489 BRCMF_E_ASSOC_START, "ASSOC_START"}, {
490 BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, {
491 BRCMF_E_RADIO, "RADIO"}, {
492 BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, {
493 BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, {
494 BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, {
495 BRCMF_E_PSK_SUP, "PSK_SUP"}, {
496 BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, {
497 BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, {
498 BRCMF_E_ICV_ERROR, "ICV_ERROR"}, {
499 BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, {
500 BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, {
501 BRCMF_E_TRACE, "TRACE"}, {
502 BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, {
503 BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
504 BRCMF_E_IF, "IF"}, {
505 BRCMF_E_RSSI, "RSSI"}, {
506 BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}
cf2b4488
HP
507 };
508 uint event_type, flags, auth_type, datalen;
628f10ba
SF
509 event_type = be32_to_cpu(event->event_type);
510 flags = be16_to_cpu(event->flags);
511 status = be32_to_cpu(event->status);
512 reason = be32_to_cpu(event->reason);
513 auth_type = be32_to_cpu(event->auth_type);
514 datalen = be32_to_cpu(event->datalen);
cf2b4488 515 /* debug dump of event messages */
a44d4236 516 sprintf(eabuf, "%pM", event->addr);
cf2b4488
HP
517
518 event_name = "UNKNOWN";
8d3d6a69 519 for (i = 0; i < ARRAY_SIZE(event_names); i++) {
cf2b4488
HP
520 if (event_names[i].event == event_type)
521 event_name = event_names[i].event_name;
522 }
523
524 DHD_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type));
1ce4784e
SS
525 DHD_EVENT(("flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n",
526 flags, status, reason, auth_type, eabuf));
cf2b4488 527
05dc0f43 528 if (flags & BRCMF_EVENT_MSG_LINK)
0f0881b0 529 link = true;
05dc0f43 530 if (flags & BRCMF_EVENT_MSG_GROUP)
0f0881b0 531 group = true;
05dc0f43 532 if (flags & BRCMF_EVENT_MSG_FLUSHTXQ)
0f0881b0 533 flush_txq = true;
cf2b4488
HP
534
535 switch (event_type) {
05dc0f43
AS
536 case BRCMF_E_START:
537 case BRCMF_E_DEAUTH:
538 case BRCMF_E_DISASSOC:
cf2b4488
HP
539 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
540 break;
541
05dc0f43
AS
542 case BRCMF_E_ASSOC_IND:
543 case BRCMF_E_REASSOC_IND:
cf2b4488
HP
544 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
545 break;
546
05dc0f43
AS
547 case BRCMF_E_ASSOC:
548 case BRCMF_E_REASSOC:
549 if (status == BRCMF_E_STATUS_SUCCESS) {
cf2b4488
HP
550 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n",
551 event_name, eabuf));
05dc0f43 552 } else if (status == BRCMF_E_STATUS_TIMEOUT) {
cf2b4488
HP
553 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n",
554 event_name, eabuf));
05dc0f43 555 } else if (status == BRCMF_E_STATUS_FAIL) {
cf2b4488
HP
556 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
557 event_name, eabuf, (int)reason));
558 } else {
559 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status "
560 "%d\n", event_name, eabuf, (int)status));
561 }
562 break;
563
05dc0f43
AS
564 case BRCMF_E_DEAUTH_IND:
565 case BRCMF_E_DISASSOC_IND:
cf2b4488
HP
566 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name,
567 eabuf, (int)reason));
568 break;
569
05dc0f43
AS
570 case BRCMF_E_AUTH:
571 case BRCMF_E_AUTH_IND:
fd4bd42e 572 if (auth_type == WLAN_AUTH_OPEN)
cf2b4488 573 auth_str = "Open System";
fd4bd42e 574 else if (auth_type == WLAN_AUTH_SHARED_KEY)
cf2b4488
HP
575 auth_str = "Shared Key";
576 else {
577 sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
578 auth_str = err_msg;
579 }
05dc0f43 580 if (event_type == BRCMF_E_AUTH_IND) {
cf2b4488
HP
581 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name,
582 eabuf, auth_str));
05dc0f43 583 } else if (status == BRCMF_E_STATUS_SUCCESS) {
cf2b4488
HP
584 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
585 event_name, eabuf, auth_str));
05dc0f43 586 } else if (status == BRCMF_E_STATUS_TIMEOUT) {
cf2b4488
HP
587 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
588 event_name, eabuf, auth_str));
05dc0f43 589 } else if (status == BRCMF_E_STATUS_FAIL) {
cf2b4488
HP
590 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, "
591 "reason %d\n",
592 event_name, eabuf, auth_str, (int)reason));
593 }
594
595 break;
596
05dc0f43
AS
597 case BRCMF_E_JOIN:
598 case BRCMF_E_ROAM:
599 case BRCMF_E_SET_SSID:
600 if (status == BRCMF_E_STATUS_SUCCESS) {
cf2b4488
HP
601 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name,
602 eabuf));
05dc0f43 603 } else if (status == BRCMF_E_STATUS_FAIL) {
cf2b4488 604 DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
05dc0f43 605 } else if (status == BRCMF_E_STATUS_NO_NETWORKS) {
cf2b4488
HP
606 DHD_EVENT(("MACEVENT: %s, no networks found\n",
607 event_name));
608 } else {
609 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
610 event_name, (int)status));
611 }
612 break;
613
05dc0f43
AS
614 case BRCMF_E_BEACON_RX:
615 if (status == BRCMF_E_STATUS_SUCCESS) {
cf2b4488 616 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
05dc0f43 617 } else if (status == BRCMF_E_STATUS_FAIL) {
cf2b4488
HP
618 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
619 } else {
620 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name,
621 status));
622 }
623 break;
624
05dc0f43 625 case BRCMF_E_LINK:
cf2b4488
HP
626 DHD_EVENT(("MACEVENT: %s %s\n", event_name,
627 link ? "UP" : "DOWN"));
628 break;
629
05dc0f43 630 case BRCMF_E_MIC_ERROR:
cf2b4488
HP
631 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
632 event_name, eabuf, group, flush_txq));
633 break;
634
05dc0f43
AS
635 case BRCMF_E_ICV_ERROR:
636 case BRCMF_E_UNICAST_DECODE_ERROR:
637 case BRCMF_E_MULTICAST_DECODE_ERROR:
cf2b4488
HP
638 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
639 break;
640
05dc0f43 641 case BRCMF_E_TXFAIL:
cf2b4488
HP
642 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
643 break;
644
05dc0f43
AS
645 case BRCMF_E_SCAN_COMPLETE:
646 case BRCMF_E_PMKID_CACHE:
cf2b4488
HP
647 DHD_EVENT(("MACEVENT: %s\n", event_name));
648 break;
649
05dc0f43
AS
650 case BRCMF_E_PFN_NET_FOUND:
651 case BRCMF_E_PFN_NET_LOST:
652 case BRCMF_E_PFN_SCAN_COMPLETE:
cf2b4488
HP
653 DHD_EVENT(("PNOEVENT: %s\n", event_name));
654 break;
655
05dc0f43
AS
656 case BRCMF_E_PSK_SUP:
657 case BRCMF_E_PRUNE:
cf2b4488
HP
658 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
659 event_name, (int)status, (int)reason));
660 break;
661
05dc0f43 662 case BRCMF_E_TRACE:
cf2b4488 663 {
66cbd3ab 664 static u32 seqnum_prev;
86c01843 665 struct msgtrace_hdr hdr;
66cbd3ab 666 u32 nblost;
cf2b4488
HP
667 char *s, *p;
668
580a0bd9 669 buf = (unsigned char *) event_data;
86c01843 670 memcpy(&hdr, buf, sizeof(struct msgtrace_hdr));
cf2b4488
HP
671
672 if (hdr.version != MSGTRACE_VERSION) {
0bef7748 673 DHD_ERROR(
cf2b4488 674 ("\nMACEVENT: %s [unsupported version --> "
1f660b9c 675 "brcmf version:%d dongle version:%d]\n",
0bef7748
AS
676 event_name, MSGTRACE_VERSION, hdr.version)
677 );
cf2b4488
HP
678 /* Reset datalen to avoid display below */
679 datalen = 0;
680 break;
681 }
682
683 /* There are 2 bytes available at the end of data */
86c01843
FL
684 *(buf + sizeof(struct msgtrace_hdr)
685 + be16_to_cpu(hdr.len)) = '\0';
cf2b4488 686
628f10ba
SF
687 if (be32_to_cpu(hdr.discarded_bytes)
688 || be32_to_cpu(hdr.discarded_printf)) {
0bef7748 689 DHD_ERROR(
cf2b4488
HP
690 ("\nWLC_E_TRACE: [Discarded traces in dongle -->"
691 "discarded_bytes %d discarded_printf %d]\n",
628f10ba
SF
692 be32_to_cpu(hdr.discarded_bytes),
693 be32_to_cpu(hdr.discarded_printf)));
cf2b4488
HP
694 }
695
628f10ba 696 nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
cf2b4488 697 if (nblost > 0) {
0bef7748 698 DHD_ERROR(
cf2b4488 699 ("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
628f10ba 700 be32_to_cpu(hdr.seqnum), nblost));
cf2b4488 701 }
628f10ba 702 seqnum_prev = be32_to_cpu(hdr.seqnum);
cf2b4488
HP
703
704 /* Display the trace buffer. Advance from \n to \n to
705 * avoid display big
706 * printf (issue with Linux printk )
707 */
86c01843 708 p = (char *)&buf[sizeof(struct msgtrace_hdr)];
cf2b4488
HP
709 while ((s = strstr(p, "\n")) != NULL) {
710 *s = '\0';
0bef7748 711 printk(KERN_DEBUG"%s\n", p);
cf2b4488
HP
712 p = s + 1;
713 }
0bef7748 714 printk(KERN_DEBUG "%s\n", p);
cf2b4488
HP
715
716 /* Reset datalen to avoid display below */
717 datalen = 0;
718 }
719 break;
720
05dc0f43 721 case BRCMF_E_RSSI:
cf2b4488 722 DHD_EVENT(("MACEVENT: %s %d\n", event_name,
628f10ba 723 be32_to_cpu(*((int *)event_data))));
cf2b4488
HP
724 break;
725
726 default:
727 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
728 "auth %d\n", event_name, event_type, eabuf,
729 (int)status, (int)reason, (int)auth_type));
730 break;
731 }
732
733 /* show any appended data */
734 if (datalen) {
580a0bd9 735 buf = (unsigned char *) event_data;
cf2b4488
HP
736 DHD_EVENT((" data (%d) : ", datalen));
737 for (i = 0; i < datalen; i++)
738 DHD_EVENT((" 0x%02x ", *buf++));
739 DHD_EVENT(("\n"));
740 }
741}
742#endif /* SHOW_EVENTS */
743
744int
abfe1804 745brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
63bec49e 746 struct brcmf_event_msg *event, void **data_ptr)
cf2b4488
HP
747{
748 /* check whether packet is a BRCM event pkt */
63bec49e 749 struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;
cf2b4488 750 char *event_data;
66cbd3ab 751 u32 type, status;
7d4df48e 752 u16 flags;
cf2b4488
HP
753 int evlen;
754
05dc0f43 755 if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) {
cf2b4488 756 DHD_ERROR(("%s: mismatched OUI, bailing\n", __func__));
b74ac12e 757 return -EBADE;
cf2b4488
HP
758 }
759
760 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
05dc0f43 761 if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) !=
cf2b4488
HP
762 BCMILCP_BCM_SUBTYPE_EVENT) {
763 DHD_ERROR(("%s: mismatched subtype, bailing\n", __func__));
b74ac12e 764 return -EBADE;
cf2b4488
HP
765 }
766
767 *data_ptr = &pvt_data[1];
768 event_data = *data_ptr;
769
770 /* memcpy since BRCM event pkt may be unaligned. */
63bec49e 771 memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg));
cf2b4488 772
56dfe3c7
SF
773 type = get_unaligned_be32(&event->event_type);
774 flags = get_unaligned_be16(&event->flags);
775 status = get_unaligned_be32(&event->status);
63bec49e
RV
776 evlen = get_unaligned_be32(&event->datalen) +
777 sizeof(struct brcmf_event);
cf2b4488
HP
778
779 switch (type) {
05dc0f43 780 case BRCMF_E_IF:
cf2b4488 781 {
bb26354a
AS
782 struct brcmf_if_event *ifevent =
783 (struct brcmf_if_event *) event_data;
cf2b4488
HP
784 DHD_TRACE(("%s: if event\n", __func__));
785
786 if (ifevent->ifidx > 0 &&
40695d1a 787 ifevent->ifidx < BRCMF_MAX_IFS) {
05dc0f43 788 if (ifevent->action == BRCMF_E_IF_ADD)
56d52fcc 789 brcmf_add_if(drvr_priv, ifevent->ifidx,
cf2b4488 790 NULL, event->ifname,
e2582ad8 791 pvt_data->eth.h_dest,
cf2b4488
HP
792 ifevent->flags,
793 ifevent->bssidx);
794 else
56d52fcc 795 brcmf_del_if(drvr_priv, ifevent->ifidx);
cf2b4488
HP
796 } else {
797 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
798 __func__, ifevent->ifidx,
799 event->ifname));
800 }
801 }
802 /* send up the if event: btamp user needs it */
56d52fcc 803 *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname);
cf2b4488
HP
804 break;
805
cf2b4488 806 /* These are what external supplicant/authenticator wants */
05dc0f43
AS
807 case BRCMF_E_LINK:
808 case BRCMF_E_ASSOC_IND:
809 case BRCMF_E_REASSOC_IND:
810 case BRCMF_E_DISASSOC_IND:
811 case BRCMF_E_MIC_ERROR:
cf2b4488
HP
812 default:
813 /* Fall through: this should get _everything_ */
814
56d52fcc 815 *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname);
cf2b4488
HP
816 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
817 __func__, type, flags, status));
818
05dc0f43
AS
819 /* put it back to BRCMF_E_NDIS_LINK */
820 if (type == BRCMF_E_NDIS_LINK) {
66cbd3ab 821 u32 temp;
cf2b4488 822
56dfe3c7 823 temp = get_unaligned_be32(&event->event_type);
cf2b4488
HP
824 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
825
05dc0f43
AS
826 temp = be32_to_cpu(BRCMF_E_NDIS_LINK);
827 memcpy((void *)(&pvt_data->msg.event_type), &temp,
828 sizeof(pvt_data->msg.event_type));
cf2b4488
HP
829 }
830 break;
831 }
832
833#ifdef SHOW_EVENTS
aba5e0ad 834 brcmf_c_show_host_event(event, event_data);
cf2b4488
HP
835#endif /* SHOW_EVENTS */
836
a1c5ad81 837 return 0;
cf2b4488
HP
838}
839
cf2b4488 840/* Convert user's input in hex pattern to byte-size mask */
aba5e0ad 841static int brcmf_c_pattern_atoh(char *src, char *dst)
cf2b4488
HP
842{
843 int i;
844 if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
845 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
846 return -1;
847 }
848 src = src + 2; /* Skip past 0x */
849 if (strlen(src) % 2 != 0) {
850 DHD_ERROR(("Mask invalid format. Length must be even.\n"));
851 return -1;
852 }
853 for (i = 0; *src != '\0'; i++) {
854 char num[3];
855 strncpy(num, src, 2);
856 num[2] = '\0';
d5642d3b 857 dst[i] = (u8) simple_strtoul(num, NULL, 16);
cf2b4488
HP
858 src += 2;
859 }
860 return i;
861}
862
863void
fb1d0aa2 864brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable,
cf2b4488
HP
865 int master_mode)
866{
867 char *argv[8];
868 int i = 0;
869 const char *str;
870 int buf_len;
871 int str_len;
872 char *arg_save = 0, *arg_org = 0;
873 int rc;
874 char buf[128];
ec66c6fa
AS
875 struct brcmf_pkt_filter_enable enable_parm;
876 struct brcmf_pkt_filter_enable *pkt_filterp;
cf2b4488 877
5fcc1fcb 878 arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC);
b229fad2 879 if (!arg_save) {
cf2b4488
HP
880 DHD_ERROR(("%s: kmalloc failed\n", __func__));
881 goto fail;
882 }
883 arg_org = arg_save;
884 memcpy(arg_save, arg, strlen(arg) + 1);
885
d5642d3b 886 argv[i] = strsep(&arg_save, " ");
cf2b4488
HP
887
888 i = 0;
889 if (NULL == argv[i]) {
890 DHD_ERROR(("No args provided\n"));
891 goto fail;
892 }
893
894 str = "pkt_filter_enable";
895 str_len = strlen(str);
896 strncpy(buf, str, str_len);
897 buf[str_len] = '\0';
898 buf_len = str_len + 1;
899
ec66c6fa 900 pkt_filterp = (struct brcmf_pkt_filter_enable *) (buf + str_len + 1);
cf2b4488
HP
901
902 /* Parse packet filter id. */
29750b90 903 enable_parm.id = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
904
905 /* Parse enable/disable value. */
29750b90 906 enable_parm.enable = enable;
cf2b4488
HP
907
908 buf_len += sizeof(enable_parm);
909 memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm));
910
911 /* Enable/disable the specified filter. */
56d52fcc 912 rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
cf2b4488
HP
913 rc = rc >= 0 ? 0 : rc;
914 if (rc)
915 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
916 __func__, arg, rc));
917 else
918 DHD_TRACE(("%s: successfully added pktfilter %s\n",
919 __func__, arg));
920
921 /* Contorl the master mode */
67ad48bc 922 brcmu_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf,
cf2b4488 923 sizeof(buf));
56d52fcc 924 rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf,
0aa94b84 925 sizeof(buf));
cf2b4488
HP
926 rc = rc >= 0 ? 0 : rc;
927 if (rc)
928 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
929 __func__, arg, rc));
930
931fail:
46d994b1 932 kfree(arg_org);
cf2b4488
HP
933}
934
fb1d0aa2 935void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
cf2b4488
HP
936{
937 const char *str;
ec66c6fa
AS
938 struct brcmf_pkt_filter pkt_filter;
939 struct brcmf_pkt_filter *pkt_filterp;
cf2b4488
HP
940 int buf_len;
941 int str_len;
942 int rc;
66cbd3ab
GKH
943 u32 mask_size;
944 u32 pattern_size;
cf2b4488
HP
945 char *argv[8], *buf = 0;
946 int i = 0;
947 char *arg_save = 0, *arg_org = 0;
cf2b4488 948
5fcc1fcb 949 arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC);
81e95f9d 950 if (!arg_save) {
cf2b4488
HP
951 DHD_ERROR(("%s: kmalloc failed\n", __func__));
952 goto fail;
953 }
954
955 arg_org = arg_save;
956
8d825a8e 957 buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC);
81e95f9d 958 if (!buf) {
cf2b4488
HP
959 DHD_ERROR(("%s: kmalloc failed\n", __func__));
960 goto fail;
961 }
962
963 memcpy(arg_save, arg, strlen(arg) + 1);
964
8d825a8e 965 if (strlen(arg) > PKTFILTER_BUF_SIZE) {
cf2b4488
HP
966 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg),
967 (int)sizeof(buf)));
968 goto fail;
969 }
970
d5642d3b 971 argv[i] = strsep(&arg_save, " ");
cf2b4488 972 while (argv[i++])
d5642d3b 973 argv[i] = strsep(&arg_save, " ");
cf2b4488
HP
974
975 i = 0;
976 if (NULL == argv[i]) {
977 DHD_ERROR(("No args provided\n"));
978 goto fail;
979 }
980
981 str = "pkt_filter_add";
982 str_len = strlen(str);
983 strncpy(buf, str, str_len);
984 buf[str_len] = '\0';
985 buf_len = str_len + 1;
986
ec66c6fa 987 pkt_filterp = (struct brcmf_pkt_filter *) (buf + str_len + 1);
cf2b4488
HP
988
989 /* Parse packet filter id. */
29750b90 990 pkt_filter.id = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
991
992 if (NULL == argv[++i]) {
993 DHD_ERROR(("Polarity not provided\n"));
994 goto fail;
995 }
996
997 /* Parse filter polarity. */
29750b90 998 pkt_filter.negate_match = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
999
1000 if (NULL == argv[++i]) {
1001 DHD_ERROR(("Filter type not provided\n"));
1002 goto fail;
1003 }
1004
1005 /* Parse filter type. */
29750b90 1006 pkt_filter.type = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
1007
1008 if (NULL == argv[++i]) {
1009 DHD_ERROR(("Offset not provided\n"));
1010 goto fail;
1011 }
1012
1013 /* Parse pattern filter offset. */
29750b90 1014 pkt_filter.u.pattern.offset = simple_strtoul(argv[i], NULL, 0);
cf2b4488
HP
1015
1016 if (NULL == argv[++i]) {
1017 DHD_ERROR(("Bitmask not provided\n"));
1018 goto fail;
1019 }
1020
1021 /* Parse pattern filter mask. */
1022 mask_size =
aba5e0ad 1023 brcmf_c_pattern_atoh
29750b90 1024 (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern);
cf2b4488
HP
1025
1026 if (NULL == argv[++i]) {
1027 DHD_ERROR(("Pattern not provided\n"));
1028 goto fail;
1029 }
1030
1031 /* Parse pattern filter pattern. */
1032 pattern_size =
aba5e0ad 1033 brcmf_c_pattern_atoh(argv[i],
cf2b4488 1034 (char *)&pkt_filterp->u.pattern.
29750b90 1035 mask_and_pattern[mask_size]);
cf2b4488
HP
1036
1037 if (mask_size != pattern_size) {
1038 DHD_ERROR(("Mask and pattern not the same size\n"));
1039 goto fail;
1040 }
1041
1042 pkt_filter.u.pattern.size_bytes = mask_size;
40695d1a
AS
1043 buf_len += BRCMF_PKT_FILTER_FIXED_LEN;
1044 buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
cf2b4488
HP
1045
1046 /* Keep-alive attributes are set in local
1047 * variable (keep_alive_pkt), and
1048 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1049 ** guarantee that the buffer is properly aligned.
1050 */
1051 memcpy((char *)pkt_filterp,
1052 &pkt_filter,
40695d1a 1053 BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN);
cf2b4488 1054
56d52fcc 1055 rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
cf2b4488
HP
1056 rc = rc >= 0 ? 0 : rc;
1057
1058 if (rc)
1059 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1060 __func__, arg, rc));
1061 else
1062 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1063 __func__, arg));
1064
1065fail:
46d994b1 1066 kfree(arg_org);
cf2b4488 1067
46d994b1 1068 kfree(buf);
cf2b4488
HP
1069}
1070
fb1d0aa2 1071void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode)
cf2b4488
HP
1072{
1073 char iovbuf[32];
1074 int retcode;
1075
67ad48bc 1076 brcmu_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
56d52fcc 1077 retcode = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR,
366bbb3f 1078 iovbuf, sizeof(iovbuf));
cf2b4488
HP
1079 retcode = retcode >= 0 ? 0 : retcode;
1080 if (retcode)
1081 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, "
1082 "retcode = %d\n", __func__, arp_mode, retcode));
1083 else
1084 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1085 __func__, arp_mode));
1086}
1087
fb1d0aa2 1088void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable)
cf2b4488
HP
1089{
1090 char iovbuf[32];
1091 int retcode;
1092
67ad48bc 1093 brcmu_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
56d52fcc 1094 retcode = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR,
366bbb3f 1095 iovbuf, sizeof(iovbuf));
cf2b4488
HP
1096 retcode = retcode >= 0 ? 0 : retcode;
1097 if (retcode)
1098 DHD_TRACE(("%s: failed to enabe ARP offload to %d, "
1099 "retcode = %d\n", __func__, arp_enable, retcode));
1100 else
1101 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1102 __func__, arp_enable));
1103}
1104
fb1d0aa2 1105int brcmf_c_preinit_ioctls(struct brcmf_pub *drvr)
cf2b4488 1106{
40695d1a 1107 char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for
cf2b4488
HP
1108 "event_msgs" + '\0' + bitvec */
1109 uint up = 0;
1110 char buf[128], *ptr;
1111 uint power_mode = PM_FAST;
8d825a8e 1112 u32 dongle_align = BRCMF_SDALIGN;
66cbd3ab 1113 u32 glom = 0;
cf2b4488
HP
1114 uint bcn_timeout = 3;
1115 int scan_assoc_time = 40;
1116 int scan_unassoc_time = 40;
8af2d2a5 1117 int i;
cf2b4488 1118
56d52fcc 1119 brcmf_os_proto_block(drvr);
cf2b4488 1120
cf2b4488 1121 /* Set Country code */
56d52fcc
AS
1122 if (drvr->country_code[0] != 0) {
1123 if (brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_COUNTRY,
1124 drvr->country_code,
1125 sizeof(drvr->country_code)) < 0) {
cf2b4488
HP
1126 DHD_ERROR(("%s: country code setting failed\n",
1127 __func__));
1128 }
1129 }
1130
1131 /* query for 'ver' to get version info from firmware */
1132 memset(buf, 0, sizeof(buf));
1133 ptr = buf;
67ad48bc 1134 brcmu_mkiovar("ver", 0, 0, buf, sizeof(buf));
56d52fcc 1135 brcmf_proto_cdc_query_ioctl(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf));
d5642d3b 1136 strsep(&ptr, "\n");
cf2b4488
HP
1137 /* Print fw version info */
1138 DHD_ERROR(("Firmware version = %s\n", buf));
1139
1140 /* Set PowerSave mode */
56d52fcc 1141 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_PM, (char *)&power_mode,
cf2b4488
HP
1142 sizeof(power_mode));
1143
1144 /* Match Host and Dongle rx alignment */
67ad48bc 1145 brcmu_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
cf2b4488 1146 sizeof(iovbuf));
56d52fcc 1147 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
0aa94b84 1148 sizeof(iovbuf));
cf2b4488
HP
1149
1150 /* disable glom option per default */
67ad48bc 1151 brcmu_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
56d52fcc 1152 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
0aa94b84 1153 sizeof(iovbuf));
cf2b4488
HP
1154
1155 /* Setup timeout if Beacons are lost and roam is off to report
1156 link down */
67ad48bc 1157 brcmu_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
cf2b4488 1158 sizeof(iovbuf));
56d52fcc 1159 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
0aa94b84 1160 sizeof(iovbuf));
cf2b4488
HP
1161
1162 /* Enable/Disable build-in roaming to allowed ext supplicant to take
1163 of romaing */
5e92aa8c
AS
1164 brcmu_mkiovar("roam_off", (char *)&brcmf_roam, 4,
1165 iovbuf, sizeof(iovbuf));
56d52fcc 1166 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
0aa94b84 1167 sizeof(iovbuf));
cf2b4488
HP
1168
1169 /* Force STA UP */
5e92aa8c 1170 if (brcmf_radio_up)
56d52fcc 1171 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_UP, (char *)&up,
0aa94b84 1172 sizeof(up));
cf2b4488
HP
1173
1174 /* Setup event_msgs */
40695d1a 1175 brcmu_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
67ad48bc 1176 iovbuf, sizeof(iovbuf));
56d52fcc 1177 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
0aa94b84 1178 sizeof(iovbuf));
cf2b4488 1179
56d52fcc 1180 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME,
cf2b4488 1181 (char *)&scan_assoc_time, sizeof(scan_assoc_time));
56d52fcc 1182 brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME,
cf2b4488
HP
1183 (char *)&scan_unassoc_time, sizeof(scan_unassoc_time));
1184
cf2b4488 1185 /* Set and enable ARP offload feature */
5e92aa8c 1186 if (brcmf_arp_enable)
56d52fcc
AS
1187 brcmf_c_arp_offload_set(drvr, brcmf_arp_mode);
1188 brcmf_c_arp_offload_enable(drvr, brcmf_arp_enable);
cf2b4488 1189
8af2d2a5
AS
1190 /* Set up pkt filter */
1191 if (brcmf_pkt_filter_enable) {
56d52fcc
AS
1192 for (i = 0; i < drvr->pktfilter_count; i++) {
1193 brcmf_c_pktfilter_offload_set(drvr,
1194 drvr->pktfilter[i]);
1195 brcmf_c_pktfilter_offload_enable(drvr,
1196 drvr->pktfilter[i],
8af2d2a5
AS
1197 brcmf_pkt_filter_init,
1198 brcmf_master_mode);
cf2b4488
HP
1199 }
1200 }
cf2b4488 1201
56d52fcc 1202 brcmf_os_proto_unblock(drvr);
cf2b4488
HP
1203
1204 return 0;
1205}
This page took 0.324936 seconds and 5 git commands to generate.