Updated to hostap_2_6
[mech_eap.git] / libeap / src / eap_server / eap_sim_db.c
index acf5435..d84c3d2 100644 (file)
@@ -66,6 +66,7 @@ struct eap_sim_db_data {
        struct eap_sim_pseudonym *pseudonyms;
        struct eap_sim_reauth *reauths;
        struct eap_sim_db_pending *pending;
+       unsigned int eap_sim_db_timeout;
 #ifdef CONFIG_SQLITE
        sqlite3 *sqlite_db;
        char db_tmp_identity[100];
@@ -76,6 +77,10 @@ struct eap_sim_db_data {
 };
 
 
+static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx);
+static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx);
+
+
 #ifdef CONFIG_SQLITE
 
 static int db_table_exists(sqlite3 *db, const char *name)
@@ -397,6 +402,57 @@ static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
 }
 
 
+static void eap_sim_db_free_pending(struct eap_sim_db_data *data,
+                                   struct eap_sim_db_pending *entry)
+{
+       eloop_cancel_timeout(eap_sim_db_query_timeout, data, entry);
+       eloop_cancel_timeout(eap_sim_db_del_timeout, data, entry);
+       os_free(entry);
+}
+
+
+static void eap_sim_db_del_pending(struct eap_sim_db_data *data,
+                                  struct eap_sim_db_pending *entry)
+{
+       struct eap_sim_db_pending **pp = &data->pending;
+
+       while (*pp != NULL) {
+               if (*pp == entry) {
+                       *pp = entry->next;
+                       eap_sim_db_free_pending(data, entry);
+                       return;
+               }
+               pp = &(*pp)->next;
+       }
+}
+
+
+static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx)
+{
+       struct eap_sim_db_data *data = eloop_ctx;
+       struct eap_sim_db_pending *entry = user_ctx;
+
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Delete query timeout for %p", entry);
+       eap_sim_db_del_pending(data, entry);
+}
+
+
+static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx)
+{
+       struct eap_sim_db_data *data = eloop_ctx;
+       struct eap_sim_db_pending *entry = user_ctx;
+
+       /*
+        * Report failure and allow some time for EAP server to process it
+        * before deleting the query.
+        */
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Query timeout for %p", entry);
+       entry->state = FAILURE;
+       data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+       eloop_register_timeout(1, 0, eap_sim_db_del_timeout, data, entry);
+}
+
+
 static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
                                     const char *imsi, char *buf)
 {
@@ -472,7 +528,7 @@ static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
 
 parse_fail:
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
-       os_free(entry);
+       eap_sim_db_free_pending(data, entry);
 }
 
 
@@ -563,7 +619,7 @@ static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
 
 parse_fail:
        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
-       os_free(entry);
+       eap_sim_db_free_pending(data, entry);
 }
 
 
@@ -690,12 +746,13 @@ static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
 /**
  * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
  * @config: Configuration data (e.g., file name)
+ * @db_timeout: Database lookup timeout
  * @get_complete_cb: Callback function for reporting availability of triplets
  * @ctx: Context pointer for get_complete_cb
  * Returns: Pointer to a private data structure or %NULL on failure
  */
 struct eap_sim_db_data *
-eap_sim_db_init(const char *config,
+eap_sim_db_init(const char *config, unsigned int db_timeout,
                void (*get_complete_cb)(void *ctx, void *session_ctx),
                void *ctx)
 {
@@ -709,6 +766,7 @@ eap_sim_db_init(const char *config,
        data->sock = -1;
        data->get_complete_cb = get_complete_cb;
        data->ctx = ctx;
+       data->eap_sim_db_timeout = db_timeout;
        data->fname = os_strdup(config);
        if (data->fname == NULL)
                goto fail;
@@ -796,7 +854,7 @@ void eap_sim_db_deinit(void *priv)
        while (pending) {
                prev_pending = pending;
                pending = pending->next;
-               os_free(prev_pending);
+               eap_sim_db_free_pending(data, prev_pending);
        }
 
        os_free(data);
@@ -833,11 +891,11 @@ static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
 }
 
 
-static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
+static void eap_sim_db_expire_pending(struct eap_sim_db_data *data,
+                                     struct eap_sim_db_pending *entry)
 {
-       /* TODO: add limit for maximum length for pending list; remove latest
-        * (i.e., last) entry from the list if the limit is reached; could also
-        * use timeout to expire pending entries */
+       eloop_register_timeout(data->eap_sim_db_timeout, 0,
+                              eap_sim_db_query_timeout, data, entry);
 }
 
 
@@ -891,7 +949,7 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
                if (entry->state == FAILURE) {
                        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
                                   "failure");
-                       os_free(entry);
+                       eap_sim_db_free_pending(data, entry);
                        return EAP_SIM_DB_FAILURE;
                }
 
@@ -911,7 +969,7 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
                os_memcpy(sres, entry->u.sim.sres,
                          num_chal * EAP_SIM_SRES_LEN);
                os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
-               os_free(entry);
+               eap_sim_db_free_pending(data, entry);
                return num_chal;
        }
 
@@ -945,7 +1003,8 @@ int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
        entry->cb_session_ctx = cb_session_ctx;
        entry->state = PENDING;
        eap_sim_db_add_pending(data, entry);
-       eap_sim_db_expire_pending(data);
+       eap_sim_db_expire_pending(data, entry);
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
 
        return EAP_SIM_DB_PENDING;
 }
@@ -1356,7 +1415,7 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
        entry = eap_sim_db_get_pending(data, imsi, 1);
        if (entry) {
                if (entry->state == FAILURE) {
-                       os_free(entry);
+                       eap_sim_db_free_pending(data, entry);
                        wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
                        return EAP_SIM_DB_FAILURE;
                }
@@ -1375,7 +1434,7 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
                os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
                os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
                *res_len = entry->u.aka.res_len;
-               os_free(entry);
+               eap_sim_db_free_pending(data, entry);
                return 0;
        }
 
@@ -1406,7 +1465,8 @@ int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
        entry->cb_session_ctx = cb_session_ctx;
        entry->state = PENDING;
        eap_sim_db_add_pending(data, entry);
-       eap_sim_db_expire_pending(data);
+       eap_sim_db_expire_pending(data, entry);
+       wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
 
        return EAP_SIM_DB_PENDING;
 }