2 * Copyright (c) 2010 Broadcom Corporation
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.
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.
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/sched.h>
19 #include <linux/netdevice.h>
20 #include <asm/unaligned.h>
22 #include <brcmu_wifi.h>
23 #include <brcmu_utils.h>
26 #include "dhd_proto.h"
29 #define BRCM_OUI "\x00\x10\x18"
30 #define DOT11_OUI_LEN 3
31 #define BCMILCP_BCM_SUBTYPE_EVENT 1
32 #define PKTFILTER_BUF_SIZE 2048
36 #define MSGTRACE_VERSION 1
39 const char brcmf_version
[] =
40 "Dongle Host Driver, version " BRCMF_VERSION_STR
"\nCompiled on " __DATE__
43 const char brcmf_version
[] = "Dongle Host Driver, version " BRCMF_VERSION_STR
;
62 const struct brcmu_iovar brcmf_iovars
[] = {
63 {"version", IOV_VERSION
, 0, IOVT_BUFFER
, sizeof(brcmf_version
)}
66 {"msglevel", IOV_MSGLEVEL
, 0, IOVT_UINT32
, 0}
69 {"bcmerrorstr", IOV_BCMERRORSTR
, 0, IOVT_BUFFER
, BCME_STRLEN
}
71 {"bcmerror", IOV_BCMERROR
, 0, IOVT_INT8
, 0}
73 {"dump", IOV_DUMP
, 0, IOVT_BUFFER
, BRCMF_IOCTL_MAXLEN
}
75 {"clearcounts", IOV_CLEARCOUNTS
, 0, IOVT_VOID
, 0}
77 {"gpioob", IOV_GPIOOB
, 0, IOVT_UINT32
, 0}
79 {"ioctl_timeout", IOV_IOCTLTIMEOUT
, 0, IOVT_UINT32
, 0}
84 /* Message trace header */
88 u16 len
; /* Len of the trace */
89 u32 seqnum
; /* Sequence number of message. Useful
90 * if the messsage has been lost
91 * because of DMA error or a bus reset
94 u32 discarded_bytes
; /* Number of discarded bytes because of
96 u32 discarded_printf
; /* Number of discarded printf
97 because of trace overflow */
100 void brcmf_c_init(void)
102 /* Init global variables at run-time, not as part of the declaration.
103 * This is required to support init/de-init of the driver.
105 * of globals as part of the declaration results in non-deterministic
106 * behaviour since the value of the globals may be different on the
107 * first time that the driver is initialized vs subsequent
110 brcmf_msg_level
= BRCMF_ERROR_VAL
;
113 static int brcmf_c_dump(struct brcmf_pub
*drvr
, char *buf
, int buflen
)
115 struct brcmu_strbuf b
;
116 struct brcmu_strbuf
*strbuf
= &b
;
118 brcmu_binit(strbuf
, buf
, buflen
);
121 brcmu_bprintf(strbuf
, "%s\n", brcmf_version
);
122 brcmu_bprintf(strbuf
, "\n");
123 brcmu_bprintf(strbuf
, "pub.up %d pub.txoff %d pub.busstate %d\n",
124 drvr
->up
, drvr
->txoff
, drvr
->busstate
);
125 brcmu_bprintf(strbuf
, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
126 drvr
->hdrlen
, drvr
->maxctl
, drvr
->rxsz
);
127 brcmu_bprintf(strbuf
, "pub.iswl %d pub.drv_version %ld pub.mac %pM\n",
128 drvr
->iswl
, drvr
->drv_version
, &drvr
->mac
);
129 brcmu_bprintf(strbuf
, "pub.bcmerror %d tickcnt %d\n", drvr
->bcmerror
,
132 brcmu_bprintf(strbuf
, "dongle stats:\n");
133 brcmu_bprintf(strbuf
,
134 "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
135 drvr
->dstats
.tx_packets
, drvr
->dstats
.tx_bytes
,
136 drvr
->dstats
.tx_errors
, drvr
->dstats
.tx_dropped
);
137 brcmu_bprintf(strbuf
,
138 "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
139 drvr
->dstats
.rx_packets
, drvr
->dstats
.rx_bytes
,
140 drvr
->dstats
.rx_errors
, drvr
->dstats
.rx_dropped
);
141 brcmu_bprintf(strbuf
, "multicast %ld\n", drvr
->dstats
.multicast
);
143 brcmu_bprintf(strbuf
, "bus stats:\n");
144 brcmu_bprintf(strbuf
, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
145 drvr
->tx_packets
, drvr
->tx_multicast
, drvr
->tx_errors
);
146 brcmu_bprintf(strbuf
, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
147 drvr
->tx_ctlpkts
, drvr
->tx_ctlerrs
);
148 brcmu_bprintf(strbuf
, "rx_packets %ld rx_multicast %ld rx_errors %ld\n",
149 drvr
->rx_packets
, drvr
->rx_multicast
, drvr
->rx_errors
);
150 brcmu_bprintf(strbuf
,
151 "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n",
152 drvr
->rx_ctlpkts
, drvr
->rx_ctlerrs
, drvr
->rx_dropped
,
154 brcmu_bprintf(strbuf
,
155 "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n",
156 drvr
->rx_readahead_cnt
, drvr
->tx_realloc
, drvr
->fc_packets
);
157 brcmu_bprintf(strbuf
, "wd_dpc_sched %ld\n", drvr
->wd_dpc_sched
);
158 brcmu_bprintf(strbuf
, "\n");
160 /* Add any prot info */
161 brcmf_proto_dump(drvr
, strbuf
);
162 brcmu_bprintf(strbuf
, "\n");
164 /* Add any bus info */
165 brcmf_sdbrcm_bus_dump(drvr
, strbuf
);
167 return !strbuf
->size
? -EOVERFLOW
: 0;
171 brcmf_c_doiovar(struct brcmf_pub
*drvr
, const struct brcmu_iovar
*vi
,
172 u32 actionid
, const char *name
, void *params
, int plen
,
173 void *arg
, int len
, int val_size
)
178 BRCMF_TRACE(("%s: Enter\n", __func__
));
180 bcmerror
= brcmu_iovar_lencheck(vi
, arg
, len
, IOV_ISSET(actionid
));
184 if (plen
>= (int)sizeof(int_val
))
185 memcpy(&int_val
, params
, sizeof(int_val
));
188 case IOV_GVAL(IOV_VERSION
):
189 /* Need to have checked buffer length */
190 strncpy((char *)arg
, brcmf_version
, len
);
193 case IOV_GVAL(IOV_MSGLEVEL
):
194 int_val
= (s32
) brcmf_msg_level
;
195 memcpy(arg
, &int_val
, val_size
);
198 case IOV_SVAL(IOV_MSGLEVEL
):
199 brcmf_msg_level
= int_val
;
202 case IOV_GVAL(IOV_BCMERRORSTR
):
203 strncpy((char *)arg
, "bcm_error",
205 ((char *)arg
)[BCME_STRLEN
- 1] = 0x00;
208 case IOV_GVAL(IOV_BCMERROR
):
209 int_val
= (s32
) drvr
->bcmerror
;
210 memcpy(arg
, &int_val
, val_size
);
213 case IOV_GVAL(IOV_DUMP
):
214 bcmerror
= brcmf_c_dump(drvr
, arg
, len
);
217 case IOV_SVAL(IOV_CLEARCOUNTS
):
218 drvr
->tx_packets
= drvr
->rx_packets
= 0;
219 drvr
->tx_errors
= drvr
->rx_errors
= 0;
220 drvr
->tx_ctlpkts
= drvr
->rx_ctlpkts
= 0;
221 drvr
->tx_ctlerrs
= drvr
->rx_ctlerrs
= 0;
222 drvr
->rx_dropped
= 0;
223 drvr
->rx_readahead_cnt
= 0;
224 drvr
->tx_realloc
= 0;
225 drvr
->wd_dpc_sched
= 0;
226 memset(&drvr
->dstats
, 0, sizeof(drvr
->dstats
));
227 brcmf_bus_clearcounts(drvr
);
230 case IOV_GVAL(IOV_IOCTLTIMEOUT
):{
231 int_val
= (s32
) brcmf_os_get_ioctl_resp_timeout();
232 memcpy(arg
, &int_val
, sizeof(int_val
));
236 case IOV_SVAL(IOV_IOCTLTIMEOUT
):{
240 brcmf_os_set_ioctl_resp_timeout((unsigned int)
246 bcmerror
= -ENOTSUPP
;
254 bool brcmf_c_prec_enq(struct brcmf_pub
*drvr
, struct pktq
*q
,
255 struct sk_buff
*pkt
, int prec
)
258 int eprec
= -1; /* precedence to evict from */
261 /* Fast case, precedence queue is not full and we are also not
262 * exceeding total queue length
264 if (!pktq_pfull(q
, prec
) && !pktq_full(q
)) {
265 brcmu_pktq_penq(q
, prec
, pkt
);
269 /* Determine precedence from which to evict packet, if any */
270 if (pktq_pfull(q
, prec
))
272 else if (pktq_full(q
)) {
273 p
= brcmu_pktq_peek_tail(q
, &eprec
);
278 /* Evict if needed */
280 /* Detect queueing to unconfigured precedence */
281 discard_oldest
= AC_BITMAP_TST(drvr
->wme_dp
, eprec
);
282 if (eprec
== prec
&& !discard_oldest
)
283 return false; /* refuse newer (incoming) packet */
284 /* Evict packet according to discard policy */
285 p
= discard_oldest
? brcmu_pktq_pdeq(q
, eprec
) :
286 brcmu_pktq_pdeq_tail(q
, eprec
);
288 BRCMF_ERROR(("%s: brcmu_pktq_penq() failed, oldest %d.",
289 __func__
, discard_oldest
));
291 brcmu_pkt_buf_free_skb(p
);
295 p
= brcmu_pktq_penq(q
, prec
, pkt
);
297 BRCMF_ERROR(("%s: brcmu_pktq_penq() failed.", __func__
));
304 brcmf_c_iovar_op(struct brcmf_pub
*drvr
, const char *name
,
305 void *params
, int plen
, void *arg
, int len
, bool set
)
309 const struct brcmu_iovar
*vi
= NULL
;
312 BRCMF_TRACE(("%s: Enter\n", __func__
));
314 if (name
== NULL
|| len
<= 0)
317 /* Set does not take qualifiers */
318 if (set
&& (params
|| plen
))
321 /* Get must have return space;*/
322 if (!set
&& !(arg
&& len
))
325 vi
= brcmu_iovar_lookup(brcmf_iovars
, name
);
327 bcmerror
= -ENOTSUPP
;
331 BRCMF_CTL(("%s: %s %s, len %d plen %d\n", __func__
,
332 name
, (set
? "set" : "get"), len
, plen
));
334 /* set up 'params' pointer in case this is a set command so that
335 * the convenience int and bool code can be common to set and get
337 if (params
== NULL
) {
342 if (vi
->type
== IOVT_VOID
)
344 else if (vi
->type
== IOVT_BUFFER
)
347 /* all other types are integer sized */
348 val_size
= sizeof(int);
350 actionid
= set
? IOV_SVAL(vi
->varid
) : IOV_GVAL(vi
->varid
);
352 brcmf_c_doiovar(drvr
, vi
, actionid
, name
, params
, plen
, arg
, len
,
359 int brcmf_c_ioctl(struct brcmf_pub
*drvr
, struct brcmf_c_ioctl
*ioc
, void *buf
,
364 BRCMF_TRACE(("%s: Enter\n", __func__
));
370 case BRCMF_GET_MAGIC
:
371 if (buflen
< sizeof(int))
372 bcmerror
= -EOVERFLOW
;
374 *(int *)buf
= BRCMF_IOCTL_MAGIC
;
377 case BRCMF_GET_VERSION
:
378 if (buflen
< sizeof(int))
379 bcmerror
= -EOVERFLOW
;
381 *(int *)buf
= BRCMF_IOCTL_VERSION
;
389 /* scan past the name to any arguments */
390 for (arg
= buf
, arglen
= buflen
; *arg
&& arglen
;
395 bcmerror
= -EOVERFLOW
;
399 /* account for the NUL terminator */
402 /* call with the appropriate arguments */
403 if (ioc
->cmd
== BRCMF_GET_VAR
)
404 bcmerror
= brcmf_c_iovar_op(drvr
, buf
, arg
,
405 arglen
, buf
, buflen
, IOV_GET
);
408 brcmf_c_iovar_op(drvr
, buf
, NULL
, 0, arg
,
410 if (bcmerror
!= -ENOTSUPP
)
413 /* if still not found, try bus module */
414 if (ioc
->cmd
== BRCMF_GET_VAR
)
415 bcmerror
= brcmf_sdbrcm_bus_iovar_op(drvr
,
416 buf
, arg
, arglen
, buf
, buflen
,
419 bcmerror
= brcmf_sdbrcm_bus_iovar_op(drvr
,
420 buf
, NULL
, 0, arg
, arglen
,
427 bcmerror
= -ENOTSUPP
;
435 brcmf_c_show_host_event(struct brcmf_event_msg
*event
, void *event_data
)
437 uint i
, status
, reason
;
438 bool group
= false, flush_txq
= false, link
= false;
439 char *auth_str
, *event_name
;
441 char err_msg
[256], eabuf
[ETHER_ADDR_STR_LEN
];
447 BRCMF_E_SET_SSID
, "SET_SSID"}, {
448 BRCMF_E_JOIN
, "JOIN"}, {
449 BRCMF_E_START
, "START"}, {
450 BRCMF_E_AUTH
, "AUTH"}, {
451 BRCMF_E_AUTH_IND
, "AUTH_IND"}, {
452 BRCMF_E_DEAUTH
, "DEAUTH"}, {
453 BRCMF_E_DEAUTH_IND
, "DEAUTH_IND"}, {
454 BRCMF_E_ASSOC
, "ASSOC"}, {
455 BRCMF_E_ASSOC_IND
, "ASSOC_IND"}, {
456 BRCMF_E_REASSOC
, "REASSOC"}, {
457 BRCMF_E_REASSOC_IND
, "REASSOC_IND"}, {
458 BRCMF_E_DISASSOC
, "DISASSOC"}, {
459 BRCMF_E_DISASSOC_IND
, "DISASSOC_IND"}, {
460 BRCMF_E_QUIET_START
, "START_QUIET"}, {
461 BRCMF_E_QUIET_END
, "END_QUIET"}, {
462 BRCMF_E_BEACON_RX
, "BEACON_RX"}, {
463 BRCMF_E_LINK
, "LINK"}, {
464 BRCMF_E_MIC_ERROR
, "MIC_ERROR"}, {
465 BRCMF_E_NDIS_LINK
, "NDIS_LINK"}, {
466 BRCMF_E_ROAM
, "ROAM"}, {
467 BRCMF_E_TXFAIL
, "TXFAIL"}, {
468 BRCMF_E_PMKID_CACHE
, "PMKID_CACHE"}, {
469 BRCMF_E_RETROGRADE_TSF
, "RETROGRADE_TSF"}, {
470 BRCMF_E_PRUNE
, "PRUNE"}, {
471 BRCMF_E_AUTOAUTH
, "AUTOAUTH"}, {
472 BRCMF_E_EAPOL_MSG
, "EAPOL_MSG"}, {
473 BRCMF_E_SCAN_COMPLETE
, "SCAN_COMPLETE"}, {
474 BRCMF_E_ADDTS_IND
, "ADDTS_IND"}, {
475 BRCMF_E_DELTS_IND
, "DELTS_IND"}, {
476 BRCMF_E_BCNSENT_IND
, "BCNSENT_IND"}, {
477 BRCMF_E_BCNRX_MSG
, "BCNRX_MSG"}, {
478 BRCMF_E_BCNLOST_MSG
, "BCNLOST_MSG"}, {
479 BRCMF_E_ROAM_PREP
, "ROAM_PREP"}, {
480 BRCMF_E_PFN_NET_FOUND
, "PNO_NET_FOUND"}, {
481 BRCMF_E_PFN_NET_LOST
, "PNO_NET_LOST"}, {
482 BRCMF_E_RESET_COMPLETE
, "RESET_COMPLETE"}, {
483 BRCMF_E_JOIN_START
, "JOIN_START"}, {
484 BRCMF_E_ROAM_START
, "ROAM_START"}, {
485 BRCMF_E_ASSOC_START
, "ASSOC_START"}, {
486 BRCMF_E_IBSS_ASSOC
, "IBSS_ASSOC"}, {
487 BRCMF_E_RADIO
, "RADIO"}, {
488 BRCMF_E_PSM_WATCHDOG
, "PSM_WATCHDOG"}, {
489 BRCMF_E_PROBREQ_MSG
, "PROBREQ_MSG"}, {
490 BRCMF_E_SCAN_CONFIRM_IND
, "SCAN_CONFIRM_IND"}, {
491 BRCMF_E_PSK_SUP
, "PSK_SUP"}, {
492 BRCMF_E_COUNTRY_CODE_CHANGED
, "COUNTRY_CODE_CHANGED"}, {
493 BRCMF_E_EXCEEDED_MEDIUM_TIME
, "EXCEEDED_MEDIUM_TIME"}, {
494 BRCMF_E_ICV_ERROR
, "ICV_ERROR"}, {
495 BRCMF_E_UNICAST_DECODE_ERROR
, "UNICAST_DECODE_ERROR"}, {
496 BRCMF_E_MULTICAST_DECODE_ERROR
, "MULTICAST_DECODE_ERROR"}, {
497 BRCMF_E_TRACE
, "TRACE"}, {
498 BRCMF_E_ACTION_FRAME
, "ACTION FRAME"}, {
499 BRCMF_E_ACTION_FRAME_COMPLETE
, "ACTION FRAME TX COMPLETE"}, {
501 BRCMF_E_RSSI
, "RSSI"}, {
502 BRCMF_E_PFN_SCAN_COMPLETE
, "SCAN_COMPLETE"}
504 uint event_type
, flags
, auth_type
, datalen
;
505 event_type
= be32_to_cpu(event
->event_type
);
506 flags
= be16_to_cpu(event
->flags
);
507 status
= be32_to_cpu(event
->status
);
508 reason
= be32_to_cpu(event
->reason
);
509 auth_type
= be32_to_cpu(event
->auth_type
);
510 datalen
= be32_to_cpu(event
->datalen
);
511 /* debug dump of event messages */
512 sprintf(eabuf
, "%pM", event
->addr
);
514 event_name
= "UNKNOWN";
515 for (i
= 0; i
< ARRAY_SIZE(event_names
); i
++) {
516 if (event_names
[i
].event
== event_type
)
517 event_name
= event_names
[i
].event_name
;
520 BRCMF_EVENT(("EVENT: %s, event ID = %d\n", event_name
, event_type
));
521 BRCMF_EVENT(("flags 0x%04x, status %d, reason %d, auth_type %d"
522 " MAC %s\n", flags
, status
, reason
, auth_type
, eabuf
));
524 if (flags
& BRCMF_EVENT_MSG_LINK
)
526 if (flags
& BRCMF_EVENT_MSG_GROUP
)
528 if (flags
& BRCMF_EVENT_MSG_FLUSHTXQ
)
531 switch (event_type
) {
534 case BRCMF_E_DISASSOC
:
535 BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
538 case BRCMF_E_ASSOC_IND
:
539 case BRCMF_E_REASSOC_IND
:
540 BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
544 case BRCMF_E_REASSOC
:
545 if (status
== BRCMF_E_STATUS_SUCCESS
) {
546 BRCMF_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n",
548 } else if (status
== BRCMF_E_STATUS_TIMEOUT
) {
549 BRCMF_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n",
551 } else if (status
== BRCMF_E_STATUS_FAIL
) {
552 BRCMF_EVENT(("MACEVENT: %s, MAC %s, FAILURE,"
553 " reason %d\n", event_name
, eabuf
,
556 BRCMF_EVENT(("MACEVENT: %s, MAC %s, unexpected status "
557 "%d\n", event_name
, eabuf
, (int)status
));
561 case BRCMF_E_DEAUTH_IND
:
562 case BRCMF_E_DISASSOC_IND
:
563 BRCMF_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name
,
564 eabuf
, (int)reason
));
568 case BRCMF_E_AUTH_IND
:
569 if (auth_type
== WLAN_AUTH_OPEN
)
570 auth_str
= "Open System";
571 else if (auth_type
== WLAN_AUTH_SHARED_KEY
)
572 auth_str
= "Shared Key";
574 sprintf(err_msg
, "AUTH unknown: %d", (int)auth_type
);
577 if (event_type
== BRCMF_E_AUTH_IND
) {
578 BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name
,
580 } else if (status
== BRCMF_E_STATUS_SUCCESS
) {
581 BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
582 event_name
, eabuf
, auth_str
));
583 } else if (status
== BRCMF_E_STATUS_TIMEOUT
) {
584 BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
585 event_name
, eabuf
, auth_str
));
586 } else if (status
== BRCMF_E_STATUS_FAIL
) {
587 BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, "
589 event_name
, eabuf
, auth_str
, (int)reason
));
596 case BRCMF_E_SET_SSID
:
597 if (status
== BRCMF_E_STATUS_SUCCESS
) {
598 BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name
,
600 } else if (status
== BRCMF_E_STATUS_FAIL
) {
601 BRCMF_EVENT(("MACEVENT: %s, failed\n", event_name
));
602 } else if (status
== BRCMF_E_STATUS_NO_NETWORKS
) {
603 BRCMF_EVENT(("MACEVENT: %s, no networks found\n",
606 BRCMF_EVENT(("MACEVENT: %s, unexpected status %d\n",
607 event_name
, (int)status
));
611 case BRCMF_E_BEACON_RX
:
612 if (status
== BRCMF_E_STATUS_SUCCESS
) {
613 BRCMF_EVENT(("MACEVENT: %s, SUCCESS\n", event_name
));
614 } else if (status
== BRCMF_E_STATUS_FAIL
) {
615 BRCMF_EVENT(("MACEVENT: %s, FAIL\n", event_name
));
617 BRCMF_EVENT(("MACEVENT: %s, status %d\n", event_name
,
623 BRCMF_EVENT(("MACEVENT: %s %s\n", event_name
,
624 link
? "UP" : "DOWN"));
627 case BRCMF_E_MIC_ERROR
:
628 BRCMF_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
629 event_name
, eabuf
, group
, flush_txq
));
632 case BRCMF_E_ICV_ERROR
:
633 case BRCMF_E_UNICAST_DECODE_ERROR
:
634 case BRCMF_E_MULTICAST_DECODE_ERROR
:
635 BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
639 BRCMF_EVENT(("MACEVENT: %s, RA %s\n", event_name
, eabuf
));
642 case BRCMF_E_SCAN_COMPLETE
:
643 case BRCMF_E_PMKID_CACHE
:
644 BRCMF_EVENT(("MACEVENT: %s\n", event_name
));
647 case BRCMF_E_PFN_NET_FOUND
:
648 case BRCMF_E_PFN_NET_LOST
:
649 case BRCMF_E_PFN_SCAN_COMPLETE
:
650 BRCMF_EVENT(("PNOEVENT: %s\n", event_name
));
653 case BRCMF_E_PSK_SUP
:
655 BRCMF_EVENT(("MACEVENT: %s, status %d, reason %d\n",
656 event_name
, (int)status
, (int)reason
));
661 static u32 seqnum_prev
;
662 struct msgtrace_hdr hdr
;
666 buf
= (unsigned char *) event_data
;
667 memcpy(&hdr
, buf
, sizeof(struct msgtrace_hdr
));
669 if (hdr
.version
!= MSGTRACE_VERSION
) {
671 ("\nMACEVENT: %s [unsupported version --> "
672 "brcmf version:%d dongle version:%d]\n",
673 event_name
, MSGTRACE_VERSION
, hdr
.version
)
675 /* Reset datalen to avoid display below */
680 /* There are 2 bytes available at the end of data */
681 *(buf
+ sizeof(struct msgtrace_hdr
)
682 + be16_to_cpu(hdr
.len
)) = '\0';
684 if (be32_to_cpu(hdr
.discarded_bytes
)
685 || be32_to_cpu(hdr
.discarded_printf
)) {
687 ("\nWLC_E_TRACE: [Discarded traces in dongle -->"
688 "discarded_bytes %d discarded_printf %d]\n",
689 be32_to_cpu(hdr
.discarded_bytes
),
690 be32_to_cpu(hdr
.discarded_printf
)));
693 nblost
= be32_to_cpu(hdr
.seqnum
) - seqnum_prev
- 1;
696 ("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
697 be32_to_cpu(hdr
.seqnum
), nblost
));
699 seqnum_prev
= be32_to_cpu(hdr
.seqnum
);
701 /* Display the trace buffer. Advance from \n to \n to
703 * printf (issue with Linux printk )
705 p
= (char *)&buf
[sizeof(struct msgtrace_hdr
)];
706 while ((s
= strstr(p
, "\n")) != NULL
) {
708 printk(KERN_DEBUG
"%s\n", p
);
711 printk(KERN_DEBUG
"%s\n", p
);
713 /* Reset datalen to avoid display below */
719 BRCMF_EVENT(("MACEVENT: %s %d\n", event_name
,
720 be32_to_cpu(*((int *)event_data
))));
724 BRCMF_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
725 "auth %d\n", event_name
, event_type
, eabuf
,
726 (int)status
, (int)reason
, (int)auth_type
));
730 /* show any appended data */
732 buf
= (unsigned char *) event_data
;
733 BRCMF_EVENT((" data (%d) : ", datalen
));
734 for (i
= 0; i
< datalen
; i
++)
735 BRCMF_EVENT((" 0x%02x ", *buf
++));
739 #endif /* SHOW_EVENTS */
742 brcmf_c_host_event(struct brcmf_info
*drvr_priv
, int *ifidx
, void *pktdata
,
743 struct brcmf_event_msg
*event
, void **data_ptr
)
745 /* check whether packet is a BRCM event pkt */
746 struct brcmf_event
*pvt_data
= (struct brcmf_event
*) pktdata
;
752 if (memcmp(BRCM_OUI
, &pvt_data
->hdr
.oui
[0], DOT11_OUI_LEN
)) {
753 BRCMF_ERROR(("%s: mismatched OUI, bailing\n", __func__
));
757 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
758 if (get_unaligned_be16(&pvt_data
->hdr
.usr_subtype
) !=
759 BCMILCP_BCM_SUBTYPE_EVENT
) {
760 BRCMF_ERROR(("%s: mismatched subtype, bailing\n", __func__
));
764 *data_ptr
= &pvt_data
[1];
765 event_data
= *data_ptr
;
767 /* memcpy since BRCM event pkt may be unaligned. */
768 memcpy(event
, &pvt_data
->msg
, sizeof(struct brcmf_event_msg
));
770 type
= get_unaligned_be32(&event
->event_type
);
771 flags
= get_unaligned_be16(&event
->flags
);
772 status
= get_unaligned_be32(&event
->status
);
773 evlen
= get_unaligned_be32(&event
->datalen
) +
774 sizeof(struct brcmf_event
);
779 struct brcmf_if_event
*ifevent
=
780 (struct brcmf_if_event
*) event_data
;
781 BRCMF_TRACE(("%s: if event\n", __func__
));
783 if (ifevent
->ifidx
> 0 &&
784 ifevent
->ifidx
< BRCMF_MAX_IFS
) {
785 if (ifevent
->action
== BRCMF_E_IF_ADD
)
786 brcmf_add_if(drvr_priv
, ifevent
->ifidx
,
788 pvt_data
->eth
.h_dest
,
792 brcmf_del_if(drvr_priv
, ifevent
->ifidx
);
794 BRCMF_ERROR(("%s: Invalid ifidx %d for %s\n",
795 __func__
, ifevent
->ifidx
,
799 /* send up the if event: btamp user needs it */
800 *ifidx
= brcmf_ifname2idx(drvr_priv
, event
->ifname
);
803 /* These are what external supplicant/authenticator wants */
805 case BRCMF_E_ASSOC_IND
:
806 case BRCMF_E_REASSOC_IND
:
807 case BRCMF_E_DISASSOC_IND
:
808 case BRCMF_E_MIC_ERROR
:
810 /* Fall through: this should get _everything_ */
812 *ifidx
= brcmf_ifname2idx(drvr_priv
, event
->ifname
);
813 BRCMF_TRACE(("%s: MAC event %d, flags %x, status %x\n",
814 __func__
, type
, flags
, status
));
816 /* put it back to BRCMF_E_NDIS_LINK */
817 if (type
== BRCMF_E_NDIS_LINK
) {
820 temp
= get_unaligned_be32(&event
->event_type
);
821 BRCMF_TRACE(("Converted to WLC_E_LINK type %d\n",
824 temp
= be32_to_cpu(BRCMF_E_NDIS_LINK
);
825 memcpy((void *)(&pvt_data
->msg
.event_type
), &temp
,
826 sizeof(pvt_data
->msg
.event_type
));
832 brcmf_c_show_host_event(event
, event_data
);
833 #endif /* SHOW_EVENTS */
838 /* Convert user's input in hex pattern to byte-size mask */
839 static int brcmf_c_pattern_atoh(char *src
, char *dst
)
842 if (strncmp(src
, "0x", 2) != 0 && strncmp(src
, "0X", 2) != 0) {
843 BRCMF_ERROR(("Mask invalid format. Needs to start with 0x\n"));
846 src
= src
+ 2; /* Skip past 0x */
847 if (strlen(src
) % 2 != 0) {
848 BRCMF_ERROR(("Mask invalid format. Length must be even.\n"));
851 for (i
= 0; *src
!= '\0'; i
++) {
853 strncpy(num
, src
, 2);
855 dst
[i
] = (u8
) simple_strtoul(num
, NULL
, 16);
862 brcmf_c_pktfilter_offload_enable(struct brcmf_pub
*drvr
, char *arg
, int enable
,
870 char *arg_save
= 0, *arg_org
= 0;
873 struct brcmf_pkt_filter_enable enable_parm
;
874 struct brcmf_pkt_filter_enable
*pkt_filterp
;
876 arg_save
= kmalloc(strlen(arg
) + 1, GFP_ATOMIC
);
878 BRCMF_ERROR(("%s: kmalloc failed\n", __func__
));
882 memcpy(arg_save
, arg
, strlen(arg
) + 1);
884 argv
[i
] = strsep(&arg_save
, " ");
887 if (NULL
== argv
[i
]) {
888 BRCMF_ERROR(("No args provided\n"));
892 str
= "pkt_filter_enable";
893 str_len
= strlen(str
);
894 strncpy(buf
, str
, str_len
);
896 buf_len
= str_len
+ 1;
898 pkt_filterp
= (struct brcmf_pkt_filter_enable
*) (buf
+ str_len
+ 1);
900 /* Parse packet filter id. */
901 enable_parm
.id
= simple_strtoul(argv
[i
], NULL
, 0);
903 /* Parse enable/disable value. */
904 enable_parm
.enable
= enable
;
906 buf_len
+= sizeof(enable_parm
);
907 memcpy((char *)pkt_filterp
, &enable_parm
, sizeof(enable_parm
));
909 /* Enable/disable the specified filter. */
910 rc
= brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
, buf
, buf_len
);
911 rc
= rc
>= 0 ? 0 : rc
;
913 BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
916 BRCMF_TRACE(("%s: successfully added pktfilter %s\n",
919 /* Contorl the master mode */
920 brcmu_mkiovar("pkt_filter_mode", (char *)&master_mode
, 4, buf
,
922 rc
= brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
, buf
,
924 rc
= rc
>= 0 ? 0 : rc
;
926 BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
933 void brcmf_c_pktfilter_offload_set(struct brcmf_pub
*drvr
, char *arg
)
936 struct brcmf_pkt_filter pkt_filter
;
937 struct brcmf_pkt_filter
*pkt_filterp
;
943 char *argv
[8], *buf
= 0;
945 char *arg_save
= 0, *arg_org
= 0;
947 arg_save
= kmalloc(strlen(arg
) + 1, GFP_ATOMIC
);
949 BRCMF_ERROR(("%s: kmalloc failed\n", __func__
));
955 buf
= kmalloc(PKTFILTER_BUF_SIZE
, GFP_ATOMIC
);
957 BRCMF_ERROR(("%s: kmalloc failed\n", __func__
));
961 strcpy(arg_save
, arg
);
963 argv
[i
] = strsep(&arg_save
, " ");
965 argv
[i
] = strsep(&arg_save
, " ");
968 if (NULL
== argv
[i
]) {
969 BRCMF_ERROR(("No args provided\n"));
973 str
= "pkt_filter_add";
975 str_len
= strlen(str
);
976 buf_len
= str_len
+ 1;
978 pkt_filterp
= (struct brcmf_pkt_filter
*) (buf
+ str_len
+ 1);
980 /* Parse packet filter id. */
981 pkt_filter
.id
= simple_strtoul(argv
[i
], NULL
, 0);
983 if (NULL
== argv
[++i
]) {
984 BRCMF_ERROR(("Polarity not provided\n"));
988 /* Parse filter polarity. */
989 pkt_filter
.negate_match
= simple_strtoul(argv
[i
], NULL
, 0);
991 if (NULL
== argv
[++i
]) {
992 BRCMF_ERROR(("Filter type not provided\n"));
996 /* Parse filter type. */
997 pkt_filter
.type
= simple_strtoul(argv
[i
], NULL
, 0);
999 if (NULL
== argv
[++i
]) {
1000 BRCMF_ERROR(("Offset not provided\n"));
1004 /* Parse pattern filter offset. */
1005 pkt_filter
.u
.pattern
.offset
= simple_strtoul(argv
[i
], NULL
, 0);
1007 if (NULL
== argv
[++i
]) {
1008 BRCMF_ERROR(("Bitmask not provided\n"));
1012 /* Parse pattern filter mask. */
1014 brcmf_c_pattern_atoh
1015 (argv
[i
], (char *)pkt_filterp
->u
.pattern
.mask_and_pattern
);
1017 if (NULL
== argv
[++i
]) {
1018 BRCMF_ERROR(("Pattern not provided\n"));
1022 /* Parse pattern filter pattern. */
1024 brcmf_c_pattern_atoh(argv
[i
],
1025 (char *)&pkt_filterp
->u
.pattern
.
1026 mask_and_pattern
[mask_size
]);
1028 if (mask_size
!= pattern_size
) {
1029 BRCMF_ERROR(("Mask and pattern not the same size\n"));
1033 pkt_filter
.u
.pattern
.size_bytes
= mask_size
;
1034 buf_len
+= BRCMF_PKT_FILTER_FIXED_LEN
;
1035 buf_len
+= (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN
+ 2 * mask_size
);
1037 /* Keep-alive attributes are set in local
1038 * variable (keep_alive_pkt), and
1039 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1040 ** guarantee that the buffer is properly aligned.
1042 memcpy((char *)pkt_filterp
,
1044 BRCMF_PKT_FILTER_FIXED_LEN
+ BRCMF_PKT_FILTER_PATTERN_FIXED_LEN
);
1046 rc
= brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
, buf
, buf_len
);
1047 rc
= rc
>= 0 ? 0 : rc
;
1050 BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1051 __func__
, arg
, rc
));
1053 BRCMF_TRACE(("%s: successfully added pktfilter %s\n",
1062 void brcmf_c_arp_offload_set(struct brcmf_pub
*drvr
, int arp_mode
)
1067 brcmu_mkiovar("arp_ol", (char *)&arp_mode
, 4, iovbuf
, sizeof(iovbuf
));
1068 retcode
= brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
,
1069 iovbuf
, sizeof(iovbuf
));
1070 retcode
= retcode
>= 0 ? 0 : retcode
;
1072 BRCMF_TRACE(("%s: failed to set ARP offload mode to 0x%x, "
1073 "retcode = %d\n", __func__
, arp_mode
, retcode
));
1075 BRCMF_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1076 __func__
, arp_mode
));
1079 void brcmf_c_arp_offload_enable(struct brcmf_pub
*drvr
, int arp_enable
)
1084 brcmu_mkiovar("arpoe", (char *)&arp_enable
, 4, iovbuf
, sizeof(iovbuf
));
1085 retcode
= brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
,
1086 iovbuf
, sizeof(iovbuf
));
1087 retcode
= retcode
>= 0 ? 0 : retcode
;
1089 BRCMF_TRACE(("%s: failed to enabe ARP offload to %d, "
1090 "retcode = %d\n", __func__
, arp_enable
, retcode
));
1092 BRCMF_TRACE(("%s: successfully enabed ARP offload to %d\n",
1093 __func__
, arp_enable
));
1096 int brcmf_c_preinit_ioctls(struct brcmf_pub
*drvr
)
1098 char iovbuf
[BRCMF_EVENTING_MASK_LEN
+ 12]; /* Room for
1099 "event_msgs" + '\0' + bitvec */
1101 char buf
[128], *ptr
;
1102 uint power_mode
= PM_FAST
;
1103 u32 dongle_align
= BRCMF_SDALIGN
;
1105 uint bcn_timeout
= 3;
1106 int scan_assoc_time
= 40;
1107 int scan_unassoc_time
= 40;
1110 brcmf_os_proto_block(drvr
);
1112 /* Set Country code */
1113 if (drvr
->country_code
[0] != 0) {
1114 if (brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_COUNTRY
,
1116 sizeof(drvr
->country_code
)) < 0) {
1117 BRCMF_ERROR(("%s: country code setting failed\n",
1122 /* query for 'ver' to get version info from firmware */
1123 memset(buf
, 0, sizeof(buf
));
1125 brcmu_mkiovar("ver", 0, 0, buf
, sizeof(buf
));
1126 brcmf_proto_cdc_query_ioctl(drvr
, 0, BRCMF_C_GET_VAR
, buf
, sizeof(buf
));
1128 /* Print fw version info */
1129 BRCMF_ERROR(("Firmware version = %s\n", buf
));
1131 /* Set PowerSave mode */
1132 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_PM
, (char *)&power_mode
,
1133 sizeof(power_mode
));
1135 /* Match Host and Dongle rx alignment */
1136 brcmu_mkiovar("bus:txglomalign", (char *)&dongle_align
, 4, iovbuf
,
1138 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
, iovbuf
,
1141 /* disable glom option per default */
1142 brcmu_mkiovar("bus:txglom", (char *)&glom
, 4, iovbuf
, sizeof(iovbuf
));
1143 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
, iovbuf
,
1146 /* Setup timeout if Beacons are lost and roam is off to report
1148 brcmu_mkiovar("bcn_timeout", (char *)&bcn_timeout
, 4, iovbuf
,
1150 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
, iovbuf
,
1153 /* Enable/Disable build-in roaming to allowed ext supplicant to take
1155 brcmu_mkiovar("roam_off", (char *)&brcmf_roam
, 4,
1156 iovbuf
, sizeof(iovbuf
));
1157 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
, iovbuf
,
1162 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_UP
, (char *)&up
,
1165 /* Setup event_msgs */
1166 brcmu_mkiovar("event_msgs", drvr
->eventmask
, BRCMF_EVENTING_MASK_LEN
,
1167 iovbuf
, sizeof(iovbuf
));
1168 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_VAR
, iovbuf
,
1171 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME
,
1172 (char *)&scan_assoc_time
, sizeof(scan_assoc_time
));
1173 brcmf_proto_cdc_set_ioctl(drvr
, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME
,
1174 (char *)&scan_unassoc_time
, sizeof(scan_unassoc_time
));
1176 /* Set and enable ARP offload feature */
1177 if (brcmf_arp_enable
)
1178 brcmf_c_arp_offload_set(drvr
, brcmf_arp_mode
);
1179 brcmf_c_arp_offload_enable(drvr
, brcmf_arp_enable
);
1181 /* Set up pkt filter */
1182 if (brcmf_pkt_filter_enable
) {
1183 for (i
= 0; i
< drvr
->pktfilter_count
; i
++) {
1184 brcmf_c_pktfilter_offload_set(drvr
,
1185 drvr
->pktfilter
[i
]);
1186 brcmf_c_pktfilter_offload_enable(drvr
,
1188 brcmf_pkt_filter_init
,
1193 brcmf_os_proto_unblock(drvr
);