1/* 2 * WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers 3 * Copyright (c) 2005 Zhu Yi <yi.zhu@intel.com> 4 * Copyright (c) 2004 Lubomir Gelo <lgelo@cnc.sk> 5 * Copyright (c) 2003-2004, Jouni Malinen <j@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 31struct 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 66struct 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 98static 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 119static 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 150static 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 172static 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(¶m, 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, ¶m, sizeof(param), 1); 183} 184 185 186static 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(¶m, 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, ¶m, sizeof(param), 1); 198} 199 200 201static 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 218static 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 281static 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 291static 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 300static 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 308static 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 316static int 317wpa_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 347static 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 366static 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 373static 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 380static 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 387static 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 396static 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 403static 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 439static 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 448const 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