• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/wpa_supplicant/src/drivers/
1/*
2 * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
3 * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16#define Boolean __DummyBoolean
17#include <CoreFoundation/CoreFoundation.h>
18#undef Boolean
19
20#include "common.h"
21#include "driver.h"
22#include "eloop.h"
23#include "ieee802_11_defs.h"
24
25#include "MobileApple80211.h"
26
27struct wpa_driver_iphone_data {
28	void *ctx;
29	Apple80211Ref wireless_ctx;
30	CFArrayRef scan_results;
31	int ctrl_power;
32};
33
34
35static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
36{
37	const void *res;
38	CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
39						    kCFStringEncodingMacRoman);
40	if (str == NULL)
41		return NULL;
42
43	res = CFDictionaryGetValue(dict, str);
44	CFRelease(str);
45	return res;
46}
47
48
49static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
50{
51	struct wpa_driver_iphone_data *drv = priv;
52	CFDataRef data;
53	int err, len;
54
55	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
56				  &data);
57	if (err != 0) {
58		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
59			   "failed: %d", err);
60		return -1;
61	}
62
63	len = CFDataGetLength(data);
64	if (len > 32) {
65		CFRelease(data);
66		return -1;
67	}
68	os_memcpy(ssid, CFDataGetBytePtr(data), len);
69	CFRelease(data);
70
71	return len;
72}
73
74
75static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
76{
77	struct wpa_driver_iphone_data *drv = priv;
78	CFStringRef data;
79	int err;
80	int a1, a2, a3, a4, a5, a6;
81
82	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
83				  &data);
84	if (err != 0) {
85		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
86			   "failed: %d", err);
87		return -1;
88	}
89
90	sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
91	       "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
92	bssid[0] = a1;
93	bssid[1] = a2;
94	bssid[2] = a3;
95	bssid[3] = a4;
96	bssid[4] = a5;
97	bssid[5] = a6;
98
99	CFRelease(data);
100
101	return 0;
102}
103
104
105static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
106{
107	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
108}
109
110
111static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
112{
113	struct wpa_driver_iphone_data *drv = priv;
114	int err;
115
116	if (drv->scan_results) {
117		CFRelease(drv->scan_results);
118		drv->scan_results = NULL;
119	}
120
121	err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
122	if (err) {
123		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
124			   err);
125		return -1;
126	}
127
128	eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
129			       drv->ctx);
130	return 0;
131}
132
133
134static int wpa_driver_iphone_get_scan_results(void *priv,
135					      struct wpa_scan_result *results,
136					      size_t max_size)
137{
138	struct wpa_driver_iphone_data *drv = priv;
139	size_t i, num;
140
141	if (drv->scan_results == NULL)
142		return 0;
143
144	num = CFArrayGetCount(drv->scan_results);
145	if (num > max_size)
146		num = max_size;
147	os_memset(results, 0, num * sizeof(struct wpa_scan_result));
148
149	for (i = 0; i < num; i++) {
150		struct wpa_scan_result *res = &results[i];
151		CFDictionaryRef dict =
152			CFArrayGetValueAtIndex(drv->scan_results, i);
153		CFDataRef data;
154		CFStringRef str;
155		CFNumberRef num;
156		int val;
157
158		data = cfdict_get_key_str(dict, "SSID");
159		if (data) {
160			res->ssid_len = CFDataGetLength(data);
161			if (res->ssid_len > 32)
162				res->ssid_len = 32;
163			os_memcpy(res->ssid, CFDataGetBytePtr(data),
164				  res->ssid_len);
165		}
166
167		str = cfdict_get_key_str(dict, "BSSID");
168		if (str) {
169			int a1, a2, a3, a4, a5, a6;
170			sscanf(CFStringGetCStringPtr(
171				       str, kCFStringEncodingMacRoman),
172			       "%x:%x:%x:%x:%x:%x",
173			       &a1, &a2, &a3, &a4, &a5, &a6);
174			res->bssid[0] = a1;
175			res->bssid[1] = a2;
176			res->bssid[2] = a3;
177			res->bssid[3] = a4;
178			res->bssid[4] = a5;
179			res->bssid[5] = a6;
180		}
181
182		num = cfdict_get_key_str(dict, "CAPABILITIES");
183		if (num) {
184			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
185				res->caps = val;
186		}
187
188		num = cfdict_get_key_str(dict, "CHANNEL");
189		if (num) {
190			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
191				res->freq = 2407 + val * 5;
192		}
193
194		num = cfdict_get_key_str(dict, "RSSI");
195		if (num) {
196			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
197				res->level = val;
198		}
199
200		num = cfdict_get_key_str(dict, "NOISE");
201		if (num) {
202			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
203				res->noise = val;
204		}
205
206		data = cfdict_get_key_str(dict, "IE");
207		if (data) {
208			u8 *ptr = (u8 *) CFDataGetBytePtr(data);
209			int len = CFDataGetLength(data);
210			u8 *pos = ptr, *end = ptr + len;
211
212			while (pos + 2 < end) {
213				if (pos + 2 + pos[1] > end)
214					break;
215				if (pos[0] == WLAN_EID_RSN &&
216				    pos[1] <= SSID_MAX_WPA_IE_LEN) {
217					os_memcpy(res->rsn_ie, pos,
218						  2 + pos[1]);
219					res->rsn_ie_len = 2 + pos[1];
220				}
221				if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
222				    pos[1] > 4 && pos[2] == 0x00 &&
223				    pos[3] == 0x50 && pos[4] == 0xf2 &&
224				    pos[5] == 0x01) {
225					os_memcpy(res->wpa_ie, pos,
226						  2 + pos[1]);
227					res->wpa_ie_len = 2 + pos[1];
228				}
229
230				pos = pos + 2 + pos[1];
231			}
232		}
233	}
234
235	return num;
236}
237
238
239static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
240{
241	struct wpa_driver_iphone_data *drv = eloop_ctx;
242	u8 bssid[ETH_ALEN];
243
244	if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
245		eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
246				       drv, drv->ctx);
247		return;
248	}
249
250	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
251}
252
253
254static int wpa_driver_iphone_associate(
255	void *priv, struct wpa_driver_associate_params *params)
256{
257	struct wpa_driver_iphone_data *drv = priv;
258	int i, num, err;
259	size_t ssid_len;
260	CFDictionaryRef bss = NULL;
261
262	/*
263	 * TODO: Consider generating parameters instead of just using an entry
264	 * from scan results in order to support ap_scan=2.
265	 */
266
267	if (drv->scan_results == NULL) {
268		wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
269			   "associate");
270		return -1;
271	}
272
273	num = CFArrayGetCount(drv->scan_results);
274
275	for (i = 0; i < num; i++) {
276		CFDictionaryRef dict =
277			CFArrayGetValueAtIndex(drv->scan_results, i);
278		CFDataRef data;
279
280		data = cfdict_get_key_str(dict, "SSID");
281		if (data == NULL)
282			continue;
283
284		ssid_len = CFDataGetLength(data);
285		if (ssid_len != params->ssid_len ||
286		    os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
287		    != 0)
288			continue;
289
290		bss = dict;
291		break;
292	}
293
294	if (bss == NULL) {
295		wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
296			   "results - cannot associate");
297		return -1;
298	}
299
300	wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
301		   "from scan results");
302
303	err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
304	if (err) {
305		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
306			   "%d", err);
307		return -1;
308	}
309
310	/*
311	 * Driver is actually already associated; report association from an
312	 * eloop callback.
313	 */
314	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
315	eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
316			       drv->ctx);
317
318	return 0;
319}
320
321
322static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
323				     int key_idx, int set_tx, const u8 *seq,
324				     size_t seq_len, const u8 *key,
325				     size_t key_len)
326{
327	/*
328	 * TODO: Need to either support configuring PMK for 4-way handshake or
329	 * PTK for TKIP/CCMP.
330	 */
331	return -1;
332}
333
334
335static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
336{
337	os_memset(capa, 0, sizeof(*capa));
338
339	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
340		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
341		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
342		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
343	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
344		WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
345	capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
346		WPA_DRIVER_AUTH_LEAP;
347	capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
348
349	return 0;
350}
351
352
353static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
354{
355	struct wpa_driver_iphone_data *drv;
356	int err;
357	char power;
358	CFStringRef name;
359	CFDictionaryRef dict;
360
361	drv = os_zalloc(sizeof(*drv));
362	if (drv == NULL)
363		return NULL;
364	drv->ctx = ctx;
365	err = Apple80211Open(&drv->wireless_ctx);
366	if (err) {
367		wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
368			   err);
369		os_free(drv);
370		return NULL;
371	}
372
373	name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
374					 kCFStringEncodingISOLatin1);
375	if (name == NULL) {
376		wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
377		Apple80211Close(drv->wireless_ctx);
378		os_free(drv);
379		return NULL;
380	}
381
382	err = Apple80211BindToInterface(drv->wireless_ctx, name);
383	CFRelease(name);
384
385	if (err) {
386		wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
387			   "failed: %d", err);
388		Apple80211Close(drv->wireless_ctx);
389		os_free(drv);
390		return NULL;
391	}
392
393	err = Apple80211GetPower(drv->wireless_ctx, &power);
394	if (err)
395		wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
396			   err);
397
398	wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
399
400	if (!power) {
401		drv->ctrl_power = 1;
402		err = Apple80211SetPower(drv->wireless_ctx, 1);
403		if (err) {
404			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
405				   "failed: %d", err);
406			Apple80211Close(drv->wireless_ctx);
407			os_free(drv);
408			return NULL;
409		}
410	}
411
412	err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
413	if (err == 0) {
414		CFShow(dict);
415		CFRelease(dict);
416	} else {
417		printf("Apple80211GetInfoCopy: %d\n", err);
418	}
419
420	return drv;
421}
422
423
424static void wpa_driver_iphone_deinit(void *priv)
425{
426	struct wpa_driver_iphone_data *drv = priv;
427	int err;
428
429	eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
430	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
431
432	if (drv->ctrl_power) {
433		wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
434		err = Apple80211SetPower(drv->wireless_ctx, 0);
435		if (err) {
436			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
437				   "failed: %d", err);
438		}
439	}
440
441	err = Apple80211Close(drv->wireless_ctx);
442	if (err) {
443		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
444			   err);
445	}
446
447	if (drv->scan_results)
448		CFRelease(drv->scan_results);
449
450	os_free(drv);
451}
452
453
454const struct wpa_driver_ops wpa_driver_iphone_ops = {
455	.name = "iphone",
456	.desc = "iPhone/iPod touch Apple80211 driver",
457	.get_ssid = wpa_driver_iphone_get_ssid,
458	.get_bssid = wpa_driver_iphone_get_bssid,
459	.init = wpa_driver_iphone_init,
460	.deinit = wpa_driver_iphone_deinit,
461	.scan = wpa_driver_iphone_scan,
462	.get_scan_results = wpa_driver_iphone_get_scan_results,
463	.associate = wpa_driver_iphone_associate,
464	.set_key = wpa_driver_iphone_set_key,
465	.get_capa = wpa_driver_iphone_get_capa,
466};
467