Move wpa_drivers dependency into config_file.c
[libeap.git] / hostapd / ieee802_1x.c
index a6313fd..9340709 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 
 #include "includes.h"
 
+#include "common.h"
+#include "eloop.h"
+#include "crypto/md5.h"
+#include "crypto/crypto.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
 #include "hostapd.h"
 #include "ieee802_1x.h"
 #include "accounting.h"
-#include "radius/radius.h"
-#include "radius/radius_client.h"
-#include "eapol_sm.h"
-#include "md5.h"
-#include "crypto.h"
-#include "eloop.h"
 #include "sta_info.h"
 #include "wpa.h"
 #include "preauth.h"
 #include "pmksa_cache.h"
-#include "driver_i.h"
+#include "config.h"
 #include "hw_features.h"
 #include "eap_server/eap.h"
-#include "ieee802_11_defs.h"
-#include "wpa_ctrl.h"
 
 
 static void ieee802_1x_finished(struct hostapd_data *hapd,
@@ -68,7 +70,7 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
        if (sta->flags & WLAN_STA_PREAUTH) {
                rsn_preauth_send(hapd, sta, buf, len);
        } else {
-               hostapd_send_eapol(hapd, sta->addr, buf, len, encrypt);
+               hapd->drv.send_eapol(hapd, sta->addr, buf, len, encrypt);
        }
 
        os_free(buf);
@@ -88,8 +90,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
                        wpa_msg(hapd->msg_ctx, MSG_INFO,
                                AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
                sta->flags |= WLAN_STA_AUTHORIZED;
-               res = hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
-                                           WLAN_STA_AUTHORIZED, ~0);
+               res = hapd->drv.set_authorized(hapd, sta, 1);
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
                               HOSTAPD_LEVEL_DEBUG, "authorizing port");
        } else {
@@ -99,8 +100,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
                                AP_STA_DISCONNECTED MACSTR,
                                MAC2STR(sta->addr));
                sta->flags &= ~WLAN_STA_AUTHORIZED;
-               res = hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
-                                           0, ~WLAN_STA_AUTHORIZED);
+               res = hapd->drv.set_authorized(hapd, sta, 0);
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
                               HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
        }
@@ -229,11 +229,11 @@ ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
        wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
                        key->key[key->idx], key->len[key->idx]);
 
-       if (hostapd_set_key(ifname, hapd, WPA_ALG_WEP, NULL, key->idx, 1,
-                           NULL, 0, key->key[key->idx], key->len[key->idx]))
+       if (hapd->drv.set_key(ifname, hapd, WPA_ALG_WEP, NULL, key->idx, 1,
+                             NULL, 0, key->key[key->idx], key->len[key->idx]))
                printf("Could not set dynamic VLAN WEP encryption key.\n");
 
-       hostapd_set_ieee8021x(ifname, hapd, 1);
+       hostapd_set_drv_ieee8021x(hapd, ifname, 1);
 
        return key;
 }
@@ -345,9 +345,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
 
                /* TODO: set encryption in TX callback, i.e., only after STA
                 * has ACKed EAPOL-Key frame */
-               if (hostapd_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
-                                   sta->addr, 0, 1, NULL, 0, ikey,
-                                   hapd->conf->individual_wep_key_len)) {
+               if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
+                                     sta->addr, 0, 1, NULL, 0, ikey,
+                                     hapd->conf->individual_wep_key_len)) {
                        wpa_printf(MSG_ERROR, "Could not set individual WEP "
                                   "encryption.");
                }
