]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
random: Add support for maintaining internal entropy store over restarts
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index 7b0bbd1665ec1aa41240f2fd7358d91b7cf96a28..0352c13e728830750847565f1cd343d383224d9e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2011, 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
@@ -19,6 +19,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/random.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
 #include "eap_server/eap_methods.h"
@@ -51,7 +52,7 @@
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi> and contributors";
 
 const char *wpa_supplicant_license =
 "This program is free software. You can distribute it and/or modify it\n"
@@ -202,7 +203,12 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
        wpa_sm_notify_disassoc(wpa_s->wpa);
        wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
        wpa_s->reassociate = 1;
-       wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+       /*
+        * If we timed out, the AP or the local radio may be busy.
+        * So, wait a second until scanning again.
+        */
+       wpa_supplicant_req_scan(wpa_s, 1, 0);
 }
 
 
@@ -397,6 +403,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        rsn_preauth_deinit(wpa_s->wpa);
 
+#ifdef CONFIG_TDLS
+       wpa_tdls_deinit(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
        pmksa_candidate_free(wpa_s->wpa);
        wpa_sm_deinit(wpa_s->wpa);
        wpa_s->wpa = NULL;
@@ -419,14 +429,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_s->ibss_rsn = NULL;
 #endif /* CONFIG_IBSS_RSN */
 
-#ifdef CONFIG_SME
-       os_free(wpa_s->sme.ft_ies);
-       wpa_s->sme.ft_ies = NULL;
-       wpa_s->sme.ft_ies_len = 0;
-#ifdef CONFIG_IEEE80211W
-       sme_stop_sa_query(wpa_s);
-#endif /* CONFIG_IEEE80211W */
-#endif /* CONFIG_SME */
+       sme_deinit(wpa_s);
 
 #ifdef CONFIG_AP
        wpa_supplicant_ap_deinit(wpa_s);
@@ -520,6 +523,41 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
 }
 
 
