]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wpa_supplicant.c
TDLS: Get TDLS related capabilities from driver
[thirdparty/hostap.git] / wpa_supplicant / wpa_supplicant.c
index 2c5a20c6207b7bc76b189b3ddad3ed8d7130d50e..058feed1e80de044353ef7830626c936a3da3d41 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "common.h"
 #include "crypto/random.h"
+#include "crypto/sha1.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
 #include "eap_server/eap_methods.h"
@@ -35,7 +36,6 @@
 #include "rsn_supp/preauth.h"
 #include "rsn_supp/pmksa_cache.h"
 #include "common/wpa_ctrl.h"
-#include "mlme.h"
 #include "common/ieee802_11_defs.h"
 #include "p2p/p2p.h"
 #include "blacklist.h"
 #include "wps_supplicant.h"
 #include "ibss_rsn.h"
 #include "sme.h"
+#include "gas_query.h"
 #include "ap.h"
 #include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
 #include "bss.h"
 #include "scan.h"
+#include "offchannel.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
@@ -368,6 +370,22 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
 }
 
 
+static void free_hw_features(struct wpa_supplicant *wpa_s)
+{
+       int i;
+       if (wpa_s->hw.modes == NULL)
+               return;
+
+       for (i = 0; i < wpa_s->hw.num_modes; i++) {
+               os_free(wpa_s->hw.modes[i].channels);
+               os_free(wpa_s->hw.modes[i].rates);
+       }
+
+       os_free(wpa_s->hw.modes);
+       wpa_s->hw.modes = NULL;
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        bgscan_deinit(wpa_s);
@@ -417,8 +435,6 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpa_supplicant_cancel_scan(wpa_s);
        wpa_supplicant_cancel_auth_timeout(wpa_s);
 
-       ieee80211_sta_deinit(wpa_s);
-
        wpas_wps_deinit(wpa_s);
 
        wpabuf_free(wpa_s->pending_eapol_rx);
@@ -439,8 +455,19 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        wpas_p2p_deinit(wpa_s);
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_OFFCHANNEL
+       offchannel_deinit(wpa_s);
+#endif /* CONFIG_OFFCHANNEL */
+
+       wpa_supplicant_cancel_sched_scan(wpa_s);
+
        os_free(wpa_s->next_scan_freqs);
        wpa_s->next_scan_freqs = NULL;
+
+       gas_query_deinit(wpa_s->gas);
+       wpa_s->gas = NULL;
+
+       free_hw_features(wpa_s);
 }
 
 
@@ -527,6 +554,8 @@ const char * wpa_supplicant_state_txt(enum wpa_states state)
 
 static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
 {
+       if (wpas_driver_bss_selection(wpa_s))
+               return;
        if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
                return;
 
@@ -684,7 +713,6 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
 {
        struct wpa_config *conf;
-       struct wpa_ssid *old_ssid;
        int reconf_ctrl;
        int old_ap_scan;
 
@@ -709,10 +737,10 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        }
 
        eapol_sm_invalidate_cached_session(wpa_s->eapol);
-       old_ssid = wpa_s->current_ssid;
-       wpa_s->current_ssid = NULL;
-       if (old_ssid != wpa_s->current_ssid)
-               wpas_notify_network_changed(wpa_s);
+       if (wpa_s->current_ssid) {
+               wpa_supplicant_deauthenticate(wpa_s,
+                                             WLAN_REASON_DEAUTH_LEAVING);
+       }
 
        /*
         * TODO: should notify EAPOL SM about changes in opensc_engine_path,
@@ -727,6 +755,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        }
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
        wpa_sm_set_config(wpa_s->wpa, NULL);
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
        wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
        rsn_preauth_deinit(wpa_s->wpa);
 
@@ -935,6 +964,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_IEEE80211W */
 
+       wpa_s->wpa_proto = proto;
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
        wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
                         !!(ssid->proto & WPA_PROTO_RSN));
@@ -1047,8 +1077,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 
        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
+#ifndef CONFIG_NO_PBKDF2
+               if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
+                   ssid->passphrase) {
+                       u8 psk[PMK_LEN];
+                       pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid,
+                                   bss->ssid_len, 4096, psk, PMK_LEN);
+                       wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+                                       psk, PMK_LEN);
+                       wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+               }
+#endif /* CONFIG_NO_PBKDF2 */
+       } else
                wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
        return 0;
@@ -1100,7 +1142,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 
 #ifdef CONFIG_TDLS
-       wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1), bss->ie_len);
+       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) &&
@@ -1111,7 +1155,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 
        os_memset(&params, 0, sizeof(params));
        wpa_s->reassociate = 0;
