driver_hostap.c

Go to the documentation of this file.
00001 
00016 #include <stdlib.h>
00017 #include <stdio.h>
00018 #include <unistd.h>
00019 #include <string.h>
00020 #include <sys/ioctl.h>
00021 #include <errno.h>
00022 
00023 #include "wireless_copy.h"
00024 #include "common.h"
00025 #include "driver.h"
00026 #include "driver_wext.h"
00027 #include "eloop.h"
00028 #include "driver_hostap.h"
00029 #include "l2_packet.h"
00030 #include "wpa_supplicant.h"
00031 
00032 
00033 struct wpa_driver_hostap_data {
00034         void *wext; /* private data for driver_wext */
00035         void *ctx;
00036         char ifname[IFNAMSIZ + 1];
00037         int sock;
00038         int current_mode; /* infra/adhoc */
00039 };
00040 
00041 
00042 static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
00043                          struct prism2_hostapd_param *param,
00044                          int len, int show_err)
00045 {
00046         struct iwreq iwr;
00047 
00048         memset(&iwr, 0, sizeof(iwr));
00049         strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00050         iwr.u.data.pointer = (caddr_t) param;
00051         iwr.u.data.length = len;
00052 
00053         if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
00054                 int ret = errno;
00055                 if (show_err) 
00056                         perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
00057                 return ret;
00058         }
00059 
00060         return 0;
00061 }
00062 
00063 
00064 static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
00065                                         const u8 *wpa_ie, size_t wpa_ie_len)
00066 {
00067         struct prism2_hostapd_param *param;
00068         int res;
00069         size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
00070         if (blen < sizeof(*param))
00071                 blen = sizeof(*param);
00072 
00073         param = (struct prism2_hostapd_param *) malloc(blen);
00074         if (param == NULL)
00075                 return -1;
00076 
00077         memset(param, 0, blen);
00078         param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
00079         param->u.generic_elem.len = wpa_ie_len;
00080         memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
00081         res = hostapd_ioctl(drv, param, blen, 1);
00082 
00083         free(param);
00084 
00085         return res;
00086 }
00087 
00088 
00089 static int prism2param(struct wpa_driver_hostap_data *drv, int param,
00090                        int value)
00091 {
00092         struct iwreq iwr;
00093         int *i, ret = 0;
00094 
00095         memset(&iwr, 0, sizeof(iwr));
00096         strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00097         i = (int *) iwr.u.name;
00098         *i++ = param;
00099         *i++ = value;
00100 
00101         if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
00102                 perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
00103                 ret = -1;
00104         }
00105         return ret;
00106 }
00107 
00108 
00109 static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
00110 {
00111         struct wpa_driver_hostap_data *drv = priv;
00112         int ret = 0;
00113 
00114         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
00115 
00116         if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
00117                 ret = -1;
00118         if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
00119                 ret = -1;
00120         if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
00121                 ret = -1;
00122 
00123         return ret;
00124 }
00125 
00126 
00127 static void show_set_key_error(struct prism2_hostapd_param *param)
00128 {
00129         switch (param->u.crypt.err) {
00130         case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
00131                 wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
00132                            param->u.crypt.alg);
00133                 wpa_printf(MSG_INFO, "You may need to load kernel module to "
00134                            "register that algorithm.");
00135                 wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
00136                            "WEP.");
00137                 break;
00138         case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
00139                 wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
00140                            MAC2STR(param->sta_addr));
00141                 break;
00142         case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
00143                 wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
00144                 break;
00145         case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
00146                 wpa_printf(MSG_INFO, "Key setting failed.");
00147                 break;
00148         case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
00149                 wpa_printf(MSG_INFO, "TX key index setting failed.");
00150                 break;
00151         case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
00152                 wpa_printf(MSG_INFO, "Card configuration failed.");
00153                 break;
00154         }
00155 }
00156 
00157 
00158 static int wpa_driver_hostap_set_key(void *priv, wpa_alg alg,
00159                                      const u8 *addr, int key_idx,
00160                                      int set_tx, const u8 *seq, size_t seq_len,
00161                                      const u8 *key, size_t key_len)
00162 {
00163         struct wpa_driver_hostap_data *drv = priv;
00164         struct prism2_hostapd_param *param;
00165         u8 *buf;
00166         size_t blen;
00167         int ret = 0;
00168         char *alg_name;
00169 
00170         switch (alg) {
00171         case WPA_ALG_NONE:
00172                 alg_name = "none";
00173                 break;
00174         case WPA_ALG_WEP:
00175                 alg_name = "WEP";
00176                 break;
00177         case WPA_ALG_TKIP:
00178                 alg_name = "TKIP";
00179                 break;
00180         case WPA_ALG_CCMP:
00181                 alg_name = "CCMP";
00182                 break;
00183         default:
00184                 return -1;
00185         }
00186 
00187         wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
00188                    "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
00189                    (unsigned long) seq_len, (unsigned long) key_len);
00190 
00191         if (seq_len > 8)
00192                 return -2;
00193 
00194         blen = sizeof(*param) + key_len;
00195         buf = malloc(blen);
00196         if (buf == NULL)
00197                 return -1;
00198         memset(buf, 0, blen);
00199 
00200         param = (struct prism2_hostapd_param *) buf;
00201         param->cmd = PRISM2_SET_ENCRYPTION;
00202         /* TODO: In theory, STA in client mode can use five keys; four default
00203          * keys for receiving (with keyidx 0..3) and one individual key for
00204          * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
00205          * keyidx 0 is reserved for this unicast use and default keys can only
00206          * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
00207          * This should be fine for more or less all cases, but for completeness
00208          * sake, the driver could be enhanced to support the missing key. */
00209 #if 0
00210         if (addr == NULL)
00211                 memset(param->sta_addr, 0xff, ETH_ALEN);
00212         else
00213                 memcpy(param->sta_addr, addr, ETH_ALEN);
00214 #else
00215         memset(param->sta_addr, 0xff, ETH_ALEN);
00216 #endif
00217         strncpy((char *) param->u.crypt.alg, alg_name,
00218                 HOSTAP_CRYPT_ALG_NAME_LEN);
00219         param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
00220         param->u.crypt.idx = key_idx;
00221         memcpy(param->u.crypt.seq, seq, seq_len);
00222         param->u.crypt.key_len = key_len;
00223         memcpy((u8 *) (param + 1), key, key_len);
00224 
00225         if (hostapd_ioctl(drv, param, blen, 1)) {
00226                 wpa_printf(MSG_WARNING, "Failed to set encryption.");
00227                 show_set_key_error(param);
00228                 ret = -1;
00229         }
00230         free(buf);
00231 
00232         return ret;
00233 }
00234 
00235 
00236 static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
00237 {
00238         struct wpa_driver_hostap_data *drv = priv;
00239         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
00240         return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
00241 }
00242 
00243 
00244 static int wpa_driver_hostap_set_drop_unencrypted(void *priv, int enabled)
00245 {
00246         struct wpa_driver_hostap_data *drv = priv;
00247         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
00248         return prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, enabled);
00249 }
00250 
00251 
00252 static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
00253                                    int type)
00254 {
00255         struct iwreq iwr;
00256         int *i, ret = 0;
00257 
00258         wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
00259 
00260         memset(&iwr, 0, sizeof(iwr));
00261         strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
00262         i = (int *) iwr.u.name;
00263         *i++ = type;
00264 
00265         if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
00266                 perror("ioctl[PRISM2_IOCTL_RESET]");
00267                 ret = -1;
00268         }
00269         return ret;
00270 }
00271 
00272 
00273 static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
00274                                   const u8 *addr, int cmd, int reason_code)
00275 {
00276         struct prism2_hostapd_param param;
00277         int ret;
00278 
00279         /* There does not seem to be a better way of deauthenticating or
00280          * disassociating with Prism2/2.5/3 than sending the management frame
00281          * and then resetting the Port0 to make sure both the AP and the STA
00282          * end up in disconnected state. */
00283         memset(&param, 0, sizeof(param));
00284         param.cmd = PRISM2_HOSTAPD_MLME;
00285         memcpy(param.sta_addr, addr, ETH_ALEN);
00286         param.u.mlme.cmd = cmd;
00287         param.u.mlme.reason_code = reason_code;
00288         ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
00289         if (ret == 0) {
00290                 usleep(100000);
00291                 ret = wpa_driver_hostap_reset(drv, 2);
00292         }
00293         return ret;
00294 }
00295 
00296 
00297 static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
00298                                             int reason_code)
00299 {
00300         struct wpa_driver_hostap_data *drv = priv;
00301         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
00302         return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
00303                                       reason_code);
00304 }
00305 
00306 
00307 static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
00308                                           int reason_code)
00309 {
00310         struct wpa_driver_hostap_data *drv = priv;
00311         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
00312         return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
00313                                       reason_code);
00314 }
00315 
00316 
00317 static int
00318 wpa_driver_hostap_associate(void *priv,
00319                             struct wpa_driver_associate_params *params)
00320 {
00321         struct wpa_driver_hostap_data *drv = priv;
00322         int ret = 0;
00323         int allow_unencrypted_eapol;
00324 
00325         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
00326 
00327         if (params->mode != drv->current_mode) {
00328                 /* At the moment, Host AP driver requires host_roaming=2 for
00329                  * infrastructure mode and host_roaming=0 for adhoc. */
00330                 if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
00331                                 params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
00332                     0) {
00333                         wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
00334                                    __func__);
00335                 }
00336                 drv->current_mode = params->mode;
00337         }
00338 
00339         if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
00340                         params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
00341                 ret = -1;
00342         if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
00343                                          params->wpa_ie_len) < 0)
00344                 ret = -1;
00345         if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
00346                 ret = -1;
00347         if (params->freq &&
00348             wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
00349                 ret = -1;
00350         if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
00351             < 0)
00352                 ret = -1;
00353         if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
00354                 ret = -1;
00355 
00356         /* Allow unencrypted EAPOL messages even if pairwise keys are set when
00357          * not using WPA. IEEE 802.1X specifies that these frames are not
00358          * encrypted, but WPA encrypts them when pairwise keys are in use. */
00359         if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
00360             params->key_mgmt_suite == KEY_MGMT_PSK)
00361                 allow_unencrypted_eapol = 0;
00362         else
00363                 allow_unencrypted_eapol = 1;
00364         
00365         if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
00366                         allow_unencrypted_eapol) < 0) {
00367                 wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
00368                            "ieee_802_1x param");
00369                 /* Ignore this error.. driver_hostap.c can also be used with
00370                  * other drivers that do not support this prism2_param. */
00371         }
00372 
00373         return ret;
00374 }
00375 
00376 
00377 static int wpa_driver_hostap_scan(void *priv, const u8 *ssid, size_t ssid_len)
00378 {
00379         struct wpa_driver_hostap_data *drv = priv;
00380         struct prism2_hostapd_param param;
00381         int ret;
00382 
00383         if (ssid == NULL) {
00384                 /* Use standard Linux Wireless Extensions ioctl if possible
00385                  * because some drivers using hostap code in wpa_supplicant
00386                  * might not support Host AP specific scan request (with SSID
00387                  * info). */
00388                 return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
00389         }
00390 
00391         if (ssid_len > 32)
00392                 ssid_len = 32;
00393 
00394         memset(&param, 0, sizeof(param));
00395         param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
00396         param.u.scan_req.ssid_len = ssid_len;
00397         memcpy(param.u.scan_req.ssid, ssid, ssid_len);
00398         ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
00399 
00400         /* Not all drivers generate "scan completed" wireless event, so try to
00401          * read results after a timeout. */
00402         eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
00403                                drv->ctx);
00404 
00405         return ret;
00406 }
00407 
00408 
00409 static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
00410 {
00411         struct wpa_driver_hostap_data *drv = priv;
00412         int algs = 0;
00413 
00414         if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
00415                 algs |= 1;
00416         if (auth_alg & AUTH_ALG_SHARED_KEY)
00417                 algs |= 2;
00418         if (auth_alg & AUTH_ALG_LEAP)
00419                 algs |= 4;
00420         if (algs == 0)
00421                 algs = 1; /* at least one algorithm should be set */
00422 
00423         return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
00424 }
00425 
00426 
00427 static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
00428 {
00429         struct wpa_driver_hostap_data *drv = priv;
00430         return wpa_driver_wext_get_bssid(drv->wext, bssid);
00431 }
00432 
00433 
00434 static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
00435 {
00436         struct wpa_driver_hostap_data *drv = priv;
00437         return wpa_driver_wext_get_ssid(drv->wext, ssid);
00438 }
00439 
00440 
00441 static int wpa_driver_hostap_get_scan_results(void *priv,
00442                                               struct wpa_scan_result *results,
00443                                               size_t max_size)
00444 {
00445         struct wpa_driver_hostap_data *drv = priv;
00446         return wpa_driver_wext_get_scan_results(drv->wext, results, max_size);
00447 }
00448 
00449 
00450 static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
00451 {
00452         struct wpa_driver_hostap_data *drv;
00453 
00454         drv = malloc(sizeof(*drv));
00455         if (drv == NULL)
00456                 return NULL;
00457         memset(drv, 0, sizeof(*drv));
00458         drv->wext = wpa_driver_wext_init(ctx, ifname);
00459         if (drv->wext == NULL) {
00460                 free(drv);
00461                 return NULL;
00462         }
00463 
00464         drv->ctx = ctx;
00465         strncpy(drv->ifname, ifname, sizeof(drv->ifname));
00466         drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
00467         if (drv->sock < 0) {
00468                 perror("socket");
00469                 wpa_driver_wext_deinit(drv->wext);
00470                 free(drv);
00471                 return NULL;
00472         }
00473 
00474         if (strncmp(ifname, "wlan", 4) == 0) {
00475                 /*
00476                  * Host AP driver may use both wlan# and wifi# interface in
00477                  * wireless events.
00478                  */
00479                 char ifname2[IFNAMSIZ + 1];
00480                 strncpy(ifname2, ifname, sizeof(ifname2));
00481                 memcpy(ifname2, "wifi", 4);
00482                 wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
00483         }
00484 
00485         return drv;
00486 }
00487 
00488 
00489 static void wpa_driver_hostap_deinit(void *priv)
00490 {
00491         struct wpa_driver_hostap_data *drv = priv;
00492         wpa_driver_wext_deinit(drv->wext);
00493         close(drv->sock);
00494         free(drv);
00495 }
00496 
00497 
00498 const struct wpa_driver_ops wpa_driver_hostap_ops = {
00499         .name = "hostap",
00500         .desc = "Host AP driver (Intersil Prism2/2.5/3)",
00501         .get_bssid = wpa_driver_hostap_get_bssid,
00502         .get_ssid = wpa_driver_hostap_get_ssid,
00503         .set_wpa = wpa_driver_hostap_set_wpa,
00504         .set_key = wpa_driver_hostap_set_key,
00505         .set_countermeasures = wpa_driver_hostap_set_countermeasures,
00506         .set_drop_unencrypted = wpa_driver_hostap_set_drop_unencrypted,
00507         .scan = wpa_driver_hostap_scan,
00508         .get_scan_results = wpa_driver_hostap_get_scan_results,
00509         .deauthenticate = wpa_driver_hostap_deauthenticate,
00510         .disassociate = wpa_driver_hostap_disassociate,
00511         .associate = wpa_driver_hostap_associate,
00512         .set_auth_alg = wpa_driver_hostap_set_auth_alg,
00513         .init = wpa_driver_hostap_init,
00514         .deinit = wpa_driver_hostap_deinit,
00515 };
00516 

Generated on Sat May 6 21:13:32 2006 for wpa_supplicant by  doxygen 1.4.2