wpa_supplicant: Initial Revision 0.8.X

Based on:
commit 0725cc7b7efc434910e89865c42eda7ce61bbf08
Author: Jouni Malinen <j@w1.fi>
Date:   Thu Apr 21 20:41:01 2011 +0300

    Enable CONFIG_DRIVER_NL80211=y in the default configuration

    nl80211 should be preferred over WEXT with any recent Linux
    kernel version.

Change-Id: I26aec5afbbd4f4a1f5fd900912545b6f5050de64
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m
new file mode 100644
index 0000000..8213fda
--- /dev/null
+++ b/src/drivers/driver_iphone.m
@@ -0,0 +1,466 @@
+/*
+ * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
+ * Copyright (c) 2007, 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.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+
+#include "MobileApple80211.h"
+
+struct wpa_driver_iphone_data {
+	void *ctx;
+	Apple80211Ref wireless_ctx;
+	CFArrayRef scan_results;
+	int ctrl_power;
+};
+
+
+static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
+{
+	const void *res;
+	CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
+						    kCFStringEncodingMacRoman);
+	if (str == NULL)
+		return NULL;
+
+	res = CFDictionaryGetValue(dict, str);
+	CFRelease(str);
+	return res;
+}
+
+
+static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	CFDataRef data;
+	int err, len;
+
+	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
+				  &data);
+	if (err != 0) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
+			   "failed: %d", err);
+		return -1;
+	}
+
+	len = CFDataGetLength(data);
+	if (len > 32) {
+		CFRelease(data);
+		return -1;
+	}
+	os_memcpy(ssid, CFDataGetBytePtr(data), len);
+	CFRelease(data);
+
+	return len;
+}
+
+
+static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	CFStringRef data;
+	int err;
+	int a1, a2, a3, a4, a5, a6;
+
+	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
+				  &data);
+	if (err != 0) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
+			   "failed: %d", err);
+		return -1;
+	}
+
+	sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
+	       "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
+	bssid[0] = a1;
+	bssid[1] = a2;
+	bssid[2] = a3;
+	bssid[3] = a4;
+	bssid[4] = a5;
+	bssid[5] = a6;
+
+	CFRelease(data);
+
+	return 0;
+}
+
+
+static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	int err;
+
+	if (drv->scan_results) {
+		CFRelease(drv->scan_results);
+		drv->scan_results = NULL;
+	}
+
+	err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
+			   err);
+		return -1;
+	}
+
+	eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
+			       drv->ctx);
+	return 0;
+}
+
+
+static int wpa_driver_iphone_get_scan_results(void *priv,
+					      struct wpa_scan_result *results,
+					      size_t max_size)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	size_t i, num;
+
+	if (drv->scan_results == NULL)
+		return 0;
+
+	num = CFArrayGetCount(drv->scan_results);
+	if (num > max_size)
+		num = max_size;
+	os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+	for (i = 0; i < num; i++) {
+		struct wpa_scan_result *res = &results[i];
+		CFDictionaryRef dict =
+			CFArrayGetValueAtIndex(drv->scan_results, i);
+		CFDataRef data;
+		CFStringRef str;
+		CFNumberRef num;
+		int val;
+
+		data = cfdict_get_key_str(dict, "SSID");
+		if (data) {
+			res->ssid_len = CFDataGetLength(data);
+			if (res->ssid_len > 32)
+				res->ssid_len = 32;
+			os_memcpy(res->ssid, CFDataGetBytePtr(data),
+				  res->ssid_len);
+		}
+
+		str = cfdict_get_key_str(dict, "BSSID");
+		if (str) {
+			int a1, a2, a3, a4, a5, a6;
+			sscanf(CFStringGetCStringPtr(
+				       str, kCFStringEncodingMacRoman),
+			       "%x:%x:%x:%x:%x:%x",
+			       &a1, &a2, &a3, &a4, &a5, &a6);
+			res->bssid[0] = a1;
+			res->bssid[1] = a2;
+			res->bssid[2] = a3;
+			res->bssid[3] = a4;
+			res->bssid[4] = a5;
+			res->bssid[5] = a6;
+		}
+
+		num = cfdict_get_key_str(dict, "CAPABILITIES");
+		if (num) {
+			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+				res->caps = val;
+		}
+
+		num = cfdict_get_key_str(dict, "CHANNEL");
+		if (num) {
+			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+				res->freq = 2407 + val * 5;
+		}
+
+		num = cfdict_get_key_str(dict, "RSSI");
+		if (num) {
+			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+				res->level = val;
+		}
+
+		num = cfdict_get_key_str(dict, "NOISE");
+		if (num) {
+			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+				res->noise = val;
+		}
+
+		data = cfdict_get_key_str(dict, "IE");
+		if (data) {
+			u8 *ptr = (u8 *) CFDataGetBytePtr(data);
+			int len = CFDataGetLength(data);
+			u8 *pos = ptr, *end = ptr + len;
+
+			while (pos + 2 < end) {
+				if (pos + 2 + pos[1] > end)
+					break;
+				if (pos[0] == WLAN_EID_RSN &&
+				    pos[1] <= SSID_MAX_WPA_IE_LEN) {
+					os_memcpy(res->rsn_ie, pos,
+						  2 + pos[1]);
+					res->rsn_ie_len = 2 + pos[1];
+				}
+				if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+				    pos[1] > 4 && pos[2] == 0x00 &&
+				    pos[3] == 0x50 && pos[4] == 0xf2 &&
+				    pos[5] == 0x01) {
+					os_memcpy(res->wpa_ie, pos,
+						  2 + pos[1]);
+					res->wpa_ie_len = 2 + pos[1];
+				}
+
+				pos = pos + 2 + pos[1];
+			}
+		}
+	}
+
+	return num;
+}
+
+
+static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_iphone_data *drv = eloop_ctx;
+	u8 bssid[ETH_ALEN];
+
+	if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
+		eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
+				       drv, drv->ctx);
+		return;
+	}
+
+	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_iphone_associate(
+	void *priv, struct wpa_driver_associate_params *params)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	int i, num, err;
+	size_t ssid_len;
+	CFDictionaryRef bss = NULL;
+
+	/*
+	 * TODO: Consider generating parameters instead of just using an entry
+	 * from scan results in order to support ap_scan=2.
+	 */
+
+	if (drv->scan_results == NULL) {
+		wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
+			   "associate");
+		return -1;
+	}
+
+	num = CFArrayGetCount(drv->scan_results);
+
+	for (i = 0; i < num; i++) {
+		CFDictionaryRef dict =
+			CFArrayGetValueAtIndex(drv->scan_results, i);
+		CFDataRef data;
+
+		data = cfdict_get_key_str(dict, "SSID");
+		if (data == NULL)
+			continue;
+
+		ssid_len = CFDataGetLength(data);
+		if (ssid_len != params->ssid_len ||
+		    os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
+		    != 0)
+			continue;
+
+		bss = dict;
+		break;
+	}
+
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
+			   "results - cannot associate");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
+		   "from scan results");
+
+	err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
+			   "%d", err);
+		return -1;
+	}
+
+	/*
+	 * Driver is actually already associated; report association from an
+	 * eloop callback.
+	 */
+	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+	eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
+			       drv->ctx);
+
+	return 0;
+}
+
+
+static int wpa_driver_iphone_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)
+{
+	/*
+	 * TODO: Need to either support configuring PMK for 4-way handshake or
+	 * PTK for TKIP/CCMP.
+	 */
+	return -1;
+}
+
+
+static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	os_memset(capa, 0, sizeof(*capa));
+
+	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+		WPA_DRIVER_AUTH_LEAP;
+	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+	return 0;
+}
+
+
+static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
+{
+	struct wpa_driver_iphone_data *drv;
+	int err;
+	char power;
+	CFStringRef name;
+	CFDictionaryRef dict;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	drv->ctx = ctx;
+	err = Apple80211Open(&drv->wireless_ctx);
+	if (err) {
+		wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
+			   err);
+		os_free(drv);
+		return NULL;
+	}
+
+	name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
+					 kCFStringEncodingISOLatin1);
+	if (name == NULL) {
+		wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
+		Apple80211Close(drv->wireless_ctx);
+		os_free(drv);
+		return NULL;
+	}
+
+	err = Apple80211BindToInterface(drv->wireless_ctx, name);
+	CFRelease(name);
+
+	if (err) {
+		wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
+			   "failed: %d", err);
+		Apple80211Close(drv->wireless_ctx);
+		os_free(drv);
+		return NULL;
+	}
+
+	err = Apple80211GetPower(drv->wireless_ctx, &power);
+	if (err)
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
+			   err);
+
+	wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
+
+	if (!power) {
+		drv->ctrl_power = 1;
+		err = Apple80211SetPower(drv->wireless_ctx, 1);
+		if (err) {
+			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
+				   "failed: %d", err);
+			Apple80211Close(drv->wireless_ctx);
+			os_free(drv);
+			return NULL;
+		}
+	}
+
+	err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
+	if (err == 0) {
+		CFShow(dict);
+		CFRelease(dict);
+	} else {
+		printf("Apple80211GetInfoCopy: %d\n", err);
+	}
+
+	return drv;
+}
+
+
+static void wpa_driver_iphone_deinit(void *priv)
+{
+	struct wpa_driver_iphone_data *drv = priv;
+	int err;
+
+	eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
+	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+
+	if (drv->ctrl_power) {
+		wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
+		err = Apple80211SetPower(drv->wireless_ctx, 0);
+		if (err) {
+			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
+				   "failed: %d", err);
+		}
+	}
+
+	err = Apple80211Close(drv->wireless_ctx);
+	if (err) {
+		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
+			   err);
+	}
+
+	if (drv->scan_results)
+		CFRelease(drv->scan_results);
+
+	os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_iphone_ops = {
+	.name = "iphone",
+	.desc = "iPhone/iPod touch Apple80211 driver",
+	.get_ssid = wpa_driver_iphone_get_ssid,
+	.get_bssid = wpa_driver_iphone_get_bssid,
+	.init = wpa_driver_iphone_init,
+	.deinit = wpa_driver_iphone_deinit,
+	.scan = wpa_driver_iphone_scan,
+	.get_scan_results = wpa_driver_iphone_get_scan_results,
+	.associate = wpa_driver_iphone_associate,
+	.set_key = wpa_driver_iphone_set_key,
+	.get_capa = wpa_driver_iphone_get_capa,
+};