1/* 2 * WPA Supplicant - driver interaction with Linux Prism54.org driver 3 * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> 4 * Copyright (c) 2004, Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Alternatively, this software may be distributed under the terms of BSD 11 * license. 12 * 13 * See README and COPYING for more details. 14 */ 15 16#include "includes.h" 17#include <sys/ioctl.h> 18 19#include "wireless_copy.h" 20#include "common.h" 21#include "driver.h" 22#include "driver_wext.h" 23#include "driver_hostap.h" 24 25struct wpa_driver_prism54_data { 26 void *wext; /* private data for driver_wext */ 27 void *ctx; 28 char ifname[IFNAMSIZ + 1]; 29 int sock; 30}; 31 32#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12 33#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25 34#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26 35 36static void show_set_key_error(struct prism2_hostapd_param *); 37 38static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv, 39 struct prism2_hostapd_param *param, 40 int len, int show_err) 41{ 42 struct iwreq iwr; 43 44 os_memset(&iwr, 0, sizeof(iwr)); 45 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); 46 iwr.u.data.pointer = (caddr_t) param; 47 iwr.u.data.length = len; 48 49 if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) { 50 int ret = errno; 51 if (show_err) 52 perror("ioctl[PRISM54_HOSTAPD]"); 53 return ret; 54 } 55 56 return 0; 57} 58 59 60static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv, 61 const u8 *wpa_ie, 62 size_t wpa_ie_len) 63{ 64 struct prism2_hostapd_param *param; 65 int res; 66 size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len; 67 if (blen < sizeof(*param)) 68 blen = sizeof(*param); 69 70 param = os_zalloc(blen); 71 if (param == NULL) 72 return -1; 73 74 param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT; 75 param->u.generic_elem.len = wpa_ie_len; 76 os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len); 77 res = hostapd_ioctl_prism54(drv, param, blen, 1); 78 79 os_free(param); 80 81 return res; 82} 83 84 85/* This is called at wpa_supplicant daemon init time */ 86static int wpa_driver_prism54_set_wpa(void *priv, int enabled) 87{ 88 struct wpa_driver_prism54_data *drv = priv; 89 struct prism2_hostapd_param *param; 90 int res; 91 size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; 92 if (blen < sizeof(*param)) 93 blen = sizeof(*param); 94 95 param = os_zalloc(blen); 96 if (param == NULL) 97 return -1; 98 99 param->cmd = PRISM54_SET_WPA; 100 param->u.generic_elem.len = 0; 101 res = hostapd_ioctl_prism54(drv, param, blen, 1); 102 103 os_free(param); 104 105 return res; 106} 107 108 109static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg, 110 const u8 *addr, int key_idx, int set_tx, 111 const u8 *seq, size_t seq_len, 112 const u8 *key, size_t key_len) 113{ 114 struct wpa_driver_prism54_data *drv = priv; 115 struct prism2_hostapd_param *param; 116 u8 *buf; 117 size_t blen; 118 int ret = 0; 119 char *alg_name; 120 121 switch (alg) { 122 case WPA_ALG_NONE: 123 alg_name = "none"; 124 return -1; 125 break; 126 case WPA_ALG_WEP: 127 alg_name = "WEP"; 128 return -1; 129 break; 130 case WPA_ALG_TKIP: 131 alg_name = "TKIP"; 132 break; 133 case WPA_ALG_CCMP: 134 alg_name = "CCMP"; 135 return -1; 136 break; 137 default: 138 return -1; 139 } 140 141 wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu " 142 "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx, 143 (unsigned long) seq_len, (unsigned long) key_len); 144 145 if (seq_len > 8) 146 return -2; 147 148 blen = sizeof(*param) + key_len; 149 buf = os_zalloc(blen); 150 if (buf == NULL) 151 return -1; 152 153 param = (struct prism2_hostapd_param *) buf; 154 param->cmd = PRISM2_SET_ENCRYPTION; 155 /* TODO: In theory, STA in client mode can use five keys; four default 156 * keys for receiving (with keyidx 0..3) and one individual key for 157 * both transmitting and receiving (keyidx 0) _unicast_ packets. Now, 158 * keyidx 0 is reserved for this unicast use and default keys can only 159 * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported). 160 * This should be fine for more or less all cases, but for completeness 161 * sake, the driver could be enhanced to support the missing key. */ 162#if 0 163 if (addr == NULL) 164 os_memset(param->sta_addr, 0xff, ETH_ALEN); 165 else 166 os_memcpy(param->sta_addr, addr, ETH_ALEN); 167#else 168 os_memset(param->sta_addr, 0xff, ETH_ALEN); 169#endif 170 os_strlcpy((char *) param->u.crypt.alg, alg_name, 171 HOSTAP_CRYPT_ALG_NAME_LEN); 172 param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0; 173 param->u.crypt.idx = key_idx; 174 os_memcpy(param->u.crypt.seq, seq, seq_len); 175 param->u.crypt.key_len = key_len; 176 os_memcpy((u8 *) (param + 1), key, key_len); 177 178 if (hostapd_ioctl_prism54(drv, param, blen, 1)) { 179 wpa_printf(MSG_WARNING, "Failed to set encryption."); 180 show_set_key_error(param); 181 ret = -1; 182 } 183 os_free(buf); 184 185 return ret; 186} 187 188 189static int wpa_driver_prism54_set_countermeasures(void *priv, 190 int enabled) 191{ 192 /* FIX */ 193 printf("wpa_driver_prism54_set_countermeasures - not yet " 194 "implemented\n"); 195 return 0; 196} 197 198 199static int wpa_driver_prism54_set_drop_unencrypted(void *priv, 200 int enabled) 201{ 202 struct wpa_driver_prism54_data *drv = priv; 203 struct prism2_hostapd_param *param; 204 int res; 205 size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN; 206 if (blen < sizeof(*param)) 207 blen = sizeof(*param); 208 209 param = os_zalloc(blen); 210 if (param == NULL) 211 return -1; 212 213 param->cmd = PRISM54_DROP_UNENCRYPTED; 214 param->u.generic_elem.len = 0; 215 res = hostapd_ioctl_prism54(drv, param, blen, 1); 216 217 os_free(param); 218 219 return res; 220} 221 222 223static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr, 224 int reason_code) 225{ 226 /* FIX */ 227 printf("wpa_driver_prism54_deauthenticate - not yet implemented\n"); 228 return 0; 229} 230 231 232static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr, 233 int reason_code) 234{ 235 /* FIX */ 236 printf("wpa_driver_prism54_disassociate - not yet implemented\n"); 237 return 0; 238} 239 240 241static int 242wpa_driver_prism54_associate(void *priv, 243 struct wpa_driver_associate_params *params) 244{ 245 struct wpa_driver_prism54_data *drv = priv; 246 int ret = 0; 247 248 if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie, 249 params->wpa_ie_len) < 0) 250 ret = -1; 251 if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) 252 ret = -1; 253 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, 254 params->ssid_len) < 0) 255 ret = -1; 256 if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) 257 ret = -1; 258 259 return ret; 260} 261 262static void show_set_key_error(struct prism2_hostapd_param *param) 263{ 264 switch (param->u.crypt.err) { 265 case HOSTAP_CRYPT_ERR_UNKNOWN_ALG: 266 wpa_printf(MSG_INFO, "Unknown algorithm '%s'.", 267 param->u.crypt.alg); 268 wpa_printf(MSG_INFO, "You may need to load kernel module to " 269 "register that algorithm."); 270 wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for " 271 "WEP."); 272 break; 273 case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR: 274 wpa_printf(MSG_INFO, "Unknown address " MACSTR ".", 275 MAC2STR(param->sta_addr)); 276 break; 277 case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED: 278 wpa_printf(MSG_INFO, "Crypt algorithm initialization failed."); 279 break; 280 case HOSTAP_CRYPT_ERR_KEY_SET_FAILED: 281 wpa_printf(MSG_INFO, "Key setting failed."); 282 break; 283 case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED: 284 wpa_printf(MSG_INFO, "TX key index setting failed."); 285 break; 286 case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED: 287 wpa_printf(MSG_INFO, "Card configuration failed."); 288 break; 289 } 290} 291 292 293static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid) 294{ 295 struct wpa_driver_prism54_data *drv = priv; 296 return wpa_driver_wext_get_bssid(drv->wext, bssid); 297} 298 299 300static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid) 301{ 302 struct wpa_driver_prism54_data *drv = priv; 303 return wpa_driver_wext_get_ssid(drv->wext, ssid); 304} 305 306 307static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len) 308{ 309 struct wpa_driver_prism54_data *drv = priv; 310 return wpa_driver_wext_scan(drv->wext, ssid, ssid_len); 311} 312 313 314static struct wpa_scan_results * 315wpa_driver_prism54_get_scan_results(void *priv) 316{ 317 struct wpa_driver_prism54_data *drv = priv; 318 return wpa_driver_wext_get_scan_results(drv->wext); 319} 320 321 322static int wpa_driver_prism54_set_operstate(void *priv, int state) 323{ 324 struct wpa_driver_prism54_data *drv = priv; 325 return wpa_driver_wext_set_operstate(drv->wext, state); 326} 327 328 329static void * wpa_driver_prism54_init(void *ctx, const char *ifname) 330{ 331 struct wpa_driver_prism54_data *drv; 332 333 drv = os_zalloc(sizeof(*drv)); 334 if (drv == NULL) 335 return NULL; 336 drv->wext = wpa_driver_wext_init(ctx, ifname); 337 if (drv->wext == NULL) { 338 os_free(drv); 339 return NULL; 340 } 341 342 drv->ctx = ctx; 343 os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)); 344 drv->sock = socket(PF_INET, SOCK_DGRAM, 0); 345 if (drv->sock < 0) { 346 wpa_driver_wext_deinit(drv->wext); 347 os_free(drv); 348 return NULL; 349 } 350 351 return drv; 352} 353 354 355static void wpa_driver_prism54_deinit(void *priv) 356{ 357 struct wpa_driver_prism54_data *drv = priv; 358 wpa_driver_wext_deinit(drv->wext); 359 close(drv->sock); 360 os_free(drv); 361} 362 363 364const struct wpa_driver_ops wpa_driver_prism54_ops = { 365 .name = "prism54", 366 .desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)", 367 .get_bssid = wpa_driver_prism54_get_bssid, 368 .get_ssid = wpa_driver_prism54_get_ssid, 369 .set_wpa = wpa_driver_prism54_set_wpa, 370 .set_key = wpa_driver_prism54_set_key, 371 .set_countermeasures = wpa_driver_prism54_set_countermeasures, 372 .set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted, 373 .scan = wpa_driver_prism54_scan, 374 .get_scan_results2 = wpa_driver_prism54_get_scan_results, 375 .deauthenticate = wpa_driver_prism54_deauthenticate, 376 .disassociate = wpa_driver_prism54_disassociate, 377 .associate = wpa_driver_prism54_associate, 378 .init = wpa_driver_prism54_init, 379 .deinit = wpa_driver_prism54_deinit, 380 .set_operstate = wpa_driver_prism54_set_operstate, 381}; 382