| /* |
| * --------------------------------------------------------------------------- |
| * 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() */ |
| |