@@ -359,10 +359,7 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
 
 const char *radius_mode_txt(struct hostapd_data *hapd)
 {
-       if (hapd->iface->current_mode == NULL)
-               return "802.11";
-
-       switch (hapd->iface->current_mode->mode) {
+       switch (hapd->iface->conf->hw_mode) {
        case HOSTAPD_MODE_IEEE80211A:
                return "802.11a";
        case HOSTAPD_MODE_IEEE80211G:
@@ -537,7 +534,8 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
 
        /* State attribute must be copied if and only if this packet is
         * Access-Request reply to the previous Access-Challenge */
-       if (sm->last_recv_radius && sm->last_recv_radius->hdr->code ==
+       if (sm->last_recv_radius &&
+           radius_msg_get_hdr(sm->last_recv_radius)->code ==
            RADIUS_CODE_ACCESS_CHALLENGE) {
                int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
                                               RADIUS_ATTR_STATE);
@@ -556,33 +554,10 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
 
  fail:
        radius_msg_free(msg);
-       os_free(msg);
 }
 #endif /* CONFIG_NO_RADIUS */
 
 
-char *eap_type_text(u8 type)
-{
-       switch (type) {
-       case EAP_TYPE_IDENTITY: return "Identity";
-       case EAP_TYPE_NOTIFICATION: return "Notification";
-       case EAP_TYPE_NAK: return "Nak";
-       case EAP_TYPE_MD5: return "MD5-Challenge";
-       case EAP_TYPE_OTP: return "One-Time Password";
-       case EAP_TYPE_GTC: return "Generic Token Card";
-       case EAP_TYPE_TLS: return "TLS";
-       case EAP_TYPE_TTLS: return "TTLS";
-       case EAP_TYPE_PEAP: return "PEAP";
-       case EAP_TYPE_SIM: return "SIM";
-       case EAP_TYPE_FAST: return "FAST";
-       case EAP_TYPE_SAKE: return "SAKE";
-       case EAP_TYPE_PSK: return "PSK";
-       case EAP_TYPE_PAX: return "PAX";
-       default: return "Unknown";
-       }
-}
-
-
 static void handle_eap_response(struct hostapd_data *hapd,
                                struct sta_info *sta, struct eap_hdr *eap,
                                size_t len)
@@ -605,7 +580,7 @@ static void handle_eap_response(struct hostapd_data *hapd,
                       HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
                       "id=%d len=%d) from STA: EAP Response-%s (%d)",
                       eap->code, eap->identifier, be_to_host16(eap->length),
-                      eap_type_text(type), type);
+                      eap_server_get_name(0, type), type);
 
        sm->dot1xAuthEapolRespFramesRx++;
 
@@ -665,6 +640,23 @@ static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
+static struct eapol_state_machine *
+ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       int flags = 0;
+       if (sta->flags & WLAN_STA_PREAUTH)
+               flags |= EAPOL_SM_PREAUTH;
+       if (sta->wpa_sm) {
+               if (wpa_auth_sta_get_pmksa(sta->wpa_sm))
+                       flags |= EAPOL_SM_USES_WPA;
+               if (wpa_auth_sta_get_pmksa(sta->wpa_sm))
+                       flags |= EAPOL_SM_FROM_PMKSA_CACHE;
+       }
+       return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
+                               sta->wps_ie, sta);
+}
+
+
 /**
  * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
  * @hapd: hostapd BSS data
@@ -739,9 +731,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
                return;
 
        if (!sta->eapol_sm) {
-               sta->eapol_sm = eapol_auth_alloc(hapd->eapol_auth, sta->addr,
-                                                sta->flags & WLAN_STA_PREAUTH,
-                                                sta);
+               sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
                if (!sta->eapol_sm)
                        return;
 
@@ -858,9 +848,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
        if (sta->eapol_sm == NULL) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
                               HOSTAPD_LEVEL_DEBUG, "start authentication");
-               sta->eapol_sm = eapol_auth_alloc(hapd->eapol_auth, sta->addr,
-                                                sta->flags & WLAN_STA_PREAUTH,
-                                                sta);
+               sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
                if (sta->eapol_sm == NULL) {
                        hostapd_logger(hapd, sta->addr,
                                       HOSTAPD_MODULE_IEEE8021X,
@@ -929,10 +917,7 @@ void ieee802_1x_free_station(struct sta_info *sta)
        sta->eapol_sm = NULL;
 
 #ifndef CONFIG_NO_RADIUS
-       if (sm->last_recv_radius) {
-               radius_msg_free(sm->last_recv_radius);
-               os_free(sm->last_recv_radius);
-       }
+       radius_msg_free(sm->last_recv_radius);
        radius_free_class(&sm->radius_class);
 #endif /* CONFIG_NO_RADIUS */
 
@@ -991,12 +976,14 @@ static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
                if (eap_type >= 0)
                        sm->eap_type_authsrv = eap_type;
                os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
-                           eap_type >= 0 ? eap_type_text(eap_type) : "??",
+                           eap_type >= 0 ? eap_server_get_name(0, eap_type) :
+                           "??",
                            eap_type);
                break;
        case EAP_CODE_RESPONSE:
                os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
