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