Added support for global driver data (shared by multiple interfaces)
[libeap.git] / wpa_supplicant / wpa_supplicant.c
index 9bd5435..9813a47 100644 (file)
@@ -38,6 +38,8 @@
 #include "ieee802_11_defs.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
+#include "wps/wps.h"
+#include "wps_supplicant.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
@@ -187,7 +189,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_supplicant *wpa_s = eloop_ctx;
        const u8 *bssid = wpa_s->bssid;
-       if (os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+       if (is_zero_ether_addr(bssid))
                bssid = wpa_s->pending_bssid;
        wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
                MAC2STR(bssid));
@@ -212,7 +214,7 @@ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
                                     int sec, int usec)
 {
        if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
-           wpa_s->driver && os_strcmp(wpa_s->driver->name, "wired") == 0)
+           wpa_s->driver && IS_WIRED(wpa_s->driver))
                return;
 
        wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
@@ -251,11 +253,9 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
        struct eapol_config eapol_conf;
        struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-       if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-           wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK) {
-               eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
-               eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
-       }
+       eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+       eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
            wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
                eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
@@ -274,17 +274,17 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
                                EAPOL_REQUIRE_KEY_BROADCAST;
                }
 
-               if (wpa_s->conf && wpa_s->driver &&
-                   os_strcmp(wpa_s->driver->name, "wired") == 0) {
+               if (wpa_s->conf && wpa_s->driver && IS_WIRED(wpa_s->driver)) {
                        eapol_conf.required_keys = 0;
                }
        }
        if (wpa_s->conf)
                eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
        eapol_conf.workaround = ssid->eap_workaround;
-       eapol_conf.eap_disabled = wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
-               wpa_s->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
-               wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+       eapol_conf.eap_disabled =
+               !wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
+               wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+               wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
        eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 #endif /* IEEE8021X_EAPOL */
 }
@@ -304,7 +304,9 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 {
        int i;
 
-       if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
+       if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+               wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
+       else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
        else
                wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
@@ -384,6 +386,8 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_supplicant_cancel_auth_timeout(wpa_s);
 
        ieee80211_sta_deinit(wpa_s);
+
+       wpas_wps_deinit(wpa_s);
 }
 
 
@@ -562,8 +566,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
         * TODO: should notify EAPOL SM about changes in opensc_engine_path,
         * pkcs11_engine_path, pkcs11_module_path.
         */
