brcmfmac-objs += \
wl_cfg80211.o \
fwil.o \
+ fweh.o \
dhd_cdc.o \
dhd_common.o \
dhd_linux.o
#define BRCMF_VERSION_STR "4.218.248.5"
+#include "fweh.h"
+
/*******************************************************************************
* IO codes that are interpreted by dongle firmware
******************************************************************************/
#define DOT11_BSSTYPE_ANY 2
#define DOT11_MAX_DEFAULT_KEYS 4
-#define BRCMF_EVENT_MSG_LINK 0x01
-#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
-#define BRCMF_EVENT_MSG_GROUP 0x04
-
#define BRCMF_ESCAN_REQ_VERSION 1
#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */
#define BRCMF_STA_ASSOC 0x10 /* Associated */
-struct brcmf_event_msg {
- __be16 version;
- __be16 flags;
- __be32 event_type;
- __be32 status;
- __be32 reason;
- __be32 auth_type;
- __be32 datalen;
- u8 addr[ETH_ALEN];
- char ifname[IFNAMSIZ];
- u8 ifidx;
- u8 bsscfgidx;
-} __packed;
-
-struct brcm_ethhdr {
- u16 subtype;
- u16 length;
- u8 version;
- u8 oui[3];
- u16 usr_subtype;
-} __packed;
-
-struct brcmf_event {
- struct ethhdr eth;
- struct brcm_ethhdr hdr;
- struct brcmf_event_msg msg;
-} __packed;
-
-/* event codes sent by the dongle to this driver */
-#define BRCMF_E_SET_SSID 0
-#define BRCMF_E_JOIN 1
-#define BRCMF_E_START 2
-#define BRCMF_E_AUTH 3
-#define BRCMF_E_AUTH_IND 4
-#define BRCMF_E_DEAUTH 5
-#define BRCMF_E_DEAUTH_IND 6
-#define BRCMF_E_ASSOC 7
-#define BRCMF_E_ASSOC_IND 8
-#define BRCMF_E_REASSOC 9
-#define BRCMF_E_REASSOC_IND 10
-#define BRCMF_E_DISASSOC 11
-#define BRCMF_E_DISASSOC_IND 12
-#define BRCMF_E_QUIET_START 13
-#define BRCMF_E_QUIET_END 14
-#define BRCMF_E_BEACON_RX 15
-#define BRCMF_E_LINK 16
-#define BRCMF_E_MIC_ERROR 17
-#define BRCMF_E_NDIS_LINK 18
-#define BRCMF_E_ROAM 19
-#define BRCMF_E_TXFAIL 20
-#define BRCMF_E_PMKID_CACHE 21
-#define BRCMF_E_RETROGRADE_TSF 22
-#define BRCMF_E_PRUNE 23
-#define BRCMF_E_AUTOAUTH 24
-#define BRCMF_E_EAPOL_MSG 25
-#define BRCMF_E_SCAN_COMPLETE 26
-#define BRCMF_E_ADDTS_IND 27
-#define BRCMF_E_DELTS_IND 28
-#define BRCMF_E_BCNSENT_IND 29
-#define BRCMF_E_BCNRX_MSG 30
-#define BRCMF_E_BCNLOST_MSG 31
-#define BRCMF_E_ROAM_PREP 32
-#define BRCMF_E_PFN_NET_FOUND 33
-#define BRCMF_E_PFN_NET_LOST 34
-#define BRCMF_E_RESET_COMPLETE 35
-#define BRCMF_E_JOIN_START 36
-#define BRCMF_E_ROAM_START 37
-#define BRCMF_E_ASSOC_START 38
-#define BRCMF_E_IBSS_ASSOC 39
-#define BRCMF_E_RADIO 40
-#define BRCMF_E_PSM_WATCHDOG 41
-#define BRCMF_E_PROBREQ_MSG 44
-#define BRCMF_E_SCAN_CONFIRM_IND 45
-#define BRCMF_E_PSK_SUP 46
-#define BRCMF_E_COUNTRY_CODE_CHANGED 47
-#define BRCMF_E_EXCEEDED_MEDIUM_TIME 48
-#define BRCMF_E_ICV_ERROR 49
-#define BRCMF_E_UNICAST_DECODE_ERROR 50
-#define BRCMF_E_MULTICAST_DECODE_ERROR 51
-#define BRCMF_E_TRACE 52
-#define BRCMF_E_IF 54
-#define BRCMF_E_RSSI 56
-#define BRCMF_E_PFN_SCAN_COMPLETE 57
-#define BRCMF_E_EXTLOG_MSG 58
-#define BRCMF_E_ACTION_FRAME 59
-#define BRCMF_E_ACTION_FRAME_COMPLETE 60
-#define BRCMF_E_PRE_ASSOC_IND 61
-#define BRCMF_E_PRE_REASSOC_IND 62
-#define BRCMF_E_CHANNEL_ADOPTED 63
-#define BRCMF_E_AP_STARTED 64
-#define BRCMF_E_DFS_AP_STOP 65
-#define BRCMF_E_DFS_AP_RESUME 66
-#define BRCMF_E_RESERVED1 67
-#define BRCMF_E_RESERVED2 68
-#define BRCMF_E_ESCAN_RESULT 69
-#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70
-#define BRCMF_E_DCS_REQUEST 73
-
-#define BRCMF_E_FIFO_CREDIT_MAP 74
-
-#define BRCMF_E_LAST 75
-
#define BRCMF_E_STATUS_SUCCESS 0
#define BRCMF_E_STATUS_FAIL 1
#define BRCMF_E_STATUS_TIMEOUT 2
u8 macvalue[ETH_ALEN];
atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait;
+
+ struct brcmf_fweh_info fweh;
#ifdef DEBUG
struct dentry *dbgfs_dir;
#endif
struct sk_buff *pkt, int prec);
/* Receive frame for delivery to OS. Callee disposes of rxp. */
-extern void brcmf_rx_frame(struct device *dev, int ifidx,
+extern void brcmf_rx_frame(struct device *dev, u8 ifidx,
struct sk_buff_head *rxlist);
static inline void brcmf_rx_packet(struct device *dev, int ifidx,
struct sk_buff *pkt)
return p != NULL;
}
-#ifdef DEBUG
-static void
-brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
-{
- uint i, status, reason;
- bool group = false, flush_txq = false, link = false;
- char *auth_str, *event_name;
- unsigned char *buf;
- char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
- static struct {
- uint event;
- char *event_name;
- } event_names[] = {
- {
- BRCMF_E_SET_SSID, "SET_SSID"}, {
- BRCMF_E_JOIN, "JOIN"}, {
- BRCMF_E_START, "START"}, {
- BRCMF_E_AUTH, "AUTH"}, {
- BRCMF_E_AUTH_IND, "AUTH_IND"}, {
- BRCMF_E_DEAUTH, "DEAUTH"}, {
- BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, {
- BRCMF_E_ASSOC, "ASSOC"}, {
- BRCMF_E_ASSOC_IND, "ASSOC_IND"}, {
- BRCMF_E_REASSOC, "REASSOC"}, {
- BRCMF_E_REASSOC_IND, "REASSOC_IND"}, {
- BRCMF_E_DISASSOC, "DISASSOC"}, {
- BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, {
- BRCMF_E_QUIET_START, "START_QUIET"}, {
- BRCMF_E_QUIET_END, "END_QUIET"}, {
- BRCMF_E_BEACON_RX, "BEACON_RX"}, {
- BRCMF_E_LINK, "LINK"}, {
- BRCMF_E_MIC_ERROR, "MIC_ERROR"}, {
- BRCMF_E_NDIS_LINK, "NDIS_LINK"}, {
- BRCMF_E_ROAM, "ROAM"}, {
- BRCMF_E_TXFAIL, "TXFAIL"}, {
- BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, {
- BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, {
- BRCMF_E_PRUNE, "PRUNE"}, {
- BRCMF_E_AUTOAUTH, "AUTOAUTH"}, {
- BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, {
- BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
- BRCMF_E_ADDTS_IND, "ADDTS_IND"}, {
- BRCMF_E_DELTS_IND, "DELTS_IND"}, {
- BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, {
- BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, {
- BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, {
- BRCMF_E_ROAM_PREP, "ROAM_PREP"}, {
- BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, {
- BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, {
- BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, {
- BRCMF_E_JOIN_START, "JOIN_START"}, {
- BRCMF_E_ROAM_START, "ROAM_START"}, {
- BRCMF_E_ASSOC_START, "ASSOC_START"}, {
- BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, {
- BRCMF_E_RADIO, "RADIO"}, {
- BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, {
- BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, {
- BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, {
- BRCMF_E_PSK_SUP, "PSK_SUP"}, {
- BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, {
- BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, {
- BRCMF_E_ICV_ERROR, "ICV_ERROR"}, {
- BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, {
- BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, {
- BRCMF_E_TRACE, "TRACE"}, {
- BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, {
- BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
- BRCMF_E_IF, "IF"}, {
- BRCMF_E_RSSI, "RSSI"}, {
- BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
- BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT"}
- };
- uint event_type, flags, auth_type, datalen;
- static u32 seqnum_prev;
- struct msgtrace_hdr hdr;
- u32 nblost;
- char *s, *p;
-
- event_type = be32_to_cpu(event->event_type);
- flags = be16_to_cpu(event->flags);
- status = be32_to_cpu(event->status);
- reason = be32_to_cpu(event->reason);
- auth_type = be32_to_cpu(event->auth_type);
- datalen = be32_to_cpu(event->datalen);
- /* debug dump of event messages */
- sprintf(eabuf, "%pM", event->addr);
-
- event_name = "UNKNOWN";
- for (i = 0; i < ARRAY_SIZE(event_names); i++) {
- if (event_names[i].event == event_type)
- event_name = event_names[i].event_name;
- }
-
- brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type);
- brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n",
- flags, status, reason, auth_type, eabuf);
-
- if (flags & BRCMF_EVENT_MSG_LINK)
- link = true;
- if (flags & BRCMF_EVENT_MSG_GROUP)
- group = true;
- if (flags & BRCMF_EVENT_MSG_FLUSHTXQ)
- flush_txq = true;
-
- switch (event_type) {
- case BRCMF_E_START:
- case BRCMF_E_DEAUTH:
- case BRCMF_E_DISASSOC:
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
- break;
-
- case BRCMF_E_ASSOC_IND:
- case BRCMF_E_REASSOC_IND:
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
- break;
-
- case BRCMF_E_ASSOC:
- case BRCMF_E_REASSOC:
- if (status == BRCMF_E_STATUS_SUCCESS)
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n",
- event_name, eabuf);
- else if (status == BRCMF_E_STATUS_TIMEOUT)
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n",
- event_name, eabuf);
- else if (status == BRCMF_E_STATUS_FAIL)
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
- event_name, eabuf, (int)reason);
- else
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n",
- event_name, eabuf, (int)status);
- break;
-
- case BRCMF_E_DEAUTH_IND:
- case BRCMF_E_DISASSOC_IND:
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n",
- event_name, eabuf, (int)reason);
- break;
-
- case BRCMF_E_AUTH:
- case BRCMF_E_AUTH_IND:
- if (auth_type == WLAN_AUTH_OPEN)
- auth_str = "Open System";
- else if (auth_type == WLAN_AUTH_SHARED_KEY)
- auth_str = "Shared Key";
- else {
- sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
- auth_str = err_msg;
- }
- if (event_type == BRCMF_E_AUTH_IND)
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n",
- event_name, eabuf, auth_str);
- else if (status == BRCMF_E_STATUS_SUCCESS)
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n",
- event_name, eabuf, auth_str);
- else if (status == BRCMF_E_STATUS_TIMEOUT)
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
- event_name, eabuf, auth_str);
- else if (status == BRCMF_E_STATUS_FAIL) {
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
- event_name, eabuf, auth_str, (int)reason);
- }
-
- break;
-
- case BRCMF_E_JOIN:
- case BRCMF_E_ROAM:
- case BRCMF_E_SET_SSID:
- if (status == BRCMF_E_STATUS_SUCCESS)
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n",
- event_name, eabuf);
- else if (status == BRCMF_E_STATUS_FAIL)
- brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name);
- else if (status == BRCMF_E_STATUS_NO_NETWORKS)
- brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n",
- event_name);
- else
- brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n",
- event_name, (int)status);
- break;
-
- case BRCMF_E_BEACON_RX:
- if (status == BRCMF_E_STATUS_SUCCESS)
- brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name);
- else if (status == BRCMF_E_STATUS_FAIL)
- brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name);
- else
- brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n",
- event_name, status);
- break;
-
- case BRCMF_E_LINK:
- brcmf_dbg(EVENT, "MACEVENT: %s %s\n",
- event_name, link ? "UP" : "DOWN");
- break;
-
- case BRCMF_E_MIC_ERROR:
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
- event_name, eabuf, group, flush_txq);
- break;
-
- case BRCMF_E_ICV_ERROR:
- case BRCMF_E_UNICAST_DECODE_ERROR:
- case BRCMF_E_MULTICAST_DECODE_ERROR:
- brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
- break;
-
- case BRCMF_E_TXFAIL:
- brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf);
- break;
-
- case BRCMF_E_SCAN_COMPLETE:
- case BRCMF_E_PMKID_CACHE:
- brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
- break;
-
- case BRCMF_E_ESCAN_RESULT:
- brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
- datalen = 0;
- break;
-
- case BRCMF_E_PFN_NET_FOUND:
- case BRCMF_E_PFN_NET_LOST:
- case BRCMF_E_PFN_SCAN_COMPLETE:
- brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name);
- break;
-
- case BRCMF_E_PSK_SUP:
- case BRCMF_E_PRUNE:
- brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n",
- event_name, (int)status, (int)reason);
- break;
-
- case BRCMF_E_TRACE:
- buf = (unsigned char *) event_data;
- memcpy(&hdr, buf, sizeof(struct msgtrace_hdr));
-
- if (hdr.version != MSGTRACE_VERSION) {
- brcmf_dbg(ERROR,
- "MACEVENT: %s [unsupported version --> brcmf"
- " version:%d dongle version:%d]\n",
- event_name, MSGTRACE_VERSION, hdr.version);
- /* Reset datalen to avoid display below */
- datalen = 0;
- break;
- }
-
- /* There are 2 bytes available at the end of data */
- *(buf + sizeof(struct msgtrace_hdr)
- + be16_to_cpu(hdr.len)) = '\0';
-
- if (be32_to_cpu(hdr.discarded_bytes)
- || be32_to_cpu(hdr.discarded_printf))
- brcmf_dbg(ERROR,
- "WLC_E_TRACE: [Discarded traces in dongle -->"
- " discarded_bytes %d discarded_printf %d]\n",
- be32_to_cpu(hdr.discarded_bytes),
- be32_to_cpu(hdr.discarded_printf));
-
- nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
- if (nblost > 0)
- brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum "
- " %d nblost %d\n", be32_to_cpu(hdr.seqnum),
- nblost);
- seqnum_prev = be32_to_cpu(hdr.seqnum);
-
- /* Display the trace buffer. Advance from \n to \n to
- * avoid display big
- * printf (issue with Linux printk )
- */
- p = (char *)&buf[sizeof(struct msgtrace_hdr)];
- while ((s = strstr(p, "\n")) != NULL) {
- *s = '\0';
- pr_debug("%s\n", p);
- p = s + 1;
- }
- pr_debug("%s\n", p);
-
- /* Reset datalen to avoid display below */
- datalen = 0;
- break;
-
- case BRCMF_E_RSSI:
- brcmf_dbg(EVENT, "MACEVENT: %s %d\n",
- event_name, be32_to_cpu(*((__be32 *)event_data)));
- break;
-
- default:
- brcmf_dbg(EVENT,
- "MACEVENT: %s %d, MAC %s, status %d, reason %d, "
- "auth %d\n", event_name, event_type, eabuf,
- (int)status, (int)reason, (int)auth_type);
- break;
- }
-
- /* show any appended data */
- brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data");
-}
-#endif /* DEBUG */
-
-int
-brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,
- struct brcmf_event_msg *event, void **data_ptr)
-{
- /* check whether packet is a BRCM event pkt */
- struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;
- struct brcmf_if_event *ifevent;
- struct brcmf_if *ifp;
- char *event_data;
- u32 type, status;
- u16 flags;
- int evlen;
-
- if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) {
- brcmf_dbg(ERROR, "mismatched OUI, bailing\n");
- return -EBADE;
- }
-
- /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
- if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) !=
- BCMILCP_BCM_SUBTYPE_EVENT) {
- brcmf_dbg(ERROR, "mismatched subtype, bailing\n");
- return -EBADE;
- }
-
- *data_ptr = &pvt_data[1];
- event_data = *data_ptr;
-
- /* memcpy since BRCM event pkt may be unaligned. */
- memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg));
-
- type = get_unaligned_be32(&event->event_type);
- flags = get_unaligned_be16(&event->flags);
- status = get_unaligned_be32(&event->status);
- evlen = get_unaligned_be32(&event->datalen) +
- sizeof(struct brcmf_event);
-
- switch (type) {
- case BRCMF_E_IF:
- ifevent = (struct brcmf_if_event *) event_data;
- brcmf_dbg(TRACE, "if event\n");
-
- if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
- if (ifevent->action == BRCMF_E_IF_ADD) {
- ifp = brcmf_add_if(drvr->dev, ifevent->ifidx,
- ifevent->bssidx,
- event->ifname,
- pvt_data->eth.h_dest);
- if (IS_ERR(ifp))
- return PTR_ERR(ifp);
- brcmf_net_attach(ifp);
- } else {
- brcmf_del_if(drvr, ifevent->ifidx);
- }
- } else {
- brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n",
- ifevent->ifidx, event->ifname);
- }
-
- /* send up the if event: btamp user needs it */
- *ifidx = brcmf_ifname2idx(drvr, event->ifname);
- break;
-
- /* These are what external supplicant/authenticator wants */
- case BRCMF_E_LINK:
- case BRCMF_E_ASSOC_IND:
- case BRCMF_E_REASSOC_IND:
- case BRCMF_E_DISASSOC_IND:
- case BRCMF_E_MIC_ERROR:
- default:
- /* Fall through: this should get _everything_ */
-
- *ifidx = brcmf_ifname2idx(drvr, event->ifname);
- brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n",
- type, flags, status);
-
- /* put it back to BRCMF_E_NDIS_LINK */
- if (type == BRCMF_E_NDIS_LINK) {
- u32 temp1;
- __be32 temp2;
-
- temp1 = get_unaligned_be32(&event->event_type);
- brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n",
- temp1);
-
- temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK);
- memcpy((void *)(&pvt_data->msg.event_type), &temp2,
- sizeof(pvt_data->msg.event_type));
- }
- break;
- }
-
-#ifdef DEBUG
- if (BRCMF_EVENT_ON())
- brcmf_c_show_host_event(event, event_data);
-#endif /* DEBUG */
-
- return 0;
-}
-
/* Convert user's input in hex pattern to byte-size mask */
static int brcmf_c_pattern_atoh(char *src, char *dst)
{
}
}
-static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx,
- void *pktdata, struct brcmf_event_msg *event,
- void **data)
-{
- int bcmerror = 0;
-
- bcmerror = brcmf_c_host_event(drvr, ifidx, pktdata, event, data);
- if (bcmerror != 0)
- return bcmerror;
-
- /* only forward if interface has netdev */
- if (drvr->iflist[*ifidx]->ndev)
- brcmf_cfg80211_event(drvr->iflist[*ifidx],
- event, *data);
-
- return bcmerror;
-}
-
-void brcmf_rx_frame(struct device *dev, int ifidx,
+void brcmf_rx_frame(struct device *dev, u8 ifidx,
struct sk_buff_head *skb_list)
{
unsigned char *eth;
uint len;
- void *data;
struct sk_buff *skb, *pnext;
struct brcmf_if *ifp;
- struct brcmf_event_msg event;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
skb_pull(skb, ETH_HLEN);
/* Process special event packets and then discard them */
- if (ntohs(skb->protocol) == ETH_P_LINK_CTL)
- brcmf_host_event(drvr, &ifidx,
- skb_mac_header(skb),
- &event, &data);
+ brcmf_fweh_process_skb(drvr, skb, &ifidx);
if (drvr->iflist[ifidx]) {
ifp = drvr->iflist[ifidx];
goto fail;
}
+ /* attach firmware event handler */
+ brcmf_fweh_attach(drvr);
+
INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address);
INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list);
goto fail;
}
+ ret = brcmf_fweh_activate_events(ifp);
+ if (ret < 0)
+ goto fail;
+
ret = brcmf_net_attach(ifp);
fail:
if (ret < 0) {
- brcmf_dbg(ERROR, "brcmf_net_attach failed");
+ brcmf_dbg(ERROR, "failed: %d\n", ret);
if (drvr->config)
brcmf_cfg80211_detach(drvr->config);
free_netdev(drvr->iflist[0]->ndev);
if (drvr == NULL)
return;
+ /* stop firmware event handling */
+ brcmf_fweh_detach(drvr);
+
/* make sure primary interface removed last */
for (i = BRCMF_MAX_IFS-1; i > -1; i--)
if (drvr->iflist[i])
--- /dev/null
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/netdevice.h>
+
+#include "defs.h"
+#include "brcmu_wifi.h"
+#include "brcmu_utils.h"
+
+#include "dhd.h"
+#include "dhd_dbg.h"
+#include "fweh.h"
+#include "fwil.h"
+
+/**
+ * struct brcm_ethhdr - broadcom specific ether header.
+ *
+ * @subtype: subtype for this packet.
+ * @length: TODO: length of appended data.
+ * @version: version indication.
+ * @oui: OUI of this packet.
+ * @usr_subtype: subtype for this OUI.
+ */
+struct brcm_ethhdr {
+ __be16 subtype;
+ __be16 length;
+ u8 version;
+ u8 oui[3];
+ __be16 usr_subtype;
+} __packed;
+
+struct brcmf_event_msg_be {
+ __be16 version;
+ __be16 flags;
+ __be32 event_type;
+ __be32 status;
+ __be32 reason;
+ __be32 auth_type;
+ __be32 datalen;
+ u8 addr[ETH_ALEN];
+ char ifname[IFNAMSIZ];
+ u8 ifidx;
+ u8 bsscfgidx;
+} __packed;
+
+/**
+ * struct brcmf_event - contents of broadcom event packet.
+ *
+ * @eth: standard ether header.
+ * @hdr: broadcom specific ether header.
+ * @msg: common part of the actual event message.
+ */
+struct brcmf_event {
+ struct ethhdr eth;
+ struct brcm_ethhdr hdr;
+ struct brcmf_event_msg_be msg;
+} __packed;
+
+/**
+ * struct brcmf_fweh_queue_item - event item on event queue.
+ *
+ * @q: list element for queuing.
+ * @code: event code.
+ * @ifidx: interface index related to this event.
+ * @ifaddr: ethernet address for interface.
+ * @emsg: common parameters of the firmware event message.
+ * @data: event specific data part of the firmware event.
+ */
+struct brcmf_fweh_queue_item {
+ struct list_head q;
+ enum brcmf_fweh_event_code code;
+ u8 ifidx;
+ u8 ifaddr[ETH_ALEN];
+ struct brcmf_event_msg_be emsg;
+ u8 data[0];
+};
+
+/**
+ * struct brcmf_fweh_event_name - code, name mapping entry.
+ */
+struct brcmf_fweh_event_name {
+ enum brcmf_fweh_event_code code;
+ const char *name;
+};
+
+#ifdef DEBUG
+/* array for mapping code to event name */
+static struct brcmf_fweh_event_name fweh_event_names[] = {
+ { BRCMF_E_SET_SSID, "SET_SSID" },
+ { BRCMF_E_JOIN, "JOIN" },
+ { BRCMF_E_START, "START" },
+ { BRCMF_E_AUTH, "AUTH" },
+ { BRCMF_E_AUTH_IND, "AUTH_IND" },
+ { BRCMF_E_DEAUTH, "DEAUTH" },
+ { BRCMF_E_DEAUTH_IND, "DEAUTH_IND" },
+ { BRCMF_E_ASSOC, "ASSOC" },
+ { BRCMF_E_ASSOC_IND, "ASSOC_IND" },
+ { BRCMF_E_REASSOC, "REASSOC" },
+ { BRCMF_E_REASSOC_IND, "REASSOC_IND" },
+ { BRCMF_E_DISASSOC, "DISASSOC" },
+ { BRCMF_E_DISASSOC_IND, "DISASSOC_IND" },
+ { BRCMF_E_QUIET_START, "START_QUIET" },
+ { BRCMF_E_QUIET_END, "END_QUIET" },
+ { BRCMF_E_BEACON_RX, "BEACON_RX" },
+ { BRCMF_E_LINK, "LINK" },
+ { BRCMF_E_MIC_ERROR, "MIC_ERROR" },
+ { BRCMF_E_NDIS_LINK, "NDIS_LINK" },
+ { BRCMF_E_ROAM, "ROAM" },
+ { BRCMF_E_TXFAIL, "TXFAIL" },
+ { BRCMF_E_PMKID_CACHE, "PMKID_CACHE" },
+ { BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF" },
+ { BRCMF_E_PRUNE, "PRUNE" },
+ { BRCMF_E_AUTOAUTH, "AUTOAUTH" },
+ { BRCMF_E_EAPOL_MSG, "EAPOL_MSG" },
+ { BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE" },
+ { BRCMF_E_ADDTS_IND, "ADDTS_IND" },
+ { BRCMF_E_DELTS_IND, "DELTS_IND" },
+ { BRCMF_E_BCNSENT_IND, "BCNSENT_IND" },
+ { BRCMF_E_BCNRX_MSG, "BCNRX_MSG" },
+ { BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG" },
+ { BRCMF_E_ROAM_PREP, "ROAM_PREP" },
+ { BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND" },
+ { BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST" },
+ { BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE" },
+ { BRCMF_E_JOIN_START, "JOIN_START" },
+ { BRCMF_E_ROAM_START, "ROAM_START" },
+ { BRCMF_E_ASSOC_START, "ASSOC_START" },
+ { BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC" },
+ { BRCMF_E_RADIO, "RADIO" },
+ { BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG" },
+ { BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG" },
+ { BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" },
+ { BRCMF_E_PSK_SUP, "PSK_SUP" },
+ { BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED" },
+ { BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" },
+ { BRCMF_E_ICV_ERROR, "ICV_ERROR" },
+ { BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" },
+ { BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" },
+ { BRCMF_E_TRACE, "TRACE" },
+ { BRCMF_E_IF, "IF" },
+ { BRCMF_E_RSSI, "RSSI" },
+ { BRCMF_E_PFN_SCAN_COMPLETE, "PFN_SCAN_COMPLETE" },
+ { BRCMF_E_EXTLOG_MSG, "EXTLOG_MSG" },
+ { BRCMF_E_ACTION_FRAME, "ACTION_FRAME" },
+ { BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" },
+ { BRCMF_E_PRE_ASSOC_IND, "PRE_ASSOC_IND" },
+ { BRCMF_E_PRE_REASSOC_IND, "PRE_REASSOC_IND" },
+ { BRCMF_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" },
+ { BRCMF_E_AP_STARTED, "AP_STARTED" },
+ { BRCMF_E_DFS_AP_STOP, "DFS_AP_STOP" },
+ { BRCMF_E_DFS_AP_RESUME, "DFS_AP_RESUME" },
+ { BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT" },
+ { BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "ACTION_FRM_OFF_CHAN_CMPLT" },
+ { BRCMF_E_DCS_REQUEST, "DCS_REQUEST" },
+ { BRCMF_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP"}
+};
+
+/**
+ * brcmf_fweh_event_name() - returns name for given event code.
+ *
+ * @code: code to lookup.
+ */
+static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) {
+ if (fweh_event_names[i].code == code)
+ return fweh_event_names[i].name;
+ }
+ return "unknown";
+}
+#else
+static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
+{
+ return "nodebug";
+}
+#endif
+
+/**
+ * brcmf_fweh_queue_event() - create and queue event.
+ *
+ * @ifp: firmware interface object.
+ * @code: event code.
+ * @pkt: event ether packet.
+ */
+static void brcmf_fweh_queue_event(struct brcmf_if *ifp,
+ enum brcmf_fweh_event_code code,
+ struct brcmf_event *pkt)
+{
+ struct brcmf_fweh_info *fweh = &ifp->drvr->fweh;
+ struct brcmf_fweh_queue_item *event;
+ gfp_t alloc_flag = GFP_KERNEL;
+ ulong flags;
+ void *data;
+ u32 datalen;
+
+ /* determine event data */
+ datalen = get_unaligned_be32(&pkt->msg.datalen);
+ data = &pkt[1];
+
+ if (!ifp->ndev || (code != BRCMF_E_IF && !fweh->evt_handler[code])) {
+ brcmf_dbg(EVENT, "event ignored: code=%d\n", code);
+ brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), data, datalen, "event:");
+ return;
+ }
+
+ if (in_interrupt())
+ alloc_flag = GFP_ATOMIC;
+
+ event = kzalloc(sizeof(*event) + datalen, alloc_flag);
+ event->code = code;
+ event->ifidx = ifp->idx;
+
+ /* use memcpy to get aligned event message */
+ memcpy(&event->emsg, &pkt->msg, sizeof(event->emsg));
+ memcpy(event->data, data, datalen);
+ memcpy(event->ifaddr, pkt->eth.h_dest, ETH_ALEN);
+
+ spin_lock_irqsave(&fweh->evt_q_lock, flags);
+ list_add_tail(&event->q, &fweh->event_q);
+ spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
+ schedule_work(&fweh->event_work);
+}
+
+/**
+ * brcmf_fweh_process_if_event() - handle IF event.
+ *
+ * @drvr: driver information object.
+ * @item: queue entry.
+ * @ifpp: interface object (may change upon ADD action).
+ */
+static int brcmf_fweh_process_if_event(struct brcmf_pub *drvr,
+ struct brcmf_fweh_queue_item *item,
+ struct brcmf_if **ifpp)
+{
+ struct brcmf_event_msg_be *event = &item->emsg;
+ struct brcmf_if_event *ifevent = (struct brcmf_if_event *)item->data;
+ struct brcmf_if *ifp;
+ int err = 0;
+
+ brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u\n",
+ ifevent->action, ifevent->ifidx,
+ ifevent->bssidx, ifevent->flags);
+
+ if (ifevent->ifidx >= BRCMF_MAX_IFS) {
+ brcmf_dbg(ERROR, "invalid interface index: %u\n",
+ ifevent->ifidx);
+ return -EINVAL;
+ }
+
+ switch (ifevent->action) {
+ case BRCMF_E_IF_ADD:
+ brcmf_dbg(EVENT, "adding %s (%pM, %pM)\n", event->ifname,
+ event->addr, item->ifaddr);
+ ifp = brcmf_add_if(drvr->dev, ifevent->ifidx, ifevent->bssidx,
+ event->ifname, item->ifaddr);
+ if (!IS_ERR(ifp)) {
+ *ifpp = ifp;
+ err = brcmf_net_attach(ifp);
+ } else {
+ err = PTR_ERR(ifp);
+ }
+ break;
+ case BRCMF_E_IF_DEL:
+ brcmf_del_if(drvr, ifevent->ifidx);
+ break;
+ case BRCMF_E_IF_CHANGE:
+ /* nothing to do here */
+ break;
+ default:
+ brcmf_dbg(ERROR, "unknown event action: %u\n", ifevent->action);
+ err = -EBADE;
+ break;
+ }
+ return err;
+}
+
+/**
+ * brcmf_fweh_dequeue_event() - get event from the queue.
+ *
+ * @fweh: firmware event handling info.
+ */
+static struct brcmf_fweh_queue_item *
+brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh)
+{
+ struct brcmf_fweh_queue_item *event = NULL;
+ ulong flags;
+
+ spin_lock_irqsave(&fweh->evt_q_lock, flags);
+ if (!list_empty(&fweh->event_q)) {
+ event = list_first_entry(&fweh->event_q,
+ struct brcmf_fweh_queue_item, q);
+ list_del(&event->q);
+ }
+ spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
+
+ return event;
+}
+
+/**
+ * brcmf_fweh_event_worker() - firmware event worker.
+ *
+ * @work: worker object.
+ */
+static void brcmf_fweh_event_worker(struct work_struct *work)
+{
+ struct brcmf_pub *drvr;
+ struct brcmf_if *ifp;
+ struct brcmf_fweh_info *fweh;
+ struct brcmf_fweh_queue_item *event;
+ int err = 0;
+ struct brcmf_event_msg_be *emsg_be;
+ struct brcmf_event_msg emsg;
+
+ fweh = container_of(work, struct brcmf_fweh_info, event_work);
+ drvr = container_of(fweh, struct brcmf_pub, fweh);
+
+ while ((event = brcmf_fweh_dequeue_event(fweh))) {
+ ifp = drvr->iflist[event->ifidx];
+
+ brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM:\n",
+ brcmf_fweh_event_name(event->code), event->code,
+ event->emsg.ifidx, event->emsg.bsscfgidx,
+ event->emsg.addr);
+
+ /* handle interface event */
+ if (event->code == BRCMF_E_IF) {
+ err = brcmf_fweh_process_if_event(drvr, event, &ifp);
+ if (err)
+ goto event_free;
+ }
+
+ /* convert event message */
+ emsg_be = &event->emsg;
+ emsg.version = be16_to_cpu(emsg_be->version);
+ emsg.flags = be16_to_cpu(emsg_be->flags);
+ emsg.event_code = event->code;
+ emsg.status = be32_to_cpu(emsg_be->status);
+ emsg.reason = be32_to_cpu(emsg_be->reason);
+ emsg.auth_type = be32_to_cpu(emsg_be->auth_type);
+ emsg.datalen = be32_to_cpu(emsg_be->datalen);
+ memcpy(emsg.addr, emsg_be->addr, ETH_ALEN);
+ memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname));
+ emsg.ifidx = emsg_be->ifidx;
+ emsg.bsscfgidx = emsg_be->bsscfgidx;
+
+ brcmf_dbg(EVENT, " version %u flags %u status %u reason %u\n",
+ emsg.version, emsg.flags, emsg.status, emsg.reason);
+ brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
+ min_t(u32, emsg.datalen, 64),
+ "appended:");
+
+ /* handle the event if valid interface and handler */
+ if (ifp->ndev && fweh->evt_handler[event->code])
+ err = fweh->evt_handler[event->code](ifp, &emsg,
+ event->data);
+ else
+ brcmf_dbg(ERROR, "unhandled event %d ignored\n",
+ event->code);
+ if (err) {
+ brcmf_dbg(ERROR, "event handler failed (%d)\n",
+ event->code);
+ err = 0;
+ }
+event_free:
+ kfree(event);
+ }
+}
+
+/**
+ * brcmf_fweh_attach() - initialize firmware event handling.
+ *
+ * @drvr: driver information object.
+ */
+void brcmf_fweh_attach(struct brcmf_pub *drvr)
+{
+ struct brcmf_fweh_info *fweh = &drvr->fweh;
+ INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);
+ spin_lock_init(&fweh->evt_q_lock);
+ INIT_LIST_HEAD(&fweh->event_q);
+}
+
+/**
+ * brcmf_fweh_detach() - cleanup firmware event handling.
+ *
+ * @drvr: driver information object.
+ */
+void brcmf_fweh_detach(struct brcmf_pub *drvr)
+{
+ struct brcmf_fweh_info *fweh = &drvr->fweh;
+ struct brcmf_if *ifp = drvr->iflist[0];
+ s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+
+ /* clear all events */
+ memset(eventmask, 0, BRCMF_EVENTING_MASK_LEN);
+ (void)brcmf_fil_iovar_data_set(ifp, "event_msgs",
+ eventmask, BRCMF_EVENTING_MASK_LEN);
+
+ /* cancel the worker */
+ cancel_work_sync(&fweh->event_work);
+ WARN_ON(!list_empty(&fweh->event_q));
+ memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
+}
+
+/**
+ * brcmf_fweh_register() - register handler for given event code.
+ *
+ * @drvr: driver information object.
+ * @code: event code.
+ * @handler: handler for the given event code.
+ */
+int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
+ brcmf_fweh_handler_t handler)
+{
+ if (drvr->fweh.evt_handler[code]) {
+ brcmf_dbg(ERROR, "event code %d already registered\n", code);
+ return -ENOSPC;
+ }
+ drvr->fweh.evt_handler[code] = handler;
+ brcmf_dbg(TRACE, "event handler registered for code %d\n", code);
+ return 0;
+}
+
+/**
+ * brcmf_fweh_unregister() - remove handler for given code.
+ *
+ * @drvr: driver information object.
+ * @code: event code.
+ */
+void brcmf_fweh_unregister(struct brcmf_pub *drvr,
+ enum brcmf_fweh_event_code code)
+{
+ brcmf_dbg(TRACE, "event handler cleared for code %d\n", code);
+ drvr->fweh.evt_handler[code] = NULL;
+}
+
+/**
+ * brcmf_fweh_activate_events() - enables firmware events registered.
+ *
+ * @ifp: primary interface object.
+ */
+int brcmf_fweh_activate_events(struct brcmf_if *ifp)
+{
+ int i, err;
+ s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+
+ for (i = 0; i < BRCMF_E_LAST; i++) {
+ if (ifp->drvr->fweh.evt_handler[i]) {
+ brcmf_dbg(EVENT, "enable event %s\n",
+ brcmf_fweh_event_name(i));
+ setbit(eventmask, i);
+ }
+ }
+
+ /* want to handle IF event as well */
+ setbit(eventmask, BRCMF_E_IF);
+
+ err = brcmf_fil_iovar_data_set(ifp, "event_msgs",
+ eventmask, BRCMF_EVENTING_MASK_LEN);
+ if (err)
+ brcmf_dbg(ERROR, "Set event_msgs error (%d)\n", err);
+
+ return err;
+}
+
+/**
+ * brcmf_fweh_process_event() - process skb as firmware event.
+ *
+ * @drvr: driver information object.
+ * @event_packet: event packet to process.
+ * @ifidx: index of the firmware interface (may change).
+ *
+ * If the packet buffer contains a firmware event message it will
+ * dispatch the event to a registered handler (using worker).
+ */
+void brcmf_fweh_process_event(struct brcmf_pub *drvr,
+ struct brcmf_event *event_packet, u8 *ifidx)
+{
+ enum brcmf_fweh_event_code code;
+
+ /* determine event code and interface index */
+ code = get_unaligned_be32(&event_packet->msg.event_type);
+ *ifidx = event_packet->msg.ifidx;
+
+ brcmf_fweh_queue_event(drvr->iflist[*ifidx], code, event_packet);
+}
--- /dev/null
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef FWEH_H_
+#define FWEH_H_
+
+#include <linux/unaligned/access_ok.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+
+/* formward declarations */
+struct brcmf_pub;
+struct brcmf_if;
+struct brcmf_cfg80211_info;
+struct brcmf_event;
+
+/* firmware event codes sent by the dongle */
+enum brcmf_fweh_event_code {
+ BRCMF_E_SET_SSID = 0,
+ BRCMF_E_JOIN = 1,
+ BRCMF_E_START = 2,
+ BRCMF_E_AUTH = 3,
+ BRCMF_E_AUTH_IND = 4,
+ BRCMF_E_DEAUTH = 5,
+ BRCMF_E_DEAUTH_IND = 6,
+ BRCMF_E_ASSOC = 7,
+ BRCMF_E_ASSOC_IND = 8,
+ BRCMF_E_REASSOC = 9,
+ BRCMF_E_REASSOC_IND = 10,
+ BRCMF_E_DISASSOC = 11,
+ BRCMF_E_DISASSOC_IND = 12,
+ BRCMF_E_QUIET_START = 13,
+ BRCMF_E_QUIET_END = 14,
+ BRCMF_E_BEACON_RX = 15,
+ BRCMF_E_LINK = 16,
+ BRCMF_E_MIC_ERROR = 17,
+ BRCMF_E_NDIS_LINK = 18,
+ BRCMF_E_ROAM = 19,
+ BRCMF_E_TXFAIL = 20,
+ BRCMF_E_PMKID_CACHE = 21,
+ BRCMF_E_RETROGRADE_TSF = 22,
+ BRCMF_E_PRUNE = 23,
+ BRCMF_E_AUTOAUTH = 24,
+ BRCMF_E_EAPOL_MSG = 25,
+ BRCMF_E_SCAN_COMPLETE = 26,
+ BRCMF_E_ADDTS_IND = 27,
+ BRCMF_E_DELTS_IND = 28,
+ BRCMF_E_BCNSENT_IND = 29,
+ BRCMF_E_BCNRX_MSG = 30,
+ BRCMF_E_BCNLOST_MSG = 31,
+ BRCMF_E_ROAM_PREP = 32,
+ BRCMF_E_PFN_NET_FOUND = 33,
+ BRCMF_E_PFN_NET_LOST = 34,
+ BRCMF_E_RESET_COMPLETE = 35,
+ BRCMF_E_JOIN_START = 36,
+ BRCMF_E_ROAM_START = 37,
+ BRCMF_E_ASSOC_START = 38,
+ BRCMF_E_IBSS_ASSOC = 39,
+ BRCMF_E_RADIO = 40,
+ BRCMF_E_PSM_WATCHDOG = 41,
+ BRCMF_E_PROBREQ_MSG = 44,
+ BRCMF_E_SCAN_CONFIRM_IND = 45,
+ BRCMF_E_PSK_SUP = 46,
+ BRCMF_E_COUNTRY_CODE_CHANGED = 47,
+ BRCMF_E_EXCEEDED_MEDIUM_TIME = 48,
+ BRCMF_E_ICV_ERROR = 49,
+ BRCMF_E_UNICAST_DECODE_ERROR = 50,
+ BRCMF_E_MULTICAST_DECODE_ERROR = 51,
+ BRCMF_E_TRACE = 52,
+ BRCMF_E_IF = 54,
+ BRCMF_E_RSSI = 56,
+ BRCMF_E_PFN_SCAN_COMPLETE = 57,
+ BRCMF_E_EXTLOG_MSG = 58,
+ BRCMF_E_ACTION_FRAME = 59,
+ BRCMF_E_ACTION_FRAME_COMPLETE = 60,
+ BRCMF_E_PRE_ASSOC_IND = 61,
+ BRCMF_E_PRE_REASSOC_IND = 62,
+ BRCMF_E_CHANNEL_ADOPTED = 63,
+ BRCMF_E_AP_STARTED = 64,
+ BRCMF_E_DFS_AP_STOP = 65,
+ BRCMF_E_DFS_AP_RESUME = 66,
+ BRCMF_E_ESCAN_RESULT = 69,
+ BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE = 70,
+ BRCMF_E_DCS_REQUEST = 73,
+ BRCMF_E_FIFO_CREDIT_MAP = 74,
+ BRCMF_E_LAST
+};
+
+/* flags field values in struct brcmf_event_msg */
+#define BRCMF_EVENT_MSG_LINK 0x01
+#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02
+#define BRCMF_EVENT_MSG_GROUP 0x04
+
+/**
+ * definitions for event packet validation.
+ */
+#define BRCMF_EVENT_OUI_OFFSET 19
+#define BRCM_OUI "\x00\x10\x18"
+#define DOT11_OUI_LEN 3
+#define BCMILCP_BCM_SUBTYPE_EVENT 1
+
+
+/**
+ * struct brcmf_event_msg - firmware event message.
+ *
+ * @version: version information.
+ * @flags: event flags.
+ * @event_code: firmware event code.
+ * @status: status information.
+ * @reason: reason code.
+ * @auth_type: authentication type.
+ * @datalen: lenght of event data buffer.
+ * @addr: ether address.
+ * @ifname: interface name.
+ * @ifidx: interface index.
+ * @bsscfgidx: bsscfg index.
+ */
+struct brcmf_event_msg {
+ u16 version;
+ u16 flags;
+ u32 event_code;
+ u32 status;
+ u32 reason;
+ s32 auth_type;
+ u32 datalen;
+ u8 addr[ETH_ALEN];
+ char ifname[IFNAMSIZ];
+ u8 ifidx;
+ u8 bsscfgidx;
+};
+
+typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *evtmsg,
+ void *data);
+
+/**
+ * struct brcmf_fweh_info - firmware event handling information.
+ *
+ * @event_work: event worker.
+ * @evt_q_lock: lock for event queue protection.
+ * @event_q: event queue.
+ * @evt_handler: registered event handlers.
+ */
+struct brcmf_fweh_info {
+ struct work_struct event_work;
+ struct spinlock evt_q_lock;
+ struct list_head event_q;
+ int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *evtmsg,
+ void *data);
+};
+
+void brcmf_fweh_attach(struct brcmf_pub *drvr);
+void brcmf_fweh_detach(struct brcmf_pub *drvr);
+int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
+ int (*handler)(struct brcmf_if *ifp,
+ const struct brcmf_event_msg *evtmsg,
+ void *data));
+void brcmf_fweh_unregister(struct brcmf_pub *drvr,
+ enum brcmf_fweh_event_code code);
+int brcmf_fweh_activate_events(struct brcmf_if *ifp);
+void brcmf_fweh_process_event(struct brcmf_pub *drvr,
+ struct brcmf_event *event_packet, u8 *ifidx);
+
+static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
+ struct sk_buff *skb, u8 *ifidx)
+{
+ struct brcmf_event *event_packet;
+ u8 *data;
+ u16 usr_stype;
+
+ /* only process events when protocol matches */
+ if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
+ return;
+
+ /* check for BRCM oui match */
+ event_packet = (struct brcmf_event *)skb_mac_header(skb);
+ data = (u8 *)event_packet;
+ data += BRCMF_EVENT_OUI_OFFSET;
+ if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
+ return;
+
+ /* final match on usr_subtype */
+ data += DOT11_OUI_LEN;
+ usr_stype = get_unaligned_be16(data);
+ if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
+ return;
+
+ brcmf_fweh_process_event(drvr, event_packet, ifidx);
+}
+
+#endif /* FWEH_H_ */
u32 i;
bool aborted;
- status = be32_to_cpu(e->status);
+ status = e->status;
if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
WL_ERR("scan not ready ndev %p drv_status %x\n", ndev,
static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
{
-
- cfg->el.handler[BRCMF_E_ESCAN_RESULT] =
- brcmf_cfg80211_escan_handler;
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
+ brcmf_cfg80211_escan_handler);
cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
/* Init scan_timeout timer */
init_timer(&cfg->escan_timeout);
WL_SCAN("Enter\n");
- if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) {
+ if (e->event_code == BRCMF_E_PFN_NET_LOST) {
WL_SCAN("PFN NET LOST event. Do Nothing\n");
return 0;
}
static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
const struct brcmf_event_msg *e)
{
- u32 event = be32_to_cpu(e->event_type);
- u32 status = be32_to_cpu(e->status);
+ u32 event = e->event_code;
+ u32 status = e->status;
if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
WL_CONN("Processing set ssid\n");
static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
const struct brcmf_event_msg *e)
{
- u32 event = be32_to_cpu(e->event_type);
- u16 flags = be16_to_cpu(e->flags);
+ u32 event = e->event_code;
+ u16 flags = e->flags;
if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
WL_CONN("Processing link down\n");
static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
const struct brcmf_event_msg *e)
{
- u32 event = be32_to_cpu(e->event_type);
- u32 status = be32_to_cpu(e->status);
+ u32 event = e->event_code;
+ u32 status = e->status;
if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
WL_CONN("Processing Link %s & no network found\n",
- be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
- "up" : "down");
+ e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
return true;
}
const struct brcmf_event_msg *e, void *data)
{
s32 err = 0;
- u32 event = be32_to_cpu(e->event_type);
- u32 reason = be32_to_cpu(e->reason);
- u32 len = be32_to_cpu(e->datalen);
+ u32 event = e->event_code;
+ u32 reason = e->reason;
+ u32 len = e->datalen;
static int generation;
struct station_info sinfo;
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
s32 err = 0;
- u32 event = be32_to_cpu(e->event_type);
- u32 status = be32_to_cpu(e->status);
+ u32 event = e->event_code;
+ u32 status = e->status;
if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
brcmf_notify_mic_status(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
- u16 flags = be16_to_cpu(e->flags);
+ u16 flags = e->flags;
enum nl80211_key_type key_type;
if (flags & BRCMF_EVENT_MSG_GROUP)
conf->tx_power = -1;
}
-static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
+static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
{
- memset(el, 0, sizeof(*el));
- el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status;
- el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status;
- el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status;
- el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status;
- el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status;
- el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status;
- el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status;
- el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status;
- el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
- el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results;
+ brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
+ brcmf_notify_roaming_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
+ brcmf_notify_mic_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
+ brcmf_notify_connect_status);
+ brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
+ brcmf_notify_sched_scan_results);
}
static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
return -ENOMEM;
}
-/*
-* retrieve first queued event from head
-*/
-
-static struct brcmf_cfg80211_event_q *brcmf_deq_event(
- struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_cfg80211_event_q *e = NULL;
-
- spin_lock_irq(&cfg->evt_q_lock);
- if (!list_empty(&cfg->evt_q_list)) {
- e = list_first_entry(&cfg->evt_q_list,
- struct brcmf_cfg80211_event_q, evt_q_list);
- list_del(&e->evt_q_list);
- }
- spin_unlock_irq(&cfg->evt_q_lock);
-
- return e;
-}
-
-/*
-* push event to tail of the queue
-*
-* remark: this function may not sleep as it is called in atomic context.
-*/
-
-static s32
-brcmf_enq_event(struct brcmf_if *ifp, u32 event,
- const struct brcmf_event_msg *msg, void *data)
-{
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- struct brcmf_cfg80211_event_q *e;
- s32 err = 0;
- ulong flags;
- u32 data_len;
- u32 total_len;
-
- total_len = sizeof(struct brcmf_cfg80211_event_q);
- if (data)
- data_len = be32_to_cpu(msg->datalen);
- else
- data_len = 0;
- total_len += data_len;
- e = kzalloc(total_len, GFP_ATOMIC);
- if (!e)
- return -ENOMEM;
-
- e->etype = event;
- e->ifp = ifp;
- memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
- if (data)
- memcpy(&e->edata, data, data_len);
-
- spin_lock_irqsave(&cfg->evt_q_lock, flags);
- list_add_tail(&e->evt_q_list, &cfg->evt_q_list);
- spin_unlock_irqrestore(&cfg->evt_q_lock, flags);
-
- return err;
-}
-
-static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
-{
- kfree(e);
-}
-
-static void brcmf_cfg80211_event_handler(struct work_struct *work)
-{
- struct brcmf_cfg80211_info *cfg =
- container_of(work, struct brcmf_cfg80211_info,
- event_work);
- struct brcmf_cfg80211_event_q *e;
-
- e = brcmf_deq_event(cfg);
- if (unlikely(!e)) {
- WL_ERR("event queue empty...\n");
- return;
- }
-
- do {
- WL_INFO("event type (%d)\n", e->etype);
- if (cfg->el.handler[e->etype])
- cfg->el.handler[e->etype](e->ifp, &e->emsg, e->edata);
- else
- WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
- brcmf_put_event(e);
- } while ((e = brcmf_deq_event(cfg)));
-
-}
-
-static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg)
-{
- spin_lock_init(&cfg->evt_q_lock);
- INIT_LIST_HEAD(&cfg->evt_q_list);
-}
-
-static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg)
-{
- struct brcmf_cfg80211_event_q *e;
-
- spin_lock_irq(&cfg->evt_q_lock);
- while (!list_empty(&cfg->evt_q_list)) {
- e = list_first_entry(&cfg->evt_q_list,
- struct brcmf_cfg80211_event_q, evt_q_list);
- list_del(&e->evt_q_list);
- kfree(e);
- }
- spin_unlock_irq(&cfg->evt_q_lock);
-}
-
static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
{
s32 err = 0;
cfg->active_scan = true; /* we do active scan for
specific scan per default */
cfg->dongle_up = false; /* dongle is not up yet */
- brcmf_init_eq(cfg);
err = brcmf_init_priv_mem(cfg);
if (err)
return err;
- INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler);
- brcmf_init_eloop_handler(&cfg->el);
+ brcmf_register_event_handlers(cfg);
mutex_init(&cfg->usr_sync);
brcmf_init_escan(cfg);
brcmf_init_conf(cfg->conf);
static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
{
- cancel_work_sync(&cfg->event_work);
cfg->dongle_up = false; /* dongle down */
- brcmf_flush_eq(cfg);
brcmf_link_down(cfg);
brcmf_abort_scanning(cfg);
brcmf_deinit_priv_mem(cfg);
}
}
-void brcmf_cfg80211_event(struct brcmf_if *ifp,
- const struct brcmf_event_msg *e, void *data)
-{
- struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
- u32 event_type = be32_to_cpu(e->event_type);
-
- if (!brcmf_enq_event(ifp, event_type, e, data))
- schedule_work(&cfg->event_work);
-}
-
-static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
-{
- s8 eventmask[BRCMF_EVENTING_MASK_LEN];
- s32 err = 0;
-
- WL_TRACE("Enter\n");
-
- /* Setup event_msgs */
- err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs",
- eventmask, BRCMF_EVENTING_MASK_LEN);
- if (err) {
- WL_ERR("Get event_msgs error (%d)\n", err);
- goto dongle_eventmsg_out;
- }
-
- setbit(eventmask, BRCMF_E_SET_SSID);
- setbit(eventmask, BRCMF_E_ROAM);
- setbit(eventmask, BRCMF_E_PRUNE);
- setbit(eventmask, BRCMF_E_AUTH);
- setbit(eventmask, BRCMF_E_REASSOC);
- setbit(eventmask, BRCMF_E_REASSOC_IND);
- setbit(eventmask, BRCMF_E_DEAUTH_IND);
- setbit(eventmask, BRCMF_E_DISASSOC_IND);
- setbit(eventmask, BRCMF_E_DISASSOC);
- setbit(eventmask, BRCMF_E_JOIN);
- setbit(eventmask, BRCMF_E_ASSOC_IND);
- setbit(eventmask, BRCMF_E_PSK_SUP);
- setbit(eventmask, BRCMF_E_LINK);
- setbit(eventmask, BRCMF_E_NDIS_LINK);
- setbit(eventmask, BRCMF_E_MIC_ERROR);
- setbit(eventmask, BRCMF_E_PMKID_CACHE);
- setbit(eventmask, BRCMF_E_TXFAIL);
- setbit(eventmask, BRCMF_E_JOIN_START);
- setbit(eventmask, BRCMF_E_ESCAN_RESULT);
- setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
-
- err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs",
- eventmask, BRCMF_EVENTING_MASK_LEN);
- if (err) {
- WL_ERR("Set event_msgs error (%d)\n", err);
- goto dongle_eventmsg_out;
- }
-
-dongle_eventmsg_out:
- WL_TRACE("Exit\n");
- return err;
-}
-
static s32
brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
{
brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
- err = brcmf_dongle_eventmsg(ndev);
- if (err)
- goto default_conf_out;
-
power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
power_mode);
struct list_head list;
};
-/* forward declaration */
-struct brcmf_cfg80211_info;
-
-/* cfg80211 main event loop */
-struct brcmf_cfg80211_event_loop {
- s32(*handler[BRCMF_E_LAST]) (struct brcmf_if *ifp,
- const struct brcmf_event_msg *e,
- void *data);
-};
-
-/* event queue for cfg80211 main event */
-struct brcmf_cfg80211_event_q {
- struct list_head evt_q_list;
- u32 etype;
- struct brcmf_if *ifp;
- struct brcmf_event_msg emsg;
- s8 edata[1];
-};
-
/* association inform */
struct brcmf_cfg80211_connect_info {
u8 *req_ie;
* @wiphy: wiphy object for cfg80211 interface.
* @conf: dongle configuration.
* @scan_request: cfg80211 scan request object.
- * @el: main event loop.
- * @evt_q_list: used for event queue.
- * @evt_q_lock: for event queue synchronization.
* @usr_sync: mainly for dongle up/down synchronization.
* @bss_list: bss_list holding scanned ap information.
* @scan_req_int: internal scan request object.
* @ie: information element object for internal purpose.
* @conn_info: association info.
* @pmk_list: wpa2 pmk list.
- * @event_work: event handler work struct.
* @scan_status: scan activity on the dongle.
* @pub: common driver information.
* @channel: current channel.
struct wiphy *wiphy;
struct brcmf_cfg80211_conf *conf;
struct cfg80211_scan_request *scan_request;
- struct brcmf_cfg80211_event_loop el;
- struct list_head evt_q_list;
- spinlock_t evt_q_lock;
struct mutex usr_sync;
struct brcmf_scan_results *bss_list;
struct brcmf_cfg80211_scan_req scan_req_int;
struct brcmf_cfg80211_ie ie;
struct brcmf_cfg80211_connect_info conn_info;
struct brcmf_cfg80211_pmk_list *pmk_list;
- struct work_struct event_work;
unsigned long scan_status;
struct brcmf_pub *pub;
u32 channel;
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr);
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
-
-/* event handler from dongle */
-void brcmf_cfg80211_event(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
- void *data);
s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg);