]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Propagate the EAP method error code
authorAhmed ElArabawy <arabawy@google.com>
Thu, 15 Mar 2018 16:00:10 +0000 (09:00 -0700)
committerJouni Malinen <j@w1.fi>
Sat, 31 Mar 2018 08:57:33 +0000 (11:57 +0300)
In the current implementation, upon an EAP method failure, followed by
an EAP failure, the EAP Status is propagated up in wpa_supplicant with a
general failure parameter string "failure". This parameter is used for a
notification on the dbus.

This commit reports the EAP method failure error code in a separate
callback.

The solution in this commit is generic to all EAP methods, and can be
used by any method that need to pass its error code. However, this
commit only implements the reporting for EAP-SIM and EAP-AKA methods
where the Notification Code (in AT_NOTIFICATION) is used as the method
specific error code value.

Signed-off-by: Ahmed ElArabawy <arabawy@google.com>
src/common/wpa_ctrl.h
src/eap_peer/eap.c
src/eap_peer/eap.h
src/eap_peer/eap_aka.c
src/eap_peer/eap_i.h
src/eap_peer/eap_sim.c
src/eapol_supp/eapol_supp_sm.c
src/eapol_supp/eapol_supp_sm.h
wpa_supplicant/notify.c
wpa_supplicant/notify.h
wpa_supplicant/wpas_glue.c

index df4564b782179f8498d7d082e185665172712027..a0a11397b30d2516a40ba78375c3bb145497c6d1 100644 (file)
@@ -62,6 +62,7 @@ extern "C" {
 /** 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 */
index 004370706f993f8b2a6ea8659f532be401cf15cd..e55e2d5230dd33ca56ce45f6f826944b11728c7e 100644 (file)
@@ -95,6 +95,14 @@ static void eap_notify_status(struct eap_sm *sm, const char *status,
 }
 
 
+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) {
@@ -2018,6 +2026,15 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
        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:
index b5591a01f7a5c3ca919b6d193e41b27322df2318..d0837e37a0e08b3d53a489d3161cbd4d38d8505a 100644 (file)
@@ -246,6 +246,13 @@ struct eapol_callbacks {
        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
index 7a6bfc99f0c3fc7119274c584db195f2b7e71e91..a4441413f0ddd409ab04f23f053118f39c4ae79a 100644 (file)
@@ -56,6 +56,7 @@ struct eap_aka_data {
        int kdf_negotiation;
        u16 last_kdf_attrs[EAP_AKA_PRIME_KDF_MAX];
        size_t last_kdf_count;
+       int error_code;
 };
 
 
@@ -99,6 +100,9 @@ static void * eap_aka_init(struct eap_sm *sm)
 
        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;
 
@@ -1180,6 +1184,7 @@ static struct wpabuf * eap_aka_process_notification(
 
        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)
@@ -1524,6 +1529,23 @@ static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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;
@@ -1544,6 +1566,7 @@ int eap_peer_aka_register(void)
        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);
 }
@@ -1571,6 +1594,7 @@ int eap_peer_aka_prime_register(void)
        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);
 }
index 6ab24834d654ab9a5c69effd56aa0ed9b53a3c69..096f0f28efca0a480ca8f4fd3b399162f8666015 100644 (file)
@@ -14,6 +14,8 @@
 #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 {
@@ -205,6 +207,17 @@ struct eap_method {
         */
        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
index cd687cbf8849f0876bbb55d1652c8576d58a472b..ba5eea9ddfa2a792f03362eeb1cdbe1ac7df554f 100644 (file)
@@ -47,6 +47,7 @@ struct eap_sim_data {
        } state;
        int result_ind, use_result_ind;
        int use_pseudonym;
+       int error_code;
 };
 
 
@@ -94,6 +95,9 @@ static void * eap_sim_init(struct eap_sm *sm)
                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=");
@@ -920,6 +924,7 @@ static struct wpabuf * eap_sim_process_notification(
 
        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)
@@ -1244,6 +1249,23 @@ static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+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;
@@ -1264,6 +1286,7 @@ int eap_peer_sim_register(void)
        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);
 }
index 8e4f0e46dd53752fbcf7be997656f147f82ad706..bfbc995f63d033cea59d0d807c7628ea6ce1c0de 100644 (file)
@@ -2015,6 +2015,15 @@ static void eapol_sm_notify_status(void *ctx, const char *status,
 }
 
 
+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)
@@ -2062,6 +2071,7 @@ static const struct eapol_callbacks eapol_cb =
        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,
index a25c799892327a67545355b9b715f11944c23bc9..74f40bb1cd63cd860532c43c0d220ba8294b125b 100644 (file)
@@ -271,6 +271,13 @@ struct eapol_ctx {
        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
index 3e67a77f2060c2e150a4cb6f38a8b7519623e50c..83df04f394c749da8b03ee326c3ed03aa9101427 100644 (file)
@@ -816,6 +816,12 @@ void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
 }
 
 
+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)
 {
index 0c113cab541c9a94b977aa312a371d6f353cb6a7..3ca933c7621a5fdbaede958d5b86badcc944ab66 100644 (file)
@@ -134,6 +134,7 @@ void wpas_notify_preq(struct wpa_supplicant *wpa_s,
                      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,
index e44f6afad5ff9b0ee9ace86f2bd6d6154c0b041c..4634ed7fc368cc384fd832d28ec1c08594863335 100644 (file)
@@ -1038,6 +1038,14 @@ static void wpa_supplicant_status_cb(void *ctx, const char *status,
 }
 
 
+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;
@@ -1115,6 +1123,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
        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);