-       if (bss) {
+       if (bss && !wpas_driver_bss_selection(wpa_s)) {
 #ifdef CONFIG_IEEE80211R
                const u8 *ie, *md = NULL;
 #endif /* CONFIG_IEEE80211R */
@@ -1149,6 +1193,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
                os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
        }
+       wpa_supplicant_cancel_sched_scan(wpa_s);
        wpa_supplicant_cancel_scan(wpa_s);
 
        /* Starting new association, so clear the possibly used WPA IE from the
@@ -1221,10 +1266,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        params.wps = WPS_MODE_PRIVACY;
                else
                        params.wps = WPS_MODE_OPEN;
+               wpa_s->wpa_proto = 0;
 #endif /* CONFIG_WPS */
        } else {
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
                wpa_ie_len = 0;
+               wpa_s->wpa_proto = 0;
        }
 
 #ifdef CONFIG_P2P
@@ -1257,6 +1304,22 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_INTERWORKING
+       if (wpa_s->conf->interworking) {
+               u8 *pos = wpa_ie;
+               if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+                       pos += 2 + pos[1];
+               os_memmove(pos + 6, pos, wpa_ie_len - (pos - wpa_ie));
+               wpa_ie_len += 6;
+               *pos++ = WLAN_EID_EXT_CAPAB;
+               *pos++ = 4;
+               *pos++ = 0x00;
+               *pos++ = 0x00;
+               *pos++ = 0x00;
+               *pos++ = 0x80; /* Bit 31 - Interworking */
+       }
+#endif /* CONFIG_INTERWORKING */
+
        wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
        use_crypt = 1;
        cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
@@ -1296,10 +1359,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 
        wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
        if (bss) {
-               params.bssid = bss->bssid;
                params.ssid = bss->ssid;
                params.ssid_len = bss->ssid_len;
-               params.freq = bss->freq;
+               if (!wpas_driver_bss_selection(wpa_s)) {
+                       params.bssid = bss->bssid;
+                       params.freq = bss->freq;
+               }
        } else {
                params.ssid = ssid->ssid;
                params.ssid_len = ssid->ssid_len;
@@ -1312,6 +1377,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        params.pairwise_suite = cipher_pairwise;
        params.group_suite = cipher_group;
        params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+       params.wpa_proto = wpa_s->wpa_proto;
        params.auth_alg = algs;
        params.mode = ssid->mode;
        for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -1347,21 +1413,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_IEEE80211W */
 
-#ifdef CONFIG_P2P
-       if (wpa_s->global->p2p &&
-           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
-               params.p2p = 1;
-#endif /* CONFIG_P2P */
+       params.p2p = ssid->p2p_group;
 
        if (wpa_s->parent->set_sta_uapsd)
                params.uapsd = wpa_s->parent->sta_uapsd;
        else
                params.uapsd = -1;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               ret = ieee80211_sta_associate(wpa_s, &params);
-       else
-               ret = wpa_drv_associate(wpa_s, &params);
+       ret = wpa_drv_associate(wpa_s, &params);
        if (ret < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
                        "failed");
@@ -1467,10 +1526,7 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
        u8 *addr = NULL;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-                       ieee80211_sta_disassociate(wpa_s, reason_code);
-               else
-                       wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
+               wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
                addr = wpa_s->bssid;
        }
 
@@ -1492,11 +1548,7 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
        u8 *addr = NULL;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
-               if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-                       ieee80211_sta_deauthenticate(wpa_s, reason_code);
-               else
-                       wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
-                                              reason_code);
+               wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
                addr = wpa_s->bssid;
        }
 
@@ -1632,6 +1684,15 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
                if (was_disabled != other_ssid->disabled)
                        wpas_notify_network_enabled_changed(wpa_s, other_ssid);
        }
+
+       if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+               /* We are already associated with the selected network */
+               wpa_printf(MSG_DEBUG, "Already associated with the "
+                          "selected network - do nothing");
+               return;
+       }
+
+       wpa_s->connect_without_scan = NULL;
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
        wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1656,6 +1717,16 @@ int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
        if (ap_scan < 0 || ap_scan > 2)
                return -1;
 
+#ifdef ANDROID
+       if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
+           wpa_s->wpa_state >= WPA_ASSOCIATING &&
+           wpa_s->wpa_state < WPA_COMPLETED) {
+               wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
+                          "associating", wpa_s->conf->ap_scan, ap_scan);
+               return 0;
+       }
+#endif /* ANDROID */
+
        old_ap_scan = wpa_s->conf->ap_scan;
        wpa_s->conf->ap_scan = ap_scan;
 
@@ -1768,25 +1839,15 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
        u8 bssid[ETH_ALEN];
        int wired;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-               if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
-                       wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
-                               "MLME");
-                       return NULL;
-               }
-       } else {
-               res = wpa_drv_get_ssid(wpa_s, ssid);
-               if (res < 0) {
-                       wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
-                               "driver");
-                       return NULL;
-               }
-               ssid_len = res;
+       res = wpa_drv_get_ssid(wpa_s, ssid);
+       if (res < 0) {
+               wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
+                       "driver");
+               return NULL;
        }
+       ssid_len = res;
 
