Porting WiFi drivers to Android

Porting WiFi drivers to Android



PaNiC Random Rant (or how we used to call it: .plan)

Thursday, April 29, 2010
Porting WiFi drivers to Android

For mini-box.com picoPC we want to support several USB and miniPCI WiFi dongles, this guide provides a step by step explanation of what's involved in adding a new wifi driver and making wifi work in a custom Android build  (this guide was written for android 2.1 but should be applicable to previous android releases and hopefully future releases).

Contents

0. Understand how Android WiFi works.
1. Enable building of wpa_supplicant in your BoardConfig.mk
2. (Optional) Enable debug for wpa_supplicant.
3. Provide a proper wpa_supplicant.conf for your device
4. Have the correct paths and permissions created from init.rc
5. Make sure your wpa_supplicant and dhcpcd (optional) are starting from init.rc
6. Provide your driver either as a module or built in kernel and proper kernel support for it and modify Android source code accordingly.
7. Provide a firmware if your module needs it.
8. Make your driver work with Android custom wpa_supplicant commands and SIOCSIWPRIV ioctl

Now onto details.


0. Understand how Android WiFi works.

Android uses a modified wpa_supplicant (external/wpa_supplicant) daemon for wifi support which is controlled through a socket by hardware/libhardware_legacy/wifi/wifi.c that gets controlled from Android UI through android.net.wifi package from frameworks/base/wifi/java/android/net/wifi/ and it's corresponding jni implementation in frameworks/base/core/jni/android_net_wifi_Wifi.cpp. Higher level network management is done in frameworks/base/core/java/android/net


1. Enable building of wpa_supplicant in your BoardConfig.mk

This is by simply adding: BOARD_WPA_SUPPLICANT_DRIVER := WEXT
to your BoardConfig.mk. This will set  WPA_BUILD_SUPPLICANT to true in
external/wpa_supplicant/Android.mk enabling building of driver_wext.c
If you have a custom wpa_supplicant driver (like madwifi) you can set in BOARD_WPA_SUPPLICANT_DRIVER := MADWIFI.


2. (Optional) Enable debug for wpa_supplicant.

By default wpa_supplicant is set to MSG_INFO that doesn't tell much. To enable more messages:
  2.1 modify common.c and set wpa_debug_level = MSG_DEBUG
  2.2 modify common.h and change #define wpa_printf from #ifdef ANDROID to if ((level) >= MSG_DEBUG) instead of if ((level) >= MSG_INFO)

3. Provide a proper wpa_supplicant.conf for your device

Providing a wpa_supplicant.conf it's important because the control socket for android is specified in this file (ctrl_interface= ). This file should be copied by your AndroidBoard.mk to $(TARGET_OUT_ETC)/wifi (basically /system/etc/wifi/wpa_supplicant.conf).
This location should be double checked on init.rc for service wpa_supplicant as the wpa_supplicant config file.

Minimum required config options in wpa_supplicant.conf :

ctrl_interface=DIR=/data/system/wpa_supplicant GROUP=wifi
update_config=1

Depending on your driver you might also want to add:

ap_scan=1

If you have AP association problems with should change to ap_scan=0 to let the driver do the association instead of wpa_supplicant.

If you want to let wpa_supplicant connect to non-WPA or open wireless networks (by default it skips these kind) add:

network={
key_mgmt=NONE
}

4. Have the correct permissions and paths created from init.rc

Incorrect permisions will result in wpa_supplicant not being able to create/open the control socket and libhardware_legacy/wifi/wifi.c won't connect.
Since Google modified wpa_supplicant to run as wifi user/group the directory structure and file ownership should belong to wifi user/group (see os_program_init() function in wpa_supplicant/os_unix.c).

Otherwise errors like:

E/WifiHW  (  ): Unable to open connection to supplicant on "/data/system/wpa_supplicant/wlan0": No such file or directory will appear.

Also wpa_supplicant.conf should belong to user/group wifi because wpa_supplicant will want to modify this file. If your system has /system as read-only use a location like /data/misc/wifi/wpa_supplicant.conf and modify wpa_supplicant service in init.rc with new location.

Make sure the paths are correctly created in init.rc:

