Home | History | Annotate | Download | only in drivers
      1 /*
      2  * WPA Supplicant - Mac OS X Apple80211 driver interface
      3  * Copyright (c) 2007, Jouni Malinen <j (at) 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 
     27 struct wpa_driver_osx_data {
     28 	void *ctx;
     29 	WirelessRef wireless_ctx;
     30 	CFArrayRef scan_results;
     31 };
     32 
     33 
     34 #ifndef CONFIG_NO_STDOUT_DEBUG
     35 extern int wpa_debug_level;
     36 
     37 static 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 
     50 static 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 
     60 static 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 
     87 static 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 
    109 static 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 
    115 static 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 
    162 static 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 
    201 static 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 
    225 static 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 
    249 static 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 
    306 static 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 
    342 static 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 
    360 static 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 
    420 static 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 
    447 const 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 };
    460