+#ifdef CONFIG_BGSCAN
+
+static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
+               return;
+
+       bgscan_deinit(wpa_s);
+       if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
+               if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+                       wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+                               "bgscan");
+                       /*
+                        * Live without bgscan; it is only used as a roaming
+                        * optimization, so the initial connection is not
+                        * affected.
+                        */
+               } else
+                       wpa_s->bgscan_ssid = wpa_s->current_ssid;
+       } else
+               wpa_s->bgscan_ssid = NULL;
+}
+
+
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->bgscan_ssid != NULL) {
+               bgscan_deinit(wpa_s);
+               wpa_s->bgscan_ssid = NULL;
+       }
+}
+
+#endif /* CONFIG_BGSCAN */
+
+
 /**
  * wpa_supplicant_set_state - Set current connection state
  * @wpa_s: Pointer to wpa_supplicant data
@@ -570,8 +608,20 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
        }
        wpa_s->wpa_state = state;
 
-       if (wpa_s->wpa_state != old_state)
+#ifdef CONFIG_BGSCAN
+       if (state == WPA_COMPLETED)
+               wpa_supplicant_start_bgscan(wpa_s);
+       else
+               wpa_supplicant_stop_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
+       if (wpa_s->wpa_state != old_state) {
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+
+               if (wpa_s->wpa_state == WPA_COMPLETED ||
+                   old_state == WPA_COMPLETED)
+                       wpas_notify_auth_changed(wpa_s);
+       }
 }
 
 
@@ -1027,6 +1077,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        int assoc_failed = 0;
        struct wpa_ssid *old_ssid;
 
+#ifdef CONFIG_IBSS_RSN
+       ibss_rsn_deinit(wpa_s->ibss_rsn);
+       wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
        if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
            ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
 #ifdef CONFIG_AP
@@ -1044,6 +1099,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                return;
        }
 
+#ifdef CONFIG_TDLS
+       if (bss)
+               wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
+                               bss->ie_len);
+#endif /* CONFIG_TDLS */
+
        if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
            ssid->mode == IEEE80211_MODE_INFRA) {
                sme_authenticate(wpa_s, bss, ssid);
@@ -1333,7 +1394,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        } else if (ssid->mode == WPAS_MODE_IBSS &&
                   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
                   wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
-               ibss_rsn_set_psk(wpa_s->ibss_rsn, ssid->psk);
                /*
                 * RSN IBSS authentication is per-STA and we can disable the
                 * per-BSSID authentication.
@@ -1608,6 +1668,52 @@ int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
 }
 
 
+/**
+ * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_age: Expiration age in seconds
+ * Returns: 0 if succeed or -1 if expire_age has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
+                                         unsigned int bss_expire_age)
+{
+       if (bss_expire_age < 10) {
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
+                       bss_expire_age);
+               return -1;
+       }
+       wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
+               bss_expire_age);
+       wpa_s->conf->bss_expiration_age = bss_expire_age;
+
+       return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_count: number of scans after which an unseen BSS is reclaimed
+ * Returns: 0 if succeed or -1 if expire_count has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
+                                           unsigned int bss_expire_count)
+{
+       if (bss_expire_count < 1) {
+               wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
+                       bss_expire_count);
+               return -1;
+       }
+       wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
+               bss_expire_count);
+       wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
+
+       return 0;
+}
+
+
 /**
  * wpa_supplicant_set_debug_params - Set global debug params
  * @global: wpa_global structure
@@ -1623,7 +1729,8 @@ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
        int old_level, old_timestamp, old_show_keys;
 
        /* check for allowed debuglevels */
-       if (debug_level != MSG_MSGDUMP &&
+       if (debug_level != MSG_EXCESSIVE &&
+           debug_level != MSG_MSGDUMP &&
            debug_level != MSG_DEBUG &&
            debug_level != MSG_INFO &&
            debug_level != MSG_WARNING &&
@@ -1963,6 +2070,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
        if (wpa_s == NULL)
                return NULL;
        wpa_s->scan_req = 1;
+       wpa_s->scan_interval = 5;
        wpa_s->new_connection = 1;
        wpa_s->parent = wpa_s;
 
@@ -2138,6 +2246,11 @@ next_driver:
        if (wpa_supplicant_driver_init(wpa_s) < 0)
                return -1;
 
+#ifdef CONFIG_TDLS
+       if (wpa_tdls_init(wpa_s->wpa))
+               return -1;
+#endif /* CONFIG_TDLS */
+
        if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
            wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
@@ -2167,14 +2280,6 @@ next_driver:
                return -1;
        }
 
-#ifdef CONFIG_IBSS_RSN
-       wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
-       if (!wpa_s->ibss_rsn) {
-               wpa_dbg(wpa_s, MSG_DEBUG, "Failed to init IBSS RSN");
-               return -1;
-       }
-#endif /* CONFIG_IBSS_RSN */
-
 #ifdef CONFIG_P2P
        if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
                wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
@@ -2319,6 +2424,28 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 }
 
 
+/**
+ * wpa_supplicant_get_eap_mode - Get the current EAP mode
+ * @wpa_s: Pointer to the network interface
+ * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
+ */
+const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
+{
+       const char *eapol_method;
+
+        if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
+            wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+               return "NO-EAP";
+       }
+
+       eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
+       if (eapol_method == NULL)
+               return "UNKNOWN-EAP";
+
+       return eapol_method;
+}
+
+
 /**
  * wpa_supplicant_get_iface - Get a new network interface
  * @global: Pointer to global data from wpa_supplicant_init()
@@ -2417,6 +2544,8 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                return NULL;
        }
 
+       random_init(params->entropy_file);
+
        global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
        if (global->ctrl_iface == NULL) {
                wpa_supplicant_deinit(global);
@@ -2527,6 +2656,8 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        }
        os_free(global->drv_priv);
 
+       random_deinit();
+
        eloop_destroy();
 
        if (global->params.pid_file) {
@@ -2545,6 +2676,18 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 
 void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
 {
+       if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
+           wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+               char country[3];
+               country[0] = wpa_s->conf->country[0];
+               country[1] = wpa_s->conf->country[1];
+               country[2] = '\0';
+               if (wpa_drv_set_country(wpa_s, country) < 0) {
+                       wpa_printf(MSG_ERROR, "Failed to set country code "
+                                  "'%s'", country);
+               }
+       }
+
 #ifdef CONFIG_WPS
        wpas_wps_update_config(wpa_s);
 #endif /* CONFIG_WPS */