1/* 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}; 460