--- /dev/null
+/*
+ * WEXT Emulation for Android SIOCSIWPRIV ioctl with generic Linux Wireless Extensions
+ * Copyright (c) 2010, Nicu Pavel <npavel@linuxconsulting.ro>
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * Code based on Jim Huang <jserv@0xlab.org> e9bd7cc3d137eb56ebd4220d4077563743ab6723
+ * patch for 0xdroid
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "l2_packet.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "driver_awext.h"
+#include "wpa.h"
+#include "wpa_ctrl.h"
+#include "wpa_supplicant_i.h"
+#include "config_ssid.h"
+
+#ifdef CONFIG_CLIENT_MLME
+#include <netpacket/packet.h>
+#include <hostapd_ioctl.h>
+#include <ieee80211_common.h>
+/* from net/mac80211.h */
+enum {
+ MODE_IEEE80211A = 0 /* IEEE 802.11a */,
+ MODE_IEEE80211B = 1 /* IEEE 802.11b only */,
+ MODE_ATHEROS_TURBO = 2 /* Atheros Turbo mode (2x.11a at 5 GHz) */,
+ MODE_IEEE80211G = 3 /* IEEE 802.11g (and 802.11b compatibility) */,
+ MODE_ATHEROS_TURBOG = 4 /* Atheros Turbo mode (2x.11g at 2.4 GHz) */,
+ NUM_IEEE80211_MODES = 5
+};
+
+#include "mlme.h"
+
+#ifndef ETH_P_ALL
+#define ETH_P_ALL 0x0003
+#endif
+#endif /* CONFIG_CLIENT_MLME */
+
+struct wpa_driver_awext_data {
+ struct wpa_driver_wext_data *wext; /* structure for wext */
+ u8 ssid[32];
+ unsigned int ssid_len;
+};
+
+static int wpa_driver_awext_set_auth_param(struct wpa_driver_awext_data *drv,
+ int idx, u32 value)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->wext->ifname, IFNAMSIZ);
+ iwr.u.param.flags = idx & IW_AUTH_INDEX;
+ iwr.u.param.value = value;
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ }
+
+ return ret;
+}
+
+static int wpa_driver_awext_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ int algs = 0, res;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= IW_AUTH_ALG_SHARED_KEY;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= IW_AUTH_ALG_LEAP;
+ if (algs == 0) {
+ /* at least one algorithm should be set */
+ algs = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+
+ res = wpa_driver_awext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG, algs);
+ drv->wext->auth_alg_fallback = res == -2;
+ return res;
+}
+
+static int wpa_driver_awext_set_gen_ie(void *priv, const u8 *ie,
+ size_t ie_len)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->wext->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) ie;
+ iwr.u.data.length = ie_len;
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWGENIE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int wpa_driver_awext_cipher2wext(int cipher)
+{
+ switch (cipher) {
+ case CIPHER_NONE:
+ return IW_AUTH_CIPHER_NONE;
+ case CIPHER_WEP40:
+ return IW_AUTH_CIPHER_WEP40;
+ case CIPHER_TKIP:
+ return IW_AUTH_CIPHER_TKIP;
+ case CIPHER_CCMP:
+ return IW_AUTH_CIPHER_CCMP;
+ case CIPHER_WEP104:
+ return IW_AUTH_CIPHER_WEP104;
+ default:
+ return 0;
+ }
+}
+
+
+static int wpa_driver_awext_keymgmt2wext(int keymgmt)
+{
+ switch (keymgmt) {
+ case KEY_MGMT_802_1X:
+ case KEY_MGMT_802_1X_NO_WPA:
+ return IW_AUTH_KEY_MGMT_802_1X;
+ case KEY_MGMT_PSK:
+ return IW_AUTH_KEY_MGMT_PSK;
+ default:
+ return 0;
+ }
+}
+
+
+static int
+wpa_driver_awext_auth_alg_fallback(struct wpa_driver_awext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->wext->ifname, IFNAMSIZ);
+ /* Just changing mode, not actual keys */
+ iwr.u.encoding.flags = 0;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+
+ /*
+ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+ * different things. Here they are used to indicate Open System vs.
+ * Shared Key authentication algorithm. However, some drivers may use
+ * them to select between open/restricted WEP encrypted (open = allow
+ * both unencrypted and encrypted frames; restricted = only allow
+ * encrypted frames).
+ */
+
+ if (!drv->wext->use_crypt) {
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+ if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+ }
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+
+static int
+wpa_driver_awext_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+ int value, flags;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (wpa_driver_awext_get_ifflags(drv, &flags) == 0) {
+ if (!(flags & IFF_UP)) {
+ wpa_driver_awext_set_ifflags(drv, flags | IFF_UP);
+ }
+ }
+
+ /*
+ * If the driver did not support SIOCSIWAUTH, fallback to
+ * SIOCSIWENCODE here.
+ */
+ if (drv->wext->auth_alg_fallback &&
+ wpa_driver_awext_auth_alg_fallback(drv, params) < 0)
+ ret = -1;
+
+ if (!params->bssid &&
+ wpa_driver_awext_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ if (wpa_driver_awext_set_mode(drv, params->mode) < 0)
+ ret = -1;
+ /* TODO: should consider getting wpa version and cipher/key_mgmt suites
+ * from configuration, not from here, where only the selected suite is
+ * available */
+ if (wpa_driver_awext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+ < 0)
+ ret = -1;
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+// else if (params->wpa_ie[0] == RSN_INFO_ELEM)
+// value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_awext_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_awext_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_awext_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_awext_cipher2wext(params->group_suite);
+ if (wpa_driver_awext_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_awext_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_awext_set_auth_param(drv,
+ IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+ value = params->key_mgmt_suite != KEY_MGMT_NONE ||
+ params->pairwise_suite != CIPHER_NONE ||
+ params->group_suite != CIPHER_NONE ||
+ params->wpa_ie_len;
+ if (wpa_driver_awext_set_auth_param(drv,
+ IW_AUTH_PRIVACY_INVOKED, value) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (wpa_driver_awext_set_auth_param(drv,
+ IW_AUTH_RX_UNENCRYPTED_EAPOL,
+ allow_unencrypted_eapol) < 0)
+ ret = -1;
+ if (params->freq && wpa_driver_awext_set_freq(drv, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_awext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
+ if (params->bssid &&
+ wpa_driver_awext_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_awext_set_countermeasures(void *priv,
+ int enabled)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_awext_set_auth_param(drv,
+ IW_AUTH_TKIP_COUNTERMEASURES,
+ enabled);
+}
+
+static int wpa_driver_awext_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ drv->wext->use_crypt = enabled;
+ return wpa_driver_awext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+ enabled);
+}
+
+static int wpa_driver_awext_mlme(struct wpa_driver_awext_data *drv,
+ const u8 *addr, int cmd, int reason_code)
+{
+ struct iwreq iwr;
+ struct iw_mlme mlme;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->wext->ifname, IFNAMSIZ);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.cmd = cmd;
+ mlme.reason_code = reason_code;
+ mlme.addr.sa_family = ARPHRD_ETHER;
+ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+ iwr.u.data.pointer = (caddr_t) &mlme;
+ iwr.u.data.length = sizeof(mlme);
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMLME]");
+ ret = -1;
+ }
+
+ return ret;
+}
+#ifdef CONFIG_CLIENT_MLME
+static int wpa_driver_awext_open_mlme(struct wpa_driver_awext_data *drv)
+{
+ int flags, ifindex, s, *i;
+ struct sockaddr_ll addr;
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->wext->ifname, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = PRISM2_PARAM_USER_SPACE_MLME;
+ *i++ = 1;
+
+ if (ioctl(drv->wext->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
+ wpa_printf(MSG_ERROR, "WEXT: Failed to configure driver to "
+ "use user space MLME");
+ return -1;
+ }
+
+ ifindex = if_nametoindex(drv->wext->mlmedev);
+ if (ifindex == 0) {
+ wpa_printf(MSG_ERROR, "WEXT: mlmedev='%s' not found",
+ drv->mlmedev);
+ return -1;
+ }
+
+ if (wpa_driver_awext_get_ifflags_ifname(drv, drv->wext->mlmedev, &flags) != 0
+ || wpa_driver_awext_set_ifflags_ifname(drv, drv->wext->mlmedev,
+ flags | IFF_UP) != 0) {
+ wpa_printf(MSG_ERROR, "WEXT: Could not set interface "
+ "'%s' UP", drv->mlmedev);
+ return -1;
+ }
+
+ s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (s < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifindex;
+
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(MLME)");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(s, wpa_driver_awext_mlme_read, drv, NULL))
+ {
+ wpa_printf(MSG_ERROR, "WEXT: Could not register MLME read "
+ "socket");
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+
+#endif /* CONFIG_CLIENT_MLME */
+
+static int wpa_driver_awext_pmksa(struct wpa_driver_awext_data *drv,
+ u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+ struct iwreq iwr;
+ struct iw_pmksa pmksa;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->wext->ifname, IFNAMSIZ);
+ os_memset(&pmksa, 0, sizeof(pmksa));
+ pmksa.cmd = cmd;
+ pmksa.bssid.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+ if (pmkid)
+ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+ iwr.u.data.pointer = (caddr_t) &pmksa;
+ iwr.u.data.length = sizeof(pmksa);
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+ if (errno != EOPNOTSUPP)
+ perror("ioctl[SIOCSIWPMKSA]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int wpa_driver_awext_add_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_awext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+}
+
+
+static int wpa_driver_awext_remove_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_awext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+}
+
+
+static int wpa_driver_awext_flush_pmkid(void *priv)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_awext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+static int wpa_driver_awext_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ if (!drv->wext->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->wext->capa, sizeof(*capa));
+ return 0;
+}
+
+
+static int wpa_driver_awext_set_param(void *priv, const char *param)
+{
+#ifdef CONFIG_CLIENT_MLME
+ struct wpa_driver_awext_data *drv = priv;
+ const char *pos, *pos2;
+ size_t len;
+
+ if (param == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+
+ pos = os_strstr(param, "mlmedev=");
+ if (pos) {
+ pos += 8;
+ pos2 = os_strchr(pos, ' ');
+ if (pos2)
+ len = pos2 - pos;
+ else
+ len = os_strlen(pos);
+ if (len + 1 > sizeof(drv->wext->mlmedev))
+ return -1;
+ os_memcpy(drv->wext->mlmedev, pos, len);
+ drv->wext->mlmedev[len] = '\0';
+ wpa_printf(MSG_DEBUG, "WEXT: Using user space MLME with "
+ "mlmedev='%s'", drv->wext->mlmedev);
+ drv->wext->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+
+ drv->wext->mlme_sock = wpa_driver_awext_open_mlme(drv->wext);
+ if (drv->wext->mlme_sock < 0)
+ return -1;
+ }
+#endif /* CONFIG_CLIENT_MLME */
+
+ return 0;
+}
+
+static int wpa_driver_awext_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_awext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+}
+
+static int wpa_driver_awext_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_awext_mlme(drv, addr, IW_MLME_DISASSOC,
+ reason_code);
+}
+
+int wpa_driver_awext_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+int wpa_driver_awext_set_bssid(void *priv, const u8 *bssid)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_set_bssid(drv->wext, bssid);
+}
+
+int wpa_driver_awext_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+int wpa_driver_awext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_awext_data *drv = priv;
+
+ if (ssid_len > 32)
+ return -1;
+
+ os_memset(drv->ssid, 0, 32);
+ os_memcpy(drv->ssid, ssid, ssid_len);
+ drv->ssid_len = ssid_len;
+
+ return wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len);
+}
+
+int wpa_driver_awext_set_freq(void *priv, int freq)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_set_freq(drv->wext, freq);
+}
+
+int wpa_driver_awext_get_ifflags(void *priv, int *flags)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_get_ifflags(drv->wext, flags);
+}
+
+int wpa_driver_awext_set_ifflags(struct wpa_driver_awext_data *drv, int flags)
+{
+ return wpa_driver_wext_set_ifflags(drv->wext, flags);
+}
+
+void * wpa_driver_awext_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_awext_data *drv;
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL)
+ {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->wext->ctx = ctx;
+
+ os_strncpy(drv->wext->ifname, ifname, sizeof(drv->wext->ifname));
+ drv->wext->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->wext->ioctl_sock < 0)
+ {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+void wpa_driver_awext_deinit(void *priv)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->wext->ioctl_sock);
+ os_free(drv);
+}
+
+void wpa_driver_awext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ return wpa_driver_wext_scan_timeout(eloop_ctx, timeout_ctx);
+}
+
+int wpa_driver_awext_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+struct wpa_scan_result * wpa_driver_awext_get_scan_results(void *priv)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+int wpa_driver_awext_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_set_key(drv->wext, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len);
+}
+
+int wpa_driver_awext_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_set_mode(drv->wext, mode);
+}
+
+int wpa_driver_awext_alternative_ifindex(struct wpa_driver_awext_data *drv,
+ const char *ifname)
+{
+ return wpa_driver_wext_alternative_ifindex(drv->wext, ifname);
+}
+
+int wpa_driver_awext_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+int wpa_driver_awext_set_channel(void *priv, wpa_hw_mode phymode, int chan,
+ int freq)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_awext_set_freq(drv->wext, freq);
+}
+
+int wpa_driver_awext_get_version(struct wpa_driver_awext_data *drv)
+{
+ return wpa_driver_wext_get_version(drv->wext);
+}
+
+int wpa_driver_awext_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_awext_data *drv = priv;
+ return wpa_driver_awext_set_auth_param(drv, IW_AUTH_WPA_ENABLED, enabled);
+}
+
+#ifdef ANDROID
+static int wpa_driver_priv_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len)
+{
+
+ struct wpa_driver_awext_data *drv = priv;
+ int ret = -1;
+ int flags;
+
+ wpa_printf(MSG_DEBUG, "AWEXT: %s %s", __func__, cmd);
+
+ if (os_strcasecmp(cmd, "start") == 0) {
+ wpa_printf(MSG_DEBUG,"Start command");
+ return (ret);
+ }
+
+ if (os_strcasecmp(cmd, "stop") == 0) {
+ wpa_printf(MSG_DEBUG,"Stop command");
+ if ((wpa_driver_awext_get_ifflags(drv, &flags) == 0) &&
+ (flags & IFF_UP)) {
+ wpa_printf(MSG_ERROR, "WEXT: %s when iface is UP", cmd);
+ wpa_driver_awext_set_ifflags(drv, flags & ~IFF_UP);
+ }
+
+ }
+ else if (os_strcasecmp(cmd, "reload") == 0) {
+ wpa_printf(MSG_DEBUG,"Reload command");
+ wpa_msg(drv->wext->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+ return ret;
+ }
+ else if (os_strcasecmp(cmd, "macaddr") == 0) {
+ struct ifreq ifr;
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strncpy(ifr.ifr_name, drv->wext->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCGIFHWADDR, &ifr) < 0) {
+ perror("ioctl[SIOCGIFHWADDR]");
+ ret = -1;
+ } else {
+ u8 *macaddr = (u8 *) ifr.ifr_hwaddr.sa_data;
+ ret = snprintf(buf, buf_len, "Macaddr = " MACSTR "\n",
+ MAC2STR(macaddr));
+ }
+ }
+ else if (os_strcasecmp(cmd, "scan-passive") == 0) {
+ wpa_printf(MSG_DEBUG,"Scan Passive command");
+ }
+ else if (os_strcasecmp(cmd, "scan-active") == 0) {
+ wpa_printf(MSG_DEBUG,"Scan Active command");
+ }
+ else if (os_strcasecmp(cmd, "linkspeed") == 0) {
+ struct iwreq wrq;
+ unsigned int linkspeed;
+ os_strncpy(wrq.ifr_name, drv->wext->ifname, IFNAMSIZ);
+ wpa_printf(MSG_DEBUG,"Link Speed command");
+ if (ioctl(drv->wext->ioctl_sock, SIOCGIWRATE, &wrq) < 0) {
+ perror("ioctl[SIOCGIWRATE]");
+ ret = -1;
+ } else {
+ linkspeed = wrq.u.bitrate.value / 1000000;
+ ret = snprintf(buf, buf_len, "LinkSpeed %d\n", linkspeed);
+ }
+ }
+ else if (os_strncasecmp(cmd, "scan-channels", 13) == 0) {
+ }
+ else if ((os_strcasecmp(cmd, "rssi") == 0) || (os_strcasecmp(cmd, "rssi-approx") == 0)) {
+ struct iwreq wrq;
+ struct iw_statistics stats;
+ signed int rssi;
+ wpa_printf(MSG_DEBUG, ">>>. DRIVER AWEXT RSSI ");
+ wrq.u.data.pointer = (caddr_t) &stats;
+ wrq.u.data.length = sizeof(stats);
+ wrq.u.data.flags = 1; /* Clear updated flag */
+ strncpy(wrq.ifr_name, drv->wext->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCGIWSTATS, &wrq) < 0) {
+ perror("ioctl[SIOCGIWSTATS]");
+ ret = -1;
+ } else {
+ if (stats.qual.updated & IW_QUAL_DBM) {
+ /* Values in dBm, stored in u8 with range 63 : -192 */
+ rssi = ( stats.qual.level > 63 ) ?
+ stats.qual.level - 0x100 :
+ stats.qual.level;
+ } else {
+ rssi = stats.qual.level;
+ }
+
+ if (drv->ssid_len != 0 && drv->ssid_len < buf_len) {
+ os_memcpy((void *) buf, (void *) (drv->ssid),
+ drv->ssid_len );
+ ret = drv->ssid_len;
+ ret += snprintf(&buf[ret], buf_len-ret,
+ " rssi %d\n", rssi);
+ if (ret < (int)buf_len) {
+ return( ret );
+ }
+ ret = -1;
+ }
+ }
+ }
+ else if (os_strncasecmp(cmd, "powermode", 9) == 0) {
+ }
+ else if (os_strncasecmp(cmd, "getpower", 8) == 0) {
+ }
+ else if (os_strncasecmp(cmd, "get-rts-threshold", 17) == 0) {
+ struct iwreq wrq;
+ unsigned int rtsThreshold;
+
+ strncpy(wrq.ifr_name, drv->wext->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCGIWRTS, &wrq) < 0) {
+ perror("ioctl[SIOCGIWRTS]");
+ ret = -1;
+ } else {
+ rtsThreshold = wrq.u.rts.value;
+ wpa_printf(MSG_DEBUG,"Get RTS Threshold command = %d",
+ rtsThreshold);
+ ret = snprintf(buf, buf_len, "rts-threshold = %u\n",
+ rtsThreshold);
+ if (ret < (int)buf_len) {
+ return( ret );
+ }
+ }
+ }
+ else if (os_strncasecmp(cmd, "set-rts-threshold", 17) == 0) {
+ struct iwreq wrq;
+ unsigned int rtsThreshold;
+ char *cp = cmd + 17;
+ char *endp;
+
+ strncpy(wrq.ifr_name, drv->wext->ifname, IFNAMSIZ);
+
+ if (*cp != '\0') {
+ rtsThreshold = (unsigned int)strtol(cp, &endp, 0);
+ if (endp != cp) {
+ wrq.u.rts.value = rtsThreshold;
+ wrq.u.rts.fixed = 1;
+ wrq.u.rts.disabled = 0;
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCSIWRTS, &wrq) < 0) {
+ perror("ioctl[SIOCGIWRTS]");
+ ret = -1;
+ } else {
+ rtsThreshold = wrq.u.rts.value;
+ wpa_printf(MSG_DEBUG,"Set RTS Threshold command = %d", rtsThreshold);
+ ret = 0;
+ }
+ }
+ }
+ }
+ else if (os_strcasecmp(cmd, "btcoexscan-start") == 0) {
+ }
+ else if (os_strcasecmp(cmd, "btcoexscan-stop") == 0) {
+ }
+ else if (os_strcasecmp(cmd, "rxfilter-start") == 0) {
+ wpa_printf(MSG_DEBUG,"Rx Data Filter Start command");
+ }
+ else if (os_strcasecmp(cmd, "rxfilter-stop") == 0) {
+ wpa_printf(MSG_DEBUG,"Rx Data Filter Stop command");
+ }
+ else if (os_strcasecmp(cmd, "rxfilter-statistics") == 0) {
+ }
+ else if (os_strncasecmp(cmd, "rxfilter-add", 12) == 0 ) {
+ }
+ else if (os_strncasecmp(cmd, "rxfilter-remove",15) == 0) {
+ }
+ else if (os_strcasecmp(cmd, "snr") == 0) {
+ struct iwreq wrq;
+ struct iw_statistics stats;
+ int snr, rssi, noise;
+
+ wrq.u.data.pointer = (caddr_t) &stats;
+ wrq.u.data.length = sizeof(stats);
+ wrq.u.data.flags = 1; /* Clear updated flag */
+ strncpy(wrq.ifr_name, drv->wext->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->wext->ioctl_sock, SIOCGIWSTATS, &wrq) < 0) {
+ perror("ioctl[SIOCGIWSTATS]");
+ ret = -1;
+ } else {
+ if (stats.qual.updated & IW_QUAL_DBM) {
+ /* Values in dBm, stored in u8 with range 63 : -192 */
+ rssi = ( stats.qual.level > 63 ) ?
+ stats.qual.level - 0x100 :
+ stats.qual.level;
+ noise = ( stats.qual.noise > 63 ) ?
+ stats.qual.noise - 0x100 :
+ stats.qual.noise;
+ } else {
+ rssi = stats.qual.level;
+ noise = stats.qual.noise;
+ }
+
+ snr = rssi - noise;
+
+ ret = snprintf(buf, buf_len, "snr = %u\n", (unsigned int)snr);
+ if (ret < (int)buf_len) {
+ return( ret );
+ }
+ }
+ }
+ else if (os_strncasecmp(cmd, "btcoexmode", 10) == 0) {
+ }
+ else if( os_strcasecmp(cmd, "btcoexstat") == 0 ) {
+ }
+ else {
+ wpa_printf(MSG_DEBUG,"Unsupported command");
+ }
+ return (ret);
+}
+#endif
+
+const struct wpa_driver_ops wpa_driver_awext_ops = {
+ .name = "awext",
+ .desc = "Android wireless extensions emulation",
+ .get_bssid = wpa_driver_awext_get_bssid,
+ .get_ssid = wpa_driver_awext_get_ssid,
+ .set_wpa = wpa_driver_awext_set_wpa,
+ .set_key = wpa_driver_awext_set_key,
+ .set_countermeasures = wpa_driver_awext_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_awext_set_drop_unencrypted,
+ .scan = wpa_driver_awext_scan,
+ .get_scan_results2 = wpa_driver_awext_get_scan_results,
+ .deauthenticate = wpa_driver_awext_deauthenticate,
+ .disassociate = wpa_driver_awext_disassociate,
+ .associate = wpa_driver_awext_associate,
+ .set_auth_alg = wpa_driver_awext_set_auth_alg,
+ .init = wpa_driver_awext_init,
+ .deinit = wpa_driver_awext_deinit,
+
+ .set_param = wpa_driver_awext_set_param,
+ .add_pmkid = wpa_driver_awext_add_pmkid,
+ .remove_pmkid = wpa_driver_awext_remove_pmkid,
+ .flush_pmkid = wpa_driver_awext_flush_pmkid,
+ .get_capa = wpa_driver_awext_get_capa,
+ .set_operstate = wpa_driver_awext_set_operstate,
+#ifdef CONFIG_CLIENT_MLME
+ .get_hw_feature_data = wpa_driver_awext_get_hw_feature_data,
+ .set_channel = wpa_driver_awext_set_channel,
+ .set_ssid = wpa_driver_awext_set_ssid,
+ .set_bssid = wpa_driver_awext_set_bssid,
+ .send_mlme = wpa_driver_awext_send_mlme,
+ .mlme_add_sta = wpa_driver_awext_mlme_add_sta,
+ .mlme_remove_sta = wpa_driver_awext_mlme_remove_sta,
+#endif /* CONFIG_CLIENT_MLME */
+#ifdef ANDROID
+ .driver_cmd = wpa_driver_priv_driver_cmd,
+#endif
+};