mkdir /system/etc/wifi 0770 wifi wifi
chmod 0770 /system/etc/wifi
chmod 0660 /system/etc/wifi/wpa_supplicant.conf
chown wifi wifi /system/etc/wifi/wpa_supplicant.conf
# wpa_supplicant socket
mkdir /data/system/wpa_supplicant 0771 wifi wifi
chmod 0771 /data/system/wpa_supplicant
#wpa_supplicant control socket for android wifi.c
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
chmod 0770 /data/misc/wifi
chmod 0660 /data/misc/wifi/wpa_supplicant.conf

5. Make sure your wpa_supplicant and dhcpcd are starting from init.rc

For wpa_supplicant the init.rc startup like should be:

service wpa_supplicant /system/bin/wpa_supplicant -dd -Dwext -iwlan0 -c /system/etc/wifi/wpa_supplicant.conf
group system wifi inet
disabled
oneshot

If your wifi driver creates a wifi interface with other name then wlan0 you will have to modify the above line accordingly.

You also should have dhcpcd starting from init.rc
service dhcpcd /system/bin/dhcpcd wlan0
group system dhcp
disabled
oneshot

6. Provide your driver either as a module or built in kernel and proper kernel support for it.

 First make sure that  CONFIG_PACKET and CONFIG_NET_RADIO (wireless extensions) are enabled in your kernel. The driver can be built as module (default android way) or built in kernel (if you want to rely in kernel auto probing to support multiple driver eg. USB wifi) but will require source code modifications (see below).

 - As kernel module:

   Define in your BoardConfig.mk:

   1. WIFI_DRIVER_MODULE_PATH :=
       You need to specify module name in that path too, usually should look something like /system/lib/modules/wlan.ko

   2.  WIFI_DRIVER_MODULE_NAME:= for example wlan0

   3. WIFI_DRIVER_MODULE_ARG:= for example nohwcrypt

 
   Make sure you copy your kernel module when building android to the correct location.


- As built in kernel:

  - First init.rc needs to be modified to inform hardware/libhardware_legacy/wifi/wifi.c about the name of the interface, that the driver  is already loaded and set the status of wpa_supplicant to running:

setprop wifi.interface "wlan0"
setprop wlan.driver.status "ok"
setprop init.svc.wpa_supplicant "running"

 - Secondly hardware/libhardware_legacy/wifi/wifi.c need to be modified so the functions to insmod/rmmod return 0 (simply add return 0; as the first line in functions since they are not needed when driver is built in kernel) and return before checking for /proc/modules in  check_driver_loaded() function.


 7. Provide a firmware if your driver needs it

If your driver needs a firmware you will have to copy this firmware file to /etc/firmware on your android build. Android doesn't use a standard hotplug binary (although there is an implementation available on android-x86 system/code/toolbox/hotplug.c) instead the init process takes care of firmware events and loads the firmware file from /etc/firmware (see: system/core/init/devices.c handle_firmware_event() function).
Firmware file name is defined by the driver and might also contain a folder like: RTL8192SU/rtl8192sfw.bin, entire file path should be available in /etc/firmware.


8. Make your driver work with Android custom wpa_supplicant commands and SIOCSIWPRIV ioctl.

 Android uses SIOCSIWPRIV ioctl to send commands to driver and receive information like signal strength, mac address of the AP, link speed. This ioctl is usually not implemented in any known wireless drivers except bcm4329 which is in google msm kernel branch.

The errors from not having this ioctl implemented will look like:

E/wpa_supplicant(  ): wpa_driver_priv_driver_cmd failed wpa_driver_priv_driver_cmd RSSI len = 4096
E/wpa_supplicant(  ): wpa_driver_priv_driver_cmd failed
D/wpa_supplicant(  ): wpa_driver_priv_driver_cmd LINKSPEED len = 4096
E/wpa_supplicant(  ): wpa_driver_priv_driver_cmd failed
I/wpa_supplicant(  ): CTRL-EVENT-DRIVER-STATE HANGED

After 4, WEXT_NUMBER_SEQUENTIAL_ERRORS errors android will abort using the device.

To quickly test your wifi from interface you can disable error checking in external/wpa_supplicant/driver_wext.c by simply making ret = 0; in wpa_driver_priv_driver_cmd() function after the ioctl call. This will make all access points in android UI appear without signal or MAC address.

To proper implement the ioctl you will need to modify your kernel driver to reply to SIOCSIWPRIV ioctl with RSSI (signal strength) and MACADDR commands being the most important.

A better way is to add a custom driver_xxx.c to google external/wpa_supplicant/ implementing wpa_driver_priv_driver_cmd() function that will take care of RSSI and MACADDR  through a call to SIOCGIWSTATS ioctl and the rest of the functions can be called from driver_wext.c.