-                           eap_type >= 0 ? eap_type_text(eap_type) : "??",
+                           eap_type >= 0 ? eap_server_get_name(0, eap_type) :
+                           "??",
                            eap_type);
                break;
        case EAP_CODE_SUCCESS:
@@ -1206,8 +1193,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
        int session_timeout_set, old_vlanid = 0;
        struct eapol_state_machine *sm;
        int override_eapReq = 0;
+       struct radius_hdr *hdr = radius_msg_get_hdr(msg);
 
-       sm = ieee802_1x_search_radius_identifier(hapd, msg->hdr->identifier);
+       sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
        if (sm == NULL) {
                wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
                           "station for this RADIUS message");
@@ -1217,7 +1205,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
 
        /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
         * present when packet contains an EAP-Message attribute */
-       if (msg->hdr->code == RADIUS_CODE_ACCESS_REJECT &&
+       if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
            radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
                                0) < 0 &&
            radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
@@ -1231,9 +1219,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                return RADIUS_RX_INVALID_AUTHENTICATOR;
        }
 
-       if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
-           msg->hdr->code != RADIUS_CODE_ACCESS_REJECT &&
-           msg->hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
+       if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
+           hdr->code != RADIUS_CODE_ACCESS_REJECT &&
+           hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
                printf("Unknown RADIUS message code\n");
                return RADIUS_RX_UNKNOWN;
        }
@@ -1242,11 +1230,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
        wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR,
                   MAC2STR(sta->addr));
 
-       if (sm->last_recv_radius) {
-               radius_msg_free(sm->last_recv_radius);
-               os_free(sm->last_recv_radius);
-       }
-
+       radius_msg_free(sm->last_recv_radius);
        sm->last_recv_radius = msg;
 
        session_timeout_set =
@@ -1257,7 +1241,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
                termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
 
        if (hapd->conf->acct_interim_interval == 0 &&
-           msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
+           hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
            radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
                                      &acct_interim_interval) == 0) {
                if (acct_interim_interval < 60) {
@@ -1272,7 +1256,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
        }
 
 
-       switch (msg->hdr->code) {
+       switch (hdr->code) {
        case RADIUS_CODE_ACCESS_ACCEPT:
                if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
                        sta->vlan_id = 0;
@@ -1369,11 +1353,8 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
                       HOSTAPD_LEVEL_DEBUG, "aborting authentication");
 
 #ifndef CONFIG_NO_RADIUS
-       if (sm->last_recv_radius) {
-               radius_msg_free(sm->last_recv_radius);
-               os_free(sm->last_recv_radius);
-               sm->last_recv_radius = NULL;
-       }
+       radius_msg_free(sm->last_recv_radius);
+       sm->last_recv_radius = NULL;
 #endif /* CONFIG_NO_RADIUS */
 
        if (sm->eap_if->eapTimeout) {
@@ -1383,56 +1364,12 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
                 * could only be sent if the EAP peer actually replied).
                 */
                sm->eap_if->portEnabled = FALSE;
-               hostapd_sta_deauth(hapd, sta->addr,
-                                  WLAN_REASON_PREV_AUTH_NOT_VALID);
-               sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
-                               WLAN_STA_AUTHORIZED);
-               eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-               eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
-               sta->timeout_next = STA_REMOVE;
+               ap_sta_disconnect(hapd, sta, sta->addr,
+                                 WLAN_REASON_PREV_AUTH_NOT_VALID);
        }
 }
 
 
