#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 "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 "rc4.h"
-#include "eloop.h"
+#include "sta_flags.h"
#include "sta_info.h"
#include "wpa.h"
#include "preauth.h"
#include "pmksa_cache.h"
-#include "driver.h"
+#include "driver_i.h"
#include "hw_features.h"
#include "eap_server/eap.h"
-#include "ieee802_11_defs.h"
static void ieee802_1x_finished(struct hostapd_data *hapd,
return;
if (authorized) {
+ if (!(sta->flags & WLAN_STA_AUTHORIZED))
+ 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);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "authorizing port");
} else {
+ if ((sta->flags & (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC)) ==
+ (WLAN_STA_AUTHORIZED | WLAN_STA_ASSOC))
+ wpa_msg(hapd->msg_ctx, MSG_INFO,
+ 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);
}
os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
- rc4((u8 *) (key + 1), key_len, ekey, ekey_len);
+ rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len);
os_free(ekey);
/* This header is needed here for HMAC-MD5, but it will be regenerated
}
+#ifndef CONFIG_NO_VLAN
static struct hostapd_wep_keys *
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_encryption(ifname, hapd, "WEP", NULL, key->idx,
- key->key[key->idx], key->len[key->idx], 1))
+ if (hostapd_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);
return ssid->dyn_vlan_keys[vlan_id];
}
+#endif /* CONFIG_NO_VLAN */
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
{
- struct hostapd_wep_keys *key = NULL;
+ struct eapol_authenticator *eapol = hapd->eapol_auth;
struct eapol_state_machine *sm = sta->eapol_sm;
+#ifndef CONFIG_NO_VLAN
+ struct hostapd_wep_keys *key = NULL;
int vlan_id;
+#endif /* CONFIG_NO_VLAN */
if (sm == NULL || !sm->eap_if->eapKeyData)
return;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
MAC2STR(sta->addr));
+#ifndef CONFIG_NO_VLAN
vlan_id = sta->vlan_id;
if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)
vlan_id = 0;
ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,
key->key[key->idx],
key->len[key->idx]);
- } else if (hapd->default_wep_key) {
- ieee802_1x_tx_key_one(hapd, sta, hapd->default_wep_key_idx, 1,
- hapd->default_wep_key,
+ } else
+#endif /* CONFIG_NO_VLAN */
+ if (eapol->default_wep_key) {
+ ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
+ eapol->default_wep_key,
hapd->conf->default_wep_key_len);
}
/* TODO: set encryption in TX callback, i.e., only after STA
* has ACKed EAPOL-Key frame */
- if (hostapd_set_encryption(hapd->conf->iface, hapd, "WEP",
- sta->addr, 0, ikey,
- hapd->conf->individual_wep_key_len,
- 1)) {
+ if (hostapd_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.");
}
}
+#ifndef CONFIG_NO_RADIUS
static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
struct eapol_state_machine *sm,
const u8 *eap, size_t len)
radius_msg_free(msg);
os_free(msg);
}
-
-
-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";
- }
-}
+#endif /* CONFIG_NO_RADIUS */
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++;
}
-/* Process the EAPOL frames from the Supplicant */
+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
+ * @sa: Source address (sender of the EAPOL frame)
+ * @buf: EAPOL frame
+ * @len: Length of buf in octets
+ *
+ * This function is called for each incoming EAPOL frame from the interface
+ */
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
size_t len)
{
wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
(unsigned long) len, MAC2STR(sa));
sta = ap_get_sta(hapd, sa);
- if (!sta) {
- printf(" no station information available\n");
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
+ "associated STA");
return;
}
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;
sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
}
#endif /* CONFIG_WPS */
+
+ sta->eapol_sm->eap_if->portEnabled = TRUE;
}
/* since we support version 1, we can ignore version field and proceed
}
+/**
+ * ieee802_1x_new_station - Start IEEE 802.1X authentication
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ *
+ * This function is called to start IEEE 802.1X authentication when a new
+ * station completes IEEE 802.11 association.
+ */
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
{
struct rsn_pmksa_cache_entry *pmksa;
int force_1x = 0;
#ifdef CONFIG_WPS
- if (hapd->conf->wps_state &&
+ if (hapd->conf->wps_state && hapd->conf->wpa &&
(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
/*
* Need to enable IEEE 802.1X/EAPOL state machines for possible
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,
}
-void ieee802_1x_free_radius_class(struct radius_class_data *class)
-{
- size_t i;
- if (class == NULL)
- return;
- for (i = 0; i < class->count; i++)
- os_free(class->attr[i].data);
- os_free(class->attr);
- class->attr = NULL;
- class->count = 0;
-}
-
-
-int ieee802_1x_copy_radius_class(struct radius_class_data *dst,
- const struct radius_class_data *src)
-{
- size_t i;
-
- if (src->attr == NULL)
- return 0;
-
- dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
- if (dst->attr == NULL)
- return -1;
-
- dst->count = 0;
-
- for (i = 0; i < src->count; i++) {
- dst->attr[i].data = os_malloc(src->attr[i].len);
- if (dst->attr[i].data == NULL)
- break;
- dst->count++;
- os_memcpy(dst->attr[i].data, src->attr[i].data,
- src->attr[i].len);
- dst->attr[i].len = src->attr[i].len;
- }
-
- return 0;
-}
-
-
void ieee802_1x_free_station(struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
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_free_class(&sm->radius_class);
+#endif /* CONFIG_NO_RADIUS */
os_free(sm->identity);
- ieee802_1x_free_radius_class(&sm->radius_class);
eapol_auth_free(sm);
}
+#ifndef CONFIG_NO_RADIUS
static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta)
{
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:
static void ieee802_1x_get_keys(struct hostapd_data *hapd,
struct sta_info *sta, struct radius_msg *msg,
struct radius_msg *req,
- u8 *shared_secret, size_t shared_secret_len)
+ const u8 *shared_secret,
+ size_t shared_secret_len)
{
struct radius_ms_mppe_keys *keys;
struct eapol_state_machine *sm = sta->eapol_sm;
sm == NULL)
return;
- ieee802_1x_free_radius_class(&sm->radius_class);
+ radius_free_class(&sm->radius_class);
count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
if (count <= 0)
return;
}
-/* Process the RADIUS frames from Authentication Server */
+/**
+ * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: Processing status
+ */
static RadiusRxResult
ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
- u8 *shared_secret, size_t shared_secret_len,
+ const u8 *shared_secret, size_t shared_secret_len,
void *data)
{
struct hostapd_data *hapd = data;
&termination_action))
termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
- if (hapd->conf->radius->acct_interim_interval == 0 &&
+ if (hapd->conf->acct_interim_interval == 0 &&
msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
&acct_interim_interval) == 0) {
case RADIUS_CODE_ACCESS_ACCEPT:
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
+#ifndef CONFIG_NO_VLAN
else {
old_vlanid = sta->vlan_id;
sta->vlan_id = radius_msg_get_vlanid(msg);
"ID in Access-Accept");
break;
}
+#endif /* CONFIG_NO_VLAN */
ap_sta_bind_vlan(hapd, sta, old_vlanid);
return RADIUS_RX_QUEUED;
}
+#endif /* CONFIG_NO_RADIUS */
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
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;
}
+#endif /* CONFIG_NO_RADIUS */
if (sm->eap_if->eapTimeout) {
/*
}
-#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;
+
if (hapd->conf->default_wep_key_len < 1)
return 0;
- os_free(hapd->default_wep_key);
- hapd->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
- if (hapd->default_wep_key == NULL ||
- os_get_random(hapd->default_wep_key,
+ os_free(eapol->default_wep_key);
+ eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
+ if (eapol->default_wep_key == NULL ||
+ os_get_random(eapol->default_wep_key,
hapd->conf->default_wep_key_len)) {
printf("Could not generate random WEP key.\n");
- os_free(hapd->default_wep_key);
- hapd->default_wep_key = NULL;
+ os_free(eapol->default_wep_key);
+ eapol->default_wep_key = NULL;
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
- hapd->default_wep_key,
+ eapol->default_wep_key,
hapd->conf->default_wep_key_len);
return 0;
static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
+ struct eapol_authenticator *eapol = hapd->eapol_auth;
- if (hapd->default_wep_key_idx >= 3)
- hapd->default_wep_key_idx =
+ if (eapol->default_wep_key_idx >= 3)
+ eapol->default_wep_key_idx =
hapd->conf->individual_wep_key_len > 0 ? 1 : 0;
else
- hapd->default_wep_key_idx++;
+ eapol->default_wep_key_idx++;
wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
- hapd->default_wep_key_idx);
+ eapol->default_wep_key_idx);
if (ieee802_1x_rekey_broadcast(hapd)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, "failed to generate a "
"new broadcast key");
- os_free(hapd->default_wep_key);
- hapd->default_wep_key = NULL;
+ os_free(eapol->default_wep_key);
+ eapol->default_wep_key = NULL;
return;
}
/* 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_encryption(hapd->conf->iface, hapd, "WEP", NULL,
- hapd->default_wep_key_idx,
- hapd->default_wep_key,
- hapd->conf->default_wep_key_len, 1)) {
+ 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)) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, "failed to configure a "
"new broadcast key");
- os_free(hapd->default_wep_key);
- hapd->default_wep_key = NULL;
+ os_free(eapol->default_wep_key);
+ eapol->default_wep_key = NULL;
return;
}
static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
const u8 *data, size_t datalen)
{
+#ifndef CONFIG_NO_RADIUS
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
ieee802_1x_encapsulate_radius(hapd, sta, data, datalen);
+#endif /* CONFIG_NO_RADIUS */
}
static void ieee802_1x_logger(void *ctx, const u8 *addr,
eapol_logger_level level, const char *txt)
{
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
struct hostapd_data *hapd = ctx;
int hlevel;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s",
txt);
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
}
}
+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)
hostapd_set_ieee8021x(hapd->conf->iface, hapd, 1))
return -1;
+#ifndef CONFIG_NO_RADIUS
if (radius_client_register(hapd->radius, RADIUS_AUTH,
ieee802_1x_receive_auth, hapd))
return -1;
+#endif /* CONFIG_NO_RADIUS */
if (hapd->conf->default_wep_key_len) {
hostapd_set_privacy(hapd, 1);
for (i = 0; i < 4; i++)
- hostapd_set_encryption(hapd->conf->iface, hapd,
- "none", NULL, i, NULL, 0, 0);
+ hostapd_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
+ NULL, i, 0, NULL, 0, NULL, 0);
ieee802_1x_rekey(hapd, NULL);
- if (hapd->default_wep_key == NULL)
+ if (hapd->eapol_auth->default_wep_key == NULL)
return -1;
}
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
- u8 *buf, size_t len, int ack)
+ const u8 *buf, size_t len, int ack)
{
struct ieee80211_hdr *hdr;
struct ieee802_1x_hdr *xhdr;