-       if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-               os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-       else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+       if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
                wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
                        "driver");
                return NULL;
@@ -1811,6 +1872,12 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
                     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
                        return entry;
 #endif /* CONFIG_WPS */
+
+               if (!entry->disabled && entry->bssid_set &&
+                   entry->ssid_len == 0 &&
+                   os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
+                       return entry;
+
                entry = entry->next;
        }
 
@@ -1818,6 +1885,26 @@ struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
 }
 
 
+static int select_driver(struct wpa_supplicant *wpa_s, int i)
+{
+       struct wpa_global *global = wpa_s->global;
+
+       if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
+               global->drv_priv[i] = wpa_drivers[i]->global_init();
+               if (global->drv_priv[i] == NULL) {
+                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
+                                  "'%s'", wpa_drivers[i]->name);
+                       return -1;
+               }
+       }
+
+       wpa_s->driver = wpa_drivers[i];
+       wpa_s->global_drv_priv = global->drv_priv[i];
+
+       return 0;
+}
+
+
 static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                                     const char *name)
 {
@@ -1836,9 +1923,7 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
 
        if (name == NULL) {
                /* default to first driver in the list */
-               wpa_s->driver = wpa_drivers[0];
-               wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
-               return 0;
+               return select_driver(wpa_s, 0);
        }
 
        do {
@@ -1851,12 +1936,8 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
                for (i = 0; wpa_drivers[i]; i++) {
                        if (os_strlen(wpa_drivers[i]->name) == len &&
                            os_strncmp(driver, wpa_drivers[i]->name, len) ==
-                           0) {
-                               wpa_s->driver = wpa_drivers[i];
-                               wpa_s->global_drv_priv =
-                                       wpa_s->global->drv_priv[i];
-                               return 0;
-                       }
+                           0)
+                               return select_driver(wpa_s, i);
                }
 
                driver = pos + 1;
@@ -2044,7 +2125,10 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
 
        wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
        if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
-               wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
+               if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+                                                     100000))
+                       wpa_supplicant_req_scan(wpa_s, interface_count,
+                                               100000);
                interface_count++;
        } else
                wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -2071,6 +2155,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
        wpa_s->scan_interval = 5;
        wpa_s->new_connection = 1;
        wpa_s->parent = wpa_s;
+       wpa_s->sched_scanning = 0;
 
        return wpa_s;
 }
@@ -2228,13 +2313,17 @@ next_driver:
                return -1;
        }
 
+       wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
+                                                     &wpa_s->hw.num_modes,
+                                                     &wpa_s->hw.flags);
+
        if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+               wpa_s->drv_capa_known = 1;
                wpa_s->drv_flags = capa.flags;
-               if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-                       if (ieee80211_sta_init(wpa_s))
-                               return -1;
-               }
                wpa_s->max_scan_ssids = capa.max_scan_ssids;
+               wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
+               wpa_s->sched_scan_supported = capa.sched_scan_supported;
+               wpa_s->max_match_sets = capa.max_match_sets;
                wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
                wpa_s->max_stations = capa.max_stations;
        }
@@ -2278,6 +2367,12 @@ next_driver:
                return -1;
        }
 
+       wpa_s->gas = gas_query_init(wpa_s);
+       if (wpa_s->gas == NULL) {
+               wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
+               return -1;
+       }
+
 #ifdef CONFIG_P2P
        if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
                wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
@@ -2542,7 +2637,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                return NULL;
        }
 
-       random_init();
+       random_init(params->entropy_file);
 
        global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
        if (global->ctrl_iface == NULL) {
@@ -2567,17 +2662,6 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                wpa_supplicant_deinit(global);
                return NULL;
        }
-       for (i = 0; wpa_drivers[i]; i++) {
-               if (!wpa_drivers[i]->global_init)
-                       continue;
-               global->drv_priv[i] = wpa_drivers[i]->global_init();
-               if (global->drv_priv[i] == NULL) {
-                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
-                                  "'%s'", wpa_drivers[i]->name);
-                       wpa_supplicant_deinit(global);
-                       return NULL;
-               }
-       }
 
        return global;
 }
@@ -2674,6 +2758,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 */
@@ -2686,23 +2782,6 @@ void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
 }
 
 
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-                                   size_t num_hw_features)
-{
-       size_t i;
-
-       if (hw_features == NULL)
-               return;
-
-       for (i = 0; i < num_hw_features; i++) {
-               os_free(hw_features[i].channels);
-               os_free(hw_features[i].rates);
-       }
-
-       os_free(hw_features);
-}
-
-
 static void add_freq(int *freqs, int *num_freqs, int freq)
 {
        int i;
@@ -2809,3 +2888,10 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
        wpa_supplicant_req_scan(wpa_s, timeout / 1000,
                                1000 * (timeout % 1000));
 }
+
+
+int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
+{
+       return wpa_s->conf->ap_scan == 2 ||
+               (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
+}