-#ifdef HOSTAPD_DUMP_STATE
-static void fprint_char(FILE *f, char c)
-{
-       if (c >= 32 && c < 127)
-               fprintf(f, "%c", c);
-       else
-               fprintf(f, "<%02x>", c);
-}
-
-
-void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta)
-{
-       struct eapol_state_machine *sm = sta->eapol_sm;
-       if (sm == NULL)
-               return;
-
-       fprintf(f, "%sIEEE 802.1X:\n", prefix);
-
-       if (sm->identity) {
-               size_t i;
-               fprintf(f, "%sidentity=", prefix);
-               for (i = 0; i < sm->identity_len; i++)
-                       fprint_char(f, sm->identity[i]);
-               fprintf(f, "\n");
-       }
-
-       fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
-               "Supplicant: %d (%s)\n", prefix,
-               sm->eap_type_authsrv, eap_type_text(sm->eap_type_authsrv),
-               sm->eap_type_supp, eap_type_text(sm->eap_type_supp));
-
-       fprintf(f, "%scached_packets=%s\n", prefix,
-               sm->last_recv_radius ? "[RX RADIUS]" : "");
-
-       eapol_auth_dump_state(f, prefix, sm);
-}
-#endif /* HOSTAPD_DUMP_STATE */
-
-
 static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
 {
        struct eapol_authenticator *eapol = hapd->eapol_auth;
@@ -1495,10 +1432,10 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
 
        /* TODO: Could setup key for RX here, but change default TX keyid only
         * after new broadcast key has been sent to all stations. */
-       if (hostapd_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, NULL,
-                           eapol->default_wep_key_idx, 1, NULL, 0,
-                           eapol->default_wep_key,
-                           hapd->conf->default_wep_key_len)) {
+       if (hapd->drv.set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, NULL,
+                             eapol->default_wep_key_idx, 1, NULL, 0,
+                             eapol->default_wep_key,
+                             hapd->conf->default_wep_key_len)) {
                hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
                               HOSTAPD_LEVEL_WARNING, "failed to configure a "
                               "new broadcast key");
@@ -1647,6 +1584,22 @@ static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
 }
 
 
+static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
+                                  enum eapol_event type)
+{
+       /* struct hostapd_data *hapd = ctx; */
+       struct sta_info *sta = sta_ctx;
+       switch (type) {
+       case EAPOL_AUTH_SM_CHANGE:
+               wpa_auth_sm_notify(sta->wpa_sm);
+               break;
+       case EAPOL_AUTH_REAUTHENTICATE:
+               wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
+               break;
+       }
+}
+
+
 int ieee802_1x_init(struct hostapd_data *hapd)
 {
        int i;
@@ -1654,7 +1607,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
        struct eapol_auth_cb cb;
 
        os_memset(&conf, 0, sizeof(conf));
-       conf.hapd = hapd;
+       conf.ctx = hapd;
        conf.eap_reauth_period = hapd->conf->eap_reauth_period;
        conf.wpa = hapd->conf->wpa;
        conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
@@ -1684,13 +1637,14 @@ int ieee802_1x_init(struct hostapd_data *hapd)
        cb.set_port_authorized = ieee802_1x_set_port_authorized;
        cb.abort_auth = _ieee802_1x_abort_auth;
        cb.tx_key = _ieee802_1x_tx_key;
+       cb.eapol_event = ieee802_1x_eapol_event;
 
        hapd->eapol_auth = eapol_auth_init(&conf, &cb);
        if (hapd->eapol_auth == NULL)
                return -1;
 
        if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
-           hostapd_set_ieee8021x(hapd->conf->iface, hapd, 1))
+           hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
                return -1;
 
 #ifndef CONFIG_NO_RADIUS
@@ -1700,11 +1654,10 @@ int ieee802_1x_init(struct hostapd_data *hapd)
 #endif /* CONFIG_NO_RADIUS */
 
        if (hapd->conf->default_wep_key_len) {
-               hostapd_set_privacy(hapd, 1);
-
                for (i = 0; i < 4; i++)
-                       hostapd_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
-                                       NULL, i, 0, NULL, 0, NULL, 0);
+                       hapd->drv.set_key(hapd->conf->iface, hapd,
+                                         WPA_ALG_NONE, NULL, i, 0, NULL, 0,
+                                         NULL, 0);
 
                ieee802_1x_rekey(hapd, NULL);
 
@@ -1722,22 +1675,13 @@ void ieee802_1x_deinit(struct hostapd_data *hapd)
 
        if (hapd->driver != NULL &&
            (hapd->conf->ieee802_1x || hapd->conf->wpa))
-               hostapd_set_ieee8021x(hapd->conf->iface, hapd, 0);
+               hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
 
        eapol_auth_deinit(hapd->eapol_auth);
        hapd->eapol_auth = NULL;
 }
 
 
-int ieee802_1x_reconfig(struct hostapd_data *hapd, 
-                       struct hostapd_config *oldconf,
-                       struct hostapd_bss_config *oldbss)
-{
-       ieee802_1x_deinit(hapd);
-       return ieee802_1x_init(hapd);
-}
-
-
 int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
                         const u8 *buf, size_t len, int ack)
 {