Below is a link to a patch for wpa_supplicant that I did for mini-box.com picoPC Android build. It creates a new driver awext which "emulates" android driver commands using wireless extensions ioctls.

How to use the new driver:

1. In your BoardConfig.mk define: BOARD_WPA_SUPPLICANT_DRIVER := AWEXT
2. Change init.rc wpa_supplicant service command line by replacind -Dwext with -Dawext



Patch download:  0001-Added-a-separate-driver-awext-to-emulate-Android-dri.patch

From c4efbcdfaa18c4c10bd52e4900f33b91bb412c1f Mon Sep 17 00:00:00 2001
From: Nicu Pavel <root@droids.(none)>
Date: Wed, 5 May 2010 23:43:15 +0300
Subject: [PATCH] Added a separate driver(awext) to emulate Android driver commands.

Change-Id: Ieb59015a62916b34a677e191b9df329eaaa30814
---
 Android.mk     |    6 +
 driver_awext.c |  907 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 driver_awext.h |   88 ++++++
 3 files changed, 1001 insertions(+), 0 deletions(-)
 create mode 100644 driver_awext.c
 create mode 100644 driver_awext.h

diff --git a/Android.mk b/Android.mk
index 04f559f..238b970 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,6 +90,12 @@ OBJS_d += driver_hostap.c
 CONFIG_WIRELESS_EXTENSION=y
 endif
 
+ifdef CONFIG_DRIVER_AWEXT
+L_CFLAGS += -DCONFIG_DRIVER_AWEXT
+OBJS_d += driver_awext.c
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
 ifdef CONFIG_DRIVER_WEXT
 L_CFLAGS += -DCONFIG_DRIVER_WEXT
 CONFIG_WIRELESS_EXTENSION=y
