18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation.
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license.
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details.
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define Boolean __DummyBoolean
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <CoreFoundation/CoreFoundation.h>
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#undef Boolean
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "driver.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "MobileApple80211.h"
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpa_driver_iphone_data {
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *ctx;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Apple80211Ref wireless_ctx;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFArrayRef scan_results;
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ctrl_power;
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const void *res;
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						    kCFStringEncodingMacRoman);
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (str == NULL)
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = CFDictionaryGetValue(dict, str);
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFRelease(str);
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_iphone_data *drv = priv;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFDataRef data;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err, len;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  &data);
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err != 0) {
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed: %d", err);
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = CFDataGetLength(data);
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > 32) {
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFRelease(data);
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ssid, CFDataGetBytePtr(data), len);
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFRelease(data);
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_iphone_data *drv = priv;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFStringRef data;
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int a1, a2, a3, a4, a5, a6;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  &data);
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err != 0) {
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed: %d", err);
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bssid[0] = a1;
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bssid[1] = a2;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bssid[2] = a3;
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bssid[3] = a4;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bssid[4] = a5;
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bssid[5] = a6;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFRelease(data);
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_iphone_data *drv = priv;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->scan_results) {
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFRelease(drv->scan_results);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->scan_results = NULL;
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err) {
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   err);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       drv->ctx);
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_iphone_get_scan_results(void *priv,
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      struct wpa_scan_result *results,
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      size_t max_size)
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_iphone_data *drv = priv;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i, num;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->scan_results == NULL)
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	num = CFArrayGetCount(drv->scan_results);
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (num > max_size)
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		num = max_size;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(results, 0, num * sizeof(struct wpa_scan_result));
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < num; i++) {
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_scan_result *res = &results[i];
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFDictionaryRef dict =
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			CFArrayGetValueAtIndex(drv->scan_results, i);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFDataRef data;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFStringRef str;
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFNumberRef num;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int val;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data = cfdict_get_key_str(dict, "SSID");
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data) {
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res->ssid_len = CFDataGetLength(data);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (res->ssid_len > 32)
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				res->ssid_len = 32;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(res->ssid, CFDataGetBytePtr(data),
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  res->ssid_len);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		str = cfdict_get_key_str(dict, "BSSID");
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (str) {
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int a1, a2, a3, a4, a5, a6;
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sscanf(CFStringGetCStringPtr(
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       str, kCFStringEncodingMacRoman),
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       "%x:%x:%x:%x:%x:%x",
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       &a1, &a2, &a3, &a4, &a5, &a6);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res->bssid[0] = a1;
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res->bssid[1] = a2;
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res->bssid[2] = a3;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res->bssid[3] = a4;
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res->bssid[4] = a5;
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res->bssid[5] = a6;
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		num = cfdict_get_key_str(dict, "CAPABILITIES");
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (num) {
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				res->caps = val;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		num = cfdict_get_key_str(dict, "CHANNEL");
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (num) {
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				res->freq = 2407 + val * 5;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		num = cfdict_get_key_str(dict, "RSSI");
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (num) {
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				res->level = val;
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		num = cfdict_get_key_str(dict, "NOISE");
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (num) {
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				res->noise = val;
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data = cfdict_get_key_str(dict, "IE");
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data) {
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			u8 *ptr = (u8 *) CFDataGetBytePtr(data);
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int len = CFDataGetLength(data);
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			u8 *pos = ptr, *end = ptr + len;
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			while (pos + 2 < end) {
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (pos + 2 + pos[1] > end)
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					break;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (pos[0] == WLAN_EID_RSN &&
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    pos[1] <= SSID_MAX_WPA_IE_LEN) {
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					os_memcpy(res->rsn_ie, pos,
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  2 + pos[1]);
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					res->rsn_ie_len = 2 + pos[1];
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				}
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    pos[1] > 4 && pos[2] == 0x00 &&
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    pos[3] == 0x50 && pos[4] == 0xf2 &&
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    pos[5] == 0x01) {
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					os_memcpy(res->wpa_ie, pos,
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  2 + pos[1]);
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					res->wpa_ie_len = 2 + pos[1];
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				}
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				pos = pos + 2 + pos[1];
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return num;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_iphone_data *drv = eloop_ctx;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 bssid[ETH_ALEN];
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       drv, drv->ctx);
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_iphone_associate(
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *priv, struct wpa_driver_associate_params *params)
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_iphone_data *drv = priv;
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, num, err;
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t ssid_len;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFDictionaryRef bss = NULL;
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: Consider generating parameters instead of just using an entry
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * from scan results in order to support ap_scan=2.
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->scan_results == NULL) {
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "associate");
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	num = CFArrayGetCount(drv->scan_results);
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < num; i++) {
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFDictionaryRef dict =
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			CFArrayGetValueAtIndex(drv->scan_results, i);
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFDataRef data;
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data = cfdict_get_key_str(dict, "SSID");
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (data == NULL)
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ssid_len = CFDataGetLength(data);
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ssid_len != params->ssid_len ||
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    != 0)
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss = dict;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss == NULL) {
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "results - cannot associate");
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "from scan results");
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err) {
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%d", err);
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Driver is actually already associated; report association from an
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * eloop callback.
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       drv->ctx);
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     int key_idx, int set_tx, const u8 *seq,
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     size_t seq_len, const u8 *key,
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     size_t key_len)
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: Need to either support configuring PMK for 4-way handshake or
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * PTK for TKIP/CCMP.
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(capa, 0, sizeof(*capa));
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_AUTH_LEAP;
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * wpa_driver_iphone_init(void *ctx, const char *ifname)
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_iphone_data *drv;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err;
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char power;
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFStringRef name;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFDictionaryRef dict;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv = os_zalloc(sizeof(*drv));
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv == NULL)
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ctx = ctx;
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211Open(&drv->wireless_ctx);
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err) {
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   err);
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(drv);
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 kCFStringEncodingISOLatin1);
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (name == NULL) {
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		Apple80211Close(drv->wireless_ctx);
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(drv);
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211BindToInterface(drv->wireless_ctx, name);
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	CFRelease(name);
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err) {
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed: %d", err);
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		Apple80211Close(drv->wireless_ctx);
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(drv);
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211GetPower(drv->wireless_ctx, &power);
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err)
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   err);
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!power) {
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->ctrl_power = 1;
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		err = Apple80211SetPower(drv->wireless_ctx, 1);
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (err) {
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "failed: %d", err);
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			Apple80211Close(drv->wireless_ctx);
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(drv);
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err == 0) {
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFShow(dict);
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFRelease(dict);
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("Apple80211GetInfoCopy: %d\n", err);
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return drv;
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_iphone_deinit(void *priv)
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_iphone_data *drv = priv;
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err;
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ctrl_power) {
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		err = Apple80211SetPower(drv->wireless_ctx, 0);
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (err) {
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "failed: %d", err);
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = Apple80211Close(drv->wireless_ctx);
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err) {
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   err);
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->scan_results)
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		CFRelease(drv->scan_results);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(drv);
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct wpa_driver_ops wpa_driver_iphone_ops = {
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.name = "iphone",
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.desc = "iPhone/iPod touch Apple80211 driver",
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_ssid = wpa_driver_iphone_get_ssid,
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_bssid = wpa_driver_iphone_get_bssid,
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.init = wpa_driver_iphone_init,
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.deinit = wpa_driver_iphone_deinit,
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.scan = wpa_driver_iphone_scan,
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_scan_results = wpa_driver_iphone_get_scan_results,
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.associate = wpa_driver_iphone_associate,
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_key = wpa_driver_iphone_set_key,
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_capa = wpa_driver_iphone_get_capa,
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
467