blob: 69ca4b576c3c091b45b935e06fa482b1cea1bc74 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant - Mac OS X 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 "common/ieee802_11_defs.h"
24
25#include "Apple80211.h"
26
27struct wpa_driver_osx_data {
28 void *ctx;
29 WirelessRef wireless_ctx;
30 CFArrayRef scan_results;
31};
32
33
34#ifndef CONFIG_NO_STDOUT_DEBUG
35extern int wpa_debug_level;
36
37static void dump_dict_cb(const void *key, const void *value, void *context)
38{
39 if (MSG_DEBUG < wpa_debug_level)
40 return;
41
42 wpa_printf(MSG_DEBUG, "Key:");
43 CFShow(key);
44 wpa_printf(MSG_DEBUG, "Value:");
45 CFShow(value);
46}
47#endif /* CONFIG_NO_STDOUT_DEBUG */
48
49
50static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
51{
52#ifndef CONFIG_NO_STDOUT_DEBUG
53 wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
54 title, (unsigned int) CFDictionaryGetCount(dict));
55 CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
56#endif /* CONFIG_NO_STDOUT_DEBUG */
57}
58
59
60static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
61{
62 struct wpa_driver_osx_data *drv = priv;
63 WirelessError err;
64 WirelessInfo info;
65 int len;
66
67 err = WirelessGetInfo(drv->wireless_ctx, &info);
68 if (err) {
69 wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
70 (int) err);
71 return -1;
72 }
73 if (!info.power) {
74 wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
75 return -1;
76 }
77
78 for (len = 0; len < 32; len++)
79 if (info.ssid[len] == 0)
80 break;
81
82 os_memcpy(ssid, info.ssid, len);
83 return len;
84}
85
86
87static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
88{
89 struct wpa_driver_osx_data *drv = priv;
90 WirelessError err;
91 WirelessInfo info;
92
93 err = WirelessGetInfo(drv->wireless_ctx, &info);
94 if (err) {
95 wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
96 (int) err);
97 return -1;
98 }
99 if (!info.power) {
100 wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
101 return -1;
102 }
103
104 os_memcpy(bssid, info.bssID, ETH_ALEN);
105 return 0;
106}
107
108
109static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
110{
111 wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
112}
113
114
115static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params)
116{
117 struct wpa_driver_osx_data *drv = priv;
118 WirelessError err;
119 const u8 *ssid = params->ssids[0].ssid;
120 size_t ssid_len = params->ssids[0].ssid_len;
121
122 if (drv->scan_results) {
123 CFRelease(drv->scan_results);
124 drv->scan_results = NULL;
125 }
126
127 if (ssid) {
128 CFStringRef data;
129 data = CFStringCreateWithBytes(kCFAllocatorDefault,
130 ssid, ssid_len,
131 kCFStringEncodingISOLatin1,
132 FALSE);
133 if (data == NULL) {
134 wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
135 "failed");
136 return -1;
137 }
138
139 err = WirelessDirectedScan(drv->wireless_ctx,
140 &drv->scan_results, 0, data);
141 CFRelease(data);
142 if (err) {
143 wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
144 "failed: 0x%08x", (unsigned int) err);
145 return -1;
146 }
147 } else {
148 err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
149 if (err) {
150 wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
151 "0x%08x", (unsigned int) err);
152 return -1;
153 }
154 }
155
156 eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
157 drv->ctx);
158 return 0;
159}
160
161
162static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res,
163 WirelessNetworkInfo *info)
164{
165 struct wpa_scan_res *result, **tmp;
166 size_t extra_len;
167 u8 *pos;
168
169 extra_len = 2 + info->ssid_len;
170
171 result = os_zalloc(sizeof(*result) + extra_len);
172 if (result == NULL)
173 return;
174 os_memcpy(result->bssid, info->bssid, ETH_ALEN);
175 result->freq = 2407 + info->channel * 5;
176 //result->beacon_int =;
177 result->caps = info->capability;
178 //result->qual = info->signal;
179 result->noise = info->noise;
180
181 pos = (u8 *)(result + 1);
182
183 *pos++ = WLAN_EID_SSID;
184 *pos++ = info->ssid_len;
185 os_memcpy(pos, info->ssid, info->ssid_len);
186 pos += info->ssid_len;
187
188 result->ie_len = pos - (u8 *)(result + 1);
189
190 tmp = os_realloc(res->res,
191 (res->num + 1) * sizeof(struct wpa_scan_res *));
192 if (tmp == NULL) {
193 os_free(result);
194 return;
195 }
196 tmp[res->num++] = result;
197 res->res = tmp;
198}
199
200
201static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv)
202{
203 struct wpa_driver_osx_data *drv = priv;
204 struct wpa_scan_results *res;
205 size_t i, num;
206
207 if (drv->scan_results == NULL)
208 return 0;
209
210 num = CFArrayGetCount(drv->scan_results);
211
212 res = os_zalloc(sizeof(*res));
213 if (res == NULL)
214 return NULL;
215
216 for (i = 0; i < num; i++)
217 wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *)
218 CFDataGetBytePtr(CFArrayGetValueAtIndex(
219 drv->scan_results, i)));
220
221 return res;
222}
223
224
225static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
226{
227 struct wpa_driver_osx_data *drv = eloop_ctx;
228 u8 bssid[ETH_ALEN];
229 CFDictionaryRef ai;
230
231 if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
232 eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
233 drv, drv->ctx);
234 return;
235 }
236
237 ai = WirelessGetAssociationInfo(drv->wireless_ctx);
238 if (ai) {
239 wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
240 CFRelease(ai);
241 } else {
242 wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
243 }
244
245 wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
246}
247
248
249static int wpa_driver_osx_associate(void *priv,
250 struct wpa_driver_associate_params *params)
251{
252 struct wpa_driver_osx_data *drv = priv;
253 WirelessError err;
254 CFDataRef ssid;
255 CFStringRef key;
256 int assoc_type;
257
258 ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
259 params->ssid_len);
260 if (ssid == NULL)
261 return -1;
262
263 /* TODO: support for WEP */
264 if (params->key_mgmt_suite == KEY_MGMT_PSK) {
265 if (params->passphrase == NULL)
266 return -1;
267 key = CFStringCreateWithCString(kCFAllocatorDefault,
268 params->passphrase,
269 kCFStringEncodingISOLatin1);
270 if (key == NULL) {
271 CFRelease(ssid);
272 return -1;
273 }
274 } else
275 key = NULL;
276
277 if (params->key_mgmt_suite == KEY_MGMT_NONE)
278 assoc_type = 0;
279 else
280 assoc_type = 4;
281
282 wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
283 assoc_type, key);
284 err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
285 CFRelease(ssid);
286 if (key)
287 CFRelease(key);
288 if (err) {
289 wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
290 (unsigned int) err);
291 return -1;
292 }
293
294 /*
295 * Driver is actually already associated; report association from an
296 * eloop callback.
297 */
298 eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
299 eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
300 drv->ctx);
301
302 return 0;
303}
304
305
306static int wpa_driver_osx_set_key(const char *ifname, void *priv,
307 enum wpa_alg alg, const u8 *addr,
308 int key_idx, int set_tx, const u8 *seq,
309 size_t seq_len, const u8 *key,
310 size_t key_len)
311{
312 struct wpa_driver_osx_data *drv = priv;
313 WirelessError err;
314
315 if (alg == WPA_ALG_WEP) {
316 err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
317 key);
318 if (err != 0) {
319 wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
320 "0x%08x", (unsigned int) err);
321 return -1;
322 }
323
324 return 0;
325 }
326
327 if (alg == WPA_ALG_PMK) {
328 err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
329 if (err != 0) {
330 wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
331 "0x%08x", (unsigned int) err);
332 return -1;
333 }
334 return 0;
335 }
336
337 wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
338 return -1;
339}
340
341
342static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
343{
344 os_memset(capa, 0, sizeof(*capa));
345
346 capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
347 WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
348 WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
349 WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
350 capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
351 WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
352 capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
353 WPA_DRIVER_AUTH_LEAP;
354 capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
355
356 return 0;
357}
358
359
360static void * wpa_driver_osx_init(void *ctx, const char *ifname)
361{
362 struct wpa_driver_osx_data *drv;
363 WirelessError err;
364 u8 enabled, power;
365
366 if (!WirelessIsAvailable()) {
367 wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
368 return NULL;
369 }
370
371 drv = os_zalloc(sizeof(*drv));
372 if (drv == NULL)
373 return NULL;
374 drv->ctx = ctx;
375 err = WirelessAttach(&drv->wireless_ctx, 0);
376 if (err) {
377 wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
378 (int) err);
379 os_free(drv);
380 return NULL;
381 }
382
383 err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
384 if (err)
385 wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
386 (unsigned int) err);
387 err = WirelessGetPower(drv->wireless_ctx, &power);
388 if (err)
389 wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
390 (unsigned int) err);
391
392 wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
393
394 if (!enabled) {
395 err = WirelessSetEnabled(drv->wireless_ctx, 1);
396 if (err) {
397 wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
398 " 0x%08x", (unsigned int) err);
399 WirelessDetach(drv->wireless_ctx);
400 os_free(drv);
401 return NULL;
402 }
403 }
404
405 if (!power) {
406 err = WirelessSetPower(drv->wireless_ctx, 1);
407 if (err) {
408 wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
409 "0x%08x", (unsigned int) err);
410 WirelessDetach(drv->wireless_ctx);
411 os_free(drv);
412 return NULL;
413 }
414 }
415
416 return drv;
417}
418
419
420static void wpa_driver_osx_deinit(void *priv)
421{
422 struct wpa_driver_osx_data *drv = priv;
423 WirelessError err;
424
425 eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
426 eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
427
428 err = WirelessSetPower(drv->wireless_ctx, 0);
429 if (err) {
430 wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
431 "0x%08x", (unsigned int) err);
432 }
433
434 err = WirelessDetach(drv->wireless_ctx);
435 if (err) {
436 wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
437 (unsigned int) err);
438 }
439
440 if (drv->scan_results)
441 CFRelease(drv->scan_results);
442
443 os_free(drv);
444}
445
446
447const struct wpa_driver_ops wpa_driver_osx_ops = {
448 .name = "osx",
449 .desc = "Mac OS X Apple80211 driver",
450 .get_ssid = wpa_driver_osx_get_ssid,
451 .get_bssid = wpa_driver_osx_get_bssid,
452 .init = wpa_driver_osx_init,
453 .deinit = wpa_driver_osx_deinit,
454 .scan2 = wpa_driver_osx_scan,
455 .get_scan_results2 = wpa_driver_osx_get_scan_results,
456 .associate = wpa_driver_osx_associate,
457 .set_key = wpa_driver_osx_set_key,
458 .get_capa = wpa_driver_osx_get_capa,
459};