Merged the hostap_2.6 updates, and the Leap of Faith work, from the hostap_update...
[mech_eap.git] / libeap / src / drivers / driver_nl80211_android.c
diff --git a/libeap/src/drivers/driver_nl80211_android.c b/libeap/src/drivers/driver_nl80211_android.c
new file mode 100644 (file)
index 0000000..ba47888
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Android specific
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <fcntl.h>
+
+#include "utils/common.h"
+#include "driver_nl80211.h"
+#include "android_drv.h"
+
+
+typedef struct android_wifi_priv_cmd {
+       char *buf;
+       int used_len;
+       int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+       drv_errors++;
+       if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+               drv_errors = 0;
+               wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+       }
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ifreq ifr;
+       android_wifi_priv_cmd priv_cmd;
+       char buf[MAX_DRV_CMD_SIZE];
+       int ret;
+
+       os_memset(&ifr, 0, sizeof(ifr));
+       os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+       os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+       os_memset(buf, 0, sizeof(buf));
+       os_strlcpy(buf, cmd, sizeof(buf));
+
+       priv_cmd.buf = buf;
+       priv_cmd.used_len = sizeof(buf);
+       priv_cmd.total_len = sizeof(buf);
+       ifr.ifr_data = &priv_cmd;
+
+       ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+                          __func__);
+               wpa_driver_send_hang_msg(drv);
+               return ret;
+       }
+
+       drv_errors = 0;
+       return 0;
+}
+
+
+int android_pno_start(struct i802_bss *bss,
+                     struct wpa_driver_scan_params *params)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       struct ifreq ifr;
+       android_wifi_priv_cmd priv_cmd;
+       int ret = 0, i = 0, bp;
+       char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+       bp = WEXT_PNOSETUP_HEADER_SIZE;
+       os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+       buf[bp++] = WEXT_PNO_TLV_PREFIX;
+       buf[bp++] = WEXT_PNO_TLV_VERSION;
+       buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+       buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+       while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+               /* Check that there is enough space needed for 1 more SSID, the
+                * other sections and null termination */
+               if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+                    WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+                       break;
+               wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+                                 params->ssids[i].ssid,
+                                 params->ssids[i].ssid_len);
+               buf[bp++] = WEXT_PNO_SSID_SECTION;
+               buf[bp++] = params->ssids[i].ssid_len;
+               os_memcpy(&buf[bp], params->ssids[i].ssid,
+                         params->ssids[i].ssid_len);
+               bp += params->ssids[i].ssid_len;
+               i++;
+       }
+
+       buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+                   WEXT_PNO_SCAN_INTERVAL);
+       bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+       buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+                   WEXT_PNO_REPEAT);
+       bp += WEXT_PNO_REPEAT_LENGTH;
+
+       buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+       os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+                   WEXT_PNO_MAX_REPEAT);
+       bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+       memset(&ifr, 0, sizeof(ifr));
+       memset(&priv_cmd, 0, sizeof(priv_cmd));
+       os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+       priv_cmd.buf = buf;
+       priv_cmd.used_len = bp;
+       priv_cmd.total_len = bp;
+       ifr.ifr_data = &priv_cmd;
+
+       ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+       if (ret < 0) {
+               wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+                          ret);
+               wpa_driver_send_hang_msg(drv);
+               return ret;
+       }
+
+       drv_errors = 0;
+
+       return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+int android_pno_stop(struct i802_bss *bss)
+{
+       return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+
+#ifdef ANDROID_P2P
+#ifdef ANDROID_LIB_STUB
+
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
+{
+       return 0;
+}
+
+
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
+{
+       return 0;
+}
+
+
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
+{
+       return -1;
+}
+
+
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+                                const struct wpabuf *proberesp,
+                                const struct wpabuf *assocresp)
+{
+       return 0;
+}
+
+#endif /* ANDROID_LIB_STUB */
+#endif /* ANDROID_P2P */
+
+
+int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+       return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+
+