diff --git a/driver_awext.c b/driver_awext.c
new file mode 100644
index 0000000..b0d9c32
--- /dev/null
+++ b/driver_awext.c
@@ -0,0 +1,907 @@
+/*
+ * 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 "wpa_supplicant.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 */
+    void *ctx;
+    char ifname[IFNAMSIZ + 1];
+    int ioctl_sock;
+    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->ifname, IFNAMSIZ);
+    iwr.u.param.flags = idx & IW_AUTH_INDEX;
+    iwr.u.param.value = value;
+
+    if (ioctl(drv->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->ifname, IFNAMSIZ);
+    iwr.u.data.pointer = (caddr_t) ie;
+    iwr.u.data.length = ie_len;
+
+    if (ioctl(drv->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->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->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->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->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->ifname, IFNAMSIZ);
+    i = (int *) iwr.u.name;
+    *i++ = PRISM2_PARAM_USER_SPACE_MLME;
+    *i++ = 1;
+
+    if (ioctl(drv->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->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->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->ctx = ctx;
+   
+    os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
+    drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+    if (drv->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->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);
+}
+
+int wpa_driver_awext_get_scan_results(void *priv,
+                     struct wpa_scan_result *results,
+                     size_t max_size)
+{
+    struct wpa_driver_awext_data *drv = priv;
+    return wpa_driver_wext_get_scan_results(drv->wext, results, max_size);
+}
+
+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;
+
+    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");
+    }
+    else if (os_strcasecmp(cmd, "macaddr") == 0) {
+        struct ifreq ifr;
+        os_memset(&ifr, 0, sizeof(ifr));
+        os_strncpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
+
+        if (ioctl(drv->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->ifname, IFNAMSIZ);
+        wpa_printf(MSG_DEBUG,"Link Speed command");
+        if (ioctl(drv->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->ifname, IFNAMSIZ);
+
+        if (ioctl(drv->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->ifname, IFNAMSIZ);
+
+        if (ioctl(drv->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->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->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->ifname, IFNAMSIZ);
+
+        if (ioctl(drv->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_results = 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
+};
diff --git a/driver_awext.h b/driver_awext.h
new file mode 100644
index 0000000..363d52d
--- /dev/null
+++ b/driver_awext.h
@@ -0,0 +1,88 @@
+/*
+ * WPA Supplicant - driver_wext exported functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * 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.
+ */
+
+#ifndef DRIVER_AWEXT_H
+#define DRIVER_AWEXT_H
+
+#include "driver_wext.h"
+
+struct wpa_driver_wext_data {
+    void *ctx;
+    int event_sock;
+    int ioctl_sock;
+    int mlme_sock;
+    char ifname[IFNAMSIZ + 1];
+    int ifindex;
+    int ifindex2;
+    int if_removed;
+    u8 *assoc_req_ies;
+    size_t assoc_req_ies_len;
+    u8 *assoc_resp_ies;
+    size_t assoc_resp_ies_len;
+    struct wpa_driver_capa capa;
+    int has_capability;
+    int we_version_compiled;
+
+    /* for set_auth_alg fallback */
+    int use_crypt;
+    int auth_alg_fallback;
+
+    int operstate;
+
+    char mlmedev[IFNAMSIZ + 1];
+
+    int scan_complete_events;
+    int errors;
+};
+
+struct wpa_driver_awext_data;
+
+int wpa_driver_awext_get_ifflags(void *priv, int *flags);
+int wpa_driver_awext_set_ifflags(struct wpa_driver_awext_data *drv, int flags);
+int wpa_driver_awext_get_bssid(void *priv, u8 *bssid);
+int wpa_driver_awext_set_bssid(void *priv, const u8 *bssid);
+int wpa_driver_awext_get_ssid(void *priv, u8 *ssid);
+int wpa_driver_awext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_awext_set_freq(void *priv, int freq);
+int wpa_driver_awext_set_mode(void *priv, int mode);
+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);
+int wpa_driver_awext_scan(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_awext_get_scan_results(void *priv,
+                     struct wpa_scan_result *results,
+                     size_t max_size);
+
+void wpa_driver_awext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+int wpa_driver_awext_alternative_ifindex(struct wpa_driver_awext_data *drv,
+                    const char *ifname);
+
+void * wpa_driver_awext_init(void *ctx, const char *ifname);
+void wpa_driver_awext_deinit(void *priv);
+
+int wpa_driver_awext_set_operstate(void *priv, int state);
+int wpa_driver_awext_get_version(struct wpa_driver_awext_data *drv);
+
+#ifdef ANDROID
+#define WEXT_NUMBER_SCAN_CHANNELS_FCC    11
+#define WEXT_NUMBER_SCAN_CHANNELS_ETSI    13
+#define WEXT_NUMBER_SCAN_CHANNELS_MKK1    14
+
+#define WPA_DRIVER_WEXT_WAIT_US        400000
+#define MAX_DRV_CMD_SIZE        248
+#endif
+
+#endif /* DRIVER_AWEXT_H */
--
1.6.3.3




From c4efbcdfaa18c4c10bd52e4900f33b91bb412c1f Mon Sep 17 00:00:00 2001
From: Nicu Pavel <root@droids.(none)>
Date: Wed, 5 May 2010 23:43:15 +0300
Subject: [PATCH] Added a separate driver(awext) to emulate Android driver commands.

Change-Id: Ieb59015a62916b34a677e191b9df329eaaa30814
---
 Android.mk     |    6 +
 driver_awext.c |  907 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 driver_awext.h |   88 ++++++
 3 files changed, 1001 insertions(+), 0 deletions(-)
 create mode 100644 driver_awext.c
 create mode 100644 driver_awext.h

diff --git a/Android.mk b/Android.mk
index 04f559f..238b970 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,6 +90,12 @@ OBJS_d += driver_hostap.c
 CONFIG_WIRELESS_EXTENSION=y
 endif
 
+ifdef CONFIG_DRIVER_AWEXT
+L_CFLAGS += -DCONFIG_DRIVER_AWEXT
+OBJS_d += driver_awext.c
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
 ifdef CONFIG_DRIVER_WEXT
 L_CFLAGS += -DCONFIG_DRIVER_WEXT
 CONFIG_WIRELESS_EXTENSION=y
diff --git a/driver_awext.c b/driver_awext.c
new file mode 100644
index 0000000..b0d9c32
--- /dev/null
+++ b/driver_awext.c
@@ -0,0 +1,907 @@
+/*
+ * 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 "wpa_supplicant.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 */
+    void *ctx;
+    char ifname[IFNAMSIZ + 1];
+    int ioctl_sock;
+    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->ifname, IFNAMSIZ);
+    iwr.u.param.flags = idx & IW_AUTH_INDEX;
+    iwr.u.param.value = value;
+
+    if (ioctl(drv->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->ifname, IFNAMSIZ);
+    iwr.u.data.pointer = (caddr_t) ie;
+    iwr.u.data.length = ie_len;
+
+    if (ioctl(drv->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->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->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->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->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->ifname, IFNAMSIZ);
+    i = (int *) iwr.u.name;
+    *i++ = PRISM2_PARAM_USER_SPACE_MLME;
+    *i++ = 1;
+
+    if (ioctl(drv->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->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->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->ctx = ctx;
+   
+    os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
+    drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+    if (drv->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->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);
+}
+
+int wpa_driver_awext_get_scan_results(void *priv,
+                     struct wpa_scan_result *results,
+                     size_t max_size)
+{
+    struct wpa_driver_awext_data *drv = priv;
+    return wpa_driver_wext_get_scan_results(drv->wext, results, max_size);
+}
+
+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;
+
+    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");
+    }
+    else if (os_strcasecmp(cmd, "macaddr") == 0) {
+        struct ifreq ifr;
+        os_memset(&ifr, 0, sizeof(ifr));
+        os_strncpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
+
+        if (ioctl(drv->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->ifname, IFNAMSIZ);
+        wpa_printf(MSG_DEBUG,"Link Speed command");
+        if (ioctl(drv->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->ifname, IFNAMSIZ);
+
+        if (ioctl(drv->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->ifname, IFNAMSIZ);
+
+        if (ioctl(drv->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->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->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->ifname, IFNAMSIZ);
+
+        if (ioctl(drv->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_results = 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
+};
diff --git a/driver_awext.h b/driver_awext.h
new file mode 100644
index 0000000..363d52d
--- /dev/null
+++ b/driver_awext.h
@@ -0,0 +1,88 @@
+/*
+ * WPA Supplicant - driver_wext exported functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * 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.
+ */
+
+#ifndef DRIVER_AWEXT_H
+#define DRIVER_AWEXT_H
+
+#include "driver_wext.h"
+
+struct wpa_driver_wext_data {
+    void *ctx;
+    int event_sock;
+    int ioctl_sock;
+    int mlme_sock;
+    char ifname[IFNAMSIZ + 1];
+    int ifindex;
+    int ifindex2;
+    int if_removed;
+    u8 *assoc_req_ies;
+    size_t assoc_req_ies_len;
+    u8 *assoc_resp_ies;
+    size_t assoc_resp_ies_len;
+    struct wpa_driver_capa capa;
+    int has_capability;
+    int we_version_compiled;
+
+    /* for set_auth_alg fallback */
+    int use_crypt;
+    int auth_alg_fallback;
+
+    int operstate;
+
+    char mlmedev[IFNAMSIZ + 1];
+
+    int scan_complete_events;
+    int errors;
+};
+
+struct wpa_driver_awext_data;
+
+int wpa_driver_awext_get_ifflags(void *priv, int *flags);
+int wpa_driver_awext_set_ifflags(struct wpa_driver_awext_data *drv, int flags);
+int wpa_driver_awext_get_bssid(void *priv, u8 *bssid);
+int wpa_driver_awext_set_bssid(void *priv, const u8 *bssid);
+int wpa_driver_awext_get_ssid(void *priv, u8 *ssid);
+int wpa_driver_awext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_awext_set_freq(void *priv, int freq);
+int wpa_driver_awext_set_mode(void *priv, int mode);
+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);
+int wpa_driver_awext_scan(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_awext_get_scan_results(void *priv,
+                     struct wpa_scan_result *results,
+                     size_t max_size);
+
+void wpa_driver_awext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+int wpa_driver_awext_alternative_ifindex(struct wpa_driver_awext_data *drv,
+                    const char *ifname);
+
+void * wpa_driver_awext_init(void *ctx, const char *ifname);
+void wpa_driver_awext_deinit(void *priv);
+
+int wpa_driver_awext_set_operstate(void *priv, int state);
+int wpa_driver_awext_get_version(struct wpa_driver_awext_data *drv);
+
+#ifdef ANDROID
+#define WEXT_NUMBER_SCAN_CHANNELS_FCC    11
+#define WEXT_NUMBER_SCAN_CHANNELS_ETSI    13
+#define WEXT_NUMBER_SCAN_CHANNELS_MKK1    14
+
+#define WPA_DRIVER_WEXT_WAIT_US        400000
+#define MAX_DRV_CMD_SIZE        248
+#endif
+
+#endif /* DRIVER_AWEXT_H */
--
1.6.3.3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值