1 /* 2 * WPA Supplicant - driver interaction with Linux Prism54.org driver 3 * Copyright (c) 2003-2005, Jouni Malinen <j (at) w1.fi> 4 * Copyright (c) 2004, Luis R. Rodriguez <mcgrof (at) 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 25 struct 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 36 static void show_set_key_error(struct prism2_hostapd_param *); 37 38 static 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 60 static 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 */ 86 static 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 109 static 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 189 static 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 199 static 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 223 static 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 232 static 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 241 static int 242 wpa_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 262 static 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 293 static 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 300 static 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 307 static 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 314 static struct wpa_scan_results * 315 wpa_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 322 static 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 329 static 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 355 static 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 364 const 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