1/* 2 * WPA Supplicant - driver interaction with Linux Host AP driver 3 * Copyright (c) 2003-2005, 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#include <sys/ioctl.h> 17 18#include "wireless_copy.h" 19#include "common.h" 20#include "driver.h" 21#include "driver_wext.h" 22#include "eloop.h" 23#include "driver_hostap.h" 24#include "l2_packet.h" 25#include "wpa_supplicant.h" 26 27 28struct wpa_driver_hostap_data { 29 void *wext; /* private data for driver_wext */ 30 void *ctx; 31 char ifname[IFNAMSIZ + 1]; 32 int sock; 33 int current_mode; /* infra/adhoc */ 34}; 35 36 37static int hostapd_ioctl(struct wpa_driver_hostap_data *drv, 38 struct prism2_hostapd_param *param, 39 int len, int show_err) 40{ 41 struct iwreq iwr; 42 43 os_memset(&iwr, 0, sizeof(iwr)); 44 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 45 iwr.u.data.pointer = (caddr_t) param; 46 iwr.u.data.length = len; 47 48 if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) { 49 int ret = errno; 50 if (show_err) 51 perror("ioctl[PRISM2_IOCTL_HOSTAPD]"); 52 return ret; 53 } 54 55 return 0; 56} 57 58 59static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv, 60 const u8 *wpa_ie, size_t wpa_ie_len) 61{ 62 struct prism2_hostapd_param *param; 63 int res; 64 size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len; 65 if (blen < sizeof(*param)) 66 blen = sizeof(*param); 67 68 param = os_zalloc(blen); 69 if (param == NULL) 70 return -1; 71 72 param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; 73 param->u.generic_elem.len = wpa_ie_len; 74 os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len); 75 res = hostapd_ioctl(drv, param, blen, 1); 76 77 os_free(param); 78 79 return res; 80} 81 82 83static int prism2param(struct wpa_driver_hostap_data *drv, int param, 84 int value) 85{ 86 struct iwreq iwr; 87 int *i, ret = 0; 88 89 os_memset(&iwr, 0, sizeof(iwr)); 90 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 91 i = (int *) iwr.u.name; 92 *i++ = param; 93 *i++ = value; 94 95 if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) { 96 perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]"); 97 ret = -1; 98 } 99 return ret; 100} 101 102 103static int wpa_driver_hostap_set_wpa(void *priv, int enabled) 104{ 105 struct wpa_driver_hostap_data *drv = priv; 106 int ret = 0; 107 108 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); 109 110 if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0) 111 ret = -1; 112 if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0) 113 ret = -1; 114 if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0) 115 ret = -1; 116 117 return ret; 118} 119 120 121static void show_set_key_error(struct prism2_hostapd_param *param) 122{ 123 switch (param->u.crypt.err) { 124 case HOSTAP_CRYPT_ERR_UNKNOWN_ALG: 125 wpa_printf(MSG_INFO, "Unknown algorithm '%s'.", 126 param->u.crypt.alg); 127 wpa_printf(MSG_INFO, "You may need to load kernel module to " 128 "register that algorithm."); 129 wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for " 130 "WEP."); 131 break; 132 case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR: 133 wpa_printf(MSG_INFO, "Unknown address " MACSTR ".", 134 MAC2STR(param->sta_addr)); 135 break; 136 case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED: 137 wpa_printf(MSG_INFO, "Crypt algorithm initialization failed."); 138 break; 139 case HOSTAP_CRYPT_ERR_KEY_SET_FAILED: 140 wpa_printf(MSG_INFO, "Key setting failed."); 141 break; 142 case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED: 143 wpa_printf(MSG_INFO, "TX key index setting failed."); 144 break; 145 case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED: 146 wpa_printf(MSG_INFO, "Card configuration failed."); 147 break; 148 } 149} 150 151 152static int wpa_driver_hostap_set_key(void *priv, wpa_alg alg, 153 const u8 *addr, int key_idx, 154 int set_tx, const u8 *seq, size_t seq_len, 155 const u8 *key, size_t key_len) 156{ 157 struct wpa_driver_hostap_data *drv = priv; 158 struct prism2_hostapd_param *param; 159 u8 *buf; 160 size_t blen; 161 int ret = 0; 162 char *alg_name; 163 164 switch (alg) { 165 case WPA_ALG_NONE: 166 alg_name = "none"; 167 break; 168 case WPA_ALG_WEP: 169 alg_name = "WEP"; 170 break; 171 case WPA_ALG_TKIP: 172 alg_name = "TKIP"; 173 break; 174 case WPA_ALG_CCMP: 175 alg_name = "CCMP"; 176 break; 177 default: 178 return -1; 179 } 180 181 wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu " 182 "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx, 183 (unsigned long) seq_len, (unsigned long) key_len); 184 185 if (seq_len > 8) 186 return -2; 187 188 blen = sizeof(*param) + key_len; 189 buf = os_zalloc(blen); 190 if (buf == NULL) 191 return -1; 192 193 param = (struct prism2_hostapd_param *) buf; 194 param->cmd = PRISM2_SET_ENCRYPTION; 195 /* TODO: In theory, STA in client mode can use five keys; four default 196 * keys for receiving (with keyidx 0..3) and one individual key for 197 * both transmitting and receiving (keyidx 0) _unicast_ packets. Now, 198 * keyidx 0 is reserved for this unicast use and default keys can only 199 * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported). 200 * This should be fine for more or less all cases, but for completeness 201 * sake, the driver could be enhanced to support the missing key. */ 202#if 0 203 if (addr == NULL) 204 os_memset(param->sta_addr, 0xff, ETH_ALEN); 205 else 206 os_memcpy(param->sta_addr, addr, ETH_ALEN); 207#else 208 os_memset(param->sta_addr, 0xff, ETH_ALEN); 209#endif 210 os_strncpy((char *) param->u.crypt.alg, alg_name, 211 HOSTAP_CRYPT_ALG_NAME_LEN); 212 param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; 213 param->u.crypt.idx = key_idx; 214 os_memcpy(param->u.crypt.seq, seq, seq_len); 215 param->u.crypt.key_len = key_len; 216 os_memcpy((u8 *) (param + 1), key, key_len); 217 218 if (hostapd_ioctl(drv, param, blen, 1)) { 219 wpa_printf(MSG_WARNING, "Failed to set encryption."); 220 show_set_key_error(param); 221 ret = -1; 222 } 223 os_free(buf); 224 225 return ret; 226} 227 228 229static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled) 230{ 231 struct wpa_driver_hostap_data *drv = priv; 232 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); 233 return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled); 234} 235 236 237static int wpa_driver_hostap_set_drop_unencrypted(void *priv, int enabled) 238{ 239 struct wpa_driver_hostap_data *drv = priv; 240 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled); 241 return prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, enabled); 242} 243 244 245static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv, 246 int type) 247{ 248 struct iwreq iwr; 249 int *i, ret = 0; 250 251 wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type); 252 253 os_memset(&iwr, 0, sizeof(iwr)); 254 os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 255 i = (int *) iwr.u.name; 256 *i++ = type; 257 258 if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) { 259 perror("ioctl[PRISM2_IOCTL_RESET]"); 260 ret = -1; 261 } 262 return ret; 263} 264 265 266static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv, 267 const u8 *addr, int cmd, int reason_code) 268{ 269 struct prism2_hostapd_param param; 270 int ret; 271 272 /* There does not seem to be a better way of deauthenticating or 273 * disassociating with Prism2/2.5/3 than sending the management frame 274 * and then resetting the Port0 to make sure both the AP and the STA 275 * end up in disconnected state. */ 276 os_memset(¶m, 0, sizeof(param)); 277 param.cmd = PRISM2_HOSTAPD_MLME; 278 os_memcpy(param.sta_addr, addr, ETH_ALEN); 279 param.u.mlme.cmd = cmd; 280 param.u.mlme.reason_code = reason_code; 281 ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1); 282 if (ret == 0) { 283 os_sleep(0, 100000); 284 ret = wpa_driver_hostap_reset(drv, 2); 285 } 286 return ret; 287} 288 289 290static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr, 291 int reason_code) 292{ 293 struct wpa_driver_hostap_data *drv = priv; 294 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); 295 return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH, 296 reason_code); 297} 298 299 300static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr, 301 int reason_code) 302{ 303 struct wpa_driver_hostap_data *drv = priv; 304 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); 305 return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC, 306 reason_code); 307} 308 309 310static int 311wpa_driver_hostap_associate(void *priv, 312 struct wpa_driver_associate_params *params) 313{ 314 struct wpa_driver_hostap_data *drv = priv; 315 int ret = 0; 316 int allow_unencrypted_eapol; 317 318 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__); 319 320 if (params->mode != drv->current_mode) { 321 /* At the moment, Host AP driver requires host_roaming=2 for 322 * infrastructure mode and host_roaming=0 for adhoc. */ 323 if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, 324 params->mode == IEEE80211_MODE_IBSS ? 0 : 2) < 325 0) { 326 wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming", 327 __func__); 328 } 329 drv->current_mode = params->mode; 330 } 331 332 if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED, 333 params->key_mgmt_suite != KEY_MGMT_NONE) < 0) 334 ret = -1; 335 if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie, 336 params->wpa_ie_len) < 0) 337 ret = -1; 338 if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0) 339 ret = -1; 340 if (params->freq && 341 wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) 342 ret = -1; 343 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len) 344 < 0) 345 ret = -1; 346 if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) 347 ret = -1; 348 349 /* Allow unencrypted EAPOL messages even if pairwise keys are set when 350 * not using WPA. IEEE 802.1X specifies that these frames are not 351 * encrypted, but WPA encrypts them when pairwise keys are in use. */ 352 if (params->key_mgmt_suite == KEY_MGMT_802_1X || 353 params->key_mgmt_suite == KEY_MGMT_PSK) 354 allow_unencrypted_eapol = 0; 355 else 356 allow_unencrypted_eapol = 1; 357 358 if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X, 359 allow_unencrypted_eapol) < 0) { 360 wpa_printf(MSG_DEBUG, "hostap: Failed to configure " 361 "ieee_802_1x param"); 362 /* Ignore this error.. driver_hostap.c can also be used with 363 * other drivers that do not support this prism2_param. */ 364 } 365 366 return ret; 367} 368 369 370static int wpa_driver_hostap_scan(void *priv, const u8 *ssid, size_t ssid_len) 371{ 372 struct wpa_driver_hostap_data *drv = priv; 373 struct prism2_hostapd_param param; 374 int ret; 375 376 if (ssid == NULL) { 377 /* Use standard Linux Wireless Extensions ioctl if possible 378 * because some drivers using hostap code in wpa_supplicant 379 * might not support Host AP specific scan request (with SSID 380 * info). */ 381 return wpa_driver_wext_scan(drv->wext, ssid, ssid_len); 382 } 383 384 if (ssid_len > 32) 385 ssid_len = 32; 386 387 os_memset(¶m, 0, sizeof(param)); 388 param.cmd = PRISM2_HOSTAPD_SCAN_REQ; 389 param.u.scan_req.ssid_len = ssid_len; 390 os_memcpy(param.u.scan_req.ssid, ssid, ssid_len); 391 ret = hostapd_ioctl(drv, ¶m, sizeof(param), 1); 392 393 /* Not all drivers generate "scan completed" wireless event, so try to 394 * read results after a timeout. */ 395 eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext, 396 drv->ctx); 397 eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext, 398 drv->ctx); 399 400 return ret; 401} 402 403 404static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg) 405{ 406 struct wpa_driver_hostap_data *drv = priv; 407 int algs = 0; 408 409 if (auth_alg & AUTH_ALG_OPEN_SYSTEM) 410 algs |= 1; 411 if (auth_alg & AUTH_ALG_SHARED_KEY) 412 algs |= 2; 413 if (auth_alg & AUTH_ALG_LEAP) 414 algs |= 4; 415 if (algs == 0) 416 algs = 1; /* at least one algorithm should be set */ 417 418 return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs); 419} 420 421 422static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid) 423{ 424 struct wpa_driver_hostap_data *drv = priv; 425 return wpa_driver_wext_get_bssid(drv->wext, bssid); 426} 427 428 429static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid) 430{ 431 struct wpa_driver_hostap_data *drv = priv; 432 return wpa_driver_wext_get_ssid(drv->wext, ssid); 433} 434 435 436static int wpa_driver_hostap_get_scan_results(void *priv, 437 struct wpa_scan_result *results, 438 size_t max_size) 439{ 440 struct wpa_driver_hostap_data *drv = priv; 441 return wpa_driver_wext_get_scan_results(drv->wext, results, max_size); 442} 443 444 445static int wpa_driver_hostap_set_operstate(void *priv, int state) 446{ 447 struct wpa_driver_hostap_data *drv = priv; 448 return wpa_driver_wext_set_operstate(drv->wext, state); 449} 450 451 452static void * wpa_driver_hostap_init(void *ctx, const char *ifname) 453{ 454 struct wpa_driver_hostap_data *drv; 455 456 drv = os_zalloc(sizeof(*drv)); 457 if (drv == NULL) 458 return NULL; 459 drv->wext = wpa_driver_wext_init(ctx, ifname); 460 if (drv->wext == NULL) { 461 os_free(drv); 462 return NULL; 463 } 464 465 drv->ctx = ctx; 466 os_strncpy(drv->ifname, ifname, sizeof(drv->ifname)); 467 drv->sock = socket(PF_INET, SOCK_DGRAM, 0); 468 if (drv->sock < 0) { 469 perror("socket"); 470 wpa_driver_wext_deinit(drv->wext); 471 os_free(drv); 472 return NULL; 473 } 474 475 if (os_strncmp(ifname, "wlan", 4) == 0) { 476 /* 477 * Host AP driver may use both wlan# and wifi# interface in 478 * wireless events. 479 */ 480 char ifname2[IFNAMSIZ + 1]; 481 os_strncpy(ifname2, ifname, sizeof(ifname2)); 482 os_memcpy(ifname2, "wifi", 4); 483 wpa_driver_wext_alternative_ifindex(drv->wext, ifname2); 484 } 485 486 return drv; 487} 488 489 490static void wpa_driver_hostap_deinit(void *priv) 491{ 492 struct wpa_driver_hostap_data *drv = priv; 493 wpa_driver_wext_deinit(drv->wext); 494 close(drv->sock); 495 os_free(drv); 496} 497 498 499const struct wpa_driver_ops wpa_driver_hostap_ops = { 500 .name = "hostap", 501 .desc = "Host AP driver (Intersil Prism2/2.5/3)", 502 .get_bssid = wpa_driver_hostap_get_bssid, 503 .get_ssid = wpa_driver_hostap_get_ssid, 504 .set_wpa = wpa_driver_hostap_set_wpa, 505 .set_key = wpa_driver_hostap_set_key, 506 .set_countermeasures = wpa_driver_hostap_set_countermeasures, 507 .set_drop_unencrypted = wpa_driver_hostap_set_drop_unencrypted, 508 .scan = wpa_driver_hostap_scan, 509 .get_scan_results = wpa_driver_hostap_get_scan_results, 510 .deauthenticate = wpa_driver_hostap_deauthenticate, 511 .disassociate = wpa_driver_hostap_disassociate, 512 .associate = wpa_driver_hostap_associate, 513 .set_auth_alg = wpa_driver_hostap_set_auth_alg, 514 .init = wpa_driver_hostap_init, 515 .deinit = wpa_driver_hostap_deinit, 516 .set_operstate = wpa_driver_hostap_set_operstate, 517}; 518