/** EAP authentication failed due to no response received */
#define WPA_EVENT_EAP_TIMEOUT_FAILURE "CTRL-EVENT-EAP-TIMEOUT-FAILURE "
#define WPA_EVENT_EAP_TIMEOUT_FAILURE2 "CTRL-EVENT-EAP-TIMEOUT-FAILURE2 "
+#define WPA_EVENT_EAP_ERROR_CODE "EAP-ERROR-CODE "
/** Network block temporarily disabled (e.g., due to authentication failure) */
#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
/** Temporarily disabled network block re-enabled */
}
+static void eap_report_error(struct eap_sm *sm, int error_code)
+{
+ wpa_printf(MSG_DEBUG, "EAP: Error notification: %d", error_code);
+ if (sm->eapol_cb->notify_eap_error)
+ sm->eapol_cb->notify_eap_error(sm->eapol_ctx, error_code);
+}
+
+
static void eap_sm_free_key(struct eap_sm *sm)
{
if (sm->eapKeyData) {
case EAP_CODE_FAILURE:
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
eap_notify_status(sm, "completion", "failure");
+
+ /* Get the error code from method */
+ if (sm->m && sm->m->get_error_code) {
+ int error_code;
+
+ error_code = sm->m->get_error_code(sm->eap_method_priv);
+ if (error_code != NO_EAP_METHOD_ERROR)
+ eap_report_error(sm, error_code);
+ }
sm->rxFailure = TRUE;
break;
case EAP_CODE_INITIATE:
void (*notify_status)(void *ctx, const char *status,
const char *parameter);
+ /**
+ * notify_eap_error - Report EAP method error code
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @error_code: Error code from the used EAP method
+ */
+ void (*notify_eap_error)(void *ctx, int error_code);
+
#ifdef CONFIG_EAP_PROXY
/**
* eap_proxy_cb - Callback signifying any updates from eap_proxy
int kdf_negotiation;
u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
size_t last_kdf_count;
+ int error_code;
};
data->eap_method = EAP_TYPE_AKA;
+ /* Zero is a valid error code, so we need to initialize */
+ data->error_code = NO_EAP_METHOD_ERROR;
+
eap_aka_state(data, CONTINUE);
data->prev_id = -1;
eap_sim_report_notification(sm->msg_ctx, attr->notification, 1);
if (attr->notification >= 0 && attr->notification < 32768) {
+ data->error_code = attr->notification;
eap_aka_state(data, FAILURE);
} else if (attr->notification == EAP_SIM_SUCCESS &&
data->state == RESULT_SUCCESS)
}
+static int eap_aka_get_error_code(void *priv)
+{
+ struct eap_aka_data *data = priv;
+ int current_data_error;
+
+ if (!data)
+ return NO_EAP_METHOD_ERROR;
+
+ current_data_error = data->error_code;
+
+ /* Now reset for next transaction */
+ data->error_code = NO_EAP_METHOD_ERROR;
+
+ return current_data_error;
+}
+
+
int eap_peer_aka_register(void)
{
struct eap_method *eap;
eap->init_for_reauth = eap_aka_init_for_reauth;
eap->get_identity = eap_aka_get_identity;
eap->get_emsk = eap_aka_get_emsk;
+ eap->get_error_code = eap_aka_get_error_code;
return eap_peer_method_register(eap);
}
eap->init_for_reauth = eap_aka_init_for_reauth;
eap->get_identity = eap_aka_get_identity;
eap->get_emsk = eap_aka_get_emsk;
+ eap->get_error_code = eap_aka_get_error_code;
return eap_peer_method_register(eap);
}
#include "eap_peer/eap.h"
#include "eap_common/eap_common.h"
+#define NO_EAP_METHOD_ERROR (-1)
+
/* RFC 4137 - EAP Peer state machine */
typedef enum {
*/
const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
+ /**
+ * get_error_code - Get the latest EAP method error code
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * Returns: An int for the EAP method specific error code if exists or
+ * NO_EAP_METHOD_ERROR otherwise.
+ *
+ * This method is an optional handler that only EAP methods that need to
+ * report their error code need to implement.
+ */
+ int (*get_error_code)(void *priv);
+
/**
* free - Free EAP method data
* @method: Pointer to the method data registered with
} state;
int result_ind, use_result_ind;
int use_pseudonym;
+ int error_code;
};
return NULL;
}
+ /* Zero is a valid error code, so we need to initialize */
+ data->error_code = NO_EAP_METHOD_ERROR;
+
data->min_num_chal = 2;
if (config && config->phase1) {
char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
eap_sim_report_notification(sm->msg_ctx, attr->notification, 0);
if (attr->notification >= 0 && attr->notification < 32768) {
+ data->error_code = attr->notification;
eap_sim_state(data, FAILURE);
} else if (attr->notification == EAP_SIM_SUCCESS &&
data->state == RESULT_SUCCESS)
}
+static int eap_sim_get_error_code(void *priv)
+{
+ struct eap_sim_data *data = priv;
+ int current_data_error;
+
+ if (!data)
+ return NO_EAP_METHOD_ERROR;
+
+ current_data_error = data->error_code;
+
+ /* Now reset for next transaction */
+ data->error_code = NO_EAP_METHOD_ERROR;
+
+ return current_data_error;
+}
+
+
int eap_peer_sim_register(void)
{
struct eap_method *eap;
eap->init_for_reauth = eap_sim_init_for_reauth;
eap->get_identity = eap_sim_get_identity;
eap->get_emsk = eap_sim_get_emsk;
+ eap->get_error_code = eap_sim_get_error_code;
return eap_peer_method_register(eap);
}
}
+static void eapol_sm_notify_eap_error(void *ctx, int error_code)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->eap_error_cb)
+ sm->ctx->eap_error_cb(sm->ctx->ctx, error_code);
+}
+
+
#ifdef CONFIG_EAP_PROXY
static void eapol_sm_eap_proxy_cb(void *ctx)
eapol_sm_eap_param_needed,
eapol_sm_notify_cert,
eapol_sm_notify_status,
+ eapol_sm_notify_eap_error,
#ifdef CONFIG_EAP_PROXY
eapol_sm_eap_proxy_cb,
eapol_sm_eap_proxy_notify_sim_status,
void (*status_cb)(void *ctx, const char *status,
const char *parameter);
+ /**
+ * eap_error_cb - Notification of EAP method error
+ * @ctx: Callback context (ctx)
+ * @error_code: EAP method error code
+ */
+ void (*eap_error_cb)(void *ctx, int error_code);
+
#ifdef CONFIG_EAP_PROXY
/**
* eap_proxy_cb - Callback signifying any updates from eap_proxy
}
+void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code)
+{
+ wpa_msg(wpa_s, MSG_ERROR, WPA_EVENT_EAP_ERROR_CODE "%d", error_code);
+}
+
+
void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
const u8 *ie, size_t ie_len, u32 ssi_signal);
void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
const char *parameter);
+void wpas_notify_eap_error(struct wpa_supplicant *wpa_s, int error_code);
void wpas_notify_network_bssid_set_changed(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_notify_network_type_changed(struct wpa_supplicant *wpa_s,
}
+static void wpa_supplicant_eap_error_cb(void *ctx, int error_code)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpas_notify_eap_error(wpa_s, error_code);
+}
+
+
static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
ctx->cert_cb = wpa_supplicant_cert_cb;
ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
ctx->status_cb = wpa_supplicant_status_cb;
+ ctx->eap_error_cb = wpa_supplicant_eap_error_cb;
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);