Home | History | Annotate | Download | only in wpa_supplicant
      1 /*
      2  * WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers
      3  * Copyright (c) 2005 Zhu Yi <yi.zhu (at) intel.com>
      4  * Copyright (c) 2004 Lubomir Gelo <lgelo (at) cnc.sk>
      5  * Copyright (c) 2003-2004, Jouni Malinen <j (at) w1.fi>
      6  *
      7  * This program is free software; you can redistribute it and/or modify
      8  * it under the terms of the GNU General Public License version 2 as
      9  * published by the Free Software Foundation.
     10  *
     11  * Alternatively, this software may be distributed under the terms of BSD
     12  * license.
     13  *
     14  * See README and COPYING for more details.
     15  *
     16  * Please note that ipw2100/2200 drivers change to use generic Linux wireless
     17  * extensions if the kernel includes support for WE-18 or newer (Linux 2.6.13
     18  * or newer). driver_wext.c should be used in those cases.
     19  */
     20 
     21 #include "includes.h"
     22 #include <sys/ioctl.h>
     23 
     24 #include "wireless_copy.h"
     25 #include "common.h"
     26 #include "driver.h"
     27 #include "l2_packet.h"
     28 #include "driver_wext.h"
     29 #include "wpa_supplicant.h"
     30 
     31 struct wpa_driver_ipw_data {
     32 	void *wext; /* private data for driver_wext */
     33 	void *ctx;
     34 	char ifname[IFNAMSIZ + 1];
     35 	int sock;
     36 };
     37 
     38 /* following definitions must be kept in sync with ipw2100.c and ipw2200.c */
     39 
     40 #define IPW_IOCTL_WPA_SUPPLICANT		SIOCIWFIRSTPRIV+30
     41 
     42 #define IPW_CMD_SET_WPA_PARAM			1
     43 #define	IPW_CMD_SET_WPA_IE			2
     44 #define IPW_CMD_SET_ENCRYPTION			3
     45 #define IPW_CMD_MLME				4
     46 
     47 #define IPW_PARAM_WPA_ENABLED			1
     48 #define IPW_PARAM_TKIP_COUNTERMEASURES		2
     49 #define IPW_PARAM_DROP_UNENCRYPTED		3
     50 #define IPW_PARAM_PRIVACY_INVOKED		4
     51 #define IPW_PARAM_AUTH_ALGS			5
     52 #define IPW_PARAM_IEEE_802_1X			6
     53 
     54 #define IPW_MLME_STA_DEAUTH			1
     55 #define IPW_MLME_STA_DISASSOC			2
     56 
     57 #define IPW_CRYPT_ERR_UNKNOWN_ALG		2
     58 #define IPW_CRYPT_ERR_UNKNOWN_ADDR		3
     59 #define IPW_CRYPT_ERR_CRYPT_INIT_FAILED		4
     60 #define IPW_CRYPT_ERR_KEY_SET_FAILED		5
     61 #define IPW_CRYPT_ERR_TX_KEY_SET_FAILED		6
     62 #define IPW_CRYPT_ERR_CARD_CONF_FAILED		7
     63 
     64 #define	IPW_CRYPT_ALG_NAME_LEN			16
     65 
     66 struct ipw_param {
     67 	u32 cmd;
     68 	u8 sta_addr[ETH_ALEN];
     69         union {
     70 		struct {
     71 			u8 name;
     72 			u32 value;
     73 		} wpa_param;
     74 		struct {
     75 			u32 len;
     76 			u8 reserved[32];
     77 			u8 data[0];
     78 		} wpa_ie;
     79 	        struct{
     80 			u32 command;
     81     			u32 reason_code;
     82 		} mlme;
     83 		struct {
     84 			u8 alg[IPW_CRYPT_ALG_NAME_LEN];
     85 			u8 set_tx;
     86 			u32 err;
     87 			u8 idx;
     88 			u8 seq[8];
     89 			u16 key_len;
     90 			u8 key[0];
     91 		} crypt;
     92 
     93 	} u;
     94 };
     95 
     96 /* end of ipw2100.c and ipw2200.c code */
     97 
     98 static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
     99 		     struct ipw_param *param, int len, int show_err)
    100 {
    101 	struct iwreq iwr;
    102 
    103 	os_memset(&iwr, 0, sizeof(iwr));
    104 	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
    105 	iwr.u.data.pointer = (caddr_t) param;
    106 	iwr.u.data.length = len;
    107 
    108 	if (ioctl(drv->sock, IPW_IOCTL_WPA_SUPPLICANT, &iwr) < 0) {
    109 		int ret = errno;
    110 		if (show_err)
    111 			perror("ioctl[IPW_IOCTL_WPA_SUPPLICANT]");
    112 		return ret;
    113 	}
    114 
    115 	return 0;
    116 }
    117 
    118 
    119 static void ipw_show_set_key_error(struct ipw_param *param)
    120 {
    121 	switch (param->u.crypt.err) {
    122 	case IPW_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 ieee80211_crypt_wep' for"
    128 			   " WEP.");
    129 		break;
    130 	case IPW_CRYPT_ERR_UNKNOWN_ADDR:
    131 		wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
    132 			   MAC2STR(param->sta_addr));
    133 		break;
    134 	case IPW_CRYPT_ERR_CRYPT_INIT_FAILED:
    135 		wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
    136 		break;
    137 	case IPW_CRYPT_ERR_KEY_SET_FAILED:
    138 		wpa_printf(MSG_INFO, "Key setting failed.");
    139 		break;
    140 	case IPW_CRYPT_ERR_TX_KEY_SET_FAILED:
    141 		wpa_printf(MSG_INFO, "TX key index setting failed.");
    142 		break;
    143 	case IPW_CRYPT_ERR_CARD_CONF_FAILED:
    144 		wpa_printf(MSG_INFO, "Card configuration failed.");
    145 		break;
    146 	}
    147 }
    148 
    149 
    150 static int ipw_set_wpa_ie(struct wpa_driver_ipw_data *drv,
    151 			  const u8 *wpa_ie, size_t wpa_ie_len)
    152 {
    153 	struct ipw_param *param;
    154 	int ret;
    155 	size_t blen = sizeof(*param) + wpa_ie_len;
    156 
    157 	param = os_zalloc(blen);
    158 	if (param == NULL)
    159 		return -1;
    160 
    161 	param->cmd = IPW_CMD_SET_WPA_IE;
    162 	param->u.wpa_ie.len = wpa_ie_len;
    163 	os_memcpy(param->u.wpa_ie.data, wpa_ie, wpa_ie_len);
    164 
    165 	ret = ipw_ioctl(drv, param, blen, 1);
    166 
    167 	os_free(param);
    168 	return ret;
    169 }
    170 
    171 
    172 static int ipw_set_wpa_param(struct wpa_driver_ipw_data *drv, u8 name,
    173 			     u32 value)
    174 {
    175 	struct ipw_param param;
    176 
    177 	os_memset(&param, 0, sizeof(param));
    178 	param.cmd = IPW_CMD_SET_WPA_PARAM;
    179 	param.u.wpa_param.name = name;
    180 	param.u.wpa_param.value = value;
    181 
    182 	return ipw_ioctl(drv, &param, sizeof(param), 1);
    183 }
    184 
    185 
    186 static int ipw_mlme(struct wpa_driver_ipw_data *drv, const u8 *addr,
    187 		    int cmd, int reason)
    188 {
    189 	struct ipw_param param;
    190 
    191 	os_memset(&param, 0, sizeof(param));
    192 	os_memcpy(param.sta_addr, addr, ETH_ALEN);
    193 	param.cmd = IPW_CMD_MLME;
    194 	param.u.mlme.command = cmd;
    195 	param.u.mlme.reason_code = reason;
    196 
    197 	return ipw_ioctl(drv, &param, sizeof(param), 1);
    198 }
    199 
    200 
    201 static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
    202 {
    203 	struct wpa_driver_ipw_data *drv = priv;
    204 	int ret = 0;
    205 
    206 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
    207 
    208 	if (!enabled && ipw_set_wpa_ie(drv, NULL, 0) < 0)
    209 		ret = -1;
    210 
    211 	if (ipw_set_wpa_param(drv, IPW_PARAM_WPA_ENABLED, enabled) < 0)
    212 		ret = -1;
    213 
    214 	return ret;
    215 }
    216 
    217 
    218 static int wpa_driver_ipw_set_key(void *priv, wpa_alg alg,
    219 				      const u8 *addr, int key_idx, int set_tx,
    220 				      const u8 *seq, size_t seq_len,
    221 				      const u8 *key, size_t key_len)
    222 {
    223 	struct wpa_driver_ipw_data *drv = priv;
    224 	struct ipw_param *param;
    225 	u8 *buf;
    226 	size_t blen;
    227 	int ret = 0;
    228 	char *alg_name;
    229 
    230 	switch (alg) {
    231 	case WPA_ALG_NONE:
    232 		alg_name = "none";
    233 		break;
    234 	case WPA_ALG_WEP:
    235 		alg_name = "WEP";
    236 		break;
    237 	case WPA_ALG_TKIP:
    238 		alg_name = "TKIP";
    239 		break;
    240 	case WPA_ALG_CCMP:
    241 		alg_name = "CCMP";
    242 		break;
    243 	default:
    244 		return -1;
    245 	}
    246 
    247 	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
    248 		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
    249 		   (unsigned long) seq_len, (unsigned long) key_len);
    250 
    251 	if (seq_len > 8)
    252 		return -2;
    253 
    254 	blen = sizeof(*param) + key_len;
    255 	buf = os_zalloc(blen);
    256 	if (buf == NULL)
    257 		return -1;
    258 
    259 	param = (struct ipw_param *) buf;
    260 	param->cmd = IPW_CMD_SET_ENCRYPTION;
    261 	os_memset(param->sta_addr, 0xff, ETH_ALEN);
    262 	os_strncpy((char *) param->u.crypt.alg, alg_name,
    263 		   IPW_CRYPT_ALG_NAME_LEN);
    264 	param->u.crypt.set_tx = set_tx ? 1 : 0;
    265 	param->u.crypt.idx = key_idx;
    266 	os_memcpy(param->u.crypt.seq, seq, seq_len);
    267 	param->u.crypt.key_len = key_len;
    268 	os_memcpy((u8 *) (param + 1), key, key_len);
    269 
    270 	if (ipw_ioctl(drv, param, blen, 1)) {
    271 		wpa_printf(MSG_WARNING, "Failed to set encryption.");
    272 		ipw_show_set_key_error(param);
    273 		ret = -1;
    274 	}
    275 	os_free(buf);
    276 
    277 	return ret;
    278 }
    279 
    280 
    281 static int wpa_driver_ipw_set_countermeasures(void *priv, int enabled)
    282 {
    283 	struct wpa_driver_ipw_data *drv = priv;
    284 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
    285 	return ipw_set_wpa_param(drv, IPW_PARAM_TKIP_COUNTERMEASURES,
    286 				     enabled);
    287 
    288 }
    289 
    290 
    291 static int wpa_driver_ipw_set_drop_unencrypted(void *priv, int enabled)
    292 {
    293 	struct wpa_driver_ipw_data *drv = priv;
    294 	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
    295 	return ipw_set_wpa_param(drv, IPW_PARAM_DROP_UNENCRYPTED,
    296 				     enabled);
    297 }
    298 
    299 
    300 static int wpa_driver_ipw_deauthenticate(void *priv, const u8 *addr,
    301 					 int reason_code)
    302 {
    303 	struct wpa_driver_ipw_data *drv = priv;
    304 	return ipw_mlme(drv, addr, IPW_MLME_STA_DEAUTH, reason_code);
    305 }
    306 
    307 
    308 static int wpa_driver_ipw_disassociate(void *priv, const u8 *addr,
    309 				       int reason_code)
    310 {
    311 	struct wpa_driver_ipw_data *drv = priv;
    312 	return ipw_mlme(drv, addr, IPW_MLME_STA_DISASSOC, reason_code);
    313 }
    314 
    315 
    316 static int
    317 wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
    318 {
    319 	struct wpa_driver_ipw_data *drv = priv;
    320 	int ret = 0;
    321 	int unencrypted_eapol;
    322 
    323 	if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
    324 		ret = -1;
    325 	if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
    326 				     params->ssid_len) < 0)
    327 		ret = -1;
    328 	if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
    329 		ret = -1;
    330 
    331 	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
    332 	    params->key_mgmt_suite == KEY_MGMT_PSK)
    333 		unencrypted_eapol = 0;
    334 	else
    335 		unencrypted_eapol = 1;
    336 
    337 	if (ipw_set_wpa_param(drv, IPW_PARAM_IEEE_802_1X,
    338 			      unencrypted_eapol) < 0) {
    339 		wpa_printf(MSG_DEBUG, "ipw: Failed to configure "
    340 			   "ieee_802_1x param");
    341 	}
    342 
    343 	return ret;
    344 }
    345 
    346 
    347 static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
    348 {
    349 	struct wpa_driver_ipw_data *drv = priv;
    350 	int algs = 0;
    351 
    352 	if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
    353 		algs |= 1;
    354 	if (auth_alg & AUTH_ALG_SHARED_KEY)
    355 		algs |= 2;
    356 	if (auth_alg & AUTH_ALG_LEAP)
    357 		algs |= 4;
    358 	if (algs == 0)
    359 		algs = 1; /* at least one algorithm should be set */
    360 
    361 	wpa_printf(MSG_DEBUG, "%s: auth_alg=0x%x", __FUNCTION__, algs);
    362 	return ipw_set_wpa_param(drv, IPW_PARAM_AUTH_ALGS, algs);
    363 }
    364 
    365 
    366 static int wpa_driver_ipw_get_bssid(void *priv, u8 *bssid)
    367 {
    368 	struct wpa_driver_ipw_data *drv = priv;
    369 	return wpa_driver_wext_get_bssid(drv->wext, bssid);
    370 }
    371 
    372 
    373 static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
    374 {
    375 	struct wpa_driver_ipw_data *drv = priv;
    376 	return wpa_driver_wext_get_ssid(drv->wext, ssid);
    377 }
    378 
    379 
    380 static int wpa_driver_ipw_scan(void *priv, const u8 *ssid, size_t ssid_len)
    381 {
    382 	struct wpa_driver_ipw_data *drv = priv;
    383 	return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
    384 }
    385 
    386 
    387 static int wpa_driver_ipw_get_scan_results(void *priv,
    388 					    struct wpa_scan_result *results,
    389 					    size_t max_size)
    390 {
    391 	struct wpa_driver_ipw_data *drv = priv;
    392 	return wpa_driver_wext_get_scan_results(drv->wext, results, max_size);
    393 }
    394 
    395 
    396 static int wpa_driver_ipw_set_operstate(void *priv, int state)
    397 {
    398 	struct wpa_driver_ipw_data *drv = priv;
    399 	return wpa_driver_wext_set_operstate(drv->wext, state);
    400 }
    401 
    402 
    403 static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
    404 {
    405 	struct wpa_driver_ipw_data *drv;
    406 	int ver;
    407 
    408 	wpa_printf(MSG_DEBUG, "%s is called", __FUNCTION__);
    409 	drv = os_zalloc(sizeof(*drv));
    410 	if (drv == NULL)
    411 		return NULL;
    412 	drv->wext = wpa_driver_wext_init(ctx, ifname);
    413 	if (drv->wext == NULL) {
    414 		os_free(drv);
    415 		return NULL;
    416 	}
    417 
    418 	ver = wpa_driver_wext_get_version(drv->wext);
    419 	if (ver >= 18) {
    420 		wpa_printf(MSG_WARNING, "Linux wireless extensions version %d "
    421 			   "detected.", ver);
    422 		wpa_printf(MSG_WARNING, "ipw2x00 driver uses driver_wext "
    423 			   "(-Dwext) instead of driver_ipw.");
    424 	}
    425 
    426 	drv->ctx = ctx;
    427 	os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
    428 	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
    429 	if (drv->sock < 0) {
    430 		wpa_driver_wext_deinit(drv->wext);
    431 		os_free(drv);
    432 		return NULL;
    433 	}
    434 
    435 	return drv;
    436 }
    437 
    438 
    439 static void wpa_driver_ipw_deinit(void *priv)
    440 {
    441 	struct wpa_driver_ipw_data *drv = priv;
    442 	wpa_driver_wext_deinit(drv->wext);
    443 	close(drv->sock);
    444 	os_free(drv);
    445 }
    446 
    447 
    448 const struct wpa_driver_ops wpa_driver_ipw_ops = {
    449 	.name = "ipw",
    450 	.desc = "Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 "
    451 	"or newer)",
    452 	.get_bssid = wpa_driver_ipw_get_bssid,
    453 	.get_ssid = wpa_driver_ipw_get_ssid,
    454 	.set_wpa = wpa_driver_ipw_set_wpa,
    455 	.set_key = wpa_driver_ipw_set_key,
    456 	.set_countermeasures = wpa_driver_ipw_set_countermeasures,
    457 	.set_drop_unencrypted = wpa_driver_ipw_set_drop_unencrypted,
    458 	.scan = wpa_driver_ipw_scan,
    459 	.get_scan_results = wpa_driver_ipw_get_scan_results,
    460 	.deauthenticate = wpa_driver_ipw_deauthenticate,
    461 	.disassociate = wpa_driver_ipw_disassociate,
    462 	.associate = wpa_driver_ipw_associate,
    463 	.set_auth_alg = wpa_driver_ipw_set_auth_alg,
    464 	.init = wpa_driver_ipw_init,
    465 	.deinit = wpa_driver_ipw_deinit,
    466 	.set_operstate = wpa_driver_ipw_set_operstate,
    467 };
    468