/*
* 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,
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);
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 {
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");
}
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;
}
/* 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.");
}
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:
/* 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);
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)
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++;
}
+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
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;
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,
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 */
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:
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");
/* 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) {
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;
}
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 =
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) {
}
- switch (msg->hdr->code) {
+ switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
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) {
* 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;
/* 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");
}
+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;
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;
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
#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);
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)
{