-       if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-           wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+       if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
                /*
                 * Clear forced success to clear EAP state for next
                 * authentication.
@@ -634,6 +637,12 @@ static wpa_key_mgmt key_mgmt2driver(int key_mgmt)
                return KEY_MGMT_FT_802_1X;
        case WPA_KEY_MGMT_FT_PSK:
                return KEY_MGMT_FT_PSK;
+       case WPA_KEY_MGMT_IEEE8021X_SHA256:
+               return KEY_MGMT_802_1X_SHA256;
+       case WPA_KEY_MGMT_PSK_SHA256:
+               return KEY_MGMT_PSK_SHA256;
+       case WPA_KEY_MGMT_WPS:
+               return KEY_MGMT_WPS;
        case WPA_KEY_MGMT_PSK:
        default:
                return KEY_MGMT_PSK;
@@ -676,7 +685,7 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
        }
 
 #ifdef CONFIG_IEEE80211W
-       if (!(ie->capabilities & WPA_CAPABILITY_MGMT_FRAME_PROTECTION) &&
+       if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
            ssid->ieee80211w == IEEE80211W_REQUIRED) {
                wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
                        "that does not support management frame protection - "
@@ -822,6 +831,16 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
                wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+       } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
+               wpa_msg(wpa_s, MSG_DEBUG,
+                       "WPA: using KEY_MGMT 802.1X with SHA256");
+       } else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
+               wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+               wpa_msg(wpa_s, MSG_DEBUG,
+                       "WPA: using KEY_MGMT PSK with SHA256");
+#endif /* CONFIG_IEEE80211W */
        } else if (sel & WPA_KEY_MGMT_IEEE8021X) {
                wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
                wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -845,7 +864,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 #ifdef CONFIG_IEEE80211W
        sel = ie.mgmt_group_cipher;
        if (ssid->ieee80211w == NO_IEEE80211W ||
-           !(ie.capabilities & WPA_CAPABILITY_MGMT_FRAME_PROTECTION))
+           !(ie.capabilities & WPA_CAPABILITY_MFPC))
                sel = 0;
        if (sel & WPA_CIPHER_AES_128_CMAC) {
                wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
@@ -864,7 +883,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
-       if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK))
+       if (ssid->key_mgmt &
+           (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
                wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
        else
                wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
@@ -910,7 +930,22 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
                        md = ie + 2;
                wpa_sm_set_ft_params(wpa_s->wpa, md, NULL, 0, NULL);
+               if (md) {
+                       /* Prepare for the next transition */
+                       wpa_ft_prepare_auth_request(wpa_s->wpa);
+               }
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+       } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
+                  wpa_s->conf->ap_scan == 2 &&
+                  (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+               /* Use ap_scan==1 style network selection to find the network
+                */
+               wpa_s->scan_req = 2;
+               wpa_s->reassociate = 1;
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+               return;
+#endif /* CONFIG_WPS */
        } else {
                wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
@@ -922,6 +957,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
         * previous association. */
        wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
 
+       if (wpa_drv_set_mode(wpa_s, ssid->mode)) {
+               wpa_printf(MSG_WARNING, "Failed to set operating mode");
+               assoc_failed = 1;
+       }
+
 #ifdef IEEE8021X_EAPOL
        if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
                if (ssid->leap) {
@@ -950,7 +990,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                    wpa_scan_get_ie(bss, WLAN_EID_RSN)) &&
            (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
                               WPA_KEY_MGMT_FT_IEEE8021X |
-                              WPA_KEY_MGMT_FT_PSK))) {
+                              WPA_KEY_MGMT_FT_PSK |
+                              WPA_KEY_MGMT_IEEE8021X_SHA256 |
+                              WPA_KEY_MGMT_PSK_SHA256))) {
                int try_opportunistic;
                try_opportunistic = ssid->proactive_key_caching &&
                        (ssid->proto & WPA_PROTO_RSN);
@@ -968,7 +1010,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        } else if (ssid->key_mgmt &
                   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
                    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-                   WPA_KEY_MGMT_FT_IEEE8021X)) {
+                   WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
+                   WPA_KEY_MGMT_IEEE8021X_SHA256)) {
                wpa_ie_len = sizeof(wpa_ie);
                if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
                                              wpa_ie, &wpa_ie_len)) {
@@ -977,6 +1020,17 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                                   "results)");
                        return;
                }
+#ifdef CONFIG_WPS
+       } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+               struct wpabuf *wps_ie;
+               wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
+               if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
+                       wpa_ie_len = wpabuf_len(wps_ie);
+                       os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
+               }
+               wpabuf_free(wps_ie);
+               wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+#endif /* CONFIG_WPS */
        } else {
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
                wpa_ie_len = 0;
@@ -995,6 +1049,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wep_keys_set = 1;
                }
        }
+       if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
+               use_crypt = 0;
 
 #ifdef IEEE8021X_EAPOL
        if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
@@ -1090,13 +1146,15 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
        } else {
                /* Timeout for IEEE 802.11 authentication and association */
-               int timeout;
-               if (assoc_failed)
-                       timeout = 5;
-               else if (wpa_s->conf->ap_scan == 1)
-                       timeout = 10;
-               else
-                       timeout = 60;
+               int timeout = 60;
+
+               if (assoc_failed) {
+                       /* give IBSS a bit more time */
+                       timeout = ssid->mode ? 10 : 5;
+               } else if (wpa_s->conf->ap_scan == 1) {
+                       /* give IBSS a bit more time */
+                       timeout = ssid->mode ? 20 : 10;
+               }
                wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
        }
 
@@ -1131,8 +1189,7 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
                                 int reason_code)
 {
        u8 *addr = NULL;
-       if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0)
-       {
+       if (!is_zero_ether_addr(wpa_s->bssid)) {
                if (wpa_s->use_client_mlme)
                        ieee80211_sta_disassociate(wpa_s, reason_code);
                else
@@ -1160,8 +1217,7 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
 {
        u8 *addr = NULL;
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-       if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0)
-       {
+       if (!is_zero_ether_addr(wpa_s->bssid)) {
                if (wpa_s->use_client_mlme)
                        ieee80211_sta_deauthenticate(wpa_s, reason_code);
                else
@@ -1363,7 +1419,7 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
        }
 
        wired = wpa_s->conf->ap_scan == 0 && wpa_s->driver &&
-               os_strcmp(wpa_s->driver->name, "wired") == 0;
+               IS_WIRED(wpa_s->driver);
 
        entry = wpa_s->conf->ssid;
        while (entry) {
@@ -1373,6 +1429,14 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                    (!entry->bssid_set ||
                     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
                        return entry;
+#ifdef CONFIG_WPS
+               if (!entry->disabled &&
+                   (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
+                   (entry->ssid == NULL || entry->ssid_len == 0) &&
+                   (!entry->bssid_set ||
+                    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+                       return entry;
+#endif /* CONFIG_WPS */
                entry = entry->next;
        }
 
@@ -1428,15 +1492,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 
        if (wpa_s->eapol_received == 0 &&
            (!wpa_s->driver_4way_handshake ||
-            (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
-             wpa_s->key_mgmt != WPA_KEY_MGMT_FT_PSK) ||
+            !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
             wpa_s->wpa_state != WPA_COMPLETED)) {
                /* Timeout for completing IEEE 802.1X and WPA authentication */
                wpa_supplicant_req_auth_timeout(
                        wpa_s,
-                       (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-                        wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
-                        wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) ?
+                       (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+                        wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) ?
                        70 : 10, 0);
        }
        wpa_s->eapol_received++;
@@ -1454,15 +1516,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
         * still sent to the current BSSID (if available), though. */
 
        os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
-       if (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
-           wpa_s->key_mgmt != WPA_KEY_MGMT_FT_PSK &&
+       if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
            eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
                return;
        wpa_drv_poll(wpa_s);
        if (!wpa_s->driver_4way_handshake)
                wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
-       else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-                wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+       else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
                /*
                 * Set portValid = TRUE here since we are going to skip 4-way
                 * handshake processing which would normally set portValid. We
@@ -1749,8 +1809,17 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s)
        if (wpa_supplicant_driver_init(wpa_s) < 0)
                return -1;
 
+       if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
+           wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
+               wpa_printf(MSG_DEBUG, "Failed to set country");
+               return -1;
+       }
+
        wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
 
+       if (wpas_wps_init(wpa_s))
+               return -1;
+
        if (wpa_supplicant_init_eapol(wpa_s) < 0)
                return -1;
        wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
@@ -1930,7 +1999,7 @@ struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
 struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 {
        struct wpa_global *global;
-       int ret;
+       int ret, i;
 
        if (params == NULL)
                return NULL;
@@ -1985,6 +2054,30 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                }
        }
 
+       for (i = 0; wpa_supplicant_drivers[i]; i++)
+               global->drv_count++;
+       if (global->drv_count == 0) {
+               wpa_printf(MSG_ERROR, "No drivers enabled");
+               wpa_supplicant_deinit(global);
+               return NULL;
+       }
+       global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+       if (global->drv_priv == NULL) {
+               wpa_supplicant_deinit(global);
+               return NULL;
+       }
+       for (i = 0; wpa_supplicant_drivers[i]; i++) {
+               if (!wpa_supplicant_drivers[i]->global_init)
+                       continue;
+               global->drv_priv[i] = wpa_supplicant_drivers[i]->global_init();
+               if (global->drv_priv[i] == NULL) {
+                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
+                                  "'%s'", wpa_supplicant_drivers[i]->name);
+                       wpa_supplicant_deinit(global);
+                       return NULL;
+               }
+       }
+
        return global;
 }
 
@@ -2031,6 +2124,8 @@ int wpa_supplicant_run(struct wpa_global *global)
  */
 void wpa_supplicant_deinit(struct wpa_global *global)
 {
+       int i;
+
        if (global == NULL)
                return;
 
@@ -2044,6 +2139,13 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 
        eap_peer_unregister_methods();
 
+       for (i = 0; wpa_supplicant_drivers[i]; i++) {
+               if (!global->drv_priv[i])
+                       continue;
+               wpa_supplicant_drivers[i]->global_deinit(global->drv_priv[i]);
+       }
+       os_free(global->drv_priv);
+
        eloop_destroy();
 
        if (global->params.pid_file) {