/* * --------------------------------------------------------------------------- * FILE: wext_events.c * * PURPOSE: * Code to generate iwevents. * * Copyright (C) 2006-2008 by Cambridge Silicon Radio Ltd. * * Refer to LICENSE.txt included with this source code for details on * the license terms. * * --------------------------------------------------------------------------- */ #include <linux/types.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> #include "csr_wifi_hip_unifi.h" #include "unifi_priv.h" /* * --------------------------------------------------------------------------- * wext_send_assoc_event * * Send wireless-extension events up to userland to announce * successful association with an AP. * * Arguments: * priv Pointer to driver context. * bssid MAC address of AP we associated with * req_ie, req_ie_len IEs in the original request * resp_ie, resp_ie_len IEs in the response * * Returns: * None. * * Notes: * This is sent on first successful association, and again if we * roam to another AP. * --------------------------------------------------------------------------- */ void wext_send_assoc_event(unifi_priv_t *priv, unsigned char *bssid, unsigned char *req_ie, int req_ie_len, unsigned char *resp_ie, int resp_ie_len, unsigned char *scan_ie, unsigned int scan_ie_len) { #if WIRELESS_EXT > 17 union iwreq_data wrqu; if (req_ie_len == 0) req_ie = NULL; wrqu.data.length = req_ie_len; wrqu.data.flags = 0; wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVASSOCREQIE, &wrqu, req_ie); if (resp_ie_len == 0) resp_ie = NULL; wrqu.data.length = resp_ie_len; wrqu.data.flags = 0; wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVASSOCRESPIE, &wrqu, resp_ie); if (scan_ie_len > 0) { wrqu.data.length = scan_ie_len; wrqu.data.flags = 0; wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVGENIE, &wrqu, scan_ie); } memcpy(&wrqu.ap_addr.sa_data, bssid, ETH_ALEN); wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWAP, &wrqu, NULL); #endif } /* wext_send_assoc_event() */ /* * --------------------------------------------------------------------------- * wext_send_disassoc_event * * Send a wireless-extension event up to userland to announce * that we disassociated from an AP. * * Arguments: * priv Pointer to driver context. * * Returns: * None. * * Notes: * The semantics of wpa_supplicant (the userland SME application) are * that a SIOCGIWAP event with MAC address of all zero means * disassociate. * --------------------------------------------------------------------------- */ void wext_send_disassoc_event(unifi_priv_t *priv) { #if WIRELESS_EXT > 17 union iwreq_data wrqu; memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWAP, &wrqu, NULL); #endif } /* wext_send_disassoc_event() */ /* * --------------------------------------------------------------------------- * wext_send_scan_results_event * * Send wireless-extension events up to userland to announce * completion of a scan. * * Arguments: * priv Pointer to driver context. * * Returns: * None. * * Notes: * This doesn't actually report the results, they are retrieved * using the SIOCGIWSCAN ioctl command. * --------------------------------------------------------------------------- */ void wext_send_scan_results_event(unifi_priv_t *priv) { #if WIRELESS_EXT > 17 union iwreq_data wrqu; wrqu.data.length = 0; wrqu.data.flags = 0; wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], SIOCGIWSCAN, &wrqu, NULL); #endif } /* wext_send_scan_results_event() */ /* * --------------------------------------------------------------------------- * wext_send_michaelmicfailure_event * * Send wireless-extension events up to userland to announce * completion of a scan. * * Arguments: * priv Pointer to driver context. * count, macaddr, key_type, key_idx, tsc * Parameters from report from UniFi. * * Returns: * None. * --------------------------------------------------------------------------- */ #if WIRELESS_EXT >= 18 static inline void _send_michaelmicfailure_event(struct net_device *dev, int count, const unsigned char *macaddr, int key_type, int key_idx, unsigned char *tsc) { union iwreq_data wrqu; struct iw_michaelmicfailure mmf; memset(&mmf, 0, sizeof(mmf)); mmf.flags = key_idx & IW_MICFAILURE_KEY_ID; if (key_type == CSR_GROUP) { mmf.flags |= IW_MICFAILURE_GROUP; } else { mmf.flags |= IW_MICFAILURE_PAIRWISE; } mmf.flags |= ((count << 5) & IW_MICFAILURE_COUNT); mmf.src_addr.sa_family = ARPHRD_ETHER; memcpy(mmf.src_addr.sa_data, macaddr, ETH_ALEN); memcpy(mmf.tsc, tsc, IW_ENCODE_SEQ_MAX_SIZE); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = sizeof(mmf); wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&mmf); } #elif WIRELESS_EXT >= 15 static inline void _send_michaelmicfailure_event(struct net_device *dev, int count, const unsigned char *macaddr, int key_type, int key_idx, unsigned char *tsc) { union iwreq_data wrqu; char buf[128]; sprintf(buf, "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%pM)", key_idx, (key_type == CSR_GROUP) ? "broad" : "uni", macaddr); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); } #else /* WIRELESS_EXT >= 15 */ static inline void _send_michaelmicfailure_event(struct net_device *dev, int count, const unsigned char *macaddr, int key_type, int key_idx, unsigned char *tsc) { /* Not supported before WEXT 15 */ } #endif /* WIRELESS_EXT >= 15 */ void wext_send_michaelmicfailure_event(unifi_priv_t *priv, u16 count, CsrWifiMacAddress address, CsrWifiSmeKeyType keyType, u16 interfaceTag) { unsigned char tsc[8] = {0}; if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { unifi_error(priv, "wext_send_michaelmicfailure_event bad interfaceTag\n"); return; } _send_michaelmicfailure_event(priv->netdev[interfaceTag], count, address.a, keyType, 0, tsc); } /* wext_send_michaelmicfailure_event() */ void wext_send_pmkid_candidate_event(unifi_priv_t *priv, CsrWifiMacAddress bssid, u8 preauth_allowed, u16 interfaceTag) { #if WIRELESS_EXT > 17 union iwreq_data wrqu; struct iw_pmkid_cand pmkid_cand; if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) { unifi_error(priv, "wext_send_pmkid_candidate_event bad interfaceTag\n"); return; } memset(&pmkid_cand, 0, sizeof(pmkid_cand)); if (preauth_allowed) { pmkid_cand.flags |= IW_PMKID_CAND_PREAUTH; } pmkid_cand.bssid.sa_family = ARPHRD_ETHER; memcpy(pmkid_cand.bssid.sa_data, bssid.a, ETH_ALEN); /* Used as priority, smaller the number higher the priority, not really used in our case */ pmkid_cand.index = 1; memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = sizeof(pmkid_cand); wireless_send_event(priv->netdev[interfaceTag], IWEVPMKIDCAND, &wrqu, (char *)&pmkid_cand); #endif } /* wext_send_pmkid_candidate_event() */ /* * Send a custom WEXT event to say we have completed initialisation * and are now ready for WEXT ioctls. Used by Android wpa_supplicant. */ void wext_send_started_event(unifi_priv_t *priv) { #if WIRELESS_EXT > 17 union iwreq_data wrqu; char data[] = "STARTED"; wrqu.data.length = sizeof(data); wrqu.data.flags = 0; wireless_send_event(priv->netdev[CSR_WIFI_INTERFACE_IN_USE], IWEVCUSTOM, &wrqu, data); #endif } /* wext_send_started_event() */