16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer * WPA Supplicant
3*a1157835SDaniel Fojt * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
76d49e1aeSJan Lentfer *
86d49e1aeSJan Lentfer * This file implements functions for registering and unregistering
96d49e1aeSJan Lentfer * %wpa_supplicant interfaces. In addition, this file contains number of
106d49e1aeSJan Lentfer * functions for managing network connections.
116d49e1aeSJan Lentfer */
126d49e1aeSJan Lentfer
136d49e1aeSJan Lentfer #include "includes.h"
14*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
15*a1157835SDaniel Fojt #include <net/if.h>
16*a1157835SDaniel Fojt #include <fnmatch.h>
17*a1157835SDaniel Fojt #endif /* CONFIG_MATCH_IFACE */
186d49e1aeSJan Lentfer
196d49e1aeSJan Lentfer #include "common.h"
203ff40c12SJohn Marino #include "crypto/random.h"
213ff40c12SJohn Marino #include "crypto/sha1.h"
226d49e1aeSJan Lentfer #include "eapol_supp/eapol_supp_sm.h"
236d49e1aeSJan Lentfer #include "eap_peer/eap.h"
243ff40c12SJohn Marino #include "eap_peer/eap_proxy.h"
253ff40c12SJohn Marino #include "eap_server/eap_methods.h"
263ff40c12SJohn Marino #include "rsn_supp/wpa.h"
276d49e1aeSJan Lentfer #include "eloop.h"
286d49e1aeSJan Lentfer #include "config.h"
293ff40c12SJohn Marino #include "utils/ext_password.h"
306d49e1aeSJan Lentfer #include "l2_packet/l2_packet.h"
316d49e1aeSJan Lentfer #include "wpa_supplicant_i.h"
323ff40c12SJohn Marino #include "driver_i.h"
336d49e1aeSJan Lentfer #include "ctrl_iface.h"
346d49e1aeSJan Lentfer #include "pcsc_funcs.h"
353ff40c12SJohn Marino #include "common/version.h"
363ff40c12SJohn Marino #include "rsn_supp/preauth.h"
373ff40c12SJohn Marino #include "rsn_supp/pmksa_cache.h"
383ff40c12SJohn Marino #include "common/wpa_ctrl.h"
39*a1157835SDaniel Fojt #include "common/ieee802_11_common.h"
403ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
41*a1157835SDaniel Fojt #include "common/hw_features_common.h"
42*a1157835SDaniel Fojt #include "common/gas_server.h"
43*a1157835SDaniel Fojt #include "common/dpp.h"
443ff40c12SJohn Marino #include "p2p/p2p.h"
45*a1157835SDaniel Fojt #include "fst/fst.h"
466d49e1aeSJan Lentfer #include "blacklist.h"
476d49e1aeSJan Lentfer #include "wpas_glue.h"
486d49e1aeSJan Lentfer #include "wps_supplicant.h"
493ff40c12SJohn Marino #include "ibss_rsn.h"
503ff40c12SJohn Marino #include "sme.h"
513ff40c12SJohn Marino #include "gas_query.h"
523ff40c12SJohn Marino #include "ap.h"
533ff40c12SJohn Marino #include "p2p_supplicant.h"
543ff40c12SJohn Marino #include "wifi_display.h"
553ff40c12SJohn Marino #include "notify.h"
563ff40c12SJohn Marino #include "bgscan.h"
573ff40c12SJohn Marino #include "autoscan.h"
583ff40c12SJohn Marino #include "bss.h"
593ff40c12SJohn Marino #include "scan.h"
603ff40c12SJohn Marino #include "offchannel.h"
613ff40c12SJohn Marino #include "hs20_supplicant.h"
623ff40c12SJohn Marino #include "wnm_sta.h"
63*a1157835SDaniel Fojt #include "wpas_kay.h"
64*a1157835SDaniel Fojt #include "mesh.h"
65*a1157835SDaniel Fojt #include "dpp_supplicant.h"
66*a1157835SDaniel Fojt #ifdef CONFIG_MESH
67*a1157835SDaniel Fojt #include "ap/ap_config.h"
68*a1157835SDaniel Fojt #include "ap/hostapd.h"
69*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
706d49e1aeSJan Lentfer
71*a1157835SDaniel Fojt const char *const wpa_supplicant_version =
726d49e1aeSJan Lentfer "wpa_supplicant v" VERSION_STR "\n"
73*a1157835SDaniel Fojt "Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors";
746d49e1aeSJan Lentfer
75*a1157835SDaniel Fojt const char *const wpa_supplicant_license =
763ff40c12SJohn Marino "This software may be distributed under the terms of the BSD license.\n"
773ff40c12SJohn Marino "See README for more details.\n"
786d49e1aeSJan Lentfer #ifdef EAP_TLS_OPENSSL
796d49e1aeSJan Lentfer "\nThis product includes software developed by the OpenSSL Project\n"
806d49e1aeSJan Lentfer "for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
816d49e1aeSJan Lentfer #endif /* EAP_TLS_OPENSSL */
826d49e1aeSJan Lentfer ;
836d49e1aeSJan Lentfer
846d49e1aeSJan Lentfer #ifndef CONFIG_NO_STDOUT_DEBUG
856d49e1aeSJan Lentfer /* Long text divided into parts in order to fit in C89 strings size limits. */
86*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license1 =
873ff40c12SJohn Marino "";
88*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license2 =
893ff40c12SJohn Marino "This software may be distributed under the terms of the BSD license.\n"
906d49e1aeSJan Lentfer "\n"
916d49e1aeSJan Lentfer "Redistribution and use in source and binary forms, with or without\n"
926d49e1aeSJan Lentfer "modification, are permitted provided that the following conditions are\n"
936d49e1aeSJan Lentfer "met:\n"
946d49e1aeSJan Lentfer "\n";
95*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license3 =
966d49e1aeSJan Lentfer "1. Redistributions of source code must retain the above copyright\n"
976d49e1aeSJan Lentfer " notice, this list of conditions and the following disclaimer.\n"
986d49e1aeSJan Lentfer "\n"
996d49e1aeSJan Lentfer "2. Redistributions in binary form must reproduce the above copyright\n"
1006d49e1aeSJan Lentfer " notice, this list of conditions and the following disclaimer in the\n"
1016d49e1aeSJan Lentfer " documentation and/or other materials provided with the distribution.\n"
1026d49e1aeSJan Lentfer "\n";
103*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license4 =
1046d49e1aeSJan Lentfer "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
1056d49e1aeSJan Lentfer " names of its contributors may be used to endorse or promote products\n"
1066d49e1aeSJan Lentfer " derived from this software without specific prior written permission.\n"
1076d49e1aeSJan Lentfer "\n"
1086d49e1aeSJan Lentfer "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
1096d49e1aeSJan Lentfer "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
1106d49e1aeSJan Lentfer "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
1116d49e1aeSJan Lentfer "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n";
112*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license5 =
1136d49e1aeSJan Lentfer "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
1146d49e1aeSJan Lentfer "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
1156d49e1aeSJan Lentfer "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
1166d49e1aeSJan Lentfer "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
1176d49e1aeSJan Lentfer "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
1186d49e1aeSJan Lentfer "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
1196d49e1aeSJan Lentfer "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
1206d49e1aeSJan Lentfer "\n";
1216d49e1aeSJan Lentfer #endif /* CONFIG_NO_STDOUT_DEBUG */
1226d49e1aeSJan Lentfer
123*a1157835SDaniel Fojt
124*a1157835SDaniel Fojt static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
125*a1157835SDaniel Fojt #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
126*a1157835SDaniel Fojt static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
127*a1157835SDaniel Fojt #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
128*a1157835SDaniel Fojt
129*a1157835SDaniel Fojt
1306d49e1aeSJan Lentfer /* Configure default/group WEP keys for static WEP */
wpa_set_wep_keys(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1313ff40c12SJohn Marino int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
1326d49e1aeSJan Lentfer {
1336d49e1aeSJan Lentfer int i, set = 0;
1346d49e1aeSJan Lentfer
1356d49e1aeSJan Lentfer for (i = 0; i < NUM_WEP_KEYS; i++) {
1366d49e1aeSJan Lentfer if (ssid->wep_key_len[i] == 0)
1376d49e1aeSJan Lentfer continue;
1386d49e1aeSJan Lentfer
1396d49e1aeSJan Lentfer set = 1;
1403ff40c12SJohn Marino wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
1413ff40c12SJohn Marino i, i == ssid->wep_tx_keyidx, NULL, 0,
1426d49e1aeSJan Lentfer ssid->wep_key[i], ssid->wep_key_len[i]);
1436d49e1aeSJan Lentfer }
1446d49e1aeSJan Lentfer
1456d49e1aeSJan Lentfer return set;
1466d49e1aeSJan Lentfer }
1476d49e1aeSJan Lentfer
1486d49e1aeSJan Lentfer
wpa_supplicant_set_wpa_none_key(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1493ff40c12SJohn Marino int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
1506d49e1aeSJan Lentfer struct wpa_ssid *ssid)
1516d49e1aeSJan Lentfer {
1526d49e1aeSJan Lentfer u8 key[32];
1536d49e1aeSJan Lentfer size_t keylen;
1543ff40c12SJohn Marino enum wpa_alg alg;
1556d49e1aeSJan Lentfer u8 seq[6] = { 0 };
156*a1157835SDaniel Fojt int ret;
1576d49e1aeSJan Lentfer
1586d49e1aeSJan Lentfer /* IBSS/WPA-None uses only one key (Group) for both receiving and
1596d49e1aeSJan Lentfer * sending unicast and multicast packets. */
1606d49e1aeSJan Lentfer
1613ff40c12SJohn Marino if (ssid->mode != WPAS_MODE_IBSS) {
1623ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid mode %d (not "
1633ff40c12SJohn Marino "IBSS/ad-hoc) for WPA-None", ssid->mode);
1646d49e1aeSJan Lentfer return -1;
1656d49e1aeSJan Lentfer }
1666d49e1aeSJan Lentfer
1676d49e1aeSJan Lentfer if (!ssid->psk_set) {
1683ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "WPA: No PSK configured for "
1693ff40c12SJohn Marino "WPA-None");
1706d49e1aeSJan Lentfer return -1;
1716d49e1aeSJan Lentfer }
1726d49e1aeSJan Lentfer
1736d49e1aeSJan Lentfer switch (wpa_s->group_cipher) {
1746d49e1aeSJan Lentfer case WPA_CIPHER_CCMP:
1756d49e1aeSJan Lentfer os_memcpy(key, ssid->psk, 16);
1766d49e1aeSJan Lentfer keylen = 16;
1776d49e1aeSJan Lentfer alg = WPA_ALG_CCMP;
1786d49e1aeSJan Lentfer break;
1793ff40c12SJohn Marino case WPA_CIPHER_GCMP:
1803ff40c12SJohn Marino os_memcpy(key, ssid->psk, 16);
1813ff40c12SJohn Marino keylen = 16;
1823ff40c12SJohn Marino alg = WPA_ALG_GCMP;
1833ff40c12SJohn Marino break;
1846d49e1aeSJan Lentfer case WPA_CIPHER_TKIP:
1856d49e1aeSJan Lentfer /* WPA-None uses the same Michael MIC key for both TX and RX */
1866d49e1aeSJan Lentfer os_memcpy(key, ssid->psk, 16 + 8);
1876d49e1aeSJan Lentfer os_memcpy(key + 16 + 8, ssid->psk + 16, 8);
1886d49e1aeSJan Lentfer keylen = 32;
1896d49e1aeSJan Lentfer alg = WPA_ALG_TKIP;
1906d49e1aeSJan Lentfer break;
1916d49e1aeSJan Lentfer default:
1923ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid group cipher %d for "
1936d49e1aeSJan Lentfer "WPA-None", wpa_s->group_cipher);
1946d49e1aeSJan Lentfer return -1;
1956d49e1aeSJan Lentfer }
1966d49e1aeSJan Lentfer
1976d49e1aeSJan Lentfer /* TODO: should actually remember the previously used seq#, both for TX
1986d49e1aeSJan Lentfer * and RX from each STA.. */
1996d49e1aeSJan Lentfer
200*a1157835SDaniel Fojt ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
201*a1157835SDaniel Fojt os_memset(key, 0, sizeof(key));
202*a1157835SDaniel Fojt return ret;
2036d49e1aeSJan Lentfer }
2046d49e1aeSJan Lentfer
2056d49e1aeSJan Lentfer
wpa_supplicant_timeout(void * eloop_ctx,void * timeout_ctx)2066d49e1aeSJan Lentfer static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
2076d49e1aeSJan Lentfer {
2086d49e1aeSJan Lentfer struct wpa_supplicant *wpa_s = eloop_ctx;
2096d49e1aeSJan Lentfer const u8 *bssid = wpa_s->bssid;
210*a1157835SDaniel Fojt if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
211*a1157835SDaniel Fojt (wpa_s->wpa_state == WPA_AUTHENTICATING ||
212*a1157835SDaniel Fojt wpa_s->wpa_state == WPA_ASSOCIATING))
2136d49e1aeSJan Lentfer bssid = wpa_s->pending_bssid;
2146d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
2156d49e1aeSJan Lentfer MAC2STR(bssid));
2166d49e1aeSJan Lentfer wpa_blacklist_add(wpa_s, bssid);
2176d49e1aeSJan Lentfer wpa_sm_notify_disassoc(wpa_s->wpa);
2183ff40c12SJohn Marino wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2196d49e1aeSJan Lentfer wpa_s->reassociate = 1;
2203ff40c12SJohn Marino
2213ff40c12SJohn Marino /*
2223ff40c12SJohn Marino * If we timed out, the AP or the local radio may be busy.
2233ff40c12SJohn Marino * So, wait a second until scanning again.
2243ff40c12SJohn Marino */
2253ff40c12SJohn Marino wpa_supplicant_req_scan(wpa_s, 1, 0);
2266d49e1aeSJan Lentfer }
2276d49e1aeSJan Lentfer
2286d49e1aeSJan Lentfer
2296d49e1aeSJan Lentfer /**
2306d49e1aeSJan Lentfer * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication
2316d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
2326d49e1aeSJan Lentfer * @sec: Number of seconds after which to time out authentication
2336d49e1aeSJan Lentfer * @usec: Number of microseconds after which to time out authentication
2346d49e1aeSJan Lentfer *
2356d49e1aeSJan Lentfer * This function is used to schedule a timeout for the current authentication
2366d49e1aeSJan Lentfer * attempt.
2376d49e1aeSJan Lentfer */
wpa_supplicant_req_auth_timeout(struct wpa_supplicant * wpa_s,int sec,int usec)2386d49e1aeSJan Lentfer void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
2396d49e1aeSJan Lentfer int sec, int usec)
2406d49e1aeSJan Lentfer {
2413ff40c12SJohn Marino if (wpa_s->conf->ap_scan == 0 &&
2423ff40c12SJohn Marino (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
2436d49e1aeSJan Lentfer return;
2446d49e1aeSJan Lentfer
2453ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
2466d49e1aeSJan Lentfer "%d usec", sec, usec);
2476d49e1aeSJan Lentfer eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
248*a1157835SDaniel Fojt wpa_s->last_auth_timeout_sec = sec;
2496d49e1aeSJan Lentfer eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
2506d49e1aeSJan Lentfer }
2516d49e1aeSJan Lentfer
2526d49e1aeSJan Lentfer
253*a1157835SDaniel Fojt /*
254*a1157835SDaniel Fojt * wpas_auth_timeout_restart - Restart and change timeout for authentication
255*a1157835SDaniel Fojt * @wpa_s: Pointer to wpa_supplicant data
256*a1157835SDaniel Fojt * @sec_diff: difference in seconds applied to original timeout value
257*a1157835SDaniel Fojt */
wpas_auth_timeout_restart(struct wpa_supplicant * wpa_s,int sec_diff)258*a1157835SDaniel Fojt void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff)
259*a1157835SDaniel Fojt {
260*a1157835SDaniel Fojt int new_sec = wpa_s->last_auth_timeout_sec + sec_diff;
261*a1157835SDaniel Fojt
262*a1157835SDaniel Fojt if (eloop_is_timeout_registered(wpa_supplicant_timeout, wpa_s, NULL)) {
263*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
264*a1157835SDaniel Fojt "Authentication timeout restart: %d sec", new_sec);
265*a1157835SDaniel Fojt eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
266*a1157835SDaniel Fojt eloop_register_timeout(new_sec, 0, wpa_supplicant_timeout,
267*a1157835SDaniel Fojt wpa_s, NULL);
268*a1157835SDaniel Fojt }
269*a1157835SDaniel Fojt }
270*a1157835SDaniel Fojt
271*a1157835SDaniel Fojt
2726d49e1aeSJan Lentfer /**
2736d49e1aeSJan Lentfer * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
2746d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
2756d49e1aeSJan Lentfer *
2766d49e1aeSJan Lentfer * This function is used to cancel authentication timeout scheduled with
2776d49e1aeSJan Lentfer * wpa_supplicant_req_auth_timeout() and it is called when authentication has
2786d49e1aeSJan Lentfer * been completed.
2796d49e1aeSJan Lentfer */
wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant * wpa_s)2806d49e1aeSJan Lentfer void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
2816d49e1aeSJan Lentfer {
2823ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
2836d49e1aeSJan Lentfer eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
2846d49e1aeSJan Lentfer wpa_blacklist_del(wpa_s, wpa_s->bssid);
285*a1157835SDaniel Fojt os_free(wpa_s->last_con_fail_realm);
286*a1157835SDaniel Fojt wpa_s->last_con_fail_realm = NULL;
287*a1157835SDaniel Fojt wpa_s->last_con_fail_realm_len = 0;
2886d49e1aeSJan Lentfer }
2896d49e1aeSJan Lentfer
2906d49e1aeSJan Lentfer
2916d49e1aeSJan Lentfer /**
2926d49e1aeSJan Lentfer * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
2936d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
2946d49e1aeSJan Lentfer *
2956d49e1aeSJan Lentfer * This function is used to configure EAPOL state machine based on the selected
2966d49e1aeSJan Lentfer * authentication mode.
2976d49e1aeSJan Lentfer */
wpa_supplicant_initiate_eapol(struct wpa_supplicant * wpa_s)2986d49e1aeSJan Lentfer void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
2996d49e1aeSJan Lentfer {
3006d49e1aeSJan Lentfer #ifdef IEEE8021X_EAPOL
3016d49e1aeSJan Lentfer struct eapol_config eapol_conf;
3026d49e1aeSJan Lentfer struct wpa_ssid *ssid = wpa_s->current_ssid;
3036d49e1aeSJan Lentfer
3043ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
3053ff40c12SJohn Marino if (ssid->mode == WPAS_MODE_IBSS &&
3063ff40c12SJohn Marino wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
3073ff40c12SJohn Marino wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
3083ff40c12SJohn Marino /*
3093ff40c12SJohn Marino * RSN IBSS authentication is per-STA and we can disable the
3103ff40c12SJohn Marino * per-BSSID EAPOL authentication.
3113ff40c12SJohn Marino */
3123ff40c12SJohn Marino eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
3133ff40c12SJohn Marino eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
3143ff40c12SJohn Marino eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
3153ff40c12SJohn Marino return;
3163ff40c12SJohn Marino }
3173ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
3183ff40c12SJohn Marino
3196d49e1aeSJan Lentfer eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
3206d49e1aeSJan Lentfer eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
3216d49e1aeSJan Lentfer
3226d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
3236d49e1aeSJan Lentfer wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
3246d49e1aeSJan Lentfer eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
3256d49e1aeSJan Lentfer else
3266d49e1aeSJan Lentfer eapol_sm_notify_portControl(wpa_s->eapol, Auto);
3276d49e1aeSJan Lentfer
3286d49e1aeSJan Lentfer os_memset(&eapol_conf, 0, sizeof(eapol_conf));
3296d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3306d49e1aeSJan Lentfer eapol_conf.accept_802_1x_keys = 1;
3316d49e1aeSJan Lentfer eapol_conf.required_keys = 0;
3326d49e1aeSJan Lentfer if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) {
3336d49e1aeSJan Lentfer eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST;
3346d49e1aeSJan Lentfer }
3356d49e1aeSJan Lentfer if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) {
3366d49e1aeSJan Lentfer eapol_conf.required_keys |=
3376d49e1aeSJan Lentfer EAPOL_REQUIRE_KEY_BROADCAST;
3386d49e1aeSJan Lentfer }
3396d49e1aeSJan Lentfer
3403ff40c12SJohn Marino if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)
3416d49e1aeSJan Lentfer eapol_conf.required_keys = 0;
3426d49e1aeSJan Lentfer }
3436d49e1aeSJan Lentfer eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
3446d49e1aeSJan Lentfer eapol_conf.workaround = ssid->eap_workaround;
3456d49e1aeSJan Lentfer eapol_conf.eap_disabled =
3466d49e1aeSJan Lentfer !wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
3476d49e1aeSJan Lentfer wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
3486d49e1aeSJan Lentfer wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
3493ff40c12SJohn Marino eapol_conf.external_sim = wpa_s->conf->external_sim;
350*a1157835SDaniel Fojt
351*a1157835SDaniel Fojt #ifdef CONFIG_WPS
352*a1157835SDaniel Fojt if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
353*a1157835SDaniel Fojt eapol_conf.wps |= EAPOL_LOCAL_WPS_IN_USE;
354*a1157835SDaniel Fojt if (wpa_s->current_bss) {
355*a1157835SDaniel Fojt struct wpabuf *ie;
356*a1157835SDaniel Fojt ie = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
357*a1157835SDaniel Fojt WPS_IE_VENDOR_TYPE);
358*a1157835SDaniel Fojt if (ie) {
359*a1157835SDaniel Fojt if (wps_is_20(ie))
360*a1157835SDaniel Fojt eapol_conf.wps |=
361*a1157835SDaniel Fojt EAPOL_PEER_IS_WPS20_AP;
362*a1157835SDaniel Fojt wpabuf_free(ie);
363*a1157835SDaniel Fojt }
364*a1157835SDaniel Fojt }
365*a1157835SDaniel Fojt }
366*a1157835SDaniel Fojt #endif /* CONFIG_WPS */
367*a1157835SDaniel Fojt
3686d49e1aeSJan Lentfer eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
369*a1157835SDaniel Fojt
370*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
371*a1157835SDaniel Fojt if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
372*a1157835SDaniel Fojt ieee802_1x_create_preshared_mka(wpa_s, ssid);
373*a1157835SDaniel Fojt else
374*a1157835SDaniel Fojt ieee802_1x_alloc_kay_sm(wpa_s, ssid);
375*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
3766d49e1aeSJan Lentfer #endif /* IEEE8021X_EAPOL */
3776d49e1aeSJan Lentfer }
3786d49e1aeSJan Lentfer
3796d49e1aeSJan Lentfer
3806d49e1aeSJan Lentfer /**
3816d49e1aeSJan Lentfer * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode
3826d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
3836d49e1aeSJan Lentfer * @ssid: Configuration data for the network
3846d49e1aeSJan Lentfer *
3856d49e1aeSJan Lentfer * This function is used to configure WPA state machine and related parameters
3866d49e1aeSJan Lentfer * to a mode where WPA is not enabled. This is called as part of the
3876d49e1aeSJan Lentfer * authentication configuration when the selected network does not use WPA.
3886d49e1aeSJan Lentfer */
wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)3896d49e1aeSJan Lentfer void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
3906d49e1aeSJan Lentfer struct wpa_ssid *ssid)
3916d49e1aeSJan Lentfer {
3926d49e1aeSJan Lentfer int i;
3936d49e1aeSJan Lentfer
3946d49e1aeSJan Lentfer if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
3956d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
3966d49e1aeSJan Lentfer else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
3976d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
3986d49e1aeSJan Lentfer else
3996d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
4006d49e1aeSJan Lentfer wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
4016d49e1aeSJan Lentfer wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
4026d49e1aeSJan Lentfer wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
4036d49e1aeSJan Lentfer wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
4046d49e1aeSJan Lentfer wpa_s->group_cipher = WPA_CIPHER_NONE;
4056d49e1aeSJan Lentfer wpa_s->mgmt_group_cipher = 0;
4066d49e1aeSJan Lentfer
4076d49e1aeSJan Lentfer for (i = 0; i < NUM_WEP_KEYS; i++) {
4086d49e1aeSJan Lentfer if (ssid->wep_key_len[i] > 5) {
4096d49e1aeSJan Lentfer wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
4106d49e1aeSJan Lentfer wpa_s->group_cipher = WPA_CIPHER_WEP104;
4116d49e1aeSJan Lentfer break;
4126d49e1aeSJan Lentfer } else if (ssid->wep_key_len[i] > 0) {
4136d49e1aeSJan Lentfer wpa_s->pairwise_cipher = WPA_CIPHER_WEP40;
4146d49e1aeSJan Lentfer wpa_s->group_cipher = WPA_CIPHER_WEP40;
4156d49e1aeSJan Lentfer break;
4166d49e1aeSJan Lentfer }
4176d49e1aeSJan Lentfer }
4186d49e1aeSJan Lentfer
4196d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
4206d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
4216d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
4226d49e1aeSJan Lentfer wpa_s->pairwise_cipher);
4236d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
4246d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
4256d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
4266d49e1aeSJan Lentfer wpa_s->mgmt_group_cipher);
4276d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
4286d49e1aeSJan Lentfer
4296d49e1aeSJan Lentfer pmksa_cache_clear_current(wpa_s->wpa);
4306d49e1aeSJan Lentfer }
4316d49e1aeSJan Lentfer
4326d49e1aeSJan Lentfer
free_hw_features(struct wpa_supplicant * wpa_s)4333ff40c12SJohn Marino void free_hw_features(struct wpa_supplicant *wpa_s)
4343ff40c12SJohn Marino {
4353ff40c12SJohn Marino int i;
4363ff40c12SJohn Marino if (wpa_s->hw.modes == NULL)
4373ff40c12SJohn Marino return;
4383ff40c12SJohn Marino
4393ff40c12SJohn Marino for (i = 0; i < wpa_s->hw.num_modes; i++) {
4403ff40c12SJohn Marino os_free(wpa_s->hw.modes[i].channels);
4413ff40c12SJohn Marino os_free(wpa_s->hw.modes[i].rates);
4423ff40c12SJohn Marino }
4433ff40c12SJohn Marino
4443ff40c12SJohn Marino os_free(wpa_s->hw.modes);
4453ff40c12SJohn Marino wpa_s->hw.modes = NULL;
4463ff40c12SJohn Marino }
4473ff40c12SJohn Marino
4483ff40c12SJohn Marino
free_bss_tmp_disallowed(struct wpa_supplicant * wpa_s)449*a1157835SDaniel Fojt void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
450*a1157835SDaniel Fojt {
451*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed *bss, *prev;
452*a1157835SDaniel Fojt
453*a1157835SDaniel Fojt dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
454*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed, list) {
455*a1157835SDaniel Fojt eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
456*a1157835SDaniel Fojt dl_list_del(&bss->list);
457*a1157835SDaniel Fojt os_free(bss);
458*a1157835SDaniel Fojt }
459*a1157835SDaniel Fojt }
460*a1157835SDaniel Fojt
461*a1157835SDaniel Fojt
wpas_flush_fils_hlp_req(struct wpa_supplicant * wpa_s)462*a1157835SDaniel Fojt void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
463*a1157835SDaniel Fojt {
464*a1157835SDaniel Fojt struct fils_hlp_req *req;
465*a1157835SDaniel Fojt
466*a1157835SDaniel Fojt while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
467*a1157835SDaniel Fojt list)) != NULL) {
468*a1157835SDaniel Fojt dl_list_del(&req->list);
469*a1157835SDaniel Fojt wpabuf_free(req->pkt);
470*a1157835SDaniel Fojt os_free(req);
471*a1157835SDaniel Fojt }
472*a1157835SDaniel Fojt }
473*a1157835SDaniel Fojt
474*a1157835SDaniel Fojt
wpa_supplicant_cleanup(struct wpa_supplicant * wpa_s)4756d49e1aeSJan Lentfer static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
4766d49e1aeSJan Lentfer {
477*a1157835SDaniel Fojt int i;
478*a1157835SDaniel Fojt
4793ff40c12SJohn Marino bgscan_deinit(wpa_s);
4803ff40c12SJohn Marino autoscan_deinit(wpa_s);
4816d49e1aeSJan Lentfer scard_deinit(wpa_s->scard);
4826d49e1aeSJan Lentfer wpa_s->scard = NULL;
4836d49e1aeSJan Lentfer wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
4846d49e1aeSJan Lentfer eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
4856d49e1aeSJan Lentfer l2_packet_deinit(wpa_s->l2);
4866d49e1aeSJan Lentfer wpa_s->l2 = NULL;
4876d49e1aeSJan Lentfer if (wpa_s->l2_br) {
4886d49e1aeSJan Lentfer l2_packet_deinit(wpa_s->l2_br);
4896d49e1aeSJan Lentfer wpa_s->l2_br = NULL;
4906d49e1aeSJan Lentfer }
491*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
492*a1157835SDaniel Fojt l2_packet_deinit(wpa_s->l2_test);
493*a1157835SDaniel Fojt wpa_s->l2_test = NULL;
494*a1157835SDaniel Fojt os_free(wpa_s->get_pref_freq_list_override);
495*a1157835SDaniel Fojt wpa_s->get_pref_freq_list_override = NULL;
496*a1157835SDaniel Fojt wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
497*a1157835SDaniel Fojt wpa_s->last_assoc_req_wpa_ie = NULL;
498*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
4996d49e1aeSJan Lentfer
5006d49e1aeSJan Lentfer if (wpa_s->conf != NULL) {
5013ff40c12SJohn Marino struct wpa_ssid *ssid;
5023ff40c12SJohn Marino for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
5033ff40c12SJohn Marino wpas_notify_network_removed(wpa_s, ssid);
5046d49e1aeSJan Lentfer }
5056d49e1aeSJan Lentfer
5066d49e1aeSJan Lentfer os_free(wpa_s->confname);
5076d49e1aeSJan Lentfer wpa_s->confname = NULL;
5086d49e1aeSJan Lentfer
5093ff40c12SJohn Marino os_free(wpa_s->confanother);
5103ff40c12SJohn Marino wpa_s->confanother = NULL;
5113ff40c12SJohn Marino
512*a1157835SDaniel Fojt os_free(wpa_s->last_con_fail_realm);
513*a1157835SDaniel Fojt wpa_s->last_con_fail_realm = NULL;
514*a1157835SDaniel Fojt wpa_s->last_con_fail_realm_len = 0;
515*a1157835SDaniel Fojt
5166d49e1aeSJan Lentfer wpa_sm_set_eapol(wpa_s->wpa, NULL);
5176d49e1aeSJan Lentfer eapol_sm_deinit(wpa_s->eapol);
5186d49e1aeSJan Lentfer wpa_s->eapol = NULL;
5196d49e1aeSJan Lentfer
5206d49e1aeSJan Lentfer rsn_preauth_deinit(wpa_s->wpa);
5216d49e1aeSJan Lentfer
5223ff40c12SJohn Marino #ifdef CONFIG_TDLS
5233ff40c12SJohn Marino wpa_tdls_deinit(wpa_s->wpa);
5243ff40c12SJohn Marino #endif /* CONFIG_TDLS */
5253ff40c12SJohn Marino
526*a1157835SDaniel Fojt wmm_ac_clear_saved_tspecs(wpa_s);
5276d49e1aeSJan Lentfer pmksa_candidate_free(wpa_s->wpa);
5286d49e1aeSJan Lentfer wpa_sm_deinit(wpa_s->wpa);
5296d49e1aeSJan Lentfer wpa_s->wpa = NULL;
5306d49e1aeSJan Lentfer wpa_blacklist_clear(wpa_s);
5316d49e1aeSJan Lentfer
5323ff40c12SJohn Marino wpa_bss_deinit(wpa_s);
5336d49e1aeSJan Lentfer
5343ff40c12SJohn Marino wpa_supplicant_cancel_delayed_sched_scan(wpa_s);
5356d49e1aeSJan Lentfer wpa_supplicant_cancel_scan(wpa_s);
5366d49e1aeSJan Lentfer wpa_supplicant_cancel_auth_timeout(wpa_s);
5373ff40c12SJohn Marino eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
5383ff40c12SJohn Marino #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
5393ff40c12SJohn Marino eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
5403ff40c12SJohn Marino wpa_s, NULL);
5413ff40c12SJohn Marino #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
5426d49e1aeSJan Lentfer
543*a1157835SDaniel Fojt eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
544*a1157835SDaniel Fojt
5456d49e1aeSJan Lentfer wpas_wps_deinit(wpa_s);
5466d49e1aeSJan Lentfer
5476d49e1aeSJan Lentfer wpabuf_free(wpa_s->pending_eapol_rx);
5486d49e1aeSJan Lentfer wpa_s->pending_eapol_rx = NULL;
5493ff40c12SJohn Marino
5503ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
5513ff40c12SJohn Marino ibss_rsn_deinit(wpa_s->ibss_rsn);
5523ff40c12SJohn Marino wpa_s->ibss_rsn = NULL;
5533ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
5543ff40c12SJohn Marino
5553ff40c12SJohn Marino sme_deinit(wpa_s);
5563ff40c12SJohn Marino
5573ff40c12SJohn Marino #ifdef CONFIG_AP
5583ff40c12SJohn Marino wpa_supplicant_ap_deinit(wpa_s);
5593ff40c12SJohn Marino #endif /* CONFIG_AP */
5603ff40c12SJohn Marino
5613ff40c12SJohn Marino wpas_p2p_deinit(wpa_s);
5623ff40c12SJohn Marino
5633ff40c12SJohn Marino #ifdef CONFIG_OFFCHANNEL
5643ff40c12SJohn Marino offchannel_deinit(wpa_s);
5653ff40c12SJohn Marino #endif /* CONFIG_OFFCHANNEL */
5663ff40c12SJohn Marino
5673ff40c12SJohn Marino wpa_supplicant_cancel_sched_scan(wpa_s);
5683ff40c12SJohn Marino
5693ff40c12SJohn Marino os_free(wpa_s->next_scan_freqs);
5703ff40c12SJohn Marino wpa_s->next_scan_freqs = NULL;
5713ff40c12SJohn Marino
5723ff40c12SJohn Marino os_free(wpa_s->manual_scan_freqs);
5733ff40c12SJohn Marino wpa_s->manual_scan_freqs = NULL;
574*a1157835SDaniel Fojt os_free(wpa_s->select_network_scan_freqs);
575*a1157835SDaniel Fojt wpa_s->select_network_scan_freqs = NULL;
5763ff40c12SJohn Marino
577*a1157835SDaniel Fojt os_free(wpa_s->manual_sched_scan_freqs);
578*a1157835SDaniel Fojt wpa_s->manual_sched_scan_freqs = NULL;
579*a1157835SDaniel Fojt
580*a1157835SDaniel Fojt wpas_mac_addr_rand_scan_clear(wpa_s, MAC_ADDR_RAND_ALL);
581*a1157835SDaniel Fojt
582*a1157835SDaniel Fojt /*
583*a1157835SDaniel Fojt * Need to remove any pending gas-query radio work before the
584*a1157835SDaniel Fojt * gas_query_deinit() call because gas_query::work has not yet been set
585*a1157835SDaniel Fojt * for works that have not been started. gas_query_free() will be unable
586*a1157835SDaniel Fojt * to cancel such pending radio works and once the pending gas-query
587*a1157835SDaniel Fojt * radio work eventually gets removed, the deinit notification call to
588*a1157835SDaniel Fojt * gas_query_start_cb() would result in dereferencing freed memory.
589*a1157835SDaniel Fojt */
590*a1157835SDaniel Fojt if (wpa_s->radio)
591*a1157835SDaniel Fojt radio_remove_works(wpa_s, "gas-query", 0);
5923ff40c12SJohn Marino gas_query_deinit(wpa_s->gas);
5933ff40c12SJohn Marino wpa_s->gas = NULL;
594*a1157835SDaniel Fojt gas_server_deinit(wpa_s->gas_server);
595*a1157835SDaniel Fojt wpa_s->gas_server = NULL;
5963ff40c12SJohn Marino
5973ff40c12SJohn Marino free_hw_features(wpa_s);
5983ff40c12SJohn Marino
599*a1157835SDaniel Fojt ieee802_1x_dealloc_kay_sm(wpa_s);
600*a1157835SDaniel Fojt
6013ff40c12SJohn Marino os_free(wpa_s->bssid_filter);
6023ff40c12SJohn Marino wpa_s->bssid_filter = NULL;
6033ff40c12SJohn Marino
6043ff40c12SJohn Marino os_free(wpa_s->disallow_aps_bssid);
6053ff40c12SJohn Marino wpa_s->disallow_aps_bssid = NULL;
6063ff40c12SJohn Marino os_free(wpa_s->disallow_aps_ssid);
6073ff40c12SJohn Marino wpa_s->disallow_aps_ssid = NULL;
6083ff40c12SJohn Marino
6093ff40c12SJohn Marino wnm_bss_keep_alive_deinit(wpa_s);
6103ff40c12SJohn Marino #ifdef CONFIG_WNM
6113ff40c12SJohn Marino wnm_deallocate_memory(wpa_s);
6123ff40c12SJohn Marino #endif /* CONFIG_WNM */
6133ff40c12SJohn Marino
6143ff40c12SJohn Marino ext_password_deinit(wpa_s->ext_pw);
6153ff40c12SJohn Marino wpa_s->ext_pw = NULL;
6163ff40c12SJohn Marino
6173ff40c12SJohn Marino wpabuf_free(wpa_s->last_gas_resp);
6183ff40c12SJohn Marino wpa_s->last_gas_resp = NULL;
6193ff40c12SJohn Marino wpabuf_free(wpa_s->prev_gas_resp);
6203ff40c12SJohn Marino wpa_s->prev_gas_resp = NULL;
6213ff40c12SJohn Marino
6223ff40c12SJohn Marino os_free(wpa_s->last_scan_res);
6233ff40c12SJohn Marino wpa_s->last_scan_res = NULL;
624*a1157835SDaniel Fojt
625*a1157835SDaniel Fojt #ifdef CONFIG_HS20
626*a1157835SDaniel Fojt if (wpa_s->drv_priv)
627*a1157835SDaniel Fojt wpa_drv_configure_frame_filters(wpa_s, 0);
628*a1157835SDaniel Fojt hs20_deinit(wpa_s);
629*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
630*a1157835SDaniel Fojt
631*a1157835SDaniel Fojt for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
632*a1157835SDaniel Fojt wpabuf_free(wpa_s->vendor_elem[i]);
633*a1157835SDaniel Fojt wpa_s->vendor_elem[i] = NULL;
634*a1157835SDaniel Fojt }
635*a1157835SDaniel Fojt
636*a1157835SDaniel Fojt wmm_ac_notify_disassoc(wpa_s);
637*a1157835SDaniel Fojt
638*a1157835SDaniel Fojt wpa_s->sched_scan_plans_num = 0;
639*a1157835SDaniel Fojt os_free(wpa_s->sched_scan_plans);
640*a1157835SDaniel Fojt wpa_s->sched_scan_plans = NULL;
641*a1157835SDaniel Fojt
642*a1157835SDaniel Fojt #ifdef CONFIG_MBO
643*a1157835SDaniel Fojt wpa_s->non_pref_chan_num = 0;
644*a1157835SDaniel Fojt os_free(wpa_s->non_pref_chan);
645*a1157835SDaniel Fojt wpa_s->non_pref_chan = NULL;
646*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
647*a1157835SDaniel Fojt
648*a1157835SDaniel Fojt free_bss_tmp_disallowed(wpa_s);
649*a1157835SDaniel Fojt
650*a1157835SDaniel Fojt wpabuf_free(wpa_s->lci);
651*a1157835SDaniel Fojt wpa_s->lci = NULL;
652*a1157835SDaniel Fojt wpas_clear_beacon_rep_data(wpa_s);
653*a1157835SDaniel Fojt
654*a1157835SDaniel Fojt #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
655*a1157835SDaniel Fojt #ifdef CONFIG_MESH
656*a1157835SDaniel Fojt {
657*a1157835SDaniel Fojt struct external_pmksa_cache *entry;
658*a1157835SDaniel Fojt
659*a1157835SDaniel Fojt while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
660*a1157835SDaniel Fojt struct external_pmksa_cache,
661*a1157835SDaniel Fojt list)) != NULL) {
662*a1157835SDaniel Fojt dl_list_del(&entry->list);
663*a1157835SDaniel Fojt os_free(entry->pmksa_cache);
664*a1157835SDaniel Fojt os_free(entry);
665*a1157835SDaniel Fojt }
666*a1157835SDaniel Fojt }
667*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
668*a1157835SDaniel Fojt #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
669*a1157835SDaniel Fojt
670*a1157835SDaniel Fojt wpas_flush_fils_hlp_req(wpa_s);
671*a1157835SDaniel Fojt
672*a1157835SDaniel Fojt wpabuf_free(wpa_s->ric_ies);
673*a1157835SDaniel Fojt wpa_s->ric_ies = NULL;
674*a1157835SDaniel Fojt
675*a1157835SDaniel Fojt #ifdef CONFIG_DPP
676*a1157835SDaniel Fojt wpas_dpp_deinit(wpa_s);
677*a1157835SDaniel Fojt dpp_global_deinit(wpa_s->dpp);
678*a1157835SDaniel Fojt wpa_s->dpp = NULL;
679*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
6806d49e1aeSJan Lentfer }
6816d49e1aeSJan Lentfer
6826d49e1aeSJan Lentfer
6836d49e1aeSJan Lentfer /**
6846d49e1aeSJan Lentfer * wpa_clear_keys - Clear keys configured for the driver
6856d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
6866d49e1aeSJan Lentfer * @addr: Previously used BSSID or %NULL if not available
6876d49e1aeSJan Lentfer *
6886d49e1aeSJan Lentfer * This function clears the encryption keys that has been previously configured
6896d49e1aeSJan Lentfer * for the driver.
6906d49e1aeSJan Lentfer */
wpa_clear_keys(struct wpa_supplicant * wpa_s,const u8 * addr)6916d49e1aeSJan Lentfer void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
6926d49e1aeSJan Lentfer {
6933ff40c12SJohn Marino int i, max;
6946d49e1aeSJan Lentfer
6953ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
6963ff40c12SJohn Marino max = 6;
6973ff40c12SJohn Marino #else /* CONFIG_IEEE80211W */
6983ff40c12SJohn Marino max = 4;
6993ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
7006d49e1aeSJan Lentfer
7016d49e1aeSJan Lentfer /* MLME-DELETEKEYS.request */
7023ff40c12SJohn Marino for (i = 0; i < max; i++) {
7033ff40c12SJohn Marino if (wpa_s->keys_cleared & BIT(i))
7043ff40c12SJohn Marino continue;
7053ff40c12SJohn Marino wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
7063ff40c12SJohn Marino NULL, 0);
7073ff40c12SJohn Marino }
7083ff40c12SJohn Marino if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
7093ff40c12SJohn Marino !is_zero_ether_addr(addr)) {
7106d49e1aeSJan Lentfer wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
7116d49e1aeSJan Lentfer 0);
7126d49e1aeSJan Lentfer /* MLME-SETPROTECTION.request(None) */
7136d49e1aeSJan Lentfer wpa_drv_mlme_setprotection(
7146d49e1aeSJan Lentfer wpa_s, addr,
7156d49e1aeSJan Lentfer MLME_SETPROTECTION_PROTECT_TYPE_NONE,
7166d49e1aeSJan Lentfer MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
7176d49e1aeSJan Lentfer }
7183ff40c12SJohn Marino wpa_s->keys_cleared = (u32) -1;
7196d49e1aeSJan Lentfer }
7206d49e1aeSJan Lentfer
7216d49e1aeSJan Lentfer
7226d49e1aeSJan Lentfer /**
7236d49e1aeSJan Lentfer * wpa_supplicant_state_txt - Get the connection state name as a text string
7246d49e1aeSJan Lentfer * @state: State (wpa_state; WPA_*)
7256d49e1aeSJan Lentfer * Returns: The state name as a printable text string
7266d49e1aeSJan Lentfer */
wpa_supplicant_state_txt(enum wpa_states state)7273ff40c12SJohn Marino const char * wpa_supplicant_state_txt(enum wpa_states state)
7286d49e1aeSJan Lentfer {
7296d49e1aeSJan Lentfer switch (state) {
7306d49e1aeSJan Lentfer case WPA_DISCONNECTED:
7316d49e1aeSJan Lentfer return "DISCONNECTED";
7326d49e1aeSJan Lentfer case WPA_INACTIVE:
7336d49e1aeSJan Lentfer return "INACTIVE";
7343ff40c12SJohn Marino case WPA_INTERFACE_DISABLED:
7353ff40c12SJohn Marino return "INTERFACE_DISABLED";
7366d49e1aeSJan Lentfer case WPA_SCANNING:
7376d49e1aeSJan Lentfer return "SCANNING";
7383ff40c12SJohn Marino case WPA_AUTHENTICATING:
7393ff40c12SJohn Marino return "AUTHENTICATING";
7406d49e1aeSJan Lentfer case WPA_ASSOCIATING:
7416d49e1aeSJan Lentfer return "ASSOCIATING";
7426d49e1aeSJan Lentfer case WPA_ASSOCIATED:
7436d49e1aeSJan Lentfer return "ASSOCIATED";
7446d49e1aeSJan Lentfer case WPA_4WAY_HANDSHAKE:
7456d49e1aeSJan Lentfer return "4WAY_HANDSHAKE";
7466d49e1aeSJan Lentfer case WPA_GROUP_HANDSHAKE:
7476d49e1aeSJan Lentfer return "GROUP_HANDSHAKE";
7486d49e1aeSJan Lentfer case WPA_COMPLETED:
7496d49e1aeSJan Lentfer return "COMPLETED";
7506d49e1aeSJan Lentfer default:
7516d49e1aeSJan Lentfer return "UNKNOWN";
7526d49e1aeSJan Lentfer }
7536d49e1aeSJan Lentfer }
7546d49e1aeSJan Lentfer
7556d49e1aeSJan Lentfer
7563ff40c12SJohn Marino #ifdef CONFIG_BGSCAN
7573ff40c12SJohn Marino
wpa_supplicant_start_bgscan(struct wpa_supplicant * wpa_s)7583ff40c12SJohn Marino static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
7593ff40c12SJohn Marino {
7603ff40c12SJohn Marino const char *name;
7613ff40c12SJohn Marino
7623ff40c12SJohn Marino if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
7633ff40c12SJohn Marino name = wpa_s->current_ssid->bgscan;
7643ff40c12SJohn Marino else
7653ff40c12SJohn Marino name = wpa_s->conf->bgscan;
766*a1157835SDaniel Fojt if (name == NULL || name[0] == '\0')
7673ff40c12SJohn Marino return;
7683ff40c12SJohn Marino if (wpas_driver_bss_selection(wpa_s))
7693ff40c12SJohn Marino return;
7703ff40c12SJohn Marino if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
7713ff40c12SJohn Marino return;
772*a1157835SDaniel Fojt #ifdef CONFIG_P2P
773*a1157835SDaniel Fojt if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
774*a1157835SDaniel Fojt return;
775*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
7763ff40c12SJohn Marino
7773ff40c12SJohn Marino bgscan_deinit(wpa_s);
7783ff40c12SJohn Marino if (wpa_s->current_ssid) {
7793ff40c12SJohn Marino if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
7803ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
7813ff40c12SJohn Marino "bgscan");
7823ff40c12SJohn Marino /*
7833ff40c12SJohn Marino * Live without bgscan; it is only used as a roaming
7843ff40c12SJohn Marino * optimization, so the initial connection is not
7853ff40c12SJohn Marino * affected.
7863ff40c12SJohn Marino */
7873ff40c12SJohn Marino } else {
7883ff40c12SJohn Marino struct wpa_scan_results *scan_res;
7893ff40c12SJohn Marino wpa_s->bgscan_ssid = wpa_s->current_ssid;
7903ff40c12SJohn Marino scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
7913ff40c12SJohn Marino 0);
7923ff40c12SJohn Marino if (scan_res) {
7933ff40c12SJohn Marino bgscan_notify_scan(wpa_s, scan_res);
7943ff40c12SJohn Marino wpa_scan_results_free(scan_res);
7953ff40c12SJohn Marino }
7963ff40c12SJohn Marino }
7973ff40c12SJohn Marino } else
7983ff40c12SJohn Marino wpa_s->bgscan_ssid = NULL;
7993ff40c12SJohn Marino }
8003ff40c12SJohn Marino
8013ff40c12SJohn Marino
wpa_supplicant_stop_bgscan(struct wpa_supplicant * wpa_s)8023ff40c12SJohn Marino static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
8033ff40c12SJohn Marino {
8043ff40c12SJohn Marino if (wpa_s->bgscan_ssid != NULL) {
8053ff40c12SJohn Marino bgscan_deinit(wpa_s);
8063ff40c12SJohn Marino wpa_s->bgscan_ssid = NULL;
8073ff40c12SJohn Marino }
8083ff40c12SJohn Marino }
8093ff40c12SJohn Marino
8103ff40c12SJohn Marino #endif /* CONFIG_BGSCAN */
8113ff40c12SJohn Marino
8123ff40c12SJohn Marino
wpa_supplicant_start_autoscan(struct wpa_supplicant * wpa_s)8133ff40c12SJohn Marino static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
8143ff40c12SJohn Marino {
8153ff40c12SJohn Marino if (autoscan_init(wpa_s, 0))
8163ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
8173ff40c12SJohn Marino }
8183ff40c12SJohn Marino
8193ff40c12SJohn Marino
wpa_supplicant_stop_autoscan(struct wpa_supplicant * wpa_s)8203ff40c12SJohn Marino static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
8213ff40c12SJohn Marino {
8223ff40c12SJohn Marino autoscan_deinit(wpa_s);
8233ff40c12SJohn Marino }
8243ff40c12SJohn Marino
8253ff40c12SJohn Marino
wpa_supplicant_reinit_autoscan(struct wpa_supplicant * wpa_s)8263ff40c12SJohn Marino void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
8273ff40c12SJohn Marino {
8283ff40c12SJohn Marino if (wpa_s->wpa_state == WPA_DISCONNECTED ||
8293ff40c12SJohn Marino wpa_s->wpa_state == WPA_SCANNING) {
8303ff40c12SJohn Marino autoscan_deinit(wpa_s);
8313ff40c12SJohn Marino wpa_supplicant_start_autoscan(wpa_s);
8323ff40c12SJohn Marino }
8333ff40c12SJohn Marino }
8343ff40c12SJohn Marino
8353ff40c12SJohn Marino
8366d49e1aeSJan Lentfer /**
8376d49e1aeSJan Lentfer * wpa_supplicant_set_state - Set current connection state
8386d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
8396d49e1aeSJan Lentfer * @state: The new connection state
8406d49e1aeSJan Lentfer *
8416d49e1aeSJan Lentfer * This function is called whenever the connection state changes, e.g.,
8426d49e1aeSJan Lentfer * association is completed for WPA/WPA2 4-Way Handshake is started.
8436d49e1aeSJan Lentfer */
wpa_supplicant_set_state(struct wpa_supplicant * wpa_s,enum wpa_states state)8443ff40c12SJohn Marino void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
8453ff40c12SJohn Marino enum wpa_states state)
8466d49e1aeSJan Lentfer {
8473ff40c12SJohn Marino enum wpa_states old_state = wpa_s->wpa_state;
8483ff40c12SJohn Marino
8493ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
8506d49e1aeSJan Lentfer wpa_supplicant_state_txt(wpa_s->wpa_state),
8516d49e1aeSJan Lentfer wpa_supplicant_state_txt(state));
8526d49e1aeSJan Lentfer
853*a1157835SDaniel Fojt if (state == WPA_COMPLETED &&
854*a1157835SDaniel Fojt os_reltime_initialized(&wpa_s->roam_start)) {
855*a1157835SDaniel Fojt os_reltime_age(&wpa_s->roam_start, &wpa_s->roam_time);
856*a1157835SDaniel Fojt wpa_s->roam_start.sec = 0;
857*a1157835SDaniel Fojt wpa_s->roam_start.usec = 0;
858*a1157835SDaniel Fojt wpas_notify_auth_changed(wpa_s);
859*a1157835SDaniel Fojt wpas_notify_roam_time(wpa_s);
860*a1157835SDaniel Fojt wpas_notify_roam_complete(wpa_s);
861*a1157835SDaniel Fojt } else if (state == WPA_DISCONNECTED &&
862*a1157835SDaniel Fojt os_reltime_initialized(&wpa_s->roam_start)) {
863*a1157835SDaniel Fojt wpa_s->roam_start.sec = 0;
864*a1157835SDaniel Fojt wpa_s->roam_start.usec = 0;
865*a1157835SDaniel Fojt wpa_s->roam_time.sec = 0;
866*a1157835SDaniel Fojt wpa_s->roam_time.usec = 0;
867*a1157835SDaniel Fojt wpas_notify_roam_complete(wpa_s);
868*a1157835SDaniel Fojt }
869*a1157835SDaniel Fojt
8703ff40c12SJohn Marino if (state == WPA_INTERFACE_DISABLED) {
8713ff40c12SJohn Marino /* Assure normal scan when interface is restored */
8723ff40c12SJohn Marino wpa_s->normal_scans = 0;
8733ff40c12SJohn Marino }
8743ff40c12SJohn Marino
875*a1157835SDaniel Fojt if (state == WPA_COMPLETED) {
8763ff40c12SJohn Marino wpas_connect_work_done(wpa_s);
877*a1157835SDaniel Fojt /* Reinitialize normal_scan counter */
878*a1157835SDaniel Fojt wpa_s->normal_scans = 0;
879*a1157835SDaniel Fojt }
880*a1157835SDaniel Fojt
881*a1157835SDaniel Fojt #ifdef CONFIG_P2P
882*a1157835SDaniel Fojt /*
883*a1157835SDaniel Fojt * P2PS client has to reply to Probe Request frames received on the
884*a1157835SDaniel Fojt * group operating channel. Enable Probe Request frame reporting for
885*a1157835SDaniel Fojt * P2P connected client in case p2p_cli_probe configuration property is
886*a1157835SDaniel Fojt * set to 1.
887*a1157835SDaniel Fojt */
888*a1157835SDaniel Fojt if (wpa_s->conf->p2p_cli_probe && wpa_s->current_ssid &&
889*a1157835SDaniel Fojt wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
890*a1157835SDaniel Fojt wpa_s->current_ssid->p2p_group) {
891*a1157835SDaniel Fojt if (state == WPA_COMPLETED && !wpa_s->p2p_cli_probe) {
892*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
893*a1157835SDaniel Fojt "P2P: Enable CLI Probe Request RX reporting");
894*a1157835SDaniel Fojt wpa_s->p2p_cli_probe =
895*a1157835SDaniel Fojt wpa_drv_probe_req_report(wpa_s, 1) >= 0;
896*a1157835SDaniel Fojt } else if (state != WPA_COMPLETED && wpa_s->p2p_cli_probe) {
897*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
898*a1157835SDaniel Fojt "P2P: Disable CLI Probe Request RX reporting");
899*a1157835SDaniel Fojt wpa_s->p2p_cli_probe = 0;
900*a1157835SDaniel Fojt wpa_drv_probe_req_report(wpa_s, 0);
901*a1157835SDaniel Fojt }
902*a1157835SDaniel Fojt }
903*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
9043ff40c12SJohn Marino
9056d49e1aeSJan Lentfer if (state != WPA_SCANNING)
9066d49e1aeSJan Lentfer wpa_supplicant_notify_scanning(wpa_s, 0);
9076d49e1aeSJan Lentfer
9086d49e1aeSJan Lentfer if (state == WPA_COMPLETED && wpa_s->new_connection) {
9096d49e1aeSJan Lentfer struct wpa_ssid *ssid = wpa_s->current_ssid;
910*a1157835SDaniel Fojt int fils_hlp_sent = 0;
911*a1157835SDaniel Fojt
912*a1157835SDaniel Fojt #ifdef CONFIG_SME
913*a1157835SDaniel Fojt if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
914*a1157835SDaniel Fojt wpa_auth_alg_fils(wpa_s->sme.auth_alg))
915*a1157835SDaniel Fojt fils_hlp_sent = 1;
916*a1157835SDaniel Fojt #endif /* CONFIG_SME */
917*a1157835SDaniel Fojt if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
918*a1157835SDaniel Fojt wpa_auth_alg_fils(wpa_s->auth_alg))
919*a1157835SDaniel Fojt fils_hlp_sent = 1;
920*a1157835SDaniel Fojt
9213ff40c12SJohn Marino #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
9226d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
923*a1157835SDaniel Fojt MACSTR " completed [id=%d id_str=%s%s]",
9243ff40c12SJohn Marino MAC2STR(wpa_s->bssid),
9256d49e1aeSJan Lentfer ssid ? ssid->id : -1,
926*a1157835SDaniel Fojt ssid && ssid->id_str ? ssid->id_str : "",
927*a1157835SDaniel Fojt fils_hlp_sent ? " FILS_HLP_SENT" : "");
9286d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
9293ff40c12SJohn Marino wpas_clear_temp_disabled(wpa_s, ssid, 1);
930*a1157835SDaniel Fojt wpa_blacklist_clear(wpa_s);
9313ff40c12SJohn Marino wpa_s->extra_blacklist_count = 0;
9326d49e1aeSJan Lentfer wpa_s->new_connection = 0;
9336d49e1aeSJan Lentfer wpa_drv_set_operstate(wpa_s, 1);
9343ff40c12SJohn Marino #ifndef IEEE8021X_EAPOL
9353ff40c12SJohn Marino wpa_drv_set_supp_port(wpa_s, 1);
9363ff40c12SJohn Marino #endif /* IEEE8021X_EAPOL */
9373ff40c12SJohn Marino wpa_s->after_wps = 0;
9383ff40c12SJohn Marino wpa_s->known_wps_freq = 0;
9393ff40c12SJohn Marino wpas_p2p_completed(wpa_s);
9403ff40c12SJohn Marino
9413ff40c12SJohn Marino sme_sched_obss_scan(wpa_s, 1);
942*a1157835SDaniel Fojt
943*a1157835SDaniel Fojt #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
944*a1157835SDaniel Fojt if (!fils_hlp_sent && ssid && ssid->eap.erp)
945*a1157835SDaniel Fojt wpas_update_fils_connect_params(wpa_s);
946*a1157835SDaniel Fojt #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
9476d49e1aeSJan Lentfer } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
9486d49e1aeSJan Lentfer state == WPA_ASSOCIATED) {
9496d49e1aeSJan Lentfer wpa_s->new_connection = 1;
9506d49e1aeSJan Lentfer wpa_drv_set_operstate(wpa_s, 0);
9513ff40c12SJohn Marino #ifndef IEEE8021X_EAPOL
9523ff40c12SJohn Marino wpa_drv_set_supp_port(wpa_s, 0);
9533ff40c12SJohn Marino #endif /* IEEE8021X_EAPOL */
9543ff40c12SJohn Marino sme_sched_obss_scan(wpa_s, 0);
9556d49e1aeSJan Lentfer }
9566d49e1aeSJan Lentfer wpa_s->wpa_state = state;
9573ff40c12SJohn Marino
9583ff40c12SJohn Marino #ifdef CONFIG_BGSCAN
9593ff40c12SJohn Marino if (state == WPA_COMPLETED)
9603ff40c12SJohn Marino wpa_supplicant_start_bgscan(wpa_s);
9613ff40c12SJohn Marino else if (state < WPA_ASSOCIATED)
9623ff40c12SJohn Marino wpa_supplicant_stop_bgscan(wpa_s);
9633ff40c12SJohn Marino #endif /* CONFIG_BGSCAN */
9643ff40c12SJohn Marino
965*a1157835SDaniel Fojt if (state > WPA_SCANNING)
9663ff40c12SJohn Marino wpa_supplicant_stop_autoscan(wpa_s);
9673ff40c12SJohn Marino
9683ff40c12SJohn Marino if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
9693ff40c12SJohn Marino wpa_supplicant_start_autoscan(wpa_s);
9703ff40c12SJohn Marino
971*a1157835SDaniel Fojt if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
972*a1157835SDaniel Fojt wmm_ac_notify_disassoc(wpa_s);
973*a1157835SDaniel Fojt
9743ff40c12SJohn Marino if (wpa_s->wpa_state != old_state) {
9753ff40c12SJohn Marino wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
9763ff40c12SJohn Marino
977*a1157835SDaniel Fojt /*
978*a1157835SDaniel Fojt * Notify the P2P Device interface about a state change in one
979*a1157835SDaniel Fojt * of the interfaces.
980*a1157835SDaniel Fojt */
981*a1157835SDaniel Fojt wpas_p2p_indicate_state_change(wpa_s);
982*a1157835SDaniel Fojt
9833ff40c12SJohn Marino if (wpa_s->wpa_state == WPA_COMPLETED ||
9843ff40c12SJohn Marino old_state == WPA_COMPLETED)
9853ff40c12SJohn Marino wpas_notify_auth_changed(wpa_s);
9863ff40c12SJohn Marino }
9876d49e1aeSJan Lentfer }
9886d49e1aeSJan Lentfer
9896d49e1aeSJan Lentfer
wpa_supplicant_terminate_proc(struct wpa_global * global)9903ff40c12SJohn Marino void wpa_supplicant_terminate_proc(struct wpa_global *global)
9916d49e1aeSJan Lentfer {
9923ff40c12SJohn Marino int pending = 0;
9933ff40c12SJohn Marino #ifdef CONFIG_WPS
9943ff40c12SJohn Marino struct wpa_supplicant *wpa_s = global->ifaces;
9953ff40c12SJohn Marino while (wpa_s) {
9963ff40c12SJohn Marino struct wpa_supplicant *next = wpa_s->next;
997*a1157835SDaniel Fojt if (wpas_wps_terminate_pending(wpa_s) == 1)
998*a1157835SDaniel Fojt pending = 1;
9993ff40c12SJohn Marino #ifdef CONFIG_P2P
10003ff40c12SJohn Marino if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
10013ff40c12SJohn Marino (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
10023ff40c12SJohn Marino wpas_p2p_disconnect(wpa_s);
10033ff40c12SJohn Marino #endif /* CONFIG_P2P */
10043ff40c12SJohn Marino wpa_s = next;
10056d49e1aeSJan Lentfer }
10063ff40c12SJohn Marino #endif /* CONFIG_WPS */
10073ff40c12SJohn Marino if (pending)
10083ff40c12SJohn Marino return;
10096d49e1aeSJan Lentfer eloop_terminate();
10106d49e1aeSJan Lentfer }
10116d49e1aeSJan Lentfer
10126d49e1aeSJan Lentfer
wpa_supplicant_terminate(int sig,void * signal_ctx)10133ff40c12SJohn Marino static void wpa_supplicant_terminate(int sig, void *signal_ctx)
10146d49e1aeSJan Lentfer {
10153ff40c12SJohn Marino struct wpa_global *global = signal_ctx;
10163ff40c12SJohn Marino wpa_supplicant_terminate_proc(global);
10173ff40c12SJohn Marino }
10183ff40c12SJohn Marino
10193ff40c12SJohn Marino
wpa_supplicant_clear_status(struct wpa_supplicant * wpa_s)10203ff40c12SJohn Marino void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
10213ff40c12SJohn Marino {
10223ff40c12SJohn Marino enum wpa_states old_state = wpa_s->wpa_state;
10233ff40c12SJohn Marino
10246d49e1aeSJan Lentfer wpa_s->pairwise_cipher = 0;
10256d49e1aeSJan Lentfer wpa_s->group_cipher = 0;
10266d49e1aeSJan Lentfer wpa_s->mgmt_group_cipher = 0;
10276d49e1aeSJan Lentfer wpa_s->key_mgmt = 0;
10283ff40c12SJohn Marino if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
10293ff40c12SJohn Marino wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
10303ff40c12SJohn Marino
10313ff40c12SJohn Marino if (wpa_s->wpa_state != old_state)
10323ff40c12SJohn Marino wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
10336d49e1aeSJan Lentfer }
10346d49e1aeSJan Lentfer
10356d49e1aeSJan Lentfer
10366d49e1aeSJan Lentfer /**
10376d49e1aeSJan Lentfer * wpa_supplicant_reload_configuration - Reload configuration data
10386d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
10396d49e1aeSJan Lentfer * Returns: 0 on success or -1 if configuration parsing failed
10406d49e1aeSJan Lentfer *
10416d49e1aeSJan Lentfer * This function can be used to request that the configuration data is reloaded
10426d49e1aeSJan Lentfer * (e.g., after configuration file change). This function is reloading
10436d49e1aeSJan Lentfer * configuration only for one interface, so this may need to be called multiple
10446d49e1aeSJan Lentfer * times if %wpa_supplicant is controlling multiple interfaces and all
10456d49e1aeSJan Lentfer * interfaces need reconfiguration.
10466d49e1aeSJan Lentfer */
wpa_supplicant_reload_configuration(struct wpa_supplicant * wpa_s)10476d49e1aeSJan Lentfer int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
10486d49e1aeSJan Lentfer {
10496d49e1aeSJan Lentfer struct wpa_config *conf;
10506d49e1aeSJan Lentfer int reconf_ctrl;
10513ff40c12SJohn Marino int old_ap_scan;
10523ff40c12SJohn Marino
10536d49e1aeSJan Lentfer if (wpa_s->confname == NULL)
10546d49e1aeSJan Lentfer return -1;
10553ff40c12SJohn Marino conf = wpa_config_read(wpa_s->confname, NULL);
10566d49e1aeSJan Lentfer if (conf == NULL) {
10576d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
10586d49e1aeSJan Lentfer "file '%s' - exiting", wpa_s->confname);
10596d49e1aeSJan Lentfer return -1;
10606d49e1aeSJan Lentfer }
1061*a1157835SDaniel Fojt if (wpa_s->confanother &&
1062*a1157835SDaniel Fojt !wpa_config_read(wpa_s->confanother, conf)) {
1063*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_ERROR,
1064*a1157835SDaniel Fojt "Failed to parse the configuration file '%s' - exiting",
1065*a1157835SDaniel Fojt wpa_s->confanother);
1066*a1157835SDaniel Fojt return -1;
1067*a1157835SDaniel Fojt }
10683ff40c12SJohn Marino
10693ff40c12SJohn Marino conf->changed_parameters = (unsigned int) -1;
10706d49e1aeSJan Lentfer
10716d49e1aeSJan Lentfer reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
10726d49e1aeSJan Lentfer || (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
10736d49e1aeSJan Lentfer os_strcmp(conf->ctrl_interface,
10746d49e1aeSJan Lentfer wpa_s->conf->ctrl_interface) != 0);
10756d49e1aeSJan Lentfer
10766d49e1aeSJan Lentfer if (reconf_ctrl && wpa_s->ctrl_iface) {
10776d49e1aeSJan Lentfer wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
10786d49e1aeSJan Lentfer wpa_s->ctrl_iface = NULL;
10796d49e1aeSJan Lentfer }
10806d49e1aeSJan Lentfer
10816d49e1aeSJan Lentfer eapol_sm_invalidate_cached_session(wpa_s->eapol);
10823ff40c12SJohn Marino if (wpa_s->current_ssid) {
1083*a1157835SDaniel Fojt if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
1084*a1157835SDaniel Fojt wpa_s->own_disconnect_req = 1;
10853ff40c12SJohn Marino wpa_supplicant_deauthenticate(wpa_s,
10863ff40c12SJohn Marino WLAN_REASON_DEAUTH_LEAVING);
10873ff40c12SJohn Marino }
10883ff40c12SJohn Marino
10896d49e1aeSJan Lentfer /*
10906d49e1aeSJan Lentfer * TODO: should notify EAPOL SM about changes in opensc_engine_path,
1091*a1157835SDaniel Fojt * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
10926d49e1aeSJan Lentfer */
1093*a1157835SDaniel Fojt if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
1094*a1157835SDaniel Fojt wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
1095*a1157835SDaniel Fojt wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
10966d49e1aeSJan Lentfer /*
10976d49e1aeSJan Lentfer * Clear forced success to clear EAP state for next
10986d49e1aeSJan Lentfer * authentication.
10996d49e1aeSJan Lentfer */
11006d49e1aeSJan Lentfer eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
11016d49e1aeSJan Lentfer }
11026d49e1aeSJan Lentfer eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
11036d49e1aeSJan Lentfer wpa_sm_set_config(wpa_s->wpa, NULL);
11043ff40c12SJohn Marino wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
11056d49e1aeSJan Lentfer wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
11066d49e1aeSJan Lentfer rsn_preauth_deinit(wpa_s->wpa);
11073ff40c12SJohn Marino
11083ff40c12SJohn Marino old_ap_scan = wpa_s->conf->ap_scan;
11096d49e1aeSJan Lentfer wpa_config_free(wpa_s->conf);
11106d49e1aeSJan Lentfer wpa_s->conf = conf;
11113ff40c12SJohn Marino if (old_ap_scan != wpa_s->conf->ap_scan)
11123ff40c12SJohn Marino wpas_notify_ap_scan_changed(wpa_s);
11133ff40c12SJohn Marino
11146d49e1aeSJan Lentfer if (reconf_ctrl)
11156d49e1aeSJan Lentfer wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
11166d49e1aeSJan Lentfer
11173ff40c12SJohn Marino wpa_supplicant_update_config(wpa_s);
11183ff40c12SJohn Marino
11196d49e1aeSJan Lentfer wpa_supplicant_clear_status(wpa_s);
11203ff40c12SJohn Marino if (wpa_supplicant_enabled_networks(wpa_s)) {
11216d49e1aeSJan Lentfer wpa_s->reassociate = 1;
11226d49e1aeSJan Lentfer wpa_supplicant_req_scan(wpa_s, 0, 0);
11233ff40c12SJohn Marino }
11243ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
11256d49e1aeSJan Lentfer return 0;
11266d49e1aeSJan Lentfer }
11276d49e1aeSJan Lentfer
11286d49e1aeSJan Lentfer
wpa_supplicant_reconfig(int sig,void * signal_ctx)11293ff40c12SJohn Marino static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
11306d49e1aeSJan Lentfer {
11313ff40c12SJohn Marino struct wpa_global *global = signal_ctx;
11326d49e1aeSJan Lentfer struct wpa_supplicant *wpa_s;
11336d49e1aeSJan Lentfer for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
11343ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring",
11353ff40c12SJohn Marino sig);
11366d49e1aeSJan Lentfer if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
11373ff40c12SJohn Marino wpa_supplicant_terminate_proc(global);
11386d49e1aeSJan Lentfer }
11396d49e1aeSJan Lentfer }
1140*a1157835SDaniel Fojt
1141*a1157835SDaniel Fojt if (wpa_debug_reopen_file() < 0) {
1142*a1157835SDaniel Fojt /* Ignore errors since we cannot really do much to fix this */
1143*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "Could not reopen debug log file");
1144*a1157835SDaniel Fojt }
11456d49e1aeSJan Lentfer }
11466d49e1aeSJan Lentfer
11476d49e1aeSJan Lentfer
wpa_supplicant_suites_from_ai(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_ie_data * ie)11486d49e1aeSJan Lentfer static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
11496d49e1aeSJan Lentfer struct wpa_ssid *ssid,
11506d49e1aeSJan Lentfer struct wpa_ie_data *ie)
11516d49e1aeSJan Lentfer {
11526d49e1aeSJan Lentfer int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
11536d49e1aeSJan Lentfer if (ret) {
11546d49e1aeSJan Lentfer if (ret == -2) {
11556d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
11566d49e1aeSJan Lentfer "from association info");
11576d49e1aeSJan Lentfer }
11586d49e1aeSJan Lentfer return -1;
11596d49e1aeSJan Lentfer }
11606d49e1aeSJan Lentfer
11613ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set "
11623ff40c12SJohn Marino "cipher suites");
11636d49e1aeSJan Lentfer if (!(ie->group_cipher & ssid->group_cipher)) {
11646d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
11656d49e1aeSJan Lentfer "cipher 0x%x (mask 0x%x) - reject",
11666d49e1aeSJan Lentfer ie->group_cipher, ssid->group_cipher);
11676d49e1aeSJan Lentfer return -1;
11686d49e1aeSJan Lentfer }
11696d49e1aeSJan Lentfer if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) {
11706d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise "
11716d49e1aeSJan Lentfer "cipher 0x%x (mask 0x%x) - reject",
11726d49e1aeSJan Lentfer ie->pairwise_cipher, ssid->pairwise_cipher);
11736d49e1aeSJan Lentfer return -1;
11746d49e1aeSJan Lentfer }
11756d49e1aeSJan Lentfer if (!(ie->key_mgmt & ssid->key_mgmt)) {
11766d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key "
11776d49e1aeSJan Lentfer "management 0x%x (mask 0x%x) - reject",
11786d49e1aeSJan Lentfer ie->key_mgmt, ssid->key_mgmt);
11796d49e1aeSJan Lentfer return -1;
11806d49e1aeSJan Lentfer }
11816d49e1aeSJan Lentfer
11826d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
11836d49e1aeSJan Lentfer if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
1184*a1157835SDaniel Fojt wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
11856d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
11866d49e1aeSJan Lentfer "that does not support management frame protection - "
11876d49e1aeSJan Lentfer "reject");
11886d49e1aeSJan Lentfer return -1;
11896d49e1aeSJan Lentfer }
11906d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
11916d49e1aeSJan Lentfer
11926d49e1aeSJan Lentfer return 0;
11936d49e1aeSJan Lentfer }
11946d49e1aeSJan Lentfer
11956d49e1aeSJan Lentfer
matching_ciphers(struct wpa_ssid * ssid,struct wpa_ie_data * ie,int freq)1196*a1157835SDaniel Fojt static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
1197*a1157835SDaniel Fojt int freq)
1198*a1157835SDaniel Fojt {
1199*a1157835SDaniel Fojt if (!ie->has_group)
1200*a1157835SDaniel Fojt ie->group_cipher = wpa_default_rsn_cipher(freq);
1201*a1157835SDaniel Fojt if (!ie->has_pairwise)
1202*a1157835SDaniel Fojt ie->pairwise_cipher = wpa_default_rsn_cipher(freq);
1203*a1157835SDaniel Fojt return (ie->group_cipher & ssid->group_cipher) &&
1204*a1157835SDaniel Fojt (ie->pairwise_cipher & ssid->pairwise_cipher);
1205*a1157835SDaniel Fojt }
1206*a1157835SDaniel Fojt
1207*a1157835SDaniel Fojt
12086d49e1aeSJan Lentfer /**
12096d49e1aeSJan Lentfer * wpa_supplicant_set_suites - Set authentication and encryption parameters
12106d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
12116d49e1aeSJan Lentfer * @bss: Scan results for the selected BSS, or %NULL if not available
12126d49e1aeSJan Lentfer * @ssid: Configuration data for the selected network
12136d49e1aeSJan Lentfer * @wpa_ie: Buffer for the WPA/RSN IE
12146d49e1aeSJan Lentfer * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
12156d49e1aeSJan Lentfer * used buffer length in case the functions returns success.
12166d49e1aeSJan Lentfer * Returns: 0 on success or -1 on failure
12176d49e1aeSJan Lentfer *
12186d49e1aeSJan Lentfer * This function is used to configure authentication and encryption parameters
12196d49e1aeSJan Lentfer * based on the network configuration and scan result for the selected BSS (if
12206d49e1aeSJan Lentfer * available).
12216d49e1aeSJan Lentfer */
wpa_supplicant_set_suites(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,struct wpa_ssid * ssid,u8 * wpa_ie,size_t * wpa_ie_len)12226d49e1aeSJan Lentfer int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
12233ff40c12SJohn Marino struct wpa_bss *bss, struct wpa_ssid *ssid,
12246d49e1aeSJan Lentfer u8 *wpa_ie, size_t *wpa_ie_len)
12256d49e1aeSJan Lentfer {
12266d49e1aeSJan Lentfer struct wpa_ie_data ie;
12276d49e1aeSJan Lentfer int sel, proto;
1228*a1157835SDaniel Fojt const u8 *bss_wpa, *bss_rsn, *bss_osen;
12296d49e1aeSJan Lentfer
12306d49e1aeSJan Lentfer if (bss) {
12313ff40c12SJohn Marino bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
12323ff40c12SJohn Marino bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
1233*a1157835SDaniel Fojt bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
12346d49e1aeSJan Lentfer } else
1235*a1157835SDaniel Fojt bss_wpa = bss_rsn = bss_osen = NULL;
12366d49e1aeSJan Lentfer
12376d49e1aeSJan Lentfer if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
12386d49e1aeSJan Lentfer wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
1239*a1157835SDaniel Fojt matching_ciphers(ssid, &ie, bss->freq) &&
12406d49e1aeSJan Lentfer (ie.key_mgmt & ssid->key_mgmt)) {
12413ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
12426d49e1aeSJan Lentfer proto = WPA_PROTO_RSN;
12436d49e1aeSJan Lentfer } else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
12446d49e1aeSJan Lentfer wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie) == 0 &&
12456d49e1aeSJan Lentfer (ie.group_cipher & ssid->group_cipher) &&
12466d49e1aeSJan Lentfer (ie.pairwise_cipher & ssid->pairwise_cipher) &&
12476d49e1aeSJan Lentfer (ie.key_mgmt & ssid->key_mgmt)) {
12483ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
12496d49e1aeSJan Lentfer proto = WPA_PROTO_WPA;
1250*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1251*a1157835SDaniel Fojt } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN) &&
1252*a1157835SDaniel Fojt wpa_parse_wpa_ie(bss_osen, 2 + bss_osen[1], &ie) == 0 &&
1253*a1157835SDaniel Fojt (ie.group_cipher & ssid->group_cipher) &&
1254*a1157835SDaniel Fojt (ie.pairwise_cipher & ssid->pairwise_cipher) &&
1255*a1157835SDaniel Fojt (ie.key_mgmt & ssid->key_mgmt)) {
1256*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN");
1257*a1157835SDaniel Fojt proto = WPA_PROTO_OSEN;
1258*a1157835SDaniel Fojt } else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) &&
1259*a1157835SDaniel Fojt wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
1260*a1157835SDaniel Fojt (ie.group_cipher & ssid->group_cipher) &&
1261*a1157835SDaniel Fojt (ie.pairwise_cipher & ssid->pairwise_cipher) &&
1262*a1157835SDaniel Fojt (ie.key_mgmt & ssid->key_mgmt)) {
1263*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using OSEN (within RSN)");
1264*a1157835SDaniel Fojt proto = WPA_PROTO_RSN;
1265*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
12666d49e1aeSJan Lentfer } else if (bss) {
12676d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
1268*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1269*a1157835SDaniel Fojt "WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1270*a1157835SDaniel Fojt ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
1271*a1157835SDaniel Fojt ssid->key_mgmt);
1272*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s%s",
1273*a1157835SDaniel Fojt MAC2STR(bss->bssid),
1274*a1157835SDaniel Fojt wpa_ssid_txt(bss->ssid, bss->ssid_len),
1275*a1157835SDaniel Fojt bss_wpa ? " WPA" : "",
1276*a1157835SDaniel Fojt bss_rsn ? " RSN" : "",
1277*a1157835SDaniel Fojt bss_osen ? " OSEN" : "");
1278*a1157835SDaniel Fojt if (bss_rsn) {
1279*a1157835SDaniel Fojt wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
1280*a1157835SDaniel Fojt if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
1281*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1282*a1157835SDaniel Fojt "Could not parse RSN element");
1283*a1157835SDaniel Fojt } else {
1284*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1285*a1157835SDaniel Fojt "RSN: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1286*a1157835SDaniel Fojt ie.pairwise_cipher, ie.group_cipher,
1287*a1157835SDaniel Fojt ie.key_mgmt);
1288*a1157835SDaniel Fojt }
1289*a1157835SDaniel Fojt }
1290*a1157835SDaniel Fojt if (bss_wpa) {
1291*a1157835SDaniel Fojt wpa_hexdump(MSG_DEBUG, "WPA", bss_wpa, 2 + bss_wpa[1]);
1292*a1157835SDaniel Fojt if (wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie)) {
1293*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1294*a1157835SDaniel Fojt "Could not parse WPA element");
1295*a1157835SDaniel Fojt } else {
1296*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1297*a1157835SDaniel Fojt "WPA: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1298*a1157835SDaniel Fojt ie.pairwise_cipher, ie.group_cipher,
1299*a1157835SDaniel Fojt ie.key_mgmt);
1300*a1157835SDaniel Fojt }
1301*a1157835SDaniel Fojt }
13026d49e1aeSJan Lentfer return -1;
13036d49e1aeSJan Lentfer } else {
1304*a1157835SDaniel Fojt if (ssid->proto & WPA_PROTO_OSEN)
1305*a1157835SDaniel Fojt proto = WPA_PROTO_OSEN;
1306*a1157835SDaniel Fojt else if (ssid->proto & WPA_PROTO_RSN)
13076d49e1aeSJan Lentfer proto = WPA_PROTO_RSN;
13086d49e1aeSJan Lentfer else
13096d49e1aeSJan Lentfer proto = WPA_PROTO_WPA;
13106d49e1aeSJan Lentfer if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
13116d49e1aeSJan Lentfer os_memset(&ie, 0, sizeof(ie));
13126d49e1aeSJan Lentfer ie.group_cipher = ssid->group_cipher;
13136d49e1aeSJan Lentfer ie.pairwise_cipher = ssid->pairwise_cipher;
13146d49e1aeSJan Lentfer ie.key_mgmt = ssid->key_mgmt;
13156d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
1316*a1157835SDaniel Fojt ie.mgmt_group_cipher = 0;
1317*a1157835SDaniel Fojt if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
1318*a1157835SDaniel Fojt if (ssid->group_mgmt_cipher &
1319*a1157835SDaniel Fojt WPA_CIPHER_BIP_GMAC_256)
13206d49e1aeSJan Lentfer ie.mgmt_group_cipher =
1321*a1157835SDaniel Fojt WPA_CIPHER_BIP_GMAC_256;
1322*a1157835SDaniel Fojt else if (ssid->group_mgmt_cipher &
1323*a1157835SDaniel Fojt WPA_CIPHER_BIP_CMAC_256)
1324*a1157835SDaniel Fojt ie.mgmt_group_cipher =
1325*a1157835SDaniel Fojt WPA_CIPHER_BIP_CMAC_256;
1326*a1157835SDaniel Fojt else if (ssid->group_mgmt_cipher &
1327*a1157835SDaniel Fojt WPA_CIPHER_BIP_GMAC_128)
1328*a1157835SDaniel Fojt ie.mgmt_group_cipher =
1329*a1157835SDaniel Fojt WPA_CIPHER_BIP_GMAC_128;
1330*a1157835SDaniel Fojt else
1331*a1157835SDaniel Fojt ie.mgmt_group_cipher =
1332*a1157835SDaniel Fojt WPA_CIPHER_AES_128_CMAC;
1333*a1157835SDaniel Fojt }
13346d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
1335*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1336*a1157835SDaniel Fojt if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
1337*a1157835SDaniel Fojt !ssid->owe_only &&
1338*a1157835SDaniel Fojt !bss_wpa && !bss_rsn && !bss_osen) {
1339*a1157835SDaniel Fojt wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
1340*a1157835SDaniel Fojt wpa_s->wpa_proto = 0;
1341*a1157835SDaniel Fojt *wpa_ie_len = 0;
1342*a1157835SDaniel Fojt return 0;
1343*a1157835SDaniel Fojt }
1344*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
13453ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
13463ff40c12SJohn Marino "based on configuration");
13476d49e1aeSJan Lentfer } else
13486d49e1aeSJan Lentfer proto = ie.proto;
13496d49e1aeSJan Lentfer }
13506d49e1aeSJan Lentfer
13513ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
13526d49e1aeSJan Lentfer "pairwise %d key_mgmt %d proto %d",
13536d49e1aeSJan Lentfer ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
13546d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
13556d49e1aeSJan Lentfer if (ssid->ieee80211w) {
13563ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
13576d49e1aeSJan Lentfer ie.mgmt_group_cipher);
13586d49e1aeSJan Lentfer }
13596d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
13606d49e1aeSJan Lentfer
13613ff40c12SJohn Marino wpa_s->wpa_proto = proto;
13626d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
13636d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
1364*a1157835SDaniel Fojt !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
13656d49e1aeSJan Lentfer
13666d49e1aeSJan Lentfer if (bss || !wpa_s->ap_ies_from_associnfo) {
13676d49e1aeSJan Lentfer if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
13686d49e1aeSJan Lentfer bss_wpa ? 2 + bss_wpa[1] : 0) ||
13696d49e1aeSJan Lentfer wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
13706d49e1aeSJan Lentfer bss_rsn ? 2 + bss_rsn[1] : 0))
13716d49e1aeSJan Lentfer return -1;
13726d49e1aeSJan Lentfer }
13736d49e1aeSJan Lentfer
1374*a1157835SDaniel Fojt #ifdef CONFIG_NO_WPA
1375*a1157835SDaniel Fojt wpa_s->group_cipher = WPA_CIPHER_NONE;
1376*a1157835SDaniel Fojt wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
1377*a1157835SDaniel Fojt #else /* CONFIG_NO_WPA */
13786d49e1aeSJan Lentfer sel = ie.group_cipher & ssid->group_cipher;
1379*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1380*a1157835SDaniel Fojt "WPA: AP group 0x%x network profile group 0x%x; available group 0x%x",
1381*a1157835SDaniel Fojt ie.group_cipher, ssid->group_cipher, sel);
13823ff40c12SJohn Marino wpa_s->group_cipher = wpa_pick_group_cipher(sel);
13833ff40c12SJohn Marino if (wpa_s->group_cipher < 0) {
13843ff40c12SJohn Marino wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
13853ff40c12SJohn Marino "cipher");
13866d49e1aeSJan Lentfer return -1;
13876d49e1aeSJan Lentfer }
13883ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
13893ff40c12SJohn Marino wpa_cipher_txt(wpa_s->group_cipher));
13906d49e1aeSJan Lentfer
13916d49e1aeSJan Lentfer sel = ie.pairwise_cipher & ssid->pairwise_cipher;
1392*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1393*a1157835SDaniel Fojt "WPA: AP pairwise 0x%x network profile pairwise 0x%x; available pairwise 0x%x",
1394*a1157835SDaniel Fojt ie.pairwise_cipher, ssid->pairwise_cipher, sel);
13953ff40c12SJohn Marino wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
13963ff40c12SJohn Marino if (wpa_s->pairwise_cipher < 0) {
13973ff40c12SJohn Marino wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
13983ff40c12SJohn Marino "cipher");
13996d49e1aeSJan Lentfer return -1;
14006d49e1aeSJan Lentfer }
14013ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
14023ff40c12SJohn Marino wpa_cipher_txt(wpa_s->pairwise_cipher));
1403*a1157835SDaniel Fojt #endif /* CONFIG_NO_WPA */
14046d49e1aeSJan Lentfer
14056d49e1aeSJan Lentfer sel = ie.key_mgmt & ssid->key_mgmt;
1406*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1407*a1157835SDaniel Fojt "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
1408*a1157835SDaniel Fojt ie.key_mgmt, ssid->key_mgmt, sel);
14093ff40c12SJohn Marino #ifdef CONFIG_SAE
14103ff40c12SJohn Marino if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
14113ff40c12SJohn Marino sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
14123ff40c12SJohn Marino #endif /* CONFIG_SAE */
14136d49e1aeSJan Lentfer if (0) {
14146d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211R
1415*a1157835SDaniel Fojt #ifdef CONFIG_SHA384
1416*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
1417*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
1418*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1419*a1157835SDaniel Fojt "WPA: using KEY_MGMT FT/802.1X-SHA384");
1420*a1157835SDaniel Fojt if (!ssid->ft_eap_pmksa_caching &&
1421*a1157835SDaniel Fojt pmksa_cache_get_current(wpa_s->wpa)) {
1422*a1157835SDaniel Fojt /* PMKSA caching with FT may have interoperability
1423*a1157835SDaniel Fojt * issues, so disable that case by default for now. */
1424*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1425*a1157835SDaniel Fojt "WPA: Disable PMKSA caching for FT/802.1X connection");
1426*a1157835SDaniel Fojt pmksa_cache_clear_current(wpa_s->wpa);
1427*a1157835SDaniel Fojt }
1428*a1157835SDaniel Fojt #endif /* CONFIG_SHA384 */
1429*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R */
1430*a1157835SDaniel Fojt #ifdef CONFIG_SUITEB192
1431*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
1432*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
1433*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1434*a1157835SDaniel Fojt "WPA: using KEY_MGMT 802.1X with Suite B (192-bit)");
1435*a1157835SDaniel Fojt #endif /* CONFIG_SUITEB192 */
1436*a1157835SDaniel Fojt #ifdef CONFIG_SUITEB
1437*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
1438*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
1439*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1440*a1157835SDaniel Fojt "WPA: using KEY_MGMT 802.1X with Suite B");
1441*a1157835SDaniel Fojt #endif /* CONFIG_SUITEB */
1442*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1443*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R
1444*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
1445*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
1446*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
1447*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
1448*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
1449*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
1450*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R */
1451*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
1452*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
1453*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
1454*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
1455*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
1456*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
1457*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1458*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R
14596d49e1aeSJan Lentfer } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
14606d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
14613ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
1462*a1157835SDaniel Fojt if (!ssid->ft_eap_pmksa_caching &&
1463*a1157835SDaniel Fojt pmksa_cache_get_current(wpa_s->wpa)) {
1464*a1157835SDaniel Fojt /* PMKSA caching with FT may have interoperability
1465*a1157835SDaniel Fojt * issues, so disable that case by default for now. */
1466*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1467*a1157835SDaniel Fojt "WPA: Disable PMKSA caching for FT/802.1X connection");
1468*a1157835SDaniel Fojt pmksa_cache_clear_current(wpa_s->wpa);
1469*a1157835SDaniel Fojt }
1470*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R */
1471*a1157835SDaniel Fojt #ifdef CONFIG_DPP
1472*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_DPP) {
1473*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
1474*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
1475*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
1476*a1157835SDaniel Fojt #ifdef CONFIG_SAE
1477*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_FT_SAE) {
1478*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
1479*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
1480*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_SAE) {
1481*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
1482*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
1483*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
1484*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R
14856d49e1aeSJan Lentfer } else if (sel & WPA_KEY_MGMT_FT_PSK) {
14866d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
14873ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
14886d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211R */
14896d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
14906d49e1aeSJan Lentfer } else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
14916d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
14923ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG,
14936d49e1aeSJan Lentfer "WPA: using KEY_MGMT 802.1X with SHA256");
14946d49e1aeSJan Lentfer } else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
14956d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
14963ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG,
14976d49e1aeSJan Lentfer "WPA: using KEY_MGMT PSK with SHA256");
14986d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
14996d49e1aeSJan Lentfer } else if (sel & WPA_KEY_MGMT_IEEE8021X) {
15006d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
15013ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
15026d49e1aeSJan Lentfer } else if (sel & WPA_KEY_MGMT_PSK) {
15036d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
15043ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
15056d49e1aeSJan Lentfer } else if (sel & WPA_KEY_MGMT_WPA_NONE) {
15066d49e1aeSJan Lentfer wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
15073ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
1508*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1509*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_OSEN) {
1510*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
1511*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
1512*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1513*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1514*a1157835SDaniel Fojt } else if (sel & WPA_KEY_MGMT_OWE) {
1515*a1157835SDaniel Fojt wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
1516*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE");
1517*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
15186d49e1aeSJan Lentfer } else {
15193ff40c12SJohn Marino wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
15203ff40c12SJohn Marino "authenticated key management type");
15216d49e1aeSJan Lentfer return -1;
15226d49e1aeSJan Lentfer }
15236d49e1aeSJan Lentfer
15246d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
15256d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
15266d49e1aeSJan Lentfer wpa_s->pairwise_cipher);
15276d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
15286d49e1aeSJan Lentfer
15296d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
15306d49e1aeSJan Lentfer sel = ie.mgmt_group_cipher;
1531*a1157835SDaniel Fojt if (ssid->group_mgmt_cipher)
1532*a1157835SDaniel Fojt sel &= ssid->group_mgmt_cipher;
1533*a1157835SDaniel Fojt if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
15346d49e1aeSJan Lentfer !(ie.capabilities & WPA_CAPABILITY_MFPC))
15356d49e1aeSJan Lentfer sel = 0;
1536*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
1537*a1157835SDaniel Fojt "WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
1538*a1157835SDaniel Fojt ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
15396d49e1aeSJan Lentfer if (sel & WPA_CIPHER_AES_128_CMAC) {
15406d49e1aeSJan Lentfer wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
15413ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
15426d49e1aeSJan Lentfer "AES-128-CMAC");
1543*a1157835SDaniel Fojt } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
1544*a1157835SDaniel Fojt wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
1545*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
1546*a1157835SDaniel Fojt "BIP-GMAC-128");
1547*a1157835SDaniel Fojt } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
1548*a1157835SDaniel Fojt wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
1549*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
1550*a1157835SDaniel Fojt "BIP-GMAC-256");
1551*a1157835SDaniel Fojt } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
1552*a1157835SDaniel Fojt wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
1553*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
1554*a1157835SDaniel Fojt "BIP-CMAC-256");
15556d49e1aeSJan Lentfer } else {
15566d49e1aeSJan Lentfer wpa_s->mgmt_group_cipher = 0;
15573ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
15586d49e1aeSJan Lentfer }
15596d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
15606d49e1aeSJan Lentfer wpa_s->mgmt_group_cipher);
15613ff40c12SJohn Marino wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
1562*a1157835SDaniel Fojt wpas_get_ssid_pmf(wpa_s, ssid));
15636d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
1564*a1157835SDaniel Fojt #ifdef CONFIG_OCV
1565*a1157835SDaniel Fojt wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
1566*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
15676d49e1aeSJan Lentfer
15686d49e1aeSJan Lentfer if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
15693ff40c12SJohn Marino wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
15706d49e1aeSJan Lentfer return -1;
15716d49e1aeSJan Lentfer }
15726d49e1aeSJan Lentfer
1573*a1157835SDaniel Fojt if (0) {
1574*a1157835SDaniel Fojt #ifdef CONFIG_DPP
1575*a1157835SDaniel Fojt } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
1576*a1157835SDaniel Fojt /* Use PMK from DPP network introduction (PMKSA entry) */
1577*a1157835SDaniel Fojt wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
1578*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
1579*a1157835SDaniel Fojt } else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
1580*a1157835SDaniel Fojt int psk_set = 0;
1581*a1157835SDaniel Fojt int sae_only;
1582*a1157835SDaniel Fojt
1583*a1157835SDaniel Fojt sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK |
1584*a1157835SDaniel Fojt WPA_KEY_MGMT_FT_PSK |
1585*a1157835SDaniel Fojt WPA_KEY_MGMT_PSK_SHA256)) == 0;
1586*a1157835SDaniel Fojt
1587*a1157835SDaniel Fojt if (ssid->psk_set && !sae_only) {
1588*a1157835SDaniel Fojt wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
1589*a1157835SDaniel Fojt ssid->psk, PMK_LEN);
1590*a1157835SDaniel Fojt wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
1591*a1157835SDaniel Fojt NULL);
1592*a1157835SDaniel Fojt psk_set = 1;
1593*a1157835SDaniel Fojt }
1594*a1157835SDaniel Fojt
1595*a1157835SDaniel Fojt if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
1596*a1157835SDaniel Fojt (ssid->sae_password || ssid->passphrase))
1597*a1157835SDaniel Fojt psk_set = 1;
1598*a1157835SDaniel Fojt
15993ff40c12SJohn Marino #ifndef CONFIG_NO_PBKDF2
16003ff40c12SJohn Marino if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
1601*a1157835SDaniel Fojt ssid->passphrase && !sae_only) {
16023ff40c12SJohn Marino u8 psk[PMK_LEN];
16033ff40c12SJohn Marino pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
16043ff40c12SJohn Marino 4096, psk, PMK_LEN);
16053ff40c12SJohn Marino wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
16063ff40c12SJohn Marino psk, PMK_LEN);
1607*a1157835SDaniel Fojt wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL);
1608*a1157835SDaniel Fojt psk_set = 1;
1609*a1157835SDaniel Fojt os_memset(psk, 0, sizeof(psk));
16103ff40c12SJohn Marino }
16113ff40c12SJohn Marino #endif /* CONFIG_NO_PBKDF2 */
16123ff40c12SJohn Marino #ifdef CONFIG_EXT_PASSWORD
1613*a1157835SDaniel Fojt if (ssid->ext_psk && !sae_only) {
16143ff40c12SJohn Marino struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
16153ff40c12SJohn Marino ssid->ext_psk);
16163ff40c12SJohn Marino char pw_str[64 + 1];
16173ff40c12SJohn Marino u8 psk[PMK_LEN];
16183ff40c12SJohn Marino
16193ff40c12SJohn Marino if (pw == NULL) {
16203ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
16213ff40c12SJohn Marino "found from external storage");
16223ff40c12SJohn Marino return -1;
16233ff40c12SJohn Marino }
16243ff40c12SJohn Marino
16253ff40c12SJohn Marino if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
16263ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
16273ff40c12SJohn Marino "PSK length %d in external storage",
16283ff40c12SJohn Marino (int) wpabuf_len(pw));
16293ff40c12SJohn Marino ext_password_free(pw);
16303ff40c12SJohn Marino return -1;
16313ff40c12SJohn Marino }
16323ff40c12SJohn Marino
16333ff40c12SJohn Marino os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
16343ff40c12SJohn Marino pw_str[wpabuf_len(pw)] = '\0';
16353ff40c12SJohn Marino
16363ff40c12SJohn Marino #ifndef CONFIG_NO_PBKDF2
16373ff40c12SJohn Marino if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
16383ff40c12SJohn Marino {
16393ff40c12SJohn Marino pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
16403ff40c12SJohn Marino 4096, psk, PMK_LEN);
16413ff40c12SJohn Marino os_memset(pw_str, 0, sizeof(pw_str));
16423ff40c12SJohn Marino wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
16433ff40c12SJohn Marino "external passphrase)",
16443ff40c12SJohn Marino psk, PMK_LEN);
1645*a1157835SDaniel Fojt wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
1646*a1157835SDaniel Fojt NULL);
1647*a1157835SDaniel Fojt psk_set = 1;
1648*a1157835SDaniel Fojt os_memset(psk, 0, sizeof(psk));
16493ff40c12SJohn Marino } else
16503ff40c12SJohn Marino #endif /* CONFIG_NO_PBKDF2 */
16513ff40c12SJohn Marino if (wpabuf_len(pw) == 2 * PMK_LEN) {
16523ff40c12SJohn Marino if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
16533ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
16543ff40c12SJohn Marino "Invalid PSK hex string");
16553ff40c12SJohn Marino os_memset(pw_str, 0, sizeof(pw_str));
16563ff40c12SJohn Marino ext_password_free(pw);
16573ff40c12SJohn Marino return -1;
16583ff40c12SJohn Marino }
1659*a1157835SDaniel Fojt wpa_hexdump_key(MSG_MSGDUMP,
1660*a1157835SDaniel Fojt "PSK (from external PSK)",
1661*a1157835SDaniel Fojt psk, PMK_LEN);
1662*a1157835SDaniel Fojt wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
1663*a1157835SDaniel Fojt NULL);
1664*a1157835SDaniel Fojt psk_set = 1;
1665*a1157835SDaniel Fojt os_memset(psk, 0, sizeof(psk));
16663ff40c12SJohn Marino } else {
16673ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
16683ff40c12SJohn Marino "PSK available");
16693ff40c12SJohn Marino os_memset(pw_str, 0, sizeof(pw_str));
16703ff40c12SJohn Marino ext_password_free(pw);
16713ff40c12SJohn Marino return -1;
16723ff40c12SJohn Marino }
16733ff40c12SJohn Marino
16743ff40c12SJohn Marino os_memset(pw_str, 0, sizeof(pw_str));
16753ff40c12SJohn Marino ext_password_free(pw);
16763ff40c12SJohn Marino }
16773ff40c12SJohn Marino #endif /* CONFIG_EXT_PASSWORD */
1678*a1157835SDaniel Fojt
1679*a1157835SDaniel Fojt if (!psk_set) {
1680*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO,
1681*a1157835SDaniel Fojt "No PSK available for association");
1682*a1157835SDaniel Fojt wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
1683*a1157835SDaniel Fojt return -1;
1684*a1157835SDaniel Fojt }
1685*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1686*a1157835SDaniel Fojt } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
1687*a1157835SDaniel Fojt /* OWE Diffie-Hellman exchange in (Re)Association
1688*a1157835SDaniel Fojt * Request/Response frames set the PMK, so do not override it
1689*a1157835SDaniel Fojt * here. */
1690*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
16913ff40c12SJohn Marino } else
16926d49e1aeSJan Lentfer wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
16936d49e1aeSJan Lentfer
16946d49e1aeSJan Lentfer return 0;
16956d49e1aeSJan Lentfer }
16966d49e1aeSJan Lentfer
16976d49e1aeSJan Lentfer
wpas_ext_capab_byte(struct wpa_supplicant * wpa_s,u8 * pos,int idx)16983ff40c12SJohn Marino static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
16993ff40c12SJohn Marino {
17003ff40c12SJohn Marino *pos = 0x00;
17013ff40c12SJohn Marino
17023ff40c12SJohn Marino switch (idx) {
17033ff40c12SJohn Marino case 0: /* Bits 0-7 */
17043ff40c12SJohn Marino break;
17053ff40c12SJohn Marino case 1: /* Bits 8-15 */
1706*a1157835SDaniel Fojt if (wpa_s->conf->coloc_intf_reporting) {
1707*a1157835SDaniel Fojt /* Bit 13 - Collocated Interference Reporting */
1708*a1157835SDaniel Fojt *pos |= 0x20;
1709*a1157835SDaniel Fojt }
17103ff40c12SJohn Marino break;
17113ff40c12SJohn Marino case 2: /* Bits 16-23 */
17123ff40c12SJohn Marino #ifdef CONFIG_WNM
17133ff40c12SJohn Marino *pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
1714*a1157835SDaniel Fojt if (!wpa_s->conf->disable_btm)
17153ff40c12SJohn Marino *pos |= 0x08; /* Bit 19 - BSS Transition */
17163ff40c12SJohn Marino #endif /* CONFIG_WNM */
17173ff40c12SJohn Marino break;
17183ff40c12SJohn Marino case 3: /* Bits 24-31 */
17193ff40c12SJohn Marino #ifdef CONFIG_WNM
17203ff40c12SJohn Marino *pos |= 0x02; /* Bit 25 - SSID List */
17213ff40c12SJohn Marino #endif /* CONFIG_WNM */
17223ff40c12SJohn Marino #ifdef CONFIG_INTERWORKING
17233ff40c12SJohn Marino if (wpa_s->conf->interworking)
17243ff40c12SJohn Marino *pos |= 0x80; /* Bit 31 - Interworking */
17253ff40c12SJohn Marino #endif /* CONFIG_INTERWORKING */
17263ff40c12SJohn Marino break;
17273ff40c12SJohn Marino case 4: /* Bits 32-39 */
17283ff40c12SJohn Marino #ifdef CONFIG_INTERWORKING
1729*a1157835SDaniel Fojt if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)
17303ff40c12SJohn Marino *pos |= 0x01; /* Bit 32 - QoS Map */
17313ff40c12SJohn Marino #endif /* CONFIG_INTERWORKING */
17323ff40c12SJohn Marino break;
17333ff40c12SJohn Marino case 5: /* Bits 40-47 */
1734*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1735*a1157835SDaniel Fojt if (wpa_s->conf->hs20)
1736*a1157835SDaniel Fojt *pos |= 0x40; /* Bit 46 - WNM-Notification */
1737*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1738*a1157835SDaniel Fojt #ifdef CONFIG_MBO
1739*a1157835SDaniel Fojt *pos |= 0x40; /* Bit 46 - WNM-Notification */
1740*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
17413ff40c12SJohn Marino break;
17423ff40c12SJohn Marino case 6: /* Bits 48-55 */
17433ff40c12SJohn Marino break;
1744*a1157835SDaniel Fojt case 7: /* Bits 56-63 */
1745*a1157835SDaniel Fojt break;
1746*a1157835SDaniel Fojt case 8: /* Bits 64-71 */
1747*a1157835SDaniel Fojt if (wpa_s->conf->ftm_responder)
1748*a1157835SDaniel Fojt *pos |= 0x40; /* Bit 70 - FTM responder */
1749*a1157835SDaniel Fojt if (wpa_s->conf->ftm_initiator)
1750*a1157835SDaniel Fojt *pos |= 0x80; /* Bit 71 - FTM initiator */
1751*a1157835SDaniel Fojt break;
1752*a1157835SDaniel Fojt case 9: /* Bits 72-79 */
1753*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1754*a1157835SDaniel Fojt if (!wpa_s->disable_fils)
1755*a1157835SDaniel Fojt *pos |= 0x01;
1756*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1757*a1157835SDaniel Fojt break;
17583ff40c12SJohn Marino }
17593ff40c12SJohn Marino }
17603ff40c12SJohn Marino
17613ff40c12SJohn Marino
wpas_build_ext_capab(struct wpa_supplicant * wpa_s,u8 * buf,size_t buflen)1762*a1157835SDaniel Fojt int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
17633ff40c12SJohn Marino {
17643ff40c12SJohn Marino u8 *pos = buf;
1765*a1157835SDaniel Fojt u8 len = 10, i;
17663ff40c12SJohn Marino
17673ff40c12SJohn Marino if (len < wpa_s->extended_capa_len)
17683ff40c12SJohn Marino len = wpa_s->extended_capa_len;
1769*a1157835SDaniel Fojt if (buflen < (size_t) len + 2) {
1770*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
1771*a1157835SDaniel Fojt "Not enough room for building extended capabilities element");
1772*a1157835SDaniel Fojt return -1;
1773*a1157835SDaniel Fojt }
17743ff40c12SJohn Marino
17753ff40c12SJohn Marino *pos++ = WLAN_EID_EXT_CAPAB;
17763ff40c12SJohn Marino *pos++ = len;
17773ff40c12SJohn Marino for (i = 0; i < len; i++, pos++) {
17783ff40c12SJohn Marino wpas_ext_capab_byte(wpa_s, pos, i);
17793ff40c12SJohn Marino
17803ff40c12SJohn Marino if (i < wpa_s->extended_capa_len) {
17813ff40c12SJohn Marino *pos &= ~wpa_s->extended_capa_mask[i];
17823ff40c12SJohn Marino *pos |= wpa_s->extended_capa[i];
17833ff40c12SJohn Marino }
17843ff40c12SJohn Marino }
17853ff40c12SJohn Marino
17863ff40c12SJohn Marino while (len > 0 && buf[1 + len] == 0) {
17873ff40c12SJohn Marino len--;
17883ff40c12SJohn Marino buf[1] = len;
17893ff40c12SJohn Marino }
17903ff40c12SJohn Marino if (len == 0)
17913ff40c12SJohn Marino return 0;
17923ff40c12SJohn Marino
17933ff40c12SJohn Marino return 2 + len;
17943ff40c12SJohn Marino }
17953ff40c12SJohn Marino
17963ff40c12SJohn Marino
wpas_valid_bss(struct wpa_supplicant * wpa_s,struct wpa_bss * test_bss)17973ff40c12SJohn Marino static int wpas_valid_bss(struct wpa_supplicant *wpa_s,
17983ff40c12SJohn Marino struct wpa_bss *test_bss)
17993ff40c12SJohn Marino {
18003ff40c12SJohn Marino struct wpa_bss *bss;
18013ff40c12SJohn Marino
18023ff40c12SJohn Marino dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
18033ff40c12SJohn Marino if (bss == test_bss)
18043ff40c12SJohn Marino return 1;
18053ff40c12SJohn Marino }
18063ff40c12SJohn Marino
18073ff40c12SJohn Marino return 0;
18083ff40c12SJohn Marino }
18093ff40c12SJohn Marino
18103ff40c12SJohn Marino
wpas_valid_ssid(struct wpa_supplicant * wpa_s,struct wpa_ssid * test_ssid)18113ff40c12SJohn Marino static int wpas_valid_ssid(struct wpa_supplicant *wpa_s,
18123ff40c12SJohn Marino struct wpa_ssid *test_ssid)
18133ff40c12SJohn Marino {
18143ff40c12SJohn Marino struct wpa_ssid *ssid;
18153ff40c12SJohn Marino
18163ff40c12SJohn Marino for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
18173ff40c12SJohn Marino if (ssid == test_ssid)
18183ff40c12SJohn Marino return 1;
18193ff40c12SJohn Marino }
18203ff40c12SJohn Marino
18213ff40c12SJohn Marino return 0;
18223ff40c12SJohn Marino }
18233ff40c12SJohn Marino
18243ff40c12SJohn Marino
wpas_valid_bss_ssid(struct wpa_supplicant * wpa_s,struct wpa_bss * test_bss,struct wpa_ssid * test_ssid)18253ff40c12SJohn Marino int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
18263ff40c12SJohn Marino struct wpa_ssid *test_ssid)
18273ff40c12SJohn Marino {
18283ff40c12SJohn Marino if (test_bss && !wpas_valid_bss(wpa_s, test_bss))
18293ff40c12SJohn Marino return 0;
18303ff40c12SJohn Marino
18313ff40c12SJohn Marino return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid);
18323ff40c12SJohn Marino }
18333ff40c12SJohn Marino
18343ff40c12SJohn Marino
wpas_connect_work_free(struct wpa_connect_work * cwork)18353ff40c12SJohn Marino void wpas_connect_work_free(struct wpa_connect_work *cwork)
18363ff40c12SJohn Marino {
18373ff40c12SJohn Marino if (cwork == NULL)
18383ff40c12SJohn Marino return;
18393ff40c12SJohn Marino os_free(cwork);
18403ff40c12SJohn Marino }
18413ff40c12SJohn Marino
18423ff40c12SJohn Marino
wpas_connect_work_done(struct wpa_supplicant * wpa_s)18433ff40c12SJohn Marino void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
18443ff40c12SJohn Marino {
18453ff40c12SJohn Marino struct wpa_connect_work *cwork;
18463ff40c12SJohn Marino struct wpa_radio_work *work = wpa_s->connect_work;
18473ff40c12SJohn Marino
18483ff40c12SJohn Marino if (!work)
18493ff40c12SJohn Marino return;
18503ff40c12SJohn Marino
18513ff40c12SJohn Marino wpa_s->connect_work = NULL;
18523ff40c12SJohn Marino cwork = work->ctx;
18533ff40c12SJohn Marino work->ctx = NULL;
18543ff40c12SJohn Marino wpas_connect_work_free(cwork);
18553ff40c12SJohn Marino radio_work_done(work);
18563ff40c12SJohn Marino }
18573ff40c12SJohn Marino
18583ff40c12SJohn Marino
wpas_update_random_addr(struct wpa_supplicant * wpa_s,int style)1859*a1157835SDaniel Fojt int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
1860*a1157835SDaniel Fojt {
1861*a1157835SDaniel Fojt struct os_reltime now;
1862*a1157835SDaniel Fojt u8 addr[ETH_ALEN];
1863*a1157835SDaniel Fojt
1864*a1157835SDaniel Fojt os_get_reltime(&now);
1865*a1157835SDaniel Fojt if (wpa_s->last_mac_addr_style == style &&
1866*a1157835SDaniel Fojt wpa_s->last_mac_addr_change.sec != 0 &&
1867*a1157835SDaniel Fojt !os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
1868*a1157835SDaniel Fojt wpa_s->conf->rand_addr_lifetime)) {
1869*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG,
1870*a1157835SDaniel Fojt "Previously selected random MAC address has not yet expired");
1871*a1157835SDaniel Fojt return 0;
1872*a1157835SDaniel Fojt }
1873*a1157835SDaniel Fojt
1874*a1157835SDaniel Fojt switch (style) {
1875*a1157835SDaniel Fojt case 1:
1876*a1157835SDaniel Fojt if (random_mac_addr(addr) < 0)
1877*a1157835SDaniel Fojt return -1;
1878*a1157835SDaniel Fojt break;
1879*a1157835SDaniel Fojt case 2:
1880*a1157835SDaniel Fojt os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
1881*a1157835SDaniel Fojt if (random_mac_addr_keep_oui(addr) < 0)
1882*a1157835SDaniel Fojt return -1;
1883*a1157835SDaniel Fojt break;
1884*a1157835SDaniel Fojt default:
1885*a1157835SDaniel Fojt return -1;
1886*a1157835SDaniel Fojt }
1887*a1157835SDaniel Fojt
1888*a1157835SDaniel Fojt if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
1889*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO,
1890*a1157835SDaniel Fojt "Failed to set random MAC address");
1891*a1157835SDaniel Fojt return -1;
1892*a1157835SDaniel Fojt }
1893*a1157835SDaniel Fojt
1894*a1157835SDaniel Fojt os_get_reltime(&wpa_s->last_mac_addr_change);
1895*a1157835SDaniel Fojt wpa_s->mac_addr_changed = 1;
1896*a1157835SDaniel Fojt wpa_s->last_mac_addr_style = style;
1897*a1157835SDaniel Fojt
1898*a1157835SDaniel Fojt if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
1899*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO,
1900*a1157835SDaniel Fojt "Could not update MAC address information");
1901*a1157835SDaniel Fojt return -1;
1902*a1157835SDaniel Fojt }
1903*a1157835SDaniel Fojt
1904*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
1905*a1157835SDaniel Fojt MAC2STR(addr));
1906*a1157835SDaniel Fojt
1907*a1157835SDaniel Fojt return 0;
1908*a1157835SDaniel Fojt }
1909*a1157835SDaniel Fojt
1910*a1157835SDaniel Fojt
wpas_update_random_addr_disassoc(struct wpa_supplicant * wpa_s)1911*a1157835SDaniel Fojt int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
1912*a1157835SDaniel Fojt {
1913*a1157835SDaniel Fojt if (wpa_s->wpa_state >= WPA_AUTHENTICATING ||
1914*a1157835SDaniel Fojt !wpa_s->conf->preassoc_mac_addr)
1915*a1157835SDaniel Fojt return 0;
1916*a1157835SDaniel Fojt
1917*a1157835SDaniel Fojt return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr);
1918*a1157835SDaniel Fojt }
1919*a1157835SDaniel Fojt
1920*a1157835SDaniel Fojt
19213ff40c12SJohn Marino static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
19223ff40c12SJohn Marino
19236d49e1aeSJan Lentfer /**
19246d49e1aeSJan Lentfer * wpa_supplicant_associate - Request association
19256d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
19266d49e1aeSJan Lentfer * @bss: Scan results for the selected BSS, or %NULL if not available
19276d49e1aeSJan Lentfer * @ssid: Configuration data for the selected network
19286d49e1aeSJan Lentfer *
19296d49e1aeSJan Lentfer * This function is used to request %wpa_supplicant to associate with a BSS.
19306d49e1aeSJan Lentfer */
wpa_supplicant_associate(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,struct wpa_ssid * ssid)19316d49e1aeSJan Lentfer void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
19323ff40c12SJohn Marino struct wpa_bss *bss, struct wpa_ssid *ssid)
19336d49e1aeSJan Lentfer {
19343ff40c12SJohn Marino struct wpa_connect_work *cwork;
1935*a1157835SDaniel Fojt int rand_style;
1936*a1157835SDaniel Fojt
1937*a1157835SDaniel Fojt wpa_s->own_disconnect_req = 0;
1938*a1157835SDaniel Fojt
1939*a1157835SDaniel Fojt /*
1940*a1157835SDaniel Fojt * If we are starting a new connection, any previously pending EAPOL
1941*a1157835SDaniel Fojt * RX cannot be valid anymore.
1942*a1157835SDaniel Fojt */
1943*a1157835SDaniel Fojt wpabuf_free(wpa_s->pending_eapol_rx);
1944*a1157835SDaniel Fojt wpa_s->pending_eapol_rx = NULL;
1945*a1157835SDaniel Fojt
1946*a1157835SDaniel Fojt if (ssid->mac_addr == -1)
1947*a1157835SDaniel Fojt rand_style = wpa_s->conf->mac_addr;
1948*a1157835SDaniel Fojt else
1949*a1157835SDaniel Fojt rand_style = ssid->mac_addr;
1950*a1157835SDaniel Fojt
1951*a1157835SDaniel Fojt wmm_ac_clear_saved_tspecs(wpa_s);
1952*a1157835SDaniel Fojt wpa_s->reassoc_same_bss = 0;
1953*a1157835SDaniel Fojt wpa_s->reassoc_same_ess = 0;
1954*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
1955*a1157835SDaniel Fojt wpa_s->testing_resend_assoc = 0;
1956*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
1957*a1157835SDaniel Fojt
1958*a1157835SDaniel Fojt if (wpa_s->last_ssid == ssid) {
1959*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
1960*a1157835SDaniel Fojt wpa_s->reassoc_same_ess = 1;
1961*a1157835SDaniel Fojt if (wpa_s->current_bss && wpa_s->current_bss == bss) {
1962*a1157835SDaniel Fojt wmm_ac_save_tspecs(wpa_s);
1963*a1157835SDaniel Fojt wpa_s->reassoc_same_bss = 1;
1964*a1157835SDaniel Fojt } else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
1965*a1157835SDaniel Fojt os_get_reltime(&wpa_s->roam_start);
1966*a1157835SDaniel Fojt }
1967*a1157835SDaniel Fojt }
1968*a1157835SDaniel Fojt
1969*a1157835SDaniel Fojt if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
1970*a1157835SDaniel Fojt if (wpas_update_random_addr(wpa_s, rand_style) < 0)
1971*a1157835SDaniel Fojt return;
1972*a1157835SDaniel Fojt wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
1973*a1157835SDaniel Fojt } else if (rand_style == 0 && wpa_s->mac_addr_changed) {
1974*a1157835SDaniel Fojt if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
1975*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO,
1976*a1157835SDaniel Fojt "Could not restore permanent MAC address");
1977*a1157835SDaniel Fojt return;
1978*a1157835SDaniel Fojt }
1979*a1157835SDaniel Fojt wpa_s->mac_addr_changed = 0;
1980*a1157835SDaniel Fojt if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
1981*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO,
1982*a1157835SDaniel Fojt "Could not update MAC address information");
1983*a1157835SDaniel Fojt return;
1984*a1157835SDaniel Fojt }
1985*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
1986*a1157835SDaniel Fojt }
1987*a1157835SDaniel Fojt wpa_s->last_ssid = ssid;
19883ff40c12SJohn Marino
19893ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
19903ff40c12SJohn Marino ibss_rsn_deinit(wpa_s->ibss_rsn);
19913ff40c12SJohn Marino wpa_s->ibss_rsn = NULL;
1992*a1157835SDaniel Fojt #else /* CONFIG_IBSS_RSN */
1993*a1157835SDaniel Fojt if (ssid->mode == WPAS_MODE_IBSS &&
1994*a1157835SDaniel Fojt !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
1995*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO,
1996*a1157835SDaniel Fojt "IBSS RSN not supported in the build");
1997*a1157835SDaniel Fojt return;
1998*a1157835SDaniel Fojt }
19993ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
20003ff40c12SJohn Marino
20013ff40c12SJohn Marino if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
20023ff40c12SJohn Marino ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
20033ff40c12SJohn Marino #ifdef CONFIG_AP
20043ff40c12SJohn Marino if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
20053ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
20063ff40c12SJohn Marino "mode");
20073ff40c12SJohn Marino return;
20083ff40c12SJohn Marino }
20093ff40c12SJohn Marino if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
20103ff40c12SJohn Marino wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
20113ff40c12SJohn Marino if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
20123ff40c12SJohn Marino wpas_p2p_ap_setup_failed(wpa_s);
20133ff40c12SJohn Marino return;
20143ff40c12SJohn Marino }
20153ff40c12SJohn Marino wpa_s->current_bss = bss;
20163ff40c12SJohn Marino #else /* CONFIG_AP */
20173ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
20183ff40c12SJohn Marino "the build");
20193ff40c12SJohn Marino #endif /* CONFIG_AP */
20203ff40c12SJohn Marino return;
20213ff40c12SJohn Marino }
20223ff40c12SJohn Marino
2023*a1157835SDaniel Fojt if (ssid->mode == WPAS_MODE_MESH) {
2024*a1157835SDaniel Fojt #ifdef CONFIG_MESH
2025*a1157835SDaniel Fojt if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
2026*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO,
2027*a1157835SDaniel Fojt "Driver does not support mesh mode");
2028*a1157835SDaniel Fojt return;
2029*a1157835SDaniel Fojt }
2030*a1157835SDaniel Fojt if (bss)
2031*a1157835SDaniel Fojt ssid->frequency = bss->freq;
2032*a1157835SDaniel Fojt if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
2033*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
2034*a1157835SDaniel Fojt return;
2035*a1157835SDaniel Fojt }
2036*a1157835SDaniel Fojt wpa_s->current_bss = bss;
2037*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
2038*a1157835SDaniel Fojt wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
2039*a1157835SDaniel Fojt ssid->id);
2040*a1157835SDaniel Fojt wpas_notify_mesh_group_started(wpa_s, ssid);
2041*a1157835SDaniel Fojt #else /* CONFIG_MESH */
2042*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_ERROR,
2043*a1157835SDaniel Fojt "mesh mode support not included in the build");
2044*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
2045*a1157835SDaniel Fojt return;
2046*a1157835SDaniel Fojt }
2047*a1157835SDaniel Fojt
2048*a1157835SDaniel Fojt /*
2049*a1157835SDaniel Fojt * Set WPA state machine configuration to match the selected network now
2050*a1157835SDaniel Fojt * so that the information is available before wpas_start_assoc_cb()
2051*a1157835SDaniel Fojt * gets called. This is needed at least for RSN pre-authentication where
2052*a1157835SDaniel Fojt * candidate APs are added to a list based on scan result processing
2053*a1157835SDaniel Fojt * before completion of the first association.
2054*a1157835SDaniel Fojt */
2055*a1157835SDaniel Fojt wpa_supplicant_rsn_supp_set_config(wpa_s, ssid);
2056*a1157835SDaniel Fojt
2057*a1157835SDaniel Fojt #ifdef CONFIG_DPP
2058*a1157835SDaniel Fojt if (wpas_dpp_check_connect(wpa_s, ssid, bss) != 0)
2059*a1157835SDaniel Fojt return;
2060*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
2061*a1157835SDaniel Fojt
20623ff40c12SJohn Marino #ifdef CONFIG_TDLS
20633ff40c12SJohn Marino if (bss)
20643ff40c12SJohn Marino wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
20653ff40c12SJohn Marino bss->ie_len);
20663ff40c12SJohn Marino #endif /* CONFIG_TDLS */
20673ff40c12SJohn Marino
20683ff40c12SJohn Marino if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
2069*a1157835SDaniel Fojt ssid->mode == WPAS_MODE_INFRA) {
20703ff40c12SJohn Marino sme_authenticate(wpa_s, bss, ssid);
20713ff40c12SJohn Marino return;
20723ff40c12SJohn Marino }
20733ff40c12SJohn Marino
20743ff40c12SJohn Marino if (wpa_s->connect_work) {
20753ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
20763ff40c12SJohn Marino return;
20773ff40c12SJohn Marino }
20783ff40c12SJohn Marino
2079*a1157835SDaniel Fojt if (radio_work_pending(wpa_s, "connect")) {
2080*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist");
2081*a1157835SDaniel Fojt return;
2082*a1157835SDaniel Fojt }
2083*a1157835SDaniel Fojt
2084*a1157835SDaniel Fojt #ifdef CONFIG_SME
2085*a1157835SDaniel Fojt if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
2086*a1157835SDaniel Fojt /* Clear possibly set auth_alg, if any, from last attempt. */
2087*a1157835SDaniel Fojt wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
2088*a1157835SDaniel Fojt }
2089*a1157835SDaniel Fojt #endif /* CONFIG_SME */
2090*a1157835SDaniel Fojt
2091*a1157835SDaniel Fojt wpas_abort_ongoing_scan(wpa_s);
2092*a1157835SDaniel Fojt
20933ff40c12SJohn Marino cwork = os_zalloc(sizeof(*cwork));
20943ff40c12SJohn Marino if (cwork == NULL)
20953ff40c12SJohn Marino return;
20963ff40c12SJohn Marino
20973ff40c12SJohn Marino cwork->bss = bss;
20983ff40c12SJohn Marino cwork->ssid = ssid;
20993ff40c12SJohn Marino
21003ff40c12SJohn Marino if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
21013ff40c12SJohn Marino wpas_start_assoc_cb, cwork) < 0) {
21023ff40c12SJohn Marino os_free(cwork);
21033ff40c12SJohn Marino }
21043ff40c12SJohn Marino }
21053ff40c12SJohn Marino
21063ff40c12SJohn Marino
bss_is_ibss(struct wpa_bss * bss)2107*a1157835SDaniel Fojt static int bss_is_ibss(struct wpa_bss *bss)
2108*a1157835SDaniel Fojt {
2109*a1157835SDaniel Fojt return (bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
2110*a1157835SDaniel Fojt IEEE80211_CAP_IBSS;
2111*a1157835SDaniel Fojt }
2112*a1157835SDaniel Fojt
2113*a1157835SDaniel Fojt
drv_supports_vht(struct wpa_supplicant * wpa_s,const struct wpa_ssid * ssid)2114*a1157835SDaniel Fojt static int drv_supports_vht(struct wpa_supplicant *wpa_s,
2115*a1157835SDaniel Fojt const struct wpa_ssid *ssid)
2116*a1157835SDaniel Fojt {
2117*a1157835SDaniel Fojt enum hostapd_hw_mode hw_mode;
2118*a1157835SDaniel Fojt struct hostapd_hw_modes *mode = NULL;
2119*a1157835SDaniel Fojt u8 channel;
2120*a1157835SDaniel Fojt int i;
2121*a1157835SDaniel Fojt
2122*a1157835SDaniel Fojt hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
2123*a1157835SDaniel Fojt if (hw_mode == NUM_HOSTAPD_MODES)
2124*a1157835SDaniel Fojt return 0;
2125*a1157835SDaniel Fojt for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
2126*a1157835SDaniel Fojt if (wpa_s->hw.modes[i].mode == hw_mode) {
2127*a1157835SDaniel Fojt mode = &wpa_s->hw.modes[i];
2128*a1157835SDaniel Fojt break;
2129*a1157835SDaniel Fojt }
2130*a1157835SDaniel Fojt }
2131*a1157835SDaniel Fojt
2132*a1157835SDaniel Fojt if (!mode)
2133*a1157835SDaniel Fojt return 0;
2134*a1157835SDaniel Fojt
2135*a1157835SDaniel Fojt return mode->vht_capab != 0;
2136*a1157835SDaniel Fojt }
2137*a1157835SDaniel Fojt
2138*a1157835SDaniel Fojt
ibss_mesh_setup_freq(struct wpa_supplicant * wpa_s,const struct wpa_ssid * ssid,struct hostapd_freq_params * freq)2139*a1157835SDaniel Fojt void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
2140*a1157835SDaniel Fojt const struct wpa_ssid *ssid,
2141*a1157835SDaniel Fojt struct hostapd_freq_params *freq)
2142*a1157835SDaniel Fojt {
2143*a1157835SDaniel Fojt int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
2144*a1157835SDaniel Fojt enum hostapd_hw_mode hw_mode;
2145*a1157835SDaniel Fojt struct hostapd_hw_modes *mode = NULL;
2146*a1157835SDaniel Fojt int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
2147*a1157835SDaniel Fojt 184, 192 };
2148*a1157835SDaniel Fojt int vht80[] = { 36, 52, 100, 116, 132, 149 };
2149*a1157835SDaniel Fojt struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
2150*a1157835SDaniel Fojt u8 channel;
2151*a1157835SDaniel Fojt int i, chan_idx, ht40 = -1, res, obss_scan = 1;
2152*a1157835SDaniel Fojt unsigned int j, k;
2153*a1157835SDaniel Fojt struct hostapd_freq_params vht_freq;
2154*a1157835SDaniel Fojt int chwidth, seg0, seg1;
2155*a1157835SDaniel Fojt u32 vht_caps = 0;
2156*a1157835SDaniel Fojt
2157*a1157835SDaniel Fojt freq->freq = ssid->frequency;
2158*a1157835SDaniel Fojt
2159*a1157835SDaniel Fojt for (j = 0; j < wpa_s->last_scan_res_used; j++) {
2160*a1157835SDaniel Fojt struct wpa_bss *bss = wpa_s->last_scan_res[j];
2161*a1157835SDaniel Fojt
2162*a1157835SDaniel Fojt if (ssid->mode != WPAS_MODE_IBSS)
2163*a1157835SDaniel Fojt break;
2164*a1157835SDaniel Fojt
2165*a1157835SDaniel Fojt /* Don't adjust control freq in case of fixed_freq */
2166*a1157835SDaniel Fojt if (ssid->fixed_freq)
2167*a1157835SDaniel Fojt break;
2168*a1157835SDaniel Fojt
2169*a1157835SDaniel Fojt if (!bss_is_ibss(bss))
2170*a1157835SDaniel Fojt continue;
2171*a1157835SDaniel Fojt
2172*a1157835SDaniel Fojt if (ssid->ssid_len == bss->ssid_len &&
2173*a1157835SDaniel Fojt os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) {
2174*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
2175*a1157835SDaniel Fojt "IBSS already found in scan results, adjust control freq: %d",
2176*a1157835SDaniel Fojt bss->freq);
2177*a1157835SDaniel Fojt freq->freq = bss->freq;
2178*a1157835SDaniel Fojt obss_scan = 0;
2179*a1157835SDaniel Fojt break;
2180*a1157835SDaniel Fojt }
2181*a1157835SDaniel Fojt }
2182*a1157835SDaniel Fojt
2183*a1157835SDaniel Fojt /* For IBSS check HT_IBSS flag */
2184*a1157835SDaniel Fojt if (ssid->mode == WPAS_MODE_IBSS &&
2185*a1157835SDaniel Fojt !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
2186*a1157835SDaniel Fojt return;
2187*a1157835SDaniel Fojt
2188*a1157835SDaniel Fojt if (wpa_s->group_cipher == WPA_CIPHER_WEP40 ||
2189*a1157835SDaniel Fojt wpa_s->group_cipher == WPA_CIPHER_WEP104 ||
2190*a1157835SDaniel Fojt wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
2191*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
2192*a1157835SDaniel Fojt "IBSS: WEP/TKIP detected, do not try to enable HT");
2193*a1157835SDaniel Fojt return;
2194*a1157835SDaniel Fojt }
2195*a1157835SDaniel Fojt
2196*a1157835SDaniel Fojt hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
2197*a1157835SDaniel Fojt for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
2198*a1157835SDaniel Fojt if (wpa_s->hw.modes[i].mode == hw_mode) {
2199*a1157835SDaniel Fojt mode = &wpa_s->hw.modes[i];
2200*a1157835SDaniel Fojt break;
2201*a1157835SDaniel Fojt }
2202*a1157835SDaniel Fojt }
2203*a1157835SDaniel Fojt
2204*a1157835SDaniel Fojt if (!mode)
2205*a1157835SDaniel Fojt return;
2206*a1157835SDaniel Fojt
2207*a1157835SDaniel Fojt /* HE can work without HT + VHT */
2208*a1157835SDaniel Fojt freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
2209*a1157835SDaniel Fojt
2210*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
2211*a1157835SDaniel Fojt if (ssid->disable_ht) {
2212*a1157835SDaniel Fojt freq->ht_enabled = 0;
2213*a1157835SDaniel Fojt return;
2214*a1157835SDaniel Fojt }
2215*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
2216*a1157835SDaniel Fojt
2217*a1157835SDaniel Fojt freq->ht_enabled = ht_supported(mode);
2218*a1157835SDaniel Fojt if (!freq->ht_enabled)
2219*a1157835SDaniel Fojt return;
2220*a1157835SDaniel Fojt
2221*a1157835SDaniel Fojt /* Setup higher BW only for 5 GHz */
2222*a1157835SDaniel Fojt if (mode->mode != HOSTAPD_MODE_IEEE80211A)
2223*a1157835SDaniel Fojt return;
2224*a1157835SDaniel Fojt
2225*a1157835SDaniel Fojt for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
2226*a1157835SDaniel Fojt pri_chan = &mode->channels[chan_idx];
2227*a1157835SDaniel Fojt if (pri_chan->chan == channel)
2228*a1157835SDaniel Fojt break;
2229*a1157835SDaniel Fojt pri_chan = NULL;
2230*a1157835SDaniel Fojt }
2231*a1157835SDaniel Fojt if (!pri_chan)
2232*a1157835SDaniel Fojt return;
2233*a1157835SDaniel Fojt
2234*a1157835SDaniel Fojt /* Check primary channel flags */
2235*a1157835SDaniel Fojt if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
2236*a1157835SDaniel Fojt return;
2237*a1157835SDaniel Fojt
2238*a1157835SDaniel Fojt freq->channel = pri_chan->chan;
2239*a1157835SDaniel Fojt
2240*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
2241*a1157835SDaniel Fojt if (ssid->disable_ht40) {
2242*a1157835SDaniel Fojt if (ssid->disable_vht)
2243*a1157835SDaniel Fojt return;
2244*a1157835SDaniel Fojt goto skip_ht40;
2245*a1157835SDaniel Fojt }
2246*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
2247*a1157835SDaniel Fojt
2248*a1157835SDaniel Fojt /* Check/setup HT40+/HT40- */
2249*a1157835SDaniel Fojt for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
2250*a1157835SDaniel Fojt if (ht40plus[j] == channel) {
2251*a1157835SDaniel Fojt ht40 = 1;
2252*a1157835SDaniel Fojt break;
2253*a1157835SDaniel Fojt }
2254*a1157835SDaniel Fojt }
2255*a1157835SDaniel Fojt
2256*a1157835SDaniel Fojt /* Find secondary channel */
2257*a1157835SDaniel Fojt for (i = 0; i < mode->num_channels; i++) {
2258*a1157835SDaniel Fojt sec_chan = &mode->channels[i];
2259*a1157835SDaniel Fojt if (sec_chan->chan == channel + ht40 * 4)
2260*a1157835SDaniel Fojt break;
2261*a1157835SDaniel Fojt sec_chan = NULL;
2262*a1157835SDaniel Fojt }
2263*a1157835SDaniel Fojt if (!sec_chan)
2264*a1157835SDaniel Fojt return;
2265*a1157835SDaniel Fojt
2266*a1157835SDaniel Fojt /* Check secondary channel flags */
2267*a1157835SDaniel Fojt if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
2268*a1157835SDaniel Fojt return;
2269*a1157835SDaniel Fojt
2270*a1157835SDaniel Fojt if (ht40 == -1) {
2271*a1157835SDaniel Fojt if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
2272*a1157835SDaniel Fojt return;
2273*a1157835SDaniel Fojt } else {
2274*a1157835SDaniel Fojt if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
2275*a1157835SDaniel Fojt return;
2276*a1157835SDaniel Fojt }
2277*a1157835SDaniel Fojt freq->sec_channel_offset = ht40;
2278*a1157835SDaniel Fojt
2279*a1157835SDaniel Fojt if (obss_scan) {
2280*a1157835SDaniel Fojt struct wpa_scan_results *scan_res;
2281*a1157835SDaniel Fojt
2282*a1157835SDaniel Fojt scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
2283*a1157835SDaniel Fojt if (scan_res == NULL) {
2284*a1157835SDaniel Fojt /* Back to HT20 */
2285*a1157835SDaniel Fojt freq->sec_channel_offset = 0;
2286*a1157835SDaniel Fojt return;
2287*a1157835SDaniel Fojt }
2288*a1157835SDaniel Fojt
2289*a1157835SDaniel Fojt res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
2290*a1157835SDaniel Fojt sec_chan->chan);
2291*a1157835SDaniel Fojt switch (res) {
2292*a1157835SDaniel Fojt case 0:
2293*a1157835SDaniel Fojt /* Back to HT20 */
2294*a1157835SDaniel Fojt freq->sec_channel_offset = 0;
2295*a1157835SDaniel Fojt break;
2296*a1157835SDaniel Fojt case 1:
2297*a1157835SDaniel Fojt /* Configuration allowed */
2298*a1157835SDaniel Fojt break;
2299*a1157835SDaniel Fojt case 2:
2300*a1157835SDaniel Fojt /* Switch pri/sec channels */
2301*a1157835SDaniel Fojt freq->freq = hw_get_freq(mode, sec_chan->chan);
2302*a1157835SDaniel Fojt freq->sec_channel_offset = -freq->sec_channel_offset;
2303*a1157835SDaniel Fojt freq->channel = sec_chan->chan;
2304*a1157835SDaniel Fojt break;
2305*a1157835SDaniel Fojt default:
2306*a1157835SDaniel Fojt freq->sec_channel_offset = 0;
2307*a1157835SDaniel Fojt break;
2308*a1157835SDaniel Fojt }
2309*a1157835SDaniel Fojt
2310*a1157835SDaniel Fojt wpa_scan_results_free(scan_res);
2311*a1157835SDaniel Fojt }
2312*a1157835SDaniel Fojt
2313*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
2314*a1157835SDaniel Fojt skip_ht40:
2315*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
2316*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
2317*a1157835SDaniel Fojt "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
2318*a1157835SDaniel Fojt freq->channel, freq->sec_channel_offset);
2319*a1157835SDaniel Fojt
2320*a1157835SDaniel Fojt if (!drv_supports_vht(wpa_s, ssid))
2321*a1157835SDaniel Fojt return;
2322*a1157835SDaniel Fojt
2323*a1157835SDaniel Fojt /* For IBSS check VHT_IBSS flag */
2324*a1157835SDaniel Fojt if (ssid->mode == WPAS_MODE_IBSS &&
2325*a1157835SDaniel Fojt !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
2326*a1157835SDaniel Fojt return;
2327*a1157835SDaniel Fojt
2328*a1157835SDaniel Fojt vht_freq = *freq;
2329*a1157835SDaniel Fojt
2330*a1157835SDaniel Fojt #ifdef CONFIG_VHT_OVERRIDES
2331*a1157835SDaniel Fojt if (ssid->disable_vht) {
2332*a1157835SDaniel Fojt freq->vht_enabled = 0;
2333*a1157835SDaniel Fojt return;
2334*a1157835SDaniel Fojt }
2335*a1157835SDaniel Fojt #endif /* CONFIG_VHT_OVERRIDES */
2336*a1157835SDaniel Fojt
2337*a1157835SDaniel Fojt vht_freq.vht_enabled = vht_supported(mode);
2338*a1157835SDaniel Fojt if (!vht_freq.vht_enabled)
2339*a1157835SDaniel Fojt return;
2340*a1157835SDaniel Fojt
2341*a1157835SDaniel Fojt /* setup center_freq1, bandwidth */
2342*a1157835SDaniel Fojt for (j = 0; j < ARRAY_SIZE(vht80); j++) {
2343*a1157835SDaniel Fojt if (freq->channel >= vht80[j] &&
2344*a1157835SDaniel Fojt freq->channel < vht80[j] + 16)
2345*a1157835SDaniel Fojt break;
2346*a1157835SDaniel Fojt }
2347*a1157835SDaniel Fojt
2348*a1157835SDaniel Fojt if (j == ARRAY_SIZE(vht80))
2349*a1157835SDaniel Fojt return;
2350*a1157835SDaniel Fojt
2351*a1157835SDaniel Fojt for (i = vht80[j]; i < vht80[j] + 16; i += 4) {
2352*a1157835SDaniel Fojt struct hostapd_channel_data *chan;
2353*a1157835SDaniel Fojt
2354*a1157835SDaniel Fojt chan = hw_get_channel_chan(mode, i, NULL);
2355*a1157835SDaniel Fojt if (!chan)
2356*a1157835SDaniel Fojt return;
2357*a1157835SDaniel Fojt
2358*a1157835SDaniel Fojt /* Back to HT configuration if channel not usable */
2359*a1157835SDaniel Fojt if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
2360*a1157835SDaniel Fojt return;
2361*a1157835SDaniel Fojt }
2362*a1157835SDaniel Fojt
2363*a1157835SDaniel Fojt chwidth = CHANWIDTH_80MHZ;
2364*a1157835SDaniel Fojt seg0 = vht80[j] + 6;
2365*a1157835SDaniel Fojt seg1 = 0;
2366*a1157835SDaniel Fojt
2367*a1157835SDaniel Fojt if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
2368*a1157835SDaniel Fojt /* setup center_freq2, bandwidth */
2369*a1157835SDaniel Fojt for (k = 0; k < ARRAY_SIZE(vht80); k++) {
2370*a1157835SDaniel Fojt /* Only accept 80 MHz segments separated by a gap */
2371*a1157835SDaniel Fojt if (j == k || abs(vht80[j] - vht80[k]) == 16)
2372*a1157835SDaniel Fojt continue;
2373*a1157835SDaniel Fojt for (i = vht80[k]; i < vht80[k] + 16; i += 4) {
2374*a1157835SDaniel Fojt struct hostapd_channel_data *chan;
2375*a1157835SDaniel Fojt
2376*a1157835SDaniel Fojt chan = hw_get_channel_chan(mode, i, NULL);
2377*a1157835SDaniel Fojt if (!chan)
2378*a1157835SDaniel Fojt continue;
2379*a1157835SDaniel Fojt
2380*a1157835SDaniel Fojt if (chan->flag & (HOSTAPD_CHAN_DISABLED |
2381*a1157835SDaniel Fojt HOSTAPD_CHAN_NO_IR |
2382*a1157835SDaniel Fojt HOSTAPD_CHAN_RADAR))
2383*a1157835SDaniel Fojt continue;
2384*a1157835SDaniel Fojt
2385*a1157835SDaniel Fojt /* Found a suitable second segment for 80+80 */
2386*a1157835SDaniel Fojt chwidth = CHANWIDTH_80P80MHZ;
2387*a1157835SDaniel Fojt vht_caps |=
2388*a1157835SDaniel Fojt VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
2389*a1157835SDaniel Fojt seg1 = vht80[k] + 6;
2390*a1157835SDaniel Fojt }
2391*a1157835SDaniel Fojt
2392*a1157835SDaniel Fojt if (chwidth == CHANWIDTH_80P80MHZ)
2393*a1157835SDaniel Fojt break;
2394*a1157835SDaniel Fojt }
2395*a1157835SDaniel Fojt } else if (ssid->max_oper_chwidth == CHANWIDTH_160MHZ) {
2396*a1157835SDaniel Fojt if (freq->freq == 5180) {
2397*a1157835SDaniel Fojt chwidth = CHANWIDTH_160MHZ;
2398*a1157835SDaniel Fojt vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
2399*a1157835SDaniel Fojt seg0 = 50;
2400*a1157835SDaniel Fojt } else if (freq->freq == 5520) {
2401*a1157835SDaniel Fojt chwidth = CHANWIDTH_160MHZ;
2402*a1157835SDaniel Fojt vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
2403*a1157835SDaniel Fojt seg0 = 114;
2404*a1157835SDaniel Fojt }
2405*a1157835SDaniel Fojt } else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
2406*a1157835SDaniel Fojt chwidth = CHANWIDTH_USE_HT;
2407*a1157835SDaniel Fojt seg0 = vht80[j] + 2;
2408*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
2409*a1157835SDaniel Fojt if (ssid->disable_ht40)
2410*a1157835SDaniel Fojt seg0 = 0;
2411*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
2412*a1157835SDaniel Fojt }
2413*a1157835SDaniel Fojt
2414*a1157835SDaniel Fojt if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
2415*a1157835SDaniel Fojt freq->channel, freq->ht_enabled,
2416*a1157835SDaniel Fojt vht_freq.vht_enabled, freq->he_enabled,
2417*a1157835SDaniel Fojt freq->sec_channel_offset,
2418*a1157835SDaniel Fojt chwidth, seg0, seg1, vht_caps,
2419*a1157835SDaniel Fojt &mode->he_capab[ieee80211_mode]) != 0)
2420*a1157835SDaniel Fojt return;
2421*a1157835SDaniel Fojt
2422*a1157835SDaniel Fojt *freq = vht_freq;
2423*a1157835SDaniel Fojt
2424*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d",
2425*a1157835SDaniel Fojt freq->center_freq1, freq->center_freq2, freq->bandwidth);
2426*a1157835SDaniel Fojt }
2427*a1157835SDaniel Fojt
2428*a1157835SDaniel Fojt
2429*a1157835SDaniel Fojt #ifdef CONFIG_FILS
wpas_add_fils_hlp_req(struct wpa_supplicant * wpa_s,u8 * ie_buf,size_t ie_buf_len)2430*a1157835SDaniel Fojt static size_t wpas_add_fils_hlp_req(struct wpa_supplicant *wpa_s, u8 *ie_buf,
2431*a1157835SDaniel Fojt size_t ie_buf_len)
2432*a1157835SDaniel Fojt {
2433*a1157835SDaniel Fojt struct fils_hlp_req *req;
2434*a1157835SDaniel Fojt size_t rem_len, hdr_len, hlp_len, len, ie_len = 0;
2435*a1157835SDaniel Fojt const u8 *pos;
2436*a1157835SDaniel Fojt u8 *buf = ie_buf;
2437*a1157835SDaniel Fojt
2438*a1157835SDaniel Fojt dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
2439*a1157835SDaniel Fojt list) {
2440*a1157835SDaniel Fojt rem_len = ie_buf_len - ie_len;
2441*a1157835SDaniel Fojt pos = wpabuf_head(req->pkt);
2442*a1157835SDaniel Fojt hdr_len = 1 + 2 * ETH_ALEN + 6;
2443*a1157835SDaniel Fojt hlp_len = wpabuf_len(req->pkt);
2444*a1157835SDaniel Fojt
2445*a1157835SDaniel Fojt if (rem_len < 2 + hdr_len + hlp_len) {
2446*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
2447*a1157835SDaniel Fojt "FILS: Cannot fit HLP - rem_len=%lu to_fill=%lu",
2448*a1157835SDaniel Fojt (unsigned long) rem_len,
2449*a1157835SDaniel Fojt (unsigned long) (2 + hdr_len + hlp_len));
2450*a1157835SDaniel Fojt break;
2451*a1157835SDaniel Fojt }
2452*a1157835SDaniel Fojt
2453*a1157835SDaniel Fojt len = (hdr_len + hlp_len) > 255 ? 255 : hdr_len + hlp_len;
2454*a1157835SDaniel Fojt /* Element ID */
2455*a1157835SDaniel Fojt *buf++ = WLAN_EID_EXTENSION;
2456*a1157835SDaniel Fojt /* Length */
2457*a1157835SDaniel Fojt *buf++ = len;
2458*a1157835SDaniel Fojt /* Element ID Extension */
2459*a1157835SDaniel Fojt *buf++ = WLAN_EID_EXT_FILS_HLP_CONTAINER;
2460*a1157835SDaniel Fojt /* Destination MAC address */
2461*a1157835SDaniel Fojt os_memcpy(buf, req->dst, ETH_ALEN);
2462*a1157835SDaniel Fojt buf += ETH_ALEN;
2463*a1157835SDaniel Fojt /* Source MAC address */
2464*a1157835SDaniel Fojt os_memcpy(buf, wpa_s->own_addr, ETH_ALEN);
2465*a1157835SDaniel Fojt buf += ETH_ALEN;
2466*a1157835SDaniel Fojt /* LLC/SNAP Header */
2467*a1157835SDaniel Fojt os_memcpy(buf, "\xaa\xaa\x03\x00\x00\x00", 6);
2468*a1157835SDaniel Fojt buf += 6;
2469*a1157835SDaniel Fojt /* HLP Packet */
2470*a1157835SDaniel Fojt os_memcpy(buf, pos, len - hdr_len);
2471*a1157835SDaniel Fojt buf += len - hdr_len;
2472*a1157835SDaniel Fojt pos += len - hdr_len;
2473*a1157835SDaniel Fojt
2474*a1157835SDaniel Fojt hlp_len -= len - hdr_len;
2475*a1157835SDaniel Fojt ie_len += 2 + len;
2476*a1157835SDaniel Fojt rem_len -= 2 + len;
2477*a1157835SDaniel Fojt
2478*a1157835SDaniel Fojt while (hlp_len) {
2479*a1157835SDaniel Fojt len = (hlp_len > 255) ? 255 : hlp_len;
2480*a1157835SDaniel Fojt if (rem_len < 2 + len)
2481*a1157835SDaniel Fojt break;
2482*a1157835SDaniel Fojt *buf++ = WLAN_EID_FRAGMENT;
2483*a1157835SDaniel Fojt *buf++ = len;
2484*a1157835SDaniel Fojt os_memcpy(buf, pos, len);
2485*a1157835SDaniel Fojt buf += len;
2486*a1157835SDaniel Fojt pos += len;
2487*a1157835SDaniel Fojt
2488*a1157835SDaniel Fojt hlp_len -= len;
2489*a1157835SDaniel Fojt ie_len += 2 + len;
2490*a1157835SDaniel Fojt rem_len -= 2 + len;
2491*a1157835SDaniel Fojt }
2492*a1157835SDaniel Fojt }
2493*a1157835SDaniel Fojt
2494*a1157835SDaniel Fojt return ie_len;
2495*a1157835SDaniel Fojt }
2496*a1157835SDaniel Fojt
2497*a1157835SDaniel Fojt
wpa_is_fils_supported(struct wpa_supplicant * wpa_s)2498*a1157835SDaniel Fojt int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
2499*a1157835SDaniel Fojt {
2500*a1157835SDaniel Fojt return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
2501*a1157835SDaniel Fojt (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
2502*a1157835SDaniel Fojt (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
2503*a1157835SDaniel Fojt (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
2504*a1157835SDaniel Fojt }
2505*a1157835SDaniel Fojt
2506*a1157835SDaniel Fojt
wpa_is_fils_sk_pfs_supported(struct wpa_supplicant * wpa_s)2507*a1157835SDaniel Fojt int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
2508*a1157835SDaniel Fojt {
2509*a1157835SDaniel Fojt #ifdef CONFIG_FILS_SK_PFS
2510*a1157835SDaniel Fojt return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
2511*a1157835SDaniel Fojt (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
2512*a1157835SDaniel Fojt #else /* CONFIG_FILS_SK_PFS */
2513*a1157835SDaniel Fojt return 0;
2514*a1157835SDaniel Fojt #endif /* CONFIG_FILS_SK_PFS */
2515*a1157835SDaniel Fojt }
2516*a1157835SDaniel Fojt
2517*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2518*a1157835SDaniel Fojt
2519*a1157835SDaniel Fojt
wpas_populate_assoc_ies(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,struct wpa_ssid * ssid,struct wpa_driver_associate_params * params,enum wpa_drv_update_connect_params_mask * mask)2520*a1157835SDaniel Fojt static u8 * wpas_populate_assoc_ies(
2521*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s,
2522*a1157835SDaniel Fojt struct wpa_bss *bss, struct wpa_ssid *ssid,
2523*a1157835SDaniel Fojt struct wpa_driver_associate_params *params,
2524*a1157835SDaniel Fojt enum wpa_drv_update_connect_params_mask *mask)
2525*a1157835SDaniel Fojt {
2526*a1157835SDaniel Fojt u8 *wpa_ie;
2527*a1157835SDaniel Fojt size_t max_wpa_ie_len = 500;
2528*a1157835SDaniel Fojt size_t wpa_ie_len;
2529*a1157835SDaniel Fojt int algs = WPA_AUTH_ALG_OPEN;
2530*a1157835SDaniel Fojt #ifdef CONFIG_MBO
2531*a1157835SDaniel Fojt const u8 *mbo_ie;
2532*a1157835SDaniel Fojt #endif
2533*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2534*a1157835SDaniel Fojt int sae_pmksa_cached = 0;
2535*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2536*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2537*a1157835SDaniel Fojt const u8 *realm, *username, *rrk;
2538*a1157835SDaniel Fojt size_t realm_len, username_len, rrk_len;
2539*a1157835SDaniel Fojt u16 next_seq_num;
2540*a1157835SDaniel Fojt struct fils_hlp_req *req;
2541*a1157835SDaniel Fojt
2542*a1157835SDaniel Fojt dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
2543*a1157835SDaniel Fojt list) {
2544*a1157835SDaniel Fojt max_wpa_ie_len += 3 + 2 * ETH_ALEN + 6 + wpabuf_len(req->pkt) +
2545*a1157835SDaniel Fojt 2 + 2 * wpabuf_len(req->pkt) / 255;
2546*a1157835SDaniel Fojt }
2547*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2548*a1157835SDaniel Fojt
2549*a1157835SDaniel Fojt wpa_ie = os_malloc(max_wpa_ie_len);
2550*a1157835SDaniel Fojt if (!wpa_ie) {
2551*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
2552*a1157835SDaniel Fojt "Failed to allocate connect IE buffer for %lu bytes",
2553*a1157835SDaniel Fojt (unsigned long) max_wpa_ie_len);
2554*a1157835SDaniel Fojt return NULL;
2555*a1157835SDaniel Fojt }
2556*a1157835SDaniel Fojt
2557*a1157835SDaniel Fojt if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
2558*a1157835SDaniel Fojt wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
2559*a1157835SDaniel Fojt wpa_key_mgmt_wpa(ssid->key_mgmt)) {
2560*a1157835SDaniel Fojt int try_opportunistic;
2561*a1157835SDaniel Fojt const u8 *cache_id = NULL;
2562*a1157835SDaniel Fojt
2563*a1157835SDaniel Fojt try_opportunistic = (ssid->proactive_key_caching < 0 ?
2564*a1157835SDaniel Fojt wpa_s->conf->okc :
2565*a1157835SDaniel Fojt ssid->proactive_key_caching) &&
2566*a1157835SDaniel Fojt (ssid->proto & WPA_PROTO_RSN);
2567*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2568*a1157835SDaniel Fojt if (wpa_key_mgmt_fils(ssid->key_mgmt))
2569*a1157835SDaniel Fojt cache_id = wpa_bss_get_fils_cache_id(bss);
2570*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2571*a1157835SDaniel Fojt if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
2572*a1157835SDaniel Fojt ssid, try_opportunistic,
2573*a1157835SDaniel Fojt cache_id, 0) == 0) {
2574*a1157835SDaniel Fojt eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
2575*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2576*a1157835SDaniel Fojt sae_pmksa_cached = 1;
2577*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2578*a1157835SDaniel Fojt }
2579*a1157835SDaniel Fojt wpa_ie_len = max_wpa_ie_len;
2580*a1157835SDaniel Fojt if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
2581*a1157835SDaniel Fojt wpa_ie, &wpa_ie_len)) {
2582*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
2583*a1157835SDaniel Fojt "key management and encryption suites");
2584*a1157835SDaniel Fojt os_free(wpa_ie);
2585*a1157835SDaniel Fojt return NULL;
2586*a1157835SDaniel Fojt }
2587*a1157835SDaniel Fojt #ifdef CONFIG_HS20
2588*a1157835SDaniel Fojt } else if (bss && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
2589*a1157835SDaniel Fojt (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
2590*a1157835SDaniel Fojt /* No PMKSA caching, but otherwise similar to RSN/WPA */
2591*a1157835SDaniel Fojt wpa_ie_len = max_wpa_ie_len;
2592*a1157835SDaniel Fojt if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
2593*a1157835SDaniel Fojt wpa_ie, &wpa_ie_len)) {
2594*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
2595*a1157835SDaniel Fojt "key management and encryption suites");
2596*a1157835SDaniel Fojt os_free(wpa_ie);
2597*a1157835SDaniel Fojt return NULL;
2598*a1157835SDaniel Fojt }
2599*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
2600*a1157835SDaniel Fojt } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
2601*a1157835SDaniel Fojt wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
2602*a1157835SDaniel Fojt /*
2603*a1157835SDaniel Fojt * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
2604*a1157835SDaniel Fojt * use non-WPA since the scan results did not indicate that the
2605*a1157835SDaniel Fojt * AP is using WPA or WPA2.
2606*a1157835SDaniel Fojt */
2607*a1157835SDaniel Fojt wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
2608*a1157835SDaniel Fojt wpa_ie_len = 0;
2609*a1157835SDaniel Fojt wpa_s->wpa_proto = 0;
2610*a1157835SDaniel Fojt } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
2611*a1157835SDaniel Fojt wpa_ie_len = max_wpa_ie_len;
2612*a1157835SDaniel Fojt if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
2613*a1157835SDaniel Fojt wpa_ie, &wpa_ie_len)) {
2614*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
2615*a1157835SDaniel Fojt "key management and encryption suites (no "
2616*a1157835SDaniel Fojt "scan results)");
2617*a1157835SDaniel Fojt os_free(wpa_ie);
2618*a1157835SDaniel Fojt return NULL;
2619*a1157835SDaniel Fojt }
2620*a1157835SDaniel Fojt #ifdef CONFIG_WPS
2621*a1157835SDaniel Fojt } else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
2622*a1157835SDaniel Fojt struct wpabuf *wps_ie;
2623*a1157835SDaniel Fojt wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
2624*a1157835SDaniel Fojt if (wps_ie && wpabuf_len(wps_ie) <= max_wpa_ie_len) {
2625*a1157835SDaniel Fojt wpa_ie_len = wpabuf_len(wps_ie);
2626*a1157835SDaniel Fojt os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
2627*a1157835SDaniel Fojt } else
2628*a1157835SDaniel Fojt wpa_ie_len = 0;
2629*a1157835SDaniel Fojt wpabuf_free(wps_ie);
2630*a1157835SDaniel Fojt wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
2631*a1157835SDaniel Fojt if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
2632*a1157835SDaniel Fojt params->wps = WPS_MODE_PRIVACY;
2633*a1157835SDaniel Fojt else
2634*a1157835SDaniel Fojt params->wps = WPS_MODE_OPEN;
2635*a1157835SDaniel Fojt wpa_s->wpa_proto = 0;
2636*a1157835SDaniel Fojt #endif /* CONFIG_WPS */
2637*a1157835SDaniel Fojt } else {
2638*a1157835SDaniel Fojt wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
2639*a1157835SDaniel Fojt wpa_ie_len = 0;
2640*a1157835SDaniel Fojt wpa_s->wpa_proto = 0;
2641*a1157835SDaniel Fojt }
2642*a1157835SDaniel Fojt
2643*a1157835SDaniel Fojt #ifdef IEEE8021X_EAPOL
2644*a1157835SDaniel Fojt if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
2645*a1157835SDaniel Fojt if (ssid->leap) {
2646*a1157835SDaniel Fojt if (ssid->non_leap == 0)
2647*a1157835SDaniel Fojt algs = WPA_AUTH_ALG_LEAP;
2648*a1157835SDaniel Fojt else
2649*a1157835SDaniel Fojt algs |= WPA_AUTH_ALG_LEAP;
2650*a1157835SDaniel Fojt }
2651*a1157835SDaniel Fojt }
2652*a1157835SDaniel Fojt
2653*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2654*a1157835SDaniel Fojt /* Clear FILS association */
2655*a1157835SDaniel Fojt wpa_sm_set_reset_fils_completed(wpa_s->wpa, 0);
2656*a1157835SDaniel Fojt
2657*a1157835SDaniel Fojt if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
2658*a1157835SDaniel Fojt ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
2659*a1157835SDaniel Fojt eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
2660*a1157835SDaniel Fojt &username_len, &realm, &realm_len,
2661*a1157835SDaniel Fojt &next_seq_num, &rrk, &rrk_len) == 0 &&
2662*a1157835SDaniel Fojt (!wpa_s->last_con_fail_realm ||
2663*a1157835SDaniel Fojt wpa_s->last_con_fail_realm_len != realm_len ||
2664*a1157835SDaniel Fojt os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) {
2665*a1157835SDaniel Fojt algs = WPA_AUTH_ALG_FILS;
2666*a1157835SDaniel Fojt params->fils_erp_username = username;
2667*a1157835SDaniel Fojt params->fils_erp_username_len = username_len;
2668*a1157835SDaniel Fojt params->fils_erp_realm = realm;
2669*a1157835SDaniel Fojt params->fils_erp_realm_len = realm_len;
2670*a1157835SDaniel Fojt params->fils_erp_next_seq_num = next_seq_num;
2671*a1157835SDaniel Fojt params->fils_erp_rrk = rrk;
2672*a1157835SDaniel Fojt params->fils_erp_rrk_len = rrk_len;
2673*a1157835SDaniel Fojt
2674*a1157835SDaniel Fojt if (mask)
2675*a1157835SDaniel Fojt *mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
2676*a1157835SDaniel Fojt }
2677*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2678*a1157835SDaniel Fojt #endif /* IEEE8021X_EAPOL */
2679*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2680*a1157835SDaniel Fojt if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
2681*a1157835SDaniel Fojt algs = WPA_AUTH_ALG_SAE;
2682*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2683*a1157835SDaniel Fojt
2684*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
2685*a1157835SDaniel Fojt if (ssid->auth_alg) {
2686*a1157835SDaniel Fojt algs = ssid->auth_alg;
2687*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
2688*a1157835SDaniel Fojt "Overriding auth_alg selection: 0x%x", algs);
2689*a1157835SDaniel Fojt }
2690*a1157835SDaniel Fojt
2691*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2692*a1157835SDaniel Fojt if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
2693*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
2694*a1157835SDaniel Fojt "SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
2695*a1157835SDaniel Fojt algs = WPA_AUTH_ALG_OPEN;
2696*a1157835SDaniel Fojt }
2697*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2698*a1157835SDaniel Fojt
2699*a1157835SDaniel Fojt #ifdef CONFIG_P2P
2700*a1157835SDaniel Fojt if (wpa_s->global->p2p) {
2701*a1157835SDaniel Fojt u8 *pos;
2702*a1157835SDaniel Fojt size_t len;
2703*a1157835SDaniel Fojt int res;
2704*a1157835SDaniel Fojt pos = wpa_ie + wpa_ie_len;
2705*a1157835SDaniel Fojt len = max_wpa_ie_len - wpa_ie_len;
2706*a1157835SDaniel Fojt res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
2707*a1157835SDaniel Fojt ssid->p2p_group);
2708*a1157835SDaniel Fojt if (res >= 0)
2709*a1157835SDaniel Fojt wpa_ie_len += res;
2710*a1157835SDaniel Fojt }
2711*a1157835SDaniel Fojt
2712*a1157835SDaniel Fojt wpa_s->cross_connect_disallowed = 0;
2713*a1157835SDaniel Fojt if (bss) {
2714*a1157835SDaniel Fojt struct wpabuf *p2p;
2715*a1157835SDaniel Fojt p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
2716*a1157835SDaniel Fojt if (p2p) {
2717*a1157835SDaniel Fojt wpa_s->cross_connect_disallowed =
2718*a1157835SDaniel Fojt p2p_get_cross_connect_disallowed(p2p);
2719*a1157835SDaniel Fojt wpabuf_free(p2p);
2720*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross "
2721*a1157835SDaniel Fojt "connection",
2722*a1157835SDaniel Fojt wpa_s->cross_connect_disallowed ?
2723*a1157835SDaniel Fojt "disallows" : "allows");
2724*a1157835SDaniel Fojt }
2725*a1157835SDaniel Fojt }
2726*a1157835SDaniel Fojt
2727*a1157835SDaniel Fojt os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
2728*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
2729*a1157835SDaniel Fojt
2730*a1157835SDaniel Fojt if (bss) {
2731*a1157835SDaniel Fojt wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
2732*a1157835SDaniel Fojt wpa_ie + wpa_ie_len,
2733*a1157835SDaniel Fojt max_wpa_ie_len -
2734*a1157835SDaniel Fojt wpa_ie_len);
2735*a1157835SDaniel Fojt }
2736*a1157835SDaniel Fojt
2737*a1157835SDaniel Fojt /*
2738*a1157835SDaniel Fojt * Workaround: Add Extended Capabilities element only if the AP
2739*a1157835SDaniel Fojt * included this element in Beacon/Probe Response frames. Some older
2740*a1157835SDaniel Fojt * APs seem to have interoperability issues if this element is
2741*a1157835SDaniel Fojt * included, so while the standard may require us to include the
2742*a1157835SDaniel Fojt * element in all cases, it is justifiable to skip it to avoid
2743*a1157835SDaniel Fojt * interoperability issues.
2744*a1157835SDaniel Fojt */
2745*a1157835SDaniel Fojt if (ssid->p2p_group)
2746*a1157835SDaniel Fojt wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
2747*a1157835SDaniel Fojt else
2748*a1157835SDaniel Fojt wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
2749*a1157835SDaniel Fojt
2750*a1157835SDaniel Fojt if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
2751*a1157835SDaniel Fojt u8 ext_capab[18];
2752*a1157835SDaniel Fojt int ext_capab_len;
2753*a1157835SDaniel Fojt ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
2754*a1157835SDaniel Fojt sizeof(ext_capab));
2755*a1157835SDaniel Fojt if (ext_capab_len > 0 &&
2756*a1157835SDaniel Fojt wpa_ie_len + ext_capab_len <= max_wpa_ie_len) {
2757*a1157835SDaniel Fojt u8 *pos = wpa_ie;
2758*a1157835SDaniel Fojt if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
2759*a1157835SDaniel Fojt pos += 2 + pos[1];
2760*a1157835SDaniel Fojt os_memmove(pos + ext_capab_len, pos,
2761*a1157835SDaniel Fojt wpa_ie_len - (pos - wpa_ie));
2762*a1157835SDaniel Fojt wpa_ie_len += ext_capab_len;
2763*a1157835SDaniel Fojt os_memcpy(pos, ext_capab, ext_capab_len);
2764*a1157835SDaniel Fojt }
2765*a1157835SDaniel Fojt }
2766*a1157835SDaniel Fojt
2767*a1157835SDaniel Fojt #ifdef CONFIG_HS20
2768*a1157835SDaniel Fojt if (is_hs20_network(wpa_s, ssid, bss)) {
2769*a1157835SDaniel Fojt struct wpabuf *hs20;
2770*a1157835SDaniel Fojt
2771*a1157835SDaniel Fojt hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
2772*a1157835SDaniel Fojt if (hs20) {
2773*a1157835SDaniel Fojt int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
2774*a1157835SDaniel Fojt size_t len;
2775*a1157835SDaniel Fojt
2776*a1157835SDaniel Fojt wpas_hs20_add_indication(hs20, pps_mo_id,
2777*a1157835SDaniel Fojt get_hs20_version(bss));
2778*a1157835SDaniel Fojt wpas_hs20_add_roam_cons_sel(hs20, ssid);
2779*a1157835SDaniel Fojt len = max_wpa_ie_len - wpa_ie_len;
2780*a1157835SDaniel Fojt if (wpabuf_len(hs20) <= len) {
2781*a1157835SDaniel Fojt os_memcpy(wpa_ie + wpa_ie_len,
2782*a1157835SDaniel Fojt wpabuf_head(hs20), wpabuf_len(hs20));
2783*a1157835SDaniel Fojt wpa_ie_len += wpabuf_len(hs20);
2784*a1157835SDaniel Fojt }
2785*a1157835SDaniel Fojt wpabuf_free(hs20);
2786*a1157835SDaniel Fojt
2787*a1157835SDaniel Fojt hs20_configure_frame_filters(wpa_s);
2788*a1157835SDaniel Fojt }
2789*a1157835SDaniel Fojt }
2790*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
2791*a1157835SDaniel Fojt
2792*a1157835SDaniel Fojt if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
2793*a1157835SDaniel Fojt struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
2794*a1157835SDaniel Fojt size_t len;
2795*a1157835SDaniel Fojt
2796*a1157835SDaniel Fojt len = max_wpa_ie_len - wpa_ie_len;
2797*a1157835SDaniel Fojt if (wpabuf_len(buf) <= len) {
2798*a1157835SDaniel Fojt os_memcpy(wpa_ie + wpa_ie_len,
2799*a1157835SDaniel Fojt wpabuf_head(buf), wpabuf_len(buf));
2800*a1157835SDaniel Fojt wpa_ie_len += wpabuf_len(buf);
2801*a1157835SDaniel Fojt }
2802*a1157835SDaniel Fojt }
2803*a1157835SDaniel Fojt
2804*a1157835SDaniel Fojt #ifdef CONFIG_FST
2805*a1157835SDaniel Fojt if (wpa_s->fst_ies) {
2806*a1157835SDaniel Fojt int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
2807*a1157835SDaniel Fojt
2808*a1157835SDaniel Fojt if (wpa_ie_len + fst_ies_len <= max_wpa_ie_len) {
2809*a1157835SDaniel Fojt os_memcpy(wpa_ie + wpa_ie_len,
2810*a1157835SDaniel Fojt wpabuf_head(wpa_s->fst_ies), fst_ies_len);
2811*a1157835SDaniel Fojt wpa_ie_len += fst_ies_len;
2812*a1157835SDaniel Fojt }
2813*a1157835SDaniel Fojt }
2814*a1157835SDaniel Fojt #endif /* CONFIG_FST */
2815*a1157835SDaniel Fojt
2816*a1157835SDaniel Fojt #ifdef CONFIG_MBO
2817*a1157835SDaniel Fojt mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
2818*a1157835SDaniel Fojt if (mbo_ie) {
2819*a1157835SDaniel Fojt int len;
2820*a1157835SDaniel Fojt
2821*a1157835SDaniel Fojt len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
2822*a1157835SDaniel Fojt max_wpa_ie_len - wpa_ie_len,
2823*a1157835SDaniel Fojt !!mbo_attr_from_mbo_ie(mbo_ie,
2824*a1157835SDaniel Fojt OCE_ATTR_ID_CAPA_IND));
2825*a1157835SDaniel Fojt if (len >= 0)
2826*a1157835SDaniel Fojt wpa_ie_len += len;
2827*a1157835SDaniel Fojt }
2828*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
2829*a1157835SDaniel Fojt
2830*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2831*a1157835SDaniel Fojt if (algs == WPA_AUTH_ALG_FILS) {
2832*a1157835SDaniel Fojt size_t len;
2833*a1157835SDaniel Fojt
2834*a1157835SDaniel Fojt len = wpas_add_fils_hlp_req(wpa_s, wpa_ie + wpa_ie_len,
2835*a1157835SDaniel Fojt max_wpa_ie_len - wpa_ie_len);
2836*a1157835SDaniel Fojt wpa_ie_len += len;
2837*a1157835SDaniel Fojt }
2838*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2839*a1157835SDaniel Fojt
2840*a1157835SDaniel Fojt #ifdef CONFIG_OWE
2841*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
2842*a1157835SDaniel Fojt if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) {
2843*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
2844*a1157835SDaniel Fojt } else
2845*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
2846*a1157835SDaniel Fojt if (algs == WPA_AUTH_ALG_OPEN &&
2847*a1157835SDaniel Fojt ssid->key_mgmt == WPA_KEY_MGMT_OWE) {
2848*a1157835SDaniel Fojt struct wpabuf *owe_ie;
2849*a1157835SDaniel Fojt u16 group;
2850*a1157835SDaniel Fojt
2851*a1157835SDaniel Fojt if (ssid->owe_group) {
2852*a1157835SDaniel Fojt group = ssid->owe_group;
2853*a1157835SDaniel Fojt } else if (wpa_s->assoc_status_code ==
2854*a1157835SDaniel Fojt WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
2855*a1157835SDaniel Fojt if (wpa_s->last_owe_group == 19)
2856*a1157835SDaniel Fojt group = 20;
2857*a1157835SDaniel Fojt else if (wpa_s->last_owe_group == 20)
2858*a1157835SDaniel Fojt group = 21;
2859*a1157835SDaniel Fojt else
2860*a1157835SDaniel Fojt group = OWE_DH_GROUP;
2861*a1157835SDaniel Fojt } else {
2862*a1157835SDaniel Fojt group = OWE_DH_GROUP;
2863*a1157835SDaniel Fojt }
2864*a1157835SDaniel Fojt
2865*a1157835SDaniel Fojt wpa_s->last_owe_group = group;
2866*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
2867*a1157835SDaniel Fojt owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
2868*a1157835SDaniel Fojt if (owe_ie &&
2869*a1157835SDaniel Fojt wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) {
2870*a1157835SDaniel Fojt os_memcpy(wpa_ie + wpa_ie_len,
2871*a1157835SDaniel Fojt wpabuf_head(owe_ie), wpabuf_len(owe_ie));
2872*a1157835SDaniel Fojt wpa_ie_len += wpabuf_len(owe_ie);
2873*a1157835SDaniel Fojt }
2874*a1157835SDaniel Fojt wpabuf_free(owe_ie);
2875*a1157835SDaniel Fojt }
2876*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
2877*a1157835SDaniel Fojt
2878*a1157835SDaniel Fojt #ifdef CONFIG_DPP2
2879*a1157835SDaniel Fojt if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
2880*a1157835SDaniel Fojt ssid->dpp_netaccesskey) {
2881*a1157835SDaniel Fojt dpp_pfs_free(wpa_s->dpp_pfs);
2882*a1157835SDaniel Fojt wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
2883*a1157835SDaniel Fojt ssid->dpp_netaccesskey_len);
2884*a1157835SDaniel Fojt if (!wpa_s->dpp_pfs) {
2885*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
2886*a1157835SDaniel Fojt /* Try to continue without PFS */
2887*a1157835SDaniel Fojt goto pfs_fail;
2888*a1157835SDaniel Fojt }
2889*a1157835SDaniel Fojt if (wpabuf_len(wpa_s->dpp_pfs->ie) <=
2890*a1157835SDaniel Fojt max_wpa_ie_len - wpa_ie_len) {
2891*a1157835SDaniel Fojt os_memcpy(wpa_ie + wpa_ie_len,
2892*a1157835SDaniel Fojt wpabuf_head(wpa_s->dpp_pfs->ie),
2893*a1157835SDaniel Fojt wpabuf_len(wpa_s->dpp_pfs->ie));
2894*a1157835SDaniel Fojt wpa_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
2895*a1157835SDaniel Fojt }
2896*a1157835SDaniel Fojt }
2897*a1157835SDaniel Fojt pfs_fail:
2898*a1157835SDaniel Fojt #endif /* CONFIG_DPP2 */
2899*a1157835SDaniel Fojt
2900*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R
2901*a1157835SDaniel Fojt /*
2902*a1157835SDaniel Fojt * Add MDIE under these conditions: the network profile allows FT,
2903*a1157835SDaniel Fojt * the AP supports FT, and the mobility domain ID matches.
2904*a1157835SDaniel Fojt */
2905*a1157835SDaniel Fojt if (bss && wpa_key_mgmt_ft(wpa_sm_get_key_mgmt(wpa_s->wpa))) {
2906*a1157835SDaniel Fojt const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
2907*a1157835SDaniel Fojt
2908*a1157835SDaniel Fojt if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
2909*a1157835SDaniel Fojt size_t len = 0;
2910*a1157835SDaniel Fojt const u8 *md = mdie + 2;
2911*a1157835SDaniel Fojt const u8 *wpa_md = wpa_sm_get_ft_md(wpa_s->wpa);
2912*a1157835SDaniel Fojt
2913*a1157835SDaniel Fojt if (os_memcmp(md, wpa_md,
2914*a1157835SDaniel Fojt MOBILITY_DOMAIN_ID_LEN) == 0) {
2915*a1157835SDaniel Fojt /* Add mobility domain IE */
2916*a1157835SDaniel Fojt len = wpa_ft_add_mdie(
2917*a1157835SDaniel Fojt wpa_s->wpa, wpa_ie + wpa_ie_len,
2918*a1157835SDaniel Fojt max_wpa_ie_len - wpa_ie_len, mdie);
2919*a1157835SDaniel Fojt wpa_ie_len += len;
2920*a1157835SDaniel Fojt }
2921*a1157835SDaniel Fojt #ifdef CONFIG_SME
2922*a1157835SDaniel Fojt if (len > 0 && wpa_s->sme.ft_used &&
2923*a1157835SDaniel Fojt wpa_sm_has_ptk(wpa_s->wpa)) {
2924*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
2925*a1157835SDaniel Fojt "SME: Trying to use FT over-the-air");
2926*a1157835SDaniel Fojt algs |= WPA_AUTH_ALG_FT;
2927*a1157835SDaniel Fojt }
2928*a1157835SDaniel Fojt #endif /* CONFIG_SME */
2929*a1157835SDaniel Fojt }
2930*a1157835SDaniel Fojt }
2931*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R */
2932*a1157835SDaniel Fojt
2933*a1157835SDaniel Fojt if (ssid->multi_ap_backhaul_sta) {
2934*a1157835SDaniel Fojt size_t multi_ap_ie_len;
2935*a1157835SDaniel Fojt
2936*a1157835SDaniel Fojt multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
2937*a1157835SDaniel Fojt max_wpa_ie_len - wpa_ie_len,
2938*a1157835SDaniel Fojt MULTI_AP_BACKHAUL_STA);
2939*a1157835SDaniel Fojt if (multi_ap_ie_len == 0) {
2940*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
2941*a1157835SDaniel Fojt "Multi-AP: Failed to build Multi-AP IE");
2942*a1157835SDaniel Fojt os_free(wpa_ie);
2943*a1157835SDaniel Fojt return NULL;
2944*a1157835SDaniel Fojt }
2945*a1157835SDaniel Fojt wpa_ie_len += multi_ap_ie_len;
2946*a1157835SDaniel Fojt }
2947*a1157835SDaniel Fojt
2948*a1157835SDaniel Fojt params->wpa_ie = wpa_ie;
2949*a1157835SDaniel Fojt params->wpa_ie_len = wpa_ie_len;
2950*a1157835SDaniel Fojt params->auth_alg = algs;
2951*a1157835SDaniel Fojt if (mask)
2952*a1157835SDaniel Fojt *mask |= WPA_DRV_UPDATE_ASSOC_IES | WPA_DRV_UPDATE_AUTH_TYPE;
2953*a1157835SDaniel Fojt
2954*a1157835SDaniel Fojt return wpa_ie;
2955*a1157835SDaniel Fojt }
2956*a1157835SDaniel Fojt
2957*a1157835SDaniel Fojt
2958*a1157835SDaniel Fojt #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
wpas_update_fils_connect_params(struct wpa_supplicant * wpa_s)2959*a1157835SDaniel Fojt static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
2960*a1157835SDaniel Fojt {
2961*a1157835SDaniel Fojt struct wpa_driver_associate_params params;
2962*a1157835SDaniel Fojt enum wpa_drv_update_connect_params_mask mask = 0;
2963*a1157835SDaniel Fojt u8 *wpa_ie;
2964*a1157835SDaniel Fojt
2965*a1157835SDaniel Fojt if (wpa_s->auth_alg != WPA_AUTH_ALG_OPEN)
2966*a1157835SDaniel Fojt return; /* nothing to do */
2967*a1157835SDaniel Fojt
2968*a1157835SDaniel Fojt os_memset(¶ms, 0, sizeof(params));
2969*a1157835SDaniel Fojt wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
2970*a1157835SDaniel Fojt wpa_s->current_ssid, ¶ms, &mask);
2971*a1157835SDaniel Fojt if (!wpa_ie)
2972*a1157835SDaniel Fojt return;
2973*a1157835SDaniel Fojt
2974*a1157835SDaniel Fojt if (params.auth_alg != WPA_AUTH_ALG_FILS) {
2975*a1157835SDaniel Fojt os_free(wpa_ie);
2976*a1157835SDaniel Fojt return;
2977*a1157835SDaniel Fojt }
2978*a1157835SDaniel Fojt
2979*a1157835SDaniel Fojt wpa_s->auth_alg = params.auth_alg;
2980*a1157835SDaniel Fojt wpa_drv_update_connect_params(wpa_s, ¶ms, mask);
2981*a1157835SDaniel Fojt os_free(wpa_ie);
2982*a1157835SDaniel Fojt }
2983*a1157835SDaniel Fojt #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
2984*a1157835SDaniel Fojt
2985*a1157835SDaniel Fojt
2986*a1157835SDaniel Fojt #ifdef CONFIG_MBO
wpas_update_mbo_connect_params(struct wpa_supplicant * wpa_s)2987*a1157835SDaniel Fojt void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
2988*a1157835SDaniel Fojt {
2989*a1157835SDaniel Fojt struct wpa_driver_associate_params params;
2990*a1157835SDaniel Fojt u8 *wpa_ie;
2991*a1157835SDaniel Fojt
2992*a1157835SDaniel Fojt /*
2993*a1157835SDaniel Fojt * Update MBO connect params only in case of change of MBO attributes
2994*a1157835SDaniel Fojt * when connected, if the AP support MBO.
2995*a1157835SDaniel Fojt */
2996*a1157835SDaniel Fojt
2997*a1157835SDaniel Fojt if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid ||
2998*a1157835SDaniel Fojt !wpa_s->current_bss ||
2999*a1157835SDaniel Fojt !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
3000*a1157835SDaniel Fojt return;
3001*a1157835SDaniel Fojt
3002*a1157835SDaniel Fojt os_memset(¶ms, 0, sizeof(params));
3003*a1157835SDaniel Fojt wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
3004*a1157835SDaniel Fojt wpa_s->current_ssid, ¶ms, NULL);
3005*a1157835SDaniel Fojt if (!wpa_ie)
3006*a1157835SDaniel Fojt return;
3007*a1157835SDaniel Fojt
3008*a1157835SDaniel Fojt wpa_drv_update_connect_params(wpa_s, ¶ms, WPA_DRV_UPDATE_ASSOC_IES);
3009*a1157835SDaniel Fojt os_free(wpa_ie);
3010*a1157835SDaniel Fojt }
3011*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
3012*a1157835SDaniel Fojt
3013*a1157835SDaniel Fojt
wpas_start_assoc_cb(struct wpa_radio_work * work,int deinit)30143ff40c12SJohn Marino static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
30153ff40c12SJohn Marino {
30163ff40c12SJohn Marino struct wpa_connect_work *cwork = work->ctx;
30173ff40c12SJohn Marino struct wpa_bss *bss = cwork->bss;
30183ff40c12SJohn Marino struct wpa_ssid *ssid = cwork->ssid;
30193ff40c12SJohn Marino struct wpa_supplicant *wpa_s = work->wpa_s;
3020*a1157835SDaniel Fojt u8 *wpa_ie;
30213ff40c12SJohn Marino int use_crypt, ret, i, bssid_changed;
3022*a1157835SDaniel Fojt unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
30236d49e1aeSJan Lentfer struct wpa_driver_associate_params params;
30246d49e1aeSJan Lentfer int wep_keys_set = 0;
30256d49e1aeSJan Lentfer int assoc_failed = 0;
30263ff40c12SJohn Marino struct wpa_ssid *old_ssid;
3027*a1157835SDaniel Fojt u8 prev_bssid[ETH_ALEN];
30283ff40c12SJohn Marino #ifdef CONFIG_HT_OVERRIDES
30293ff40c12SJohn Marino struct ieee80211_ht_capabilities htcaps;
30303ff40c12SJohn Marino struct ieee80211_ht_capabilities htcaps_mask;
30313ff40c12SJohn Marino #endif /* CONFIG_HT_OVERRIDES */
3032*a1157835SDaniel Fojt #ifdef CONFIG_VHT_OVERRIDES
3033*a1157835SDaniel Fojt struct ieee80211_vht_capabilities vhtcaps;
3034*a1157835SDaniel Fojt struct ieee80211_vht_capabilities vhtcaps_mask;
3035*a1157835SDaniel Fojt #endif /* CONFIG_VHT_OVERRIDES */
30366d49e1aeSJan Lentfer
30373ff40c12SJohn Marino if (deinit) {
3038*a1157835SDaniel Fojt if (work->started) {
3039*a1157835SDaniel Fojt wpa_s->connect_work = NULL;
3040*a1157835SDaniel Fojt
3041*a1157835SDaniel Fojt /* cancel possible auth. timeout */
3042*a1157835SDaniel Fojt eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
3043*a1157835SDaniel Fojt NULL);
3044*a1157835SDaniel Fojt }
30453ff40c12SJohn Marino wpas_connect_work_free(cwork);
30463ff40c12SJohn Marino return;
30473ff40c12SJohn Marino }
30483ff40c12SJohn Marino
30493ff40c12SJohn Marino wpa_s->connect_work = work;
30503ff40c12SJohn Marino
3051*a1157835SDaniel Fojt if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
3052*a1157835SDaniel Fojt wpas_network_disabled(wpa_s, ssid)) {
30533ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
30543ff40c12SJohn Marino wpas_connect_work_done(wpa_s);
30553ff40c12SJohn Marino return;
30563ff40c12SJohn Marino }
30573ff40c12SJohn Marino
3058*a1157835SDaniel Fojt os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
30593ff40c12SJohn Marino os_memset(¶ms, 0, sizeof(params));
30606d49e1aeSJan Lentfer wpa_s->reassociate = 0;
30613ff40c12SJohn Marino wpa_s->eap_expected_failure = 0;
3062*a1157835SDaniel Fojt if (bss &&
3063*a1157835SDaniel Fojt (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
30646d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211R
30653ff40c12SJohn Marino const u8 *ie, *md = NULL;
30666d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211R */
30676d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
30686d49e1aeSJan Lentfer " (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
30693ff40c12SJohn Marino wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
30703ff40c12SJohn Marino bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
30716d49e1aeSJan Lentfer os_memset(wpa_s->bssid, 0, ETH_ALEN);
30726d49e1aeSJan Lentfer os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
30733ff40c12SJohn Marino if (bssid_changed)
30743ff40c12SJohn Marino wpas_notify_bssid_changed(wpa_s);
30756d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211R
30763ff40c12SJohn Marino ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
30776d49e1aeSJan Lentfer if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
30786d49e1aeSJan Lentfer md = ie + 2;
30793ff40c12SJohn Marino wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
30806d49e1aeSJan Lentfer if (md) {
30816d49e1aeSJan Lentfer /* Prepare for the next transition */
30823ff40c12SJohn Marino wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
30836d49e1aeSJan Lentfer }
30846d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211R */
30856d49e1aeSJan Lentfer #ifdef CONFIG_WPS
30866d49e1aeSJan Lentfer } else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
30876d49e1aeSJan Lentfer wpa_s->conf->ap_scan == 2 &&
30886d49e1aeSJan Lentfer (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
30896d49e1aeSJan Lentfer /* Use ap_scan==1 style network selection to find the network
30906d49e1aeSJan Lentfer */
3091*a1157835SDaniel Fojt wpas_connect_work_done(wpa_s);
30923ff40c12SJohn Marino wpa_s->scan_req = MANUAL_SCAN_REQ;
30936d49e1aeSJan Lentfer wpa_s->reassociate = 1;
30946d49e1aeSJan Lentfer wpa_supplicant_req_scan(wpa_s, 0, 0);
30956d49e1aeSJan Lentfer return;
30966d49e1aeSJan Lentfer #endif /* CONFIG_WPS */
30976d49e1aeSJan Lentfer } else {
30986d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
30996d49e1aeSJan Lentfer wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
3100*a1157835SDaniel Fojt if (bss)
3101*a1157835SDaniel Fojt os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
3102*a1157835SDaniel Fojt else
31036d49e1aeSJan Lentfer os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
31046d49e1aeSJan Lentfer }
3105*a1157835SDaniel Fojt if (!wpa_s->pno)
31063ff40c12SJohn Marino wpa_supplicant_cancel_sched_scan(wpa_s);
3107*a1157835SDaniel Fojt
31086d49e1aeSJan Lentfer wpa_supplicant_cancel_scan(wpa_s);
31096d49e1aeSJan Lentfer
31106d49e1aeSJan Lentfer /* Starting new association, so clear the possibly used WPA IE from the
31116d49e1aeSJan Lentfer * previous association. */
31126d49e1aeSJan Lentfer wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
31136d49e1aeSJan Lentfer
3114*a1157835SDaniel Fojt wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, ¶ms, NULL);
3115*a1157835SDaniel Fojt if (!wpa_ie) {
3116*a1157835SDaniel Fojt wpas_connect_work_done(wpa_s);
31176d49e1aeSJan Lentfer return;
31186d49e1aeSJan Lentfer }
31196d49e1aeSJan Lentfer
31206d49e1aeSJan Lentfer wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
31216d49e1aeSJan Lentfer use_crypt = 1;
31223ff40c12SJohn Marino cipher_pairwise = wpa_s->pairwise_cipher;
31233ff40c12SJohn Marino cipher_group = wpa_s->group_cipher;
3124*a1157835SDaniel Fojt cipher_group_mgmt = wpa_s->mgmt_group_cipher;
31256d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
31266d49e1aeSJan Lentfer wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
31276d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
31286d49e1aeSJan Lentfer use_crypt = 0;
31296d49e1aeSJan Lentfer if (wpa_set_wep_keys(wpa_s, ssid)) {
31306d49e1aeSJan Lentfer use_crypt = 1;
31316d49e1aeSJan Lentfer wep_keys_set = 1;
31326d49e1aeSJan Lentfer }
31336d49e1aeSJan Lentfer }
31346d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
31356d49e1aeSJan Lentfer use_crypt = 0;
31366d49e1aeSJan Lentfer
31376d49e1aeSJan Lentfer #ifdef IEEE8021X_EAPOL
31386d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
31396d49e1aeSJan Lentfer if ((ssid->eapol_flags &
31406d49e1aeSJan Lentfer (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
31416d49e1aeSJan Lentfer EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
31426d49e1aeSJan Lentfer !wep_keys_set) {
31436d49e1aeSJan Lentfer use_crypt = 0;
31446d49e1aeSJan Lentfer } else {
31456d49e1aeSJan Lentfer /* Assume that dynamic WEP-104 keys will be used and
31466d49e1aeSJan Lentfer * set cipher suites in order for drivers to expect
31476d49e1aeSJan Lentfer * encryption. */
31483ff40c12SJohn Marino cipher_pairwise = cipher_group = WPA_CIPHER_WEP104;
31496d49e1aeSJan Lentfer }
31506d49e1aeSJan Lentfer }
31516d49e1aeSJan Lentfer #endif /* IEEE8021X_EAPOL */
31526d49e1aeSJan Lentfer
31536d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
31546d49e1aeSJan Lentfer /* Set the key before (and later after) association */
31556d49e1aeSJan Lentfer wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
31566d49e1aeSJan Lentfer }
31576d49e1aeSJan Lentfer
31586d49e1aeSJan Lentfer wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
31596d49e1aeSJan Lentfer if (bss) {
31603ff40c12SJohn Marino params.ssid = bss->ssid;
31613ff40c12SJohn Marino params.ssid_len = bss->ssid_len;
3162*a1157835SDaniel Fojt if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
3163*a1157835SDaniel Fojt wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
31643ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
31653ff40c12SJohn Marino MACSTR " freq=%u MHz based on scan results "
3166*a1157835SDaniel Fojt "(bssid_set=%d wps=%d)",
31673ff40c12SJohn Marino MAC2STR(bss->bssid), bss->freq,
3168*a1157835SDaniel Fojt ssid->bssid_set,
3169*a1157835SDaniel Fojt wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
31706d49e1aeSJan Lentfer params.bssid = bss->bssid;
3171*a1157835SDaniel Fojt params.freq.freq = bss->freq;
31723ff40c12SJohn Marino }
3173*a1157835SDaniel Fojt params.bssid_hint = bss->bssid;
3174*a1157835SDaniel Fojt params.freq_hint = bss->freq;
3175*a1157835SDaniel Fojt params.pbss = bss_is_pbss(bss);
31766d49e1aeSJan Lentfer } else {
3177*a1157835SDaniel Fojt if (ssid->bssid_hint_set)
3178*a1157835SDaniel Fojt params.bssid_hint = ssid->bssid_hint;
3179*a1157835SDaniel Fojt
31806d49e1aeSJan Lentfer params.ssid = ssid->ssid;
31816d49e1aeSJan Lentfer params.ssid_len = ssid->ssid_len;
3182*a1157835SDaniel Fojt params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
31836d49e1aeSJan Lentfer }
31843ff40c12SJohn Marino
31853ff40c12SJohn Marino if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
31863ff40c12SJohn Marino wpa_s->conf->ap_scan == 2) {
31873ff40c12SJohn Marino params.bssid = ssid->bssid;
31883ff40c12SJohn Marino params.fixed_bssid = 1;
31893ff40c12SJohn Marino }
31903ff40c12SJohn Marino
3191*a1157835SDaniel Fojt /* Initial frequency for IBSS/mesh */
3192*a1157835SDaniel Fojt if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
3193*a1157835SDaniel Fojt ssid->frequency > 0 && params.freq.freq == 0)
3194*a1157835SDaniel Fojt ibss_mesh_setup_freq(wpa_s, ssid, ¶ms.freq);
3195*a1157835SDaniel Fojt
3196*a1157835SDaniel Fojt if (ssid->mode == WPAS_MODE_IBSS) {
3197*a1157835SDaniel Fojt params.fixed_freq = ssid->fixed_freq;
3198*a1157835SDaniel Fojt if (ssid->beacon_int)
3199*a1157835SDaniel Fojt params.beacon_int = ssid->beacon_int;
3200*a1157835SDaniel Fojt else
3201*a1157835SDaniel Fojt params.beacon_int = wpa_s->conf->beacon_int;
3202*a1157835SDaniel Fojt }
3203*a1157835SDaniel Fojt
32046d49e1aeSJan Lentfer params.pairwise_suite = cipher_pairwise;
32056d49e1aeSJan Lentfer params.group_suite = cipher_group;
3206*a1157835SDaniel Fojt params.mgmt_group_suite = cipher_group_mgmt;
32073ff40c12SJohn Marino params.key_mgmt_suite = wpa_s->key_mgmt;
32083ff40c12SJohn Marino params.wpa_proto = wpa_s->wpa_proto;
3209*a1157835SDaniel Fojt wpa_s->auth_alg = params.auth_alg;
32106d49e1aeSJan Lentfer params.mode = ssid->mode;
32113ff40c12SJohn Marino params.bg_scan_period = ssid->bg_scan_period;
32126d49e1aeSJan Lentfer for (i = 0; i < NUM_WEP_KEYS; i++) {
32136d49e1aeSJan Lentfer if (ssid->wep_key_len[i])
32146d49e1aeSJan Lentfer params.wep_key[i] = ssid->wep_key[i];
32156d49e1aeSJan Lentfer params.wep_key_len[i] = ssid->wep_key_len[i];
32166d49e1aeSJan Lentfer }
32176d49e1aeSJan Lentfer params.wep_tx_keyidx = ssid->wep_tx_keyidx;
32186d49e1aeSJan Lentfer
3219*a1157835SDaniel Fojt if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
32203ff40c12SJohn Marino (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
32213ff40c12SJohn Marino params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
32226d49e1aeSJan Lentfer params.passphrase = ssid->passphrase;
32236d49e1aeSJan Lentfer if (ssid->psk_set)
32246d49e1aeSJan Lentfer params.psk = ssid->psk;
32256d49e1aeSJan Lentfer }
32266d49e1aeSJan Lentfer
3227*a1157835SDaniel Fojt if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
3228*a1157835SDaniel Fojt (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
3229*a1157835SDaniel Fojt params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
3230*a1157835SDaniel Fojt params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
3231*a1157835SDaniel Fojt params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
3232*a1157835SDaniel Fojt params.req_handshake_offload = 1;
3233*a1157835SDaniel Fojt
3234*a1157835SDaniel Fojt if (wpa_s->conf->key_mgmt_offload) {
3235*a1157835SDaniel Fojt if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
3236*a1157835SDaniel Fojt params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
3237*a1157835SDaniel Fojt params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
3238*a1157835SDaniel Fojt params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
3239*a1157835SDaniel Fojt params.req_key_mgmt_offload =
3240*a1157835SDaniel Fojt ssid->proactive_key_caching < 0 ?
3241*a1157835SDaniel Fojt wpa_s->conf->okc : ssid->proactive_key_caching;
3242*a1157835SDaniel Fojt else
3243*a1157835SDaniel Fojt params.req_key_mgmt_offload = 1;
3244*a1157835SDaniel Fojt
3245*a1157835SDaniel Fojt if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
3246*a1157835SDaniel Fojt params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
3247*a1157835SDaniel Fojt params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
3248*a1157835SDaniel Fojt ssid->psk_set)
3249*a1157835SDaniel Fojt params.psk = ssid->psk;
3250*a1157835SDaniel Fojt }
3251*a1157835SDaniel Fojt
32523ff40c12SJohn Marino params.drop_unencrypted = use_crypt;
32533ff40c12SJohn Marino
32546d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
3255*a1157835SDaniel Fojt params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
32563ff40c12SJohn Marino if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
32573ff40c12SJohn Marino const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
32586d49e1aeSJan Lentfer struct wpa_ie_data ie;
32596d49e1aeSJan Lentfer if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
32606d49e1aeSJan Lentfer ie.capabilities &
32616d49e1aeSJan Lentfer (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
32623ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
32633ff40c12SJohn Marino "MFP: require MFP");
32646d49e1aeSJan Lentfer params.mgmt_frame_protection =
32656d49e1aeSJan Lentfer MGMT_FRAME_PROTECTION_REQUIRED;
3266*a1157835SDaniel Fojt #ifdef CONFIG_OWE
3267*a1157835SDaniel Fojt } else if (!rsn && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
3268*a1157835SDaniel Fojt !ssid->owe_only) {
3269*a1157835SDaniel Fojt params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION;
3270*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
32716d49e1aeSJan Lentfer }
32726d49e1aeSJan Lentfer }
32736d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
32746d49e1aeSJan Lentfer
32753ff40c12SJohn Marino params.p2p = ssid->p2p_group;
32763ff40c12SJohn Marino
3277*a1157835SDaniel Fojt if (wpa_s->p2pdev->set_sta_uapsd)
3278*a1157835SDaniel Fojt params.uapsd = wpa_s->p2pdev->sta_uapsd;
32796d49e1aeSJan Lentfer else
32803ff40c12SJohn Marino params.uapsd = -1;
32813ff40c12SJohn Marino
32823ff40c12SJohn Marino #ifdef CONFIG_HT_OVERRIDES
32833ff40c12SJohn Marino os_memset(&htcaps, 0, sizeof(htcaps));
32843ff40c12SJohn Marino os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
32853ff40c12SJohn Marino params.htcaps = (u8 *) &htcaps;
32863ff40c12SJohn Marino params.htcaps_mask = (u8 *) &htcaps_mask;
32873ff40c12SJohn Marino wpa_supplicant_apply_ht_overrides(wpa_s, ssid, ¶ms);
32883ff40c12SJohn Marino #endif /* CONFIG_HT_OVERRIDES */
3289*a1157835SDaniel Fojt #ifdef CONFIG_VHT_OVERRIDES
3290*a1157835SDaniel Fojt os_memset(&vhtcaps, 0, sizeof(vhtcaps));
3291*a1157835SDaniel Fojt os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
3292*a1157835SDaniel Fojt params.vhtcaps = &vhtcaps;
3293*a1157835SDaniel Fojt params.vhtcaps_mask = &vhtcaps_mask;
3294*a1157835SDaniel Fojt wpa_supplicant_apply_vht_overrides(wpa_s, ssid, ¶ms);
3295*a1157835SDaniel Fojt #endif /* CONFIG_VHT_OVERRIDES */
32963ff40c12SJohn Marino
32973ff40c12SJohn Marino #ifdef CONFIG_P2P
32983ff40c12SJohn Marino /*
32993ff40c12SJohn Marino * If multi-channel concurrency is not supported, check for any
33003ff40c12SJohn Marino * frequency conflict. In case of any frequency conflict, remove the
33013ff40c12SJohn Marino * least prioritized connection.
33023ff40c12SJohn Marino */
33033ff40c12SJohn Marino if (wpa_s->num_multichan_concurrent < 2) {
3304*a1157835SDaniel Fojt int freq, num;
3305*a1157835SDaniel Fojt num = get_shared_radio_freqs(wpa_s, &freq, 1);
3306*a1157835SDaniel Fojt if (num > 0 && freq > 0 && freq != params.freq.freq) {
3307*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
3308*a1157835SDaniel Fojt "Assoc conflicting freq found (%d != %d)",
3309*a1157835SDaniel Fojt freq, params.freq.freq);
3310*a1157835SDaniel Fojt if (wpas_p2p_handle_frequency_conflicts(
3311*a1157835SDaniel Fojt wpa_s, params.freq.freq, ssid) < 0) {
3312*a1157835SDaniel Fojt wpas_connect_work_done(wpa_s);
3313*a1157835SDaniel Fojt os_free(wpa_ie);
33143ff40c12SJohn Marino return;
33153ff40c12SJohn Marino }
33163ff40c12SJohn Marino }
3317*a1157835SDaniel Fojt }
33183ff40c12SJohn Marino #endif /* CONFIG_P2P */
33193ff40c12SJohn Marino
3320*a1157835SDaniel Fojt if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
3321*a1157835SDaniel Fojt wpa_s->current_ssid)
3322*a1157835SDaniel Fojt params.prev_bssid = prev_bssid;
3323*a1157835SDaniel Fojt
33246d49e1aeSJan Lentfer ret = wpa_drv_associate(wpa_s, ¶ms);
3325*a1157835SDaniel Fojt os_free(wpa_ie);
33266d49e1aeSJan Lentfer if (ret < 0) {
33276d49e1aeSJan Lentfer wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
33286d49e1aeSJan Lentfer "failed");
33293ff40c12SJohn Marino if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
33303ff40c12SJohn Marino /*
33313ff40c12SJohn Marino * The driver is known to mean what is saying, so we
33323ff40c12SJohn Marino * can stop right here; the association will not
33333ff40c12SJohn Marino * succeed.
33343ff40c12SJohn Marino */
33353ff40c12SJohn Marino wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
33363ff40c12SJohn Marino wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
33373ff40c12SJohn Marino os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
33383ff40c12SJohn Marino return;
33393ff40c12SJohn Marino }
33406d49e1aeSJan Lentfer /* try to continue anyway; new association will be tried again
33416d49e1aeSJan Lentfer * after timeout */
33426d49e1aeSJan Lentfer assoc_failed = 1;
33436d49e1aeSJan Lentfer }
33446d49e1aeSJan Lentfer
33456d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
33466d49e1aeSJan Lentfer /* Set the key after the association just in case association
33476d49e1aeSJan Lentfer * cleared the previously configured key. */
33486d49e1aeSJan Lentfer wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
33496d49e1aeSJan Lentfer /* No need to timeout authentication since there is no key
33506d49e1aeSJan Lentfer * management. */
33516d49e1aeSJan Lentfer wpa_supplicant_cancel_auth_timeout(wpa_s);
33526d49e1aeSJan Lentfer wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
33533ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
33543ff40c12SJohn Marino } else if (ssid->mode == WPAS_MODE_IBSS &&
33553ff40c12SJohn Marino wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
33563ff40c12SJohn Marino wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
33573ff40c12SJohn Marino /*
33583ff40c12SJohn Marino * RSN IBSS authentication is per-STA and we can disable the
33593ff40c12SJohn Marino * per-BSSID authentication.
33603ff40c12SJohn Marino */
33613ff40c12SJohn Marino wpa_supplicant_cancel_auth_timeout(wpa_s);
33623ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
33636d49e1aeSJan Lentfer } else {
33646d49e1aeSJan Lentfer /* Timeout for IEEE 802.11 authentication and association */
33656d49e1aeSJan Lentfer int timeout = 60;
33666d49e1aeSJan Lentfer
33676d49e1aeSJan Lentfer if (assoc_failed) {
33686d49e1aeSJan Lentfer /* give IBSS a bit more time */
33693ff40c12SJohn Marino timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
33706d49e1aeSJan Lentfer } else if (wpa_s->conf->ap_scan == 1) {
33716d49e1aeSJan Lentfer /* give IBSS a bit more time */
33723ff40c12SJohn Marino timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
33736d49e1aeSJan Lentfer }
33746d49e1aeSJan Lentfer wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
33756d49e1aeSJan Lentfer }
33766d49e1aeSJan Lentfer
33773ff40c12SJohn Marino if (wep_keys_set &&
33783ff40c12SJohn Marino (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
33796d49e1aeSJan Lentfer /* Set static WEP keys again */
33806d49e1aeSJan Lentfer wpa_set_wep_keys(wpa_s, ssid);
33816d49e1aeSJan Lentfer }
33826d49e1aeSJan Lentfer
33836d49e1aeSJan Lentfer if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
33846d49e1aeSJan Lentfer /*
33856d49e1aeSJan Lentfer * Do not allow EAP session resumption between different
33866d49e1aeSJan Lentfer * network configurations.
33876d49e1aeSJan Lentfer */
33886d49e1aeSJan Lentfer eapol_sm_invalidate_cached_session(wpa_s->eapol);
33896d49e1aeSJan Lentfer }
33903ff40c12SJohn Marino old_ssid = wpa_s->current_ssid;
33916d49e1aeSJan Lentfer wpa_s->current_ssid = ssid;
3392*a1157835SDaniel Fojt
3393*a1157835SDaniel Fojt if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
33943ff40c12SJohn Marino wpa_s->current_bss = bss;
3395*a1157835SDaniel Fojt #ifdef CONFIG_HS20
3396*a1157835SDaniel Fojt hs20_configure_frame_filters(wpa_s);
3397*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
3398*a1157835SDaniel Fojt }
3399*a1157835SDaniel Fojt
34006d49e1aeSJan Lentfer wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
34016d49e1aeSJan Lentfer wpa_supplicant_initiate_eapol(wpa_s);
34023ff40c12SJohn Marino if (old_ssid != wpa_s->current_ssid)
34033ff40c12SJohn Marino wpas_notify_network_changed(wpa_s);
34046d49e1aeSJan Lentfer }
34056d49e1aeSJan Lentfer
34066d49e1aeSJan Lentfer
wpa_supplicant_clear_connection(struct wpa_supplicant * wpa_s,const u8 * addr)34073ff40c12SJohn Marino static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
34083ff40c12SJohn Marino const u8 *addr)
34096d49e1aeSJan Lentfer {
34103ff40c12SJohn Marino struct wpa_ssid *old_ssid;
34113ff40c12SJohn Marino
3412*a1157835SDaniel Fojt wpas_connect_work_done(wpa_s);
34136d49e1aeSJan Lentfer wpa_clear_keys(wpa_s, addr);
34143ff40c12SJohn Marino old_ssid = wpa_s->current_ssid;
34156d49e1aeSJan Lentfer wpa_supplicant_mark_disassoc(wpa_s);
34166d49e1aeSJan Lentfer wpa_sm_set_config(wpa_s->wpa, NULL);
34176d49e1aeSJan Lentfer eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
34183ff40c12SJohn Marino if (old_ssid != wpa_s->current_ssid)
34193ff40c12SJohn Marino wpas_notify_network_changed(wpa_s);
34203ff40c12SJohn Marino eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
34216d49e1aeSJan Lentfer }
34226d49e1aeSJan Lentfer
34236d49e1aeSJan Lentfer
34246d49e1aeSJan Lentfer /**
34256d49e1aeSJan Lentfer * wpa_supplicant_deauthenticate - Deauthenticate the current connection
34266d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
34276d49e1aeSJan Lentfer * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
34286d49e1aeSJan Lentfer *
34296d49e1aeSJan Lentfer * This function is used to request %wpa_supplicant to deauthenticate from the
34306d49e1aeSJan Lentfer * current AP.
34316d49e1aeSJan Lentfer */
wpa_supplicant_deauthenticate(struct wpa_supplicant * wpa_s,u16 reason_code)34326d49e1aeSJan Lentfer void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
3433*a1157835SDaniel Fojt u16 reason_code)
34346d49e1aeSJan Lentfer {
34356d49e1aeSJan Lentfer u8 *addr = NULL;
34363ff40c12SJohn Marino union wpa_event_data event;
34373ff40c12SJohn Marino int zero_addr = 0;
34383ff40c12SJohn Marino
34393ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
3440*a1157835SDaniel Fojt " pending_bssid=" MACSTR " reason=%d (%s) state=%s",
34413ff40c12SJohn Marino MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
3442*a1157835SDaniel Fojt reason_code, reason2str(reason_code),
3443*a1157835SDaniel Fojt wpa_supplicant_state_txt(wpa_s->wpa_state));
34443ff40c12SJohn Marino
3445*a1157835SDaniel Fojt if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
34463ff40c12SJohn Marino (wpa_s->wpa_state == WPA_AUTHENTICATING ||
34473ff40c12SJohn Marino wpa_s->wpa_state == WPA_ASSOCIATING))
34483ff40c12SJohn Marino addr = wpa_s->pending_bssid;
3449*a1157835SDaniel Fojt else if (!is_zero_ether_addr(wpa_s->bssid))
3450*a1157835SDaniel Fojt addr = wpa_s->bssid;
34513ff40c12SJohn Marino else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
34523ff40c12SJohn Marino /*
34533ff40c12SJohn Marino * When using driver-based BSS selection, we may not know the
34543ff40c12SJohn Marino * BSSID with which we are currently trying to associate. We
34553ff40c12SJohn Marino * need to notify the driver of this disconnection even in such
34563ff40c12SJohn Marino * a case, so use the all zeros address here.
34573ff40c12SJohn Marino */
34583ff40c12SJohn Marino addr = wpa_s->bssid;
34593ff40c12SJohn Marino zero_addr = 1;
34606d49e1aeSJan Lentfer }
34613ff40c12SJohn Marino
3462*a1157835SDaniel Fojt if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
3463*a1157835SDaniel Fojt wpa_s->enabled_4addr_mode = 0;
3464*a1157835SDaniel Fojt
34653ff40c12SJohn Marino #ifdef CONFIG_TDLS
34663ff40c12SJohn Marino wpa_tdls_teardown_peers(wpa_s->wpa);
34673ff40c12SJohn Marino #endif /* CONFIG_TDLS */
34683ff40c12SJohn Marino
3469*a1157835SDaniel Fojt #ifdef CONFIG_MESH
3470*a1157835SDaniel Fojt if (wpa_s->ifmsh) {
3471*a1157835SDaniel Fojt struct mesh_conf *mconf;
3472*a1157835SDaniel Fojt
3473*a1157835SDaniel Fojt mconf = wpa_s->ifmsh->mconf;
3474*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
3475*a1157835SDaniel Fojt wpa_s->ifname);
3476*a1157835SDaniel Fojt wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
3477*a1157835SDaniel Fojt mconf->meshid_len, reason_code);
3478*a1157835SDaniel Fojt wpa_supplicant_leave_mesh(wpa_s);
3479*a1157835SDaniel Fojt }
3480*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
3481*a1157835SDaniel Fojt
34823ff40c12SJohn Marino if (addr) {
34833ff40c12SJohn Marino wpa_drv_deauthenticate(wpa_s, addr, reason_code);
34843ff40c12SJohn Marino os_memset(&event, 0, sizeof(event));
3485*a1157835SDaniel Fojt event.deauth_info.reason_code = reason_code;
34863ff40c12SJohn Marino event.deauth_info.locally_generated = 1;
34873ff40c12SJohn Marino wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
34883ff40c12SJohn Marino if (zero_addr)
34893ff40c12SJohn Marino addr = NULL;
34903ff40c12SJohn Marino }
34913ff40c12SJohn Marino
34923ff40c12SJohn Marino wpa_supplicant_clear_connection(wpa_s, addr);
34933ff40c12SJohn Marino }
34943ff40c12SJohn Marino
wpa_supplicant_enable_one_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)34953ff40c12SJohn Marino static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
34963ff40c12SJohn Marino struct wpa_ssid *ssid)
34973ff40c12SJohn Marino {
34983ff40c12SJohn Marino if (!ssid || !ssid->disabled || ssid->disabled == 2)
34993ff40c12SJohn Marino return;
35003ff40c12SJohn Marino
35013ff40c12SJohn Marino ssid->disabled = 0;
3502*a1157835SDaniel Fojt ssid->owe_transition_bss_select_count = 0;
35033ff40c12SJohn Marino wpas_clear_temp_disabled(wpa_s, ssid, 1);
35043ff40c12SJohn Marino wpas_notify_network_enabled_changed(wpa_s, ssid);
35053ff40c12SJohn Marino
35063ff40c12SJohn Marino /*
35073ff40c12SJohn Marino * Try to reassociate since there is no current configuration and a new
35083ff40c12SJohn Marino * network was made available.
35093ff40c12SJohn Marino */
35103ff40c12SJohn Marino if (!wpa_s->current_ssid && !wpa_s->disconnected)
35113ff40c12SJohn Marino wpa_s->reassociate = 1;
35123ff40c12SJohn Marino }
35133ff40c12SJohn Marino
35143ff40c12SJohn Marino
35153ff40c12SJohn Marino /**
3516*a1157835SDaniel Fojt * wpa_supplicant_add_network - Add a new network
3517*a1157835SDaniel Fojt * @wpa_s: wpa_supplicant structure for a network interface
3518*a1157835SDaniel Fojt * Returns: The new network configuration or %NULL if operation failed
3519*a1157835SDaniel Fojt *
3520*a1157835SDaniel Fojt * This function performs the following operations:
3521*a1157835SDaniel Fojt * 1. Adds a new network.
3522*a1157835SDaniel Fojt * 2. Send network addition notification.
3523*a1157835SDaniel Fojt * 3. Marks the network disabled.
3524*a1157835SDaniel Fojt * 4. Set network default parameters.
3525*a1157835SDaniel Fojt */
wpa_supplicant_add_network(struct wpa_supplicant * wpa_s)3526*a1157835SDaniel Fojt struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
3527*a1157835SDaniel Fojt {
3528*a1157835SDaniel Fojt struct wpa_ssid *ssid;
3529*a1157835SDaniel Fojt
3530*a1157835SDaniel Fojt ssid = wpa_config_add_network(wpa_s->conf);
3531*a1157835SDaniel Fojt if (!ssid)
3532*a1157835SDaniel Fojt return NULL;
3533*a1157835SDaniel Fojt wpas_notify_network_added(wpa_s, ssid);
3534*a1157835SDaniel Fojt ssid->disabled = 1;
3535*a1157835SDaniel Fojt wpa_config_set_network_defaults(ssid);
3536*a1157835SDaniel Fojt
3537*a1157835SDaniel Fojt return ssid;
3538*a1157835SDaniel Fojt }
3539*a1157835SDaniel Fojt
3540*a1157835SDaniel Fojt
3541*a1157835SDaniel Fojt /**
3542*a1157835SDaniel Fojt * wpa_supplicant_remove_network - Remove a configured network based on id
3543*a1157835SDaniel Fojt * @wpa_s: wpa_supplicant structure for a network interface
3544*a1157835SDaniel Fojt * @id: Unique network id to search for
3545*a1157835SDaniel Fojt * Returns: 0 on success, or -1 if the network was not found, -2 if the network
3546*a1157835SDaniel Fojt * could not be removed
3547*a1157835SDaniel Fojt *
3548*a1157835SDaniel Fojt * This function performs the following operations:
3549*a1157835SDaniel Fojt * 1. Removes the network.
3550*a1157835SDaniel Fojt * 2. Send network removal notification.
3551*a1157835SDaniel Fojt * 3. Update internal state machines.
3552*a1157835SDaniel Fojt * 4. Stop any running sched scans.
3553*a1157835SDaniel Fojt */
wpa_supplicant_remove_network(struct wpa_supplicant * wpa_s,int id)3554*a1157835SDaniel Fojt int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
3555*a1157835SDaniel Fojt {
3556*a1157835SDaniel Fojt struct wpa_ssid *ssid;
3557*a1157835SDaniel Fojt int was_disabled;
3558*a1157835SDaniel Fojt
3559*a1157835SDaniel Fojt ssid = wpa_config_get_network(wpa_s->conf, id);
3560*a1157835SDaniel Fojt if (!ssid)
3561*a1157835SDaniel Fojt return -1;
3562*a1157835SDaniel Fojt wpas_notify_network_removed(wpa_s, ssid);
3563*a1157835SDaniel Fojt
3564*a1157835SDaniel Fojt if (wpa_s->last_ssid == ssid)
3565*a1157835SDaniel Fojt wpa_s->last_ssid = NULL;
3566*a1157835SDaniel Fojt
3567*a1157835SDaniel Fojt if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
3568*a1157835SDaniel Fojt #ifdef CONFIG_SME
3569*a1157835SDaniel Fojt wpa_s->sme.prev_bssid_set = 0;
3570*a1157835SDaniel Fojt #endif /* CONFIG_SME */
3571*a1157835SDaniel Fojt /*
3572*a1157835SDaniel Fojt * Invalidate the EAP session cache if the current or
3573*a1157835SDaniel Fojt * previously used network is removed.
3574*a1157835SDaniel Fojt */
3575*a1157835SDaniel Fojt eapol_sm_invalidate_cached_session(wpa_s->eapol);
3576*a1157835SDaniel Fojt }
3577*a1157835SDaniel Fojt
3578*a1157835SDaniel Fojt if (ssid == wpa_s->current_ssid) {
3579*a1157835SDaniel Fojt wpa_sm_set_config(wpa_s->wpa, NULL);
3580*a1157835SDaniel Fojt eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
3581*a1157835SDaniel Fojt
3582*a1157835SDaniel Fojt if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3583*a1157835SDaniel Fojt wpa_s->own_disconnect_req = 1;
3584*a1157835SDaniel Fojt wpa_supplicant_deauthenticate(wpa_s,
3585*a1157835SDaniel Fojt WLAN_REASON_DEAUTH_LEAVING);
3586*a1157835SDaniel Fojt }
3587*a1157835SDaniel Fojt
3588*a1157835SDaniel Fojt was_disabled = ssid->disabled;
3589*a1157835SDaniel Fojt
3590*a1157835SDaniel Fojt if (wpa_config_remove_network(wpa_s->conf, id) < 0)
3591*a1157835SDaniel Fojt return -2;
3592*a1157835SDaniel Fojt
3593*a1157835SDaniel Fojt if (!was_disabled && wpa_s->sched_scanning) {
3594*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
3595*a1157835SDaniel Fojt "Stop ongoing sched_scan to remove network from filters");
3596*a1157835SDaniel Fojt wpa_supplicant_cancel_sched_scan(wpa_s);
3597*a1157835SDaniel Fojt wpa_supplicant_req_scan(wpa_s, 0, 0);
3598*a1157835SDaniel Fojt }
3599*a1157835SDaniel Fojt
3600*a1157835SDaniel Fojt return 0;
3601*a1157835SDaniel Fojt }
3602*a1157835SDaniel Fojt
3603*a1157835SDaniel Fojt
3604*a1157835SDaniel Fojt /**
36053ff40c12SJohn Marino * wpa_supplicant_enable_network - Mark a configured network as enabled
36063ff40c12SJohn Marino * @wpa_s: wpa_supplicant structure for a network interface
36073ff40c12SJohn Marino * @ssid: wpa_ssid structure for a configured network or %NULL
36083ff40c12SJohn Marino *
36093ff40c12SJohn Marino * Enables the specified network or all networks if no network specified.
36103ff40c12SJohn Marino */
wpa_supplicant_enable_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)36113ff40c12SJohn Marino void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
36123ff40c12SJohn Marino struct wpa_ssid *ssid)
36133ff40c12SJohn Marino {
36143ff40c12SJohn Marino if (ssid == NULL) {
36153ff40c12SJohn Marino for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
36163ff40c12SJohn Marino wpa_supplicant_enable_one_network(wpa_s, ssid);
36173ff40c12SJohn Marino } else
36183ff40c12SJohn Marino wpa_supplicant_enable_one_network(wpa_s, ssid);
36193ff40c12SJohn Marino
3620*a1157835SDaniel Fojt if (wpa_s->reassociate && !wpa_s->disconnected &&
3621*a1157835SDaniel Fojt (!wpa_s->current_ssid ||
3622*a1157835SDaniel Fojt wpa_s->wpa_state == WPA_DISCONNECTED ||
3623*a1157835SDaniel Fojt wpa_s->wpa_state == WPA_SCANNING)) {
36243ff40c12SJohn Marino if (wpa_s->sched_scanning) {
36253ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
36263ff40c12SJohn Marino "new network to scan filters");
36273ff40c12SJohn Marino wpa_supplicant_cancel_sched_scan(wpa_s);
36283ff40c12SJohn Marino }
36293ff40c12SJohn Marino
3630*a1157835SDaniel Fojt if (wpa_supplicant_fast_associate(wpa_s) != 1) {
3631*a1157835SDaniel Fojt wpa_s->scan_req = NORMAL_SCAN_REQ;
36323ff40c12SJohn Marino wpa_supplicant_req_scan(wpa_s, 0, 0);
36333ff40c12SJohn Marino }
36343ff40c12SJohn Marino }
3635*a1157835SDaniel Fojt }
36363ff40c12SJohn Marino
36373ff40c12SJohn Marino
36383ff40c12SJohn Marino /**
36393ff40c12SJohn Marino * wpa_supplicant_disable_network - Mark a configured network as disabled
36403ff40c12SJohn Marino * @wpa_s: wpa_supplicant structure for a network interface
36413ff40c12SJohn Marino * @ssid: wpa_ssid structure for a configured network or %NULL
36423ff40c12SJohn Marino *
36433ff40c12SJohn Marino * Disables the specified network or all networks if no network specified.
36443ff40c12SJohn Marino */
wpa_supplicant_disable_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)36453ff40c12SJohn Marino void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
36463ff40c12SJohn Marino struct wpa_ssid *ssid)
36473ff40c12SJohn Marino {
36483ff40c12SJohn Marino struct wpa_ssid *other_ssid;
36493ff40c12SJohn Marino int was_disabled;
36503ff40c12SJohn Marino
36513ff40c12SJohn Marino if (ssid == NULL) {
36523ff40c12SJohn Marino if (wpa_s->sched_scanning)
36533ff40c12SJohn Marino wpa_supplicant_cancel_sched_scan(wpa_s);
36543ff40c12SJohn Marino
36553ff40c12SJohn Marino for (other_ssid = wpa_s->conf->ssid; other_ssid;
36563ff40c12SJohn Marino other_ssid = other_ssid->next) {
36573ff40c12SJohn Marino was_disabled = other_ssid->disabled;
36583ff40c12SJohn Marino if (was_disabled == 2)
36593ff40c12SJohn Marino continue; /* do not change persistent P2P group
36603ff40c12SJohn Marino * data */
36613ff40c12SJohn Marino
36623ff40c12SJohn Marino other_ssid->disabled = 1;
36633ff40c12SJohn Marino
36643ff40c12SJohn Marino if (was_disabled != other_ssid->disabled)
36653ff40c12SJohn Marino wpas_notify_network_enabled_changed(
36663ff40c12SJohn Marino wpa_s, other_ssid);
36673ff40c12SJohn Marino }
3668*a1157835SDaniel Fojt if (wpa_s->current_ssid) {
3669*a1157835SDaniel Fojt if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3670*a1157835SDaniel Fojt wpa_s->own_disconnect_req = 1;
36713ff40c12SJohn Marino wpa_supplicant_deauthenticate(
36723ff40c12SJohn Marino wpa_s, WLAN_REASON_DEAUTH_LEAVING);
3673*a1157835SDaniel Fojt }
36743ff40c12SJohn Marino } else if (ssid->disabled != 2) {
3675*a1157835SDaniel Fojt if (ssid == wpa_s->current_ssid) {
3676*a1157835SDaniel Fojt if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3677*a1157835SDaniel Fojt wpa_s->own_disconnect_req = 1;
36783ff40c12SJohn Marino wpa_supplicant_deauthenticate(
36793ff40c12SJohn Marino wpa_s, WLAN_REASON_DEAUTH_LEAVING);
3680*a1157835SDaniel Fojt }
36813ff40c12SJohn Marino
36823ff40c12SJohn Marino was_disabled = ssid->disabled;
36833ff40c12SJohn Marino
36843ff40c12SJohn Marino ssid->disabled = 1;
36853ff40c12SJohn Marino
36863ff40c12SJohn Marino if (was_disabled != ssid->disabled) {
36873ff40c12SJohn Marino wpas_notify_network_enabled_changed(wpa_s, ssid);
36883ff40c12SJohn Marino if (wpa_s->sched_scanning) {
36893ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan "
36903ff40c12SJohn Marino "to remove network from filters");
36913ff40c12SJohn Marino wpa_supplicant_cancel_sched_scan(wpa_s);
36923ff40c12SJohn Marino wpa_supplicant_req_scan(wpa_s, 0, 0);
36933ff40c12SJohn Marino }
36943ff40c12SJohn Marino }
36953ff40c12SJohn Marino }
36963ff40c12SJohn Marino }
36973ff40c12SJohn Marino
36983ff40c12SJohn Marino
36993ff40c12SJohn Marino /**
37003ff40c12SJohn Marino * wpa_supplicant_select_network - Attempt association with a network
37013ff40c12SJohn Marino * @wpa_s: wpa_supplicant structure for a network interface
37023ff40c12SJohn Marino * @ssid: wpa_ssid structure for a configured network or %NULL for any network
37033ff40c12SJohn Marino */
wpa_supplicant_select_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)37043ff40c12SJohn Marino void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
37053ff40c12SJohn Marino struct wpa_ssid *ssid)
37063ff40c12SJohn Marino {
37073ff40c12SJohn Marino
37083ff40c12SJohn Marino struct wpa_ssid *other_ssid;
37093ff40c12SJohn Marino int disconnected = 0;
37103ff40c12SJohn Marino
37113ff40c12SJohn Marino if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
3712*a1157835SDaniel Fojt if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3713*a1157835SDaniel Fojt wpa_s->own_disconnect_req = 1;
37143ff40c12SJohn Marino wpa_supplicant_deauthenticate(
37153ff40c12SJohn Marino wpa_s, WLAN_REASON_DEAUTH_LEAVING);
37163ff40c12SJohn Marino disconnected = 1;
37173ff40c12SJohn Marino }
37183ff40c12SJohn Marino
37193ff40c12SJohn Marino if (ssid)
37203ff40c12SJohn Marino wpas_clear_temp_disabled(wpa_s, ssid, 1);
37213ff40c12SJohn Marino
37223ff40c12SJohn Marino /*
37233ff40c12SJohn Marino * Mark all other networks disabled or mark all networks enabled if no
37243ff40c12SJohn Marino * network specified.
37253ff40c12SJohn Marino */
37263ff40c12SJohn Marino for (other_ssid = wpa_s->conf->ssid; other_ssid;
37273ff40c12SJohn Marino other_ssid = other_ssid->next) {
37283ff40c12SJohn Marino int was_disabled = other_ssid->disabled;
37293ff40c12SJohn Marino if (was_disabled == 2)
37303ff40c12SJohn Marino continue; /* do not change persistent P2P group data */
37313ff40c12SJohn Marino
37323ff40c12SJohn Marino other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
37333ff40c12SJohn Marino if (was_disabled && !other_ssid->disabled)
37343ff40c12SJohn Marino wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
37353ff40c12SJohn Marino
37363ff40c12SJohn Marino if (was_disabled != other_ssid->disabled)
37373ff40c12SJohn Marino wpas_notify_network_enabled_changed(wpa_s, other_ssid);
37383ff40c12SJohn Marino }
37393ff40c12SJohn Marino
3740*a1157835SDaniel Fojt if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid &&
3741*a1157835SDaniel Fojt wpa_s->wpa_state >= WPA_AUTHENTICATING) {
37423ff40c12SJohn Marino /* We are already associated with the selected network */
37433ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Already associated with the "
37443ff40c12SJohn Marino "selected network - do nothing");
37453ff40c12SJohn Marino return;
37463ff40c12SJohn Marino }
37473ff40c12SJohn Marino
37483ff40c12SJohn Marino if (ssid) {
37493ff40c12SJohn Marino wpa_s->current_ssid = ssid;
37506d49e1aeSJan Lentfer eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
3751*a1157835SDaniel Fojt wpa_s->connect_without_scan =
3752*a1157835SDaniel Fojt (ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
3753*a1157835SDaniel Fojt
3754*a1157835SDaniel Fojt /*
3755*a1157835SDaniel Fojt * Don't optimize next scan freqs since a new ESS has been
3756*a1157835SDaniel Fojt * selected.
3757*a1157835SDaniel Fojt */
3758*a1157835SDaniel Fojt os_free(wpa_s->next_scan_freqs);
3759*a1157835SDaniel Fojt wpa_s->next_scan_freqs = NULL;
3760*a1157835SDaniel Fojt } else {
37613ff40c12SJohn Marino wpa_s->connect_without_scan = NULL;
3762*a1157835SDaniel Fojt }
3763*a1157835SDaniel Fojt
37643ff40c12SJohn Marino wpa_s->disconnected = 0;
37653ff40c12SJohn Marino wpa_s->reassociate = 1;
3766*a1157835SDaniel Fojt wpa_s->last_owe_group = 0;
3767*a1157835SDaniel Fojt if (ssid)
3768*a1157835SDaniel Fojt ssid->owe_transition_bss_select_count = 0;
37693ff40c12SJohn Marino
3770*a1157835SDaniel Fojt if (wpa_s->connect_without_scan ||
3771*a1157835SDaniel Fojt wpa_supplicant_fast_associate(wpa_s) != 1) {
3772*a1157835SDaniel Fojt wpa_s->scan_req = NORMAL_SCAN_REQ;
3773*a1157835SDaniel Fojt wpas_scan_reset_sched_scan(wpa_s);
37743ff40c12SJohn Marino wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
3775*a1157835SDaniel Fojt }
37763ff40c12SJohn Marino
37773ff40c12SJohn Marino if (ssid)
37783ff40c12SJohn Marino wpas_notify_network_selected(wpa_s, ssid);
37793ff40c12SJohn Marino }
37806d49e1aeSJan Lentfer
37816d49e1aeSJan Lentfer
37823ff40c12SJohn Marino /**
37833ff40c12SJohn Marino * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
37843ff40c12SJohn Marino * @wpa_s: wpa_supplicant structure for a network interface
37853ff40c12SJohn Marino * @pkcs11_engine_path: PKCS #11 engine path or NULL
37863ff40c12SJohn Marino * @pkcs11_module_path: PKCS #11 module path or NULL
37873ff40c12SJohn Marino * Returns: 0 on success; -1 on failure
37883ff40c12SJohn Marino *
37893ff40c12SJohn Marino * Sets the PKCS #11 engine and module path. Both have to be NULL or a valid
37903ff40c12SJohn Marino * path. If resetting the EAPOL state machine with the new PKCS #11 engine and
37913ff40c12SJohn Marino * module path fails the paths will be reset to the default value (NULL).
37923ff40c12SJohn Marino */
wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant * wpa_s,const char * pkcs11_engine_path,const char * pkcs11_module_path)37933ff40c12SJohn Marino int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
37943ff40c12SJohn Marino const char *pkcs11_engine_path,
37953ff40c12SJohn Marino const char *pkcs11_module_path)
37966d49e1aeSJan Lentfer {
37973ff40c12SJohn Marino char *pkcs11_engine_path_copy = NULL;
37983ff40c12SJohn Marino char *pkcs11_module_path_copy = NULL;
37996d49e1aeSJan Lentfer
38003ff40c12SJohn Marino if (pkcs11_engine_path != NULL) {
38013ff40c12SJohn Marino pkcs11_engine_path_copy = os_strdup(pkcs11_engine_path);
38023ff40c12SJohn Marino if (pkcs11_engine_path_copy == NULL)
38036d49e1aeSJan Lentfer return -1;
38046d49e1aeSJan Lentfer }
38053ff40c12SJohn Marino if (pkcs11_module_path != NULL) {
38063ff40c12SJohn Marino pkcs11_module_path_copy = os_strdup(pkcs11_module_path);
38073ff40c12SJohn Marino if (pkcs11_module_path_copy == NULL) {
38083ff40c12SJohn Marino os_free(pkcs11_engine_path_copy);
38096d49e1aeSJan Lentfer return -1;
38106d49e1aeSJan Lentfer }
38116d49e1aeSJan Lentfer }
38126d49e1aeSJan Lentfer
38133ff40c12SJohn Marino os_free(wpa_s->conf->pkcs11_engine_path);
38143ff40c12SJohn Marino os_free(wpa_s->conf->pkcs11_module_path);
38153ff40c12SJohn Marino wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path_copy;
38163ff40c12SJohn Marino wpa_s->conf->pkcs11_module_path = pkcs11_module_path_copy;
38176d49e1aeSJan Lentfer
38183ff40c12SJohn Marino wpa_sm_set_eapol(wpa_s->wpa, NULL);
38193ff40c12SJohn Marino eapol_sm_deinit(wpa_s->eapol);
38203ff40c12SJohn Marino wpa_s->eapol = NULL;
38213ff40c12SJohn Marino if (wpa_supplicant_init_eapol(wpa_s)) {
38223ff40c12SJohn Marino /* Error -> Reset paths to the default value (NULL) once. */
38233ff40c12SJohn Marino if (pkcs11_engine_path != NULL && pkcs11_module_path != NULL)
38243ff40c12SJohn Marino wpas_set_pkcs11_engine_and_module_path(wpa_s, NULL,
38253ff40c12SJohn Marino NULL);
38263ff40c12SJohn Marino
38276d49e1aeSJan Lentfer return -1;
38286d49e1aeSJan Lentfer }
38293ff40c12SJohn Marino wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
38306d49e1aeSJan Lentfer
38316d49e1aeSJan Lentfer return 0;
38326d49e1aeSJan Lentfer }
38336d49e1aeSJan Lentfer
38346d49e1aeSJan Lentfer
38356d49e1aeSJan Lentfer /**
38363ff40c12SJohn Marino * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
38373ff40c12SJohn Marino * @wpa_s: wpa_supplicant structure for a network interface
38383ff40c12SJohn Marino * @ap_scan: AP scan mode
38393ff40c12SJohn Marino * Returns: 0 if succeed or -1 if ap_scan has an invalid value
38406d49e1aeSJan Lentfer *
38416d49e1aeSJan Lentfer */
wpa_supplicant_set_ap_scan(struct wpa_supplicant * wpa_s,int ap_scan)38423ff40c12SJohn Marino int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
38436d49e1aeSJan Lentfer {
38446d49e1aeSJan Lentfer
38453ff40c12SJohn Marino int old_ap_scan;
38463ff40c12SJohn Marino
38473ff40c12SJohn Marino if (ap_scan < 0 || ap_scan > 2)
38483ff40c12SJohn Marino return -1;
38493ff40c12SJohn Marino
3850*a1157835SDaniel Fojt if (ap_scan == 2 && os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
3851*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
3852*a1157835SDaniel Fojt "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
3853*a1157835SDaniel Fojt }
3854*a1157835SDaniel Fojt
38553ff40c12SJohn Marino #ifdef ANDROID
38563ff40c12SJohn Marino if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
38573ff40c12SJohn Marino wpa_s->wpa_state >= WPA_ASSOCIATING &&
38583ff40c12SJohn Marino wpa_s->wpa_state < WPA_COMPLETED) {
38593ff40c12SJohn Marino wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
38603ff40c12SJohn Marino "associating", wpa_s->conf->ap_scan, ap_scan);
38613ff40c12SJohn Marino return 0;
38623ff40c12SJohn Marino }
38633ff40c12SJohn Marino #endif /* ANDROID */
38643ff40c12SJohn Marino
38653ff40c12SJohn Marino old_ap_scan = wpa_s->conf->ap_scan;
38663ff40c12SJohn Marino wpa_s->conf->ap_scan = ap_scan;
38673ff40c12SJohn Marino
38683ff40c12SJohn Marino if (old_ap_scan != wpa_s->conf->ap_scan)
38693ff40c12SJohn Marino wpas_notify_ap_scan_changed(wpa_s);
38703ff40c12SJohn Marino
38713ff40c12SJohn Marino return 0;
38726d49e1aeSJan Lentfer }
38736d49e1aeSJan Lentfer
38746d49e1aeSJan Lentfer
38753ff40c12SJohn Marino /**
38763ff40c12SJohn Marino * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
38773ff40c12SJohn Marino * @wpa_s: wpa_supplicant structure for a network interface
38783ff40c12SJohn Marino * @expire_age: Expiration age in seconds
38793ff40c12SJohn Marino * Returns: 0 if succeed or -1 if expire_age has an invalid value
38803ff40c12SJohn Marino *
38813ff40c12SJohn Marino */
wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant * wpa_s,unsigned int bss_expire_age)38823ff40c12SJohn Marino int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
38833ff40c12SJohn Marino unsigned int bss_expire_age)
38843ff40c12SJohn Marino {
38853ff40c12SJohn Marino if (bss_expire_age < 10) {
38863ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
38873ff40c12SJohn Marino bss_expire_age);
38883ff40c12SJohn Marino return -1;
38893ff40c12SJohn Marino }
38903ff40c12SJohn Marino wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
38913ff40c12SJohn Marino bss_expire_age);
38923ff40c12SJohn Marino wpa_s->conf->bss_expiration_age = bss_expire_age;
38933ff40c12SJohn Marino
38943ff40c12SJohn Marino return 0;
38953ff40c12SJohn Marino }
38963ff40c12SJohn Marino
38973ff40c12SJohn Marino
38983ff40c12SJohn Marino /**
38993ff40c12SJohn Marino * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
39003ff40c12SJohn Marino * @wpa_s: wpa_supplicant structure for a network interface
39013ff40c12SJohn Marino * @expire_count: number of scans after which an unseen BSS is reclaimed
39023ff40c12SJohn Marino * Returns: 0 if succeed or -1 if expire_count has an invalid value
39033ff40c12SJohn Marino *
39043ff40c12SJohn Marino */
wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant * wpa_s,unsigned int bss_expire_count)39053ff40c12SJohn Marino int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
39063ff40c12SJohn Marino unsigned int bss_expire_count)
39073ff40c12SJohn Marino {
39083ff40c12SJohn Marino if (bss_expire_count < 1) {
39093ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
39103ff40c12SJohn Marino bss_expire_count);
39113ff40c12SJohn Marino return -1;
39123ff40c12SJohn Marino }
39133ff40c12SJohn Marino wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
39143ff40c12SJohn Marino bss_expire_count);
39153ff40c12SJohn Marino wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
39163ff40c12SJohn Marino
39173ff40c12SJohn Marino return 0;
39183ff40c12SJohn Marino }
39193ff40c12SJohn Marino
39203ff40c12SJohn Marino
39213ff40c12SJohn Marino /**
39223ff40c12SJohn Marino * wpa_supplicant_set_scan_interval - Set scan interval
39233ff40c12SJohn Marino * @wpa_s: wpa_supplicant structure for a network interface
39243ff40c12SJohn Marino * @scan_interval: scan interval in seconds
39253ff40c12SJohn Marino * Returns: 0 if succeed or -1 if scan_interval has an invalid value
39263ff40c12SJohn Marino *
39273ff40c12SJohn Marino */
wpa_supplicant_set_scan_interval(struct wpa_supplicant * wpa_s,int scan_interval)39283ff40c12SJohn Marino int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
39293ff40c12SJohn Marino int scan_interval)
39303ff40c12SJohn Marino {
39313ff40c12SJohn Marino if (scan_interval < 0) {
39323ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
39333ff40c12SJohn Marino scan_interval);
39343ff40c12SJohn Marino return -1;
39353ff40c12SJohn Marino }
39363ff40c12SJohn Marino wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
39373ff40c12SJohn Marino scan_interval);
39383ff40c12SJohn Marino wpa_supplicant_update_scan_int(wpa_s, scan_interval);
39393ff40c12SJohn Marino
39403ff40c12SJohn Marino return 0;
39413ff40c12SJohn Marino }
39423ff40c12SJohn Marino
39433ff40c12SJohn Marino
39443ff40c12SJohn Marino /**
39453ff40c12SJohn Marino * wpa_supplicant_set_debug_params - Set global debug params
39463ff40c12SJohn Marino * @global: wpa_global structure
39473ff40c12SJohn Marino * @debug_level: debug level
39483ff40c12SJohn Marino * @debug_timestamp: determines if show timestamp in debug data
39493ff40c12SJohn Marino * @debug_show_keys: determines if show keys in debug data
39503ff40c12SJohn Marino * Returns: 0 if succeed or -1 if debug_level has wrong value
39513ff40c12SJohn Marino */
wpa_supplicant_set_debug_params(struct wpa_global * global,int debug_level,int debug_timestamp,int debug_show_keys)39523ff40c12SJohn Marino int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
39533ff40c12SJohn Marino int debug_timestamp, int debug_show_keys)
39543ff40c12SJohn Marino {
39553ff40c12SJohn Marino
39563ff40c12SJohn Marino int old_level, old_timestamp, old_show_keys;
39573ff40c12SJohn Marino
39583ff40c12SJohn Marino /* check for allowed debuglevels */
39593ff40c12SJohn Marino if (debug_level != MSG_EXCESSIVE &&
39603ff40c12SJohn Marino debug_level != MSG_MSGDUMP &&
39613ff40c12SJohn Marino debug_level != MSG_DEBUG &&
39623ff40c12SJohn Marino debug_level != MSG_INFO &&
39633ff40c12SJohn Marino debug_level != MSG_WARNING &&
39643ff40c12SJohn Marino debug_level != MSG_ERROR)
39653ff40c12SJohn Marino return -1;
39663ff40c12SJohn Marino
39673ff40c12SJohn Marino old_level = wpa_debug_level;
39683ff40c12SJohn Marino old_timestamp = wpa_debug_timestamp;
39693ff40c12SJohn Marino old_show_keys = wpa_debug_show_keys;
39703ff40c12SJohn Marino
39713ff40c12SJohn Marino wpa_debug_level = debug_level;
39723ff40c12SJohn Marino wpa_debug_timestamp = debug_timestamp ? 1 : 0;
39733ff40c12SJohn Marino wpa_debug_show_keys = debug_show_keys ? 1 : 0;
39743ff40c12SJohn Marino
39753ff40c12SJohn Marino if (wpa_debug_level != old_level)
39763ff40c12SJohn Marino wpas_notify_debug_level_changed(global);
39773ff40c12SJohn Marino if (wpa_debug_timestamp != old_timestamp)
39783ff40c12SJohn Marino wpas_notify_debug_timestamp_changed(global);
39793ff40c12SJohn Marino if (wpa_debug_show_keys != old_show_keys)
39803ff40c12SJohn Marino wpas_notify_debug_show_keys_changed(global);
39813ff40c12SJohn Marino
39823ff40c12SJohn Marino return 0;
39836d49e1aeSJan Lentfer }
39846d49e1aeSJan Lentfer
39856d49e1aeSJan Lentfer
3986*a1157835SDaniel Fojt #ifdef CONFIG_OWE
owe_trans_ssid_match(struct wpa_supplicant * wpa_s,const u8 * bssid,const u8 * entry_ssid,size_t entry_ssid_len)3987*a1157835SDaniel Fojt static int owe_trans_ssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid,
3988*a1157835SDaniel Fojt const u8 *entry_ssid, size_t entry_ssid_len)
3989*a1157835SDaniel Fojt {
3990*a1157835SDaniel Fojt const u8 *owe, *pos, *end;
3991*a1157835SDaniel Fojt u8 ssid_len;
3992*a1157835SDaniel Fojt struct wpa_bss *bss;
3993*a1157835SDaniel Fojt
3994*a1157835SDaniel Fojt /* Check network profile SSID aganst the SSID in the
3995*a1157835SDaniel Fojt * OWE Transition Mode element. */
3996*a1157835SDaniel Fojt
3997*a1157835SDaniel Fojt bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
3998*a1157835SDaniel Fojt if (!bss)
3999*a1157835SDaniel Fojt return 0;
4000*a1157835SDaniel Fojt
4001*a1157835SDaniel Fojt owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
4002*a1157835SDaniel Fojt if (!owe)
4003*a1157835SDaniel Fojt return 0;
4004*a1157835SDaniel Fojt
4005*a1157835SDaniel Fojt pos = owe + 6;
4006*a1157835SDaniel Fojt end = owe + 2 + owe[1];
4007*a1157835SDaniel Fojt
4008*a1157835SDaniel Fojt if (end - pos < ETH_ALEN + 1)
4009*a1157835SDaniel Fojt return 0;
4010*a1157835SDaniel Fojt pos += ETH_ALEN;
4011*a1157835SDaniel Fojt ssid_len = *pos++;
4012*a1157835SDaniel Fojt if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
4013*a1157835SDaniel Fojt return 0;
4014*a1157835SDaniel Fojt
4015*a1157835SDaniel Fojt return entry_ssid_len == ssid_len &&
4016*a1157835SDaniel Fojt os_memcmp(pos, entry_ssid, ssid_len) == 0;
4017*a1157835SDaniel Fojt }
4018*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
4019*a1157835SDaniel Fojt
4020*a1157835SDaniel Fojt
40216d49e1aeSJan Lentfer /**
40226d49e1aeSJan Lentfer * wpa_supplicant_get_ssid - Get a pointer to the current network structure
40236d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
40246d49e1aeSJan Lentfer * Returns: A pointer to the current network structure or %NULL on failure
40256d49e1aeSJan Lentfer */
wpa_supplicant_get_ssid(struct wpa_supplicant * wpa_s)40266d49e1aeSJan Lentfer struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
40276d49e1aeSJan Lentfer {
40286d49e1aeSJan Lentfer struct wpa_ssid *entry;
4029*a1157835SDaniel Fojt u8 ssid[SSID_MAX_LEN];
40306d49e1aeSJan Lentfer int res;
40316d49e1aeSJan Lentfer size_t ssid_len;
40326d49e1aeSJan Lentfer u8 bssid[ETH_ALEN];
40336d49e1aeSJan Lentfer int wired;
40346d49e1aeSJan Lentfer
40356d49e1aeSJan Lentfer res = wpa_drv_get_ssid(wpa_s, ssid);
40366d49e1aeSJan Lentfer if (res < 0) {
40373ff40c12SJohn Marino wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
40383ff40c12SJohn Marino "driver");
40396d49e1aeSJan Lentfer return NULL;
40406d49e1aeSJan Lentfer }
40416d49e1aeSJan Lentfer ssid_len = res;
40426d49e1aeSJan Lentfer
40433ff40c12SJohn Marino if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
40443ff40c12SJohn Marino wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
40453ff40c12SJohn Marino "driver");
40466d49e1aeSJan Lentfer return NULL;
40476d49e1aeSJan Lentfer }
40486d49e1aeSJan Lentfer
40493ff40c12SJohn Marino wired = wpa_s->conf->ap_scan == 0 &&
40503ff40c12SJohn Marino (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
40516d49e1aeSJan Lentfer
40526d49e1aeSJan Lentfer entry = wpa_s->conf->ssid;
40536d49e1aeSJan Lentfer while (entry) {
40543ff40c12SJohn Marino if (!wpas_network_disabled(wpa_s, entry) &&
40556d49e1aeSJan Lentfer ((ssid_len == entry->ssid_len &&
4056*a1157835SDaniel Fojt (!entry->ssid ||
4057*a1157835SDaniel Fojt os_memcmp(ssid, entry->ssid, ssid_len) == 0)) ||
4058*a1157835SDaniel Fojt wired) &&
40596d49e1aeSJan Lentfer (!entry->bssid_set ||
40606d49e1aeSJan Lentfer os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
40616d49e1aeSJan Lentfer return entry;
40626d49e1aeSJan Lentfer #ifdef CONFIG_WPS
40633ff40c12SJohn Marino if (!wpas_network_disabled(wpa_s, entry) &&
40646d49e1aeSJan Lentfer (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
40656d49e1aeSJan Lentfer (entry->ssid == NULL || entry->ssid_len == 0) &&
40666d49e1aeSJan Lentfer (!entry->bssid_set ||
40676d49e1aeSJan Lentfer os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
40686d49e1aeSJan Lentfer return entry;
40696d49e1aeSJan Lentfer #endif /* CONFIG_WPS */
40703ff40c12SJohn Marino
4071*a1157835SDaniel Fojt #ifdef CONFIG_OWE
4072*a1157835SDaniel Fojt if (!wpas_network_disabled(wpa_s, entry) &&
4073*a1157835SDaniel Fojt owe_trans_ssid_match(wpa_s, bssid, entry->ssid,
4074*a1157835SDaniel Fojt entry->ssid_len) &&
4075*a1157835SDaniel Fojt (!entry->bssid_set ||
4076*a1157835SDaniel Fojt os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
4077*a1157835SDaniel Fojt return entry;
4078*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
4079*a1157835SDaniel Fojt
40803ff40c12SJohn Marino if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
40813ff40c12SJohn Marino entry->ssid_len == 0 &&
40823ff40c12SJohn Marino os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
40833ff40c12SJohn Marino return entry;
40843ff40c12SJohn Marino
40856d49e1aeSJan Lentfer entry = entry->next;
40866d49e1aeSJan Lentfer }
40876d49e1aeSJan Lentfer
40886d49e1aeSJan Lentfer return NULL;
40896d49e1aeSJan Lentfer }
40906d49e1aeSJan Lentfer
40916d49e1aeSJan Lentfer
select_driver(struct wpa_supplicant * wpa_s,int i)40923ff40c12SJohn Marino static int select_driver(struct wpa_supplicant *wpa_s, int i)
40933ff40c12SJohn Marino {
40943ff40c12SJohn Marino struct wpa_global *global = wpa_s->global;
40953ff40c12SJohn Marino
40963ff40c12SJohn Marino if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
4097*a1157835SDaniel Fojt global->drv_priv[i] = wpa_drivers[i]->global_init(global);
40983ff40c12SJohn Marino if (global->drv_priv[i] == NULL) {
40993ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to initialize driver "
41003ff40c12SJohn Marino "'%s'", wpa_drivers[i]->name);
41013ff40c12SJohn Marino return -1;
41023ff40c12SJohn Marino }
41033ff40c12SJohn Marino }
41043ff40c12SJohn Marino
41053ff40c12SJohn Marino wpa_s->driver = wpa_drivers[i];
41063ff40c12SJohn Marino wpa_s->global_drv_priv = global->drv_priv[i];
41073ff40c12SJohn Marino
41083ff40c12SJohn Marino return 0;
41093ff40c12SJohn Marino }
41103ff40c12SJohn Marino
41113ff40c12SJohn Marino
wpa_supplicant_set_driver(struct wpa_supplicant * wpa_s,const char * name)41126d49e1aeSJan Lentfer static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
41136d49e1aeSJan Lentfer const char *name)
41146d49e1aeSJan Lentfer {
41156d49e1aeSJan Lentfer int i;
41163ff40c12SJohn Marino size_t len;
41173ff40c12SJohn Marino const char *pos, *driver = name;
41186d49e1aeSJan Lentfer
41196d49e1aeSJan Lentfer if (wpa_s == NULL)
41206d49e1aeSJan Lentfer return -1;
41216d49e1aeSJan Lentfer
41223ff40c12SJohn Marino if (wpa_drivers[0] == NULL) {
41233ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "
41243ff40c12SJohn Marino "wpa_supplicant");
41256d49e1aeSJan Lentfer return -1;
41266d49e1aeSJan Lentfer }
41276d49e1aeSJan Lentfer
41286d49e1aeSJan Lentfer if (name == NULL) {
41296d49e1aeSJan Lentfer /* default to first driver in the list */
41303ff40c12SJohn Marino return select_driver(wpa_s, 0);
41316d49e1aeSJan Lentfer }
41326d49e1aeSJan Lentfer
41333ff40c12SJohn Marino do {
41343ff40c12SJohn Marino pos = os_strchr(driver, ',');
41353ff40c12SJohn Marino if (pos)
41363ff40c12SJohn Marino len = pos - driver;
41373ff40c12SJohn Marino else
41383ff40c12SJohn Marino len = os_strlen(driver);
41393ff40c12SJohn Marino
41403ff40c12SJohn Marino for (i = 0; wpa_drivers[i]; i++) {
41413ff40c12SJohn Marino if (os_strlen(wpa_drivers[i]->name) == len &&
41423ff40c12SJohn Marino os_strncmp(driver, wpa_drivers[i]->name, len) ==
41433ff40c12SJohn Marino 0) {
41443ff40c12SJohn Marino /* First driver that succeeds wins */
41453ff40c12SJohn Marino if (select_driver(wpa_s, i) == 0)
41466d49e1aeSJan Lentfer return 0;
41476d49e1aeSJan Lentfer }
41486d49e1aeSJan Lentfer }
41496d49e1aeSJan Lentfer
41503ff40c12SJohn Marino driver = pos + 1;
41513ff40c12SJohn Marino } while (pos);
41523ff40c12SJohn Marino
41533ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);
41546d49e1aeSJan Lentfer return -1;
41556d49e1aeSJan Lentfer }
41566d49e1aeSJan Lentfer
41576d49e1aeSJan Lentfer
41583ff40c12SJohn Marino /**
41593ff40c12SJohn Marino * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
41603ff40c12SJohn Marino * @ctx: Context pointer (wpa_s); this is the ctx variable registered
41613ff40c12SJohn Marino * with struct wpa_driver_ops::init()
41623ff40c12SJohn Marino * @src_addr: Source address of the EAPOL frame
41633ff40c12SJohn Marino * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
41643ff40c12SJohn Marino * @len: Length of the EAPOL data
41653ff40c12SJohn Marino *
41663ff40c12SJohn Marino * This function is called for each received EAPOL frame. Most driver
41673ff40c12SJohn Marino * interfaces rely on more generic OS mechanism for receiving frames through
41683ff40c12SJohn Marino * l2_packet, but if such a mechanism is not available, the driver wrapper may
41693ff40c12SJohn Marino * take care of received EAPOL frames and deliver them to the core supplicant
41703ff40c12SJohn Marino * code by calling this function.
41713ff40c12SJohn Marino */
wpa_supplicant_rx_eapol(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)41726d49e1aeSJan Lentfer void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
41736d49e1aeSJan Lentfer const u8 *buf, size_t len)
41746d49e1aeSJan Lentfer {
41756d49e1aeSJan Lentfer struct wpa_supplicant *wpa_s = ctx;
41766d49e1aeSJan Lentfer
41773ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
41786d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
41796d49e1aeSJan Lentfer
4180*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
4181*a1157835SDaniel Fojt if (wpa_s->ignore_auth_resp) {
4182*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
41833ff40c12SJohn Marino return;
41843ff40c12SJohn Marino }
4185*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
41863ff40c12SJohn Marino
41873ff40c12SJohn Marino if (wpa_s->wpa_state < WPA_ASSOCIATED ||
41883ff40c12SJohn Marino (wpa_s->last_eapol_matches_bssid &&
41893ff40c12SJohn Marino #ifdef CONFIG_AP
41903ff40c12SJohn Marino !wpa_s->ap_iface &&
41913ff40c12SJohn Marino #endif /* CONFIG_AP */
41923ff40c12SJohn Marino os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
41936d49e1aeSJan Lentfer /*
41946d49e1aeSJan Lentfer * There is possible race condition between receiving the
41956d49e1aeSJan Lentfer * association event and the EAPOL frame since they are coming
41966d49e1aeSJan Lentfer * through different paths from the driver. In order to avoid
41976d49e1aeSJan Lentfer * issues in trying to process the EAPOL frame before receiving
41986d49e1aeSJan Lentfer * association information, lets queue it for processing until
41993ff40c12SJohn Marino * the association event is received. This may also be needed in
42003ff40c12SJohn Marino * driver-based roaming case, so also use src_addr != BSSID as a
42013ff40c12SJohn Marino * trigger if we have previously confirmed that the
42023ff40c12SJohn Marino * Authenticator uses BSSID as the src_addr (which is not the
42033ff40c12SJohn Marino * case with wired IEEE 802.1X).
42046d49e1aeSJan Lentfer */
42053ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
42063ff40c12SJohn Marino "of received EAPOL frame (state=%s bssid=" MACSTR ")",
42073ff40c12SJohn Marino wpa_supplicant_state_txt(wpa_s->wpa_state),
42083ff40c12SJohn Marino MAC2STR(wpa_s->bssid));
42096d49e1aeSJan Lentfer wpabuf_free(wpa_s->pending_eapol_rx);
42106d49e1aeSJan Lentfer wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
42116d49e1aeSJan Lentfer if (wpa_s->pending_eapol_rx) {
42123ff40c12SJohn Marino os_get_reltime(&wpa_s->pending_eapol_rx_time);
42136d49e1aeSJan Lentfer os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
42146d49e1aeSJan Lentfer ETH_ALEN);
42156d49e1aeSJan Lentfer }
42166d49e1aeSJan Lentfer return;
42176d49e1aeSJan Lentfer }
42186d49e1aeSJan Lentfer
42193ff40c12SJohn Marino wpa_s->last_eapol_matches_bssid =
42203ff40c12SJohn Marino os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;
42213ff40c12SJohn Marino
42223ff40c12SJohn Marino #ifdef CONFIG_AP
42233ff40c12SJohn Marino if (wpa_s->ap_iface) {
42243ff40c12SJohn Marino wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
42253ff40c12SJohn Marino return;
42263ff40c12SJohn Marino }
42273ff40c12SJohn Marino #endif /* CONFIG_AP */
42283ff40c12SJohn Marino
42296d49e1aeSJan Lentfer if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
42303ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
42316d49e1aeSJan Lentfer "no key management is configured");
42326d49e1aeSJan Lentfer return;
42336d49e1aeSJan Lentfer }
42346d49e1aeSJan Lentfer
42356d49e1aeSJan Lentfer if (wpa_s->eapol_received == 0 &&
4236*a1157835SDaniel Fojt (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) ||
42376d49e1aeSJan Lentfer !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
42383ff40c12SJohn Marino wpa_s->wpa_state != WPA_COMPLETED) &&
42393ff40c12SJohn Marino (wpa_s->current_ssid == NULL ||
4240*a1157835SDaniel Fojt wpa_s->current_ssid->mode != WPAS_MODE_IBSS)) {
42416d49e1aeSJan Lentfer /* Timeout for completing IEEE 802.1X and WPA authentication */
4242*a1157835SDaniel Fojt int timeout = 10;
4243*a1157835SDaniel Fojt
4244*a1157835SDaniel Fojt if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
42456d49e1aeSJan Lentfer wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
4246*a1157835SDaniel Fojt wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
4247*a1157835SDaniel Fojt /* Use longer timeout for IEEE 802.1X/EAP */
4248*a1157835SDaniel Fojt timeout = 70;
4249*a1157835SDaniel Fojt }
4250*a1157835SDaniel Fojt
4251*a1157835SDaniel Fojt #ifdef CONFIG_WPS
4252*a1157835SDaniel Fojt if (wpa_s->current_ssid && wpa_s->current_bss &&
4253*a1157835SDaniel Fojt (wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
4254*a1157835SDaniel Fojt eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
4255*a1157835SDaniel Fojt /*
4256*a1157835SDaniel Fojt * Use shorter timeout if going through WPS AP iteration
4257*a1157835SDaniel Fojt * for PIN config method with an AP that does not
4258*a1157835SDaniel Fojt * advertise Selected Registrar.
4259*a1157835SDaniel Fojt */
4260*a1157835SDaniel Fojt struct wpabuf *wps_ie;
4261*a1157835SDaniel Fojt
4262*a1157835SDaniel Fojt wps_ie = wpa_bss_get_vendor_ie_multi(
4263*a1157835SDaniel Fojt wpa_s->current_bss, WPS_IE_VENDOR_TYPE);
4264*a1157835SDaniel Fojt if (wps_ie &&
4265*a1157835SDaniel Fojt !wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1))
4266*a1157835SDaniel Fojt timeout = 10;
4267*a1157835SDaniel Fojt wpabuf_free(wps_ie);
4268*a1157835SDaniel Fojt }
4269*a1157835SDaniel Fojt #endif /* CONFIG_WPS */
4270*a1157835SDaniel Fojt
4271*a1157835SDaniel Fojt wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
42726d49e1aeSJan Lentfer }
42736d49e1aeSJan Lentfer wpa_s->eapol_received++;
42746d49e1aeSJan Lentfer
42756d49e1aeSJan Lentfer if (wpa_s->countermeasures) {
42763ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
42773ff40c12SJohn Marino "EAPOL packet");
42786d49e1aeSJan Lentfer return;
42796d49e1aeSJan Lentfer }
42806d49e1aeSJan Lentfer
42813ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
42823ff40c12SJohn Marino if (wpa_s->current_ssid &&
42833ff40c12SJohn Marino wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
42843ff40c12SJohn Marino ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
42853ff40c12SJohn Marino return;
42863ff40c12SJohn Marino }
42873ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
42883ff40c12SJohn Marino
42896d49e1aeSJan Lentfer /* Source address of the incoming EAPOL frame could be compared to the
42906d49e1aeSJan Lentfer * current BSSID. However, it is possible that a centralized
42916d49e1aeSJan Lentfer * Authenticator could be using another MAC address than the BSSID of
42926d49e1aeSJan Lentfer * an AP, so just allow any address to be used for now. The replies are
42936d49e1aeSJan Lentfer * still sent to the current BSSID (if available), though. */
42946d49e1aeSJan Lentfer
42956d49e1aeSJan Lentfer os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
42966d49e1aeSJan Lentfer if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
4297*a1157835SDaniel Fojt wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
4298*a1157835SDaniel Fojt wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
42996d49e1aeSJan Lentfer eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
43006d49e1aeSJan Lentfer return;
43016d49e1aeSJan Lentfer wpa_drv_poll(wpa_s);
4302*a1157835SDaniel Fojt if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
43036d49e1aeSJan Lentfer wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
43046d49e1aeSJan Lentfer else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
43056d49e1aeSJan Lentfer /*
43066d49e1aeSJan Lentfer * Set portValid = TRUE here since we are going to skip 4-way
43076d49e1aeSJan Lentfer * handshake processing which would normally set portValid. We
43086d49e1aeSJan Lentfer * need this to allow the EAPOL state machines to be completed
43096d49e1aeSJan Lentfer * without going through EAPOL-Key handshake.
43106d49e1aeSJan Lentfer */
43116d49e1aeSJan Lentfer eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
43126d49e1aeSJan Lentfer }
43136d49e1aeSJan Lentfer }
43146d49e1aeSJan Lentfer
43156d49e1aeSJan Lentfer
wpa_supplicant_update_mac_addr(struct wpa_supplicant * wpa_s)43163ff40c12SJohn Marino int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
43176d49e1aeSJan Lentfer {
4318*a1157835SDaniel Fojt if ((!wpa_s->p2p_mgmt ||
4319*a1157835SDaniel Fojt !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
4320*a1157835SDaniel Fojt !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
43213ff40c12SJohn Marino l2_packet_deinit(wpa_s->l2);
43223ff40c12SJohn Marino wpa_s->l2 = l2_packet_init(wpa_s->ifname,
43233ff40c12SJohn Marino wpa_drv_get_mac_addr(wpa_s),
43243ff40c12SJohn Marino ETH_P_EAPOL,
43253ff40c12SJohn Marino wpa_supplicant_rx_eapol, wpa_s, 0);
43263ff40c12SJohn Marino if (wpa_s->l2 == NULL)
43273ff40c12SJohn Marino return -1;
4328*a1157835SDaniel Fojt
4329*a1157835SDaniel Fojt if (l2_packet_set_packet_filter(wpa_s->l2,
4330*a1157835SDaniel Fojt L2_PACKET_FILTER_PKTTYPE))
4331*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
4332*a1157835SDaniel Fojt "Failed to attach pkt_type filter");
43333ff40c12SJohn Marino } else {
43343ff40c12SJohn Marino const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
43353ff40c12SJohn Marino if (addr)
43363ff40c12SJohn Marino os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
43373ff40c12SJohn Marino }
43383ff40c12SJohn Marino
43393ff40c12SJohn Marino if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
43403ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
43413ff40c12SJohn Marino return -1;
43423ff40c12SJohn Marino }
43433ff40c12SJohn Marino
4344*a1157835SDaniel Fojt wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
4345*a1157835SDaniel Fojt
43463ff40c12SJohn Marino return 0;
43476d49e1aeSJan Lentfer }
43486d49e1aeSJan Lentfer
43496d49e1aeSJan Lentfer
wpa_supplicant_rx_eapol_bridge(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)43503ff40c12SJohn Marino static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
43513ff40c12SJohn Marino const u8 *buf, size_t len)
43526d49e1aeSJan Lentfer {
43536d49e1aeSJan Lentfer struct wpa_supplicant *wpa_s = ctx;
43543ff40c12SJohn Marino const struct l2_ethhdr *eth;
43553ff40c12SJohn Marino
43563ff40c12SJohn Marino if (len < sizeof(*eth))
43573ff40c12SJohn Marino return;
43583ff40c12SJohn Marino eth = (const struct l2_ethhdr *) buf;
43593ff40c12SJohn Marino
43603ff40c12SJohn Marino if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
43613ff40c12SJohn Marino !(eth->h_dest[0] & 0x01)) {
43623ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
43633ff40c12SJohn Marino " (bridge - not for this interface - ignore)",
43643ff40c12SJohn Marino MAC2STR(src_addr), MAC2STR(eth->h_dest));
43653ff40c12SJohn Marino return;
43663ff40c12SJohn Marino }
43673ff40c12SJohn Marino
43683ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
43693ff40c12SJohn Marino " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
43703ff40c12SJohn Marino wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
43713ff40c12SJohn Marino len - sizeof(*eth));
43726d49e1aeSJan Lentfer }
43736d49e1aeSJan Lentfer
43746d49e1aeSJan Lentfer
43756d49e1aeSJan Lentfer /**
43766d49e1aeSJan Lentfer * wpa_supplicant_driver_init - Initialize driver interface parameters
43776d49e1aeSJan Lentfer * @wpa_s: Pointer to wpa_supplicant data
43786d49e1aeSJan Lentfer * Returns: 0 on success, -1 on failure
43796d49e1aeSJan Lentfer *
43806d49e1aeSJan Lentfer * This function is called to initialize driver interface parameters.
43816d49e1aeSJan Lentfer * wpa_drv_init() must have been called before this function to initialize the
43826d49e1aeSJan Lentfer * driver interface.
43836d49e1aeSJan Lentfer */
wpa_supplicant_driver_init(struct wpa_supplicant * wpa_s)43846d49e1aeSJan Lentfer int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
43856d49e1aeSJan Lentfer {
43866d49e1aeSJan Lentfer static int interface_count = 0;
43876d49e1aeSJan Lentfer
43883ff40c12SJohn Marino if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
43896d49e1aeSJan Lentfer return -1;
43906d49e1aeSJan Lentfer
43913ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
43926d49e1aeSJan Lentfer MAC2STR(wpa_s->own_addr));
4393*a1157835SDaniel Fojt os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
43943ff40c12SJohn Marino wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
43956d49e1aeSJan Lentfer
43966d49e1aeSJan Lentfer if (wpa_s->bridge_ifname[0]) {
43973ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
43983ff40c12SJohn Marino "interface '%s'", wpa_s->bridge_ifname);
4399*a1157835SDaniel Fojt wpa_s->l2_br = l2_packet_init_bridge(
4400*a1157835SDaniel Fojt wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
4401*a1157835SDaniel Fojt ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
44026d49e1aeSJan Lentfer if (wpa_s->l2_br == NULL) {
44033ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
44046d49e1aeSJan Lentfer "connection for the bridge interface '%s'",
44056d49e1aeSJan Lentfer wpa_s->bridge_ifname);
44066d49e1aeSJan Lentfer return -1;
44076d49e1aeSJan Lentfer }
44086d49e1aeSJan Lentfer }
44096d49e1aeSJan Lentfer
4410*a1157835SDaniel Fojt if (wpa_s->conf->ap_scan == 2 &&
4411*a1157835SDaniel Fojt os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
4412*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
4413*a1157835SDaniel Fojt "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
4414*a1157835SDaniel Fojt }
4415*a1157835SDaniel Fojt
44166d49e1aeSJan Lentfer wpa_clear_keys(wpa_s, NULL);
44176d49e1aeSJan Lentfer
44186d49e1aeSJan Lentfer /* Make sure that TKIP countermeasures are not left enabled (could
44196d49e1aeSJan Lentfer * happen if wpa_supplicant is killed during countermeasures. */
44206d49e1aeSJan Lentfer wpa_drv_set_countermeasures(wpa_s, 0);
44216d49e1aeSJan Lentfer
44223ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver");
44236d49e1aeSJan Lentfer wpa_drv_flush_pmkid(wpa_s);
44246d49e1aeSJan Lentfer
44253ff40c12SJohn Marino wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
44263ff40c12SJohn Marino wpa_s->prev_scan_wildcard = 0;
44273ff40c12SJohn Marino
44283ff40c12SJohn Marino if (wpa_supplicant_enabled_networks(wpa_s)) {
44293ff40c12SJohn Marino if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
44303ff40c12SJohn Marino wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
44313ff40c12SJohn Marino interface_count = 0;
44323ff40c12SJohn Marino }
4433*a1157835SDaniel Fojt #ifndef ANDROID
4434*a1157835SDaniel Fojt if (!wpa_s->p2p_mgmt &&
4435*a1157835SDaniel Fojt wpa_supplicant_delayed_sched_scan(wpa_s,
4436*a1157835SDaniel Fojt interface_count % 3,
44373ff40c12SJohn Marino 100000))
4438*a1157835SDaniel Fojt wpa_supplicant_req_scan(wpa_s, interface_count % 3,
44393ff40c12SJohn Marino 100000);
4440*a1157835SDaniel Fojt #endif /* ANDROID */
44416d49e1aeSJan Lentfer interface_count++;
44423ff40c12SJohn Marino } else
44433ff40c12SJohn Marino wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
44446d49e1aeSJan Lentfer
44456d49e1aeSJan Lentfer return 0;
44466d49e1aeSJan Lentfer }
44476d49e1aeSJan Lentfer
44486d49e1aeSJan Lentfer
wpa_supplicant_daemon(const char * pid_file)44496d49e1aeSJan Lentfer static int wpa_supplicant_daemon(const char *pid_file)
44506d49e1aeSJan Lentfer {
44516d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Daemonize..");
44526d49e1aeSJan Lentfer return os_daemonize(pid_file);
44536d49e1aeSJan Lentfer }
44546d49e1aeSJan Lentfer
44556d49e1aeSJan Lentfer
4456*a1157835SDaniel Fojt static struct wpa_supplicant *
wpa_supplicant_alloc(struct wpa_supplicant * parent)4457*a1157835SDaniel Fojt wpa_supplicant_alloc(struct wpa_supplicant *parent)
44586d49e1aeSJan Lentfer {
44596d49e1aeSJan Lentfer struct wpa_supplicant *wpa_s;
44606d49e1aeSJan Lentfer
44616d49e1aeSJan Lentfer wpa_s = os_zalloc(sizeof(*wpa_s));
44626d49e1aeSJan Lentfer if (wpa_s == NULL)
44636d49e1aeSJan Lentfer return NULL;
44643ff40c12SJohn Marino wpa_s->scan_req = INITIAL_SCAN_REQ;
44653ff40c12SJohn Marino wpa_s->scan_interval = 5;
44663ff40c12SJohn Marino wpa_s->new_connection = 1;
4467*a1157835SDaniel Fojt wpa_s->parent = parent ? parent : wpa_s;
4468*a1157835SDaniel Fojt wpa_s->p2pdev = wpa_s->parent;
44693ff40c12SJohn Marino wpa_s->sched_scanning = 0;
44706d49e1aeSJan Lentfer
4471*a1157835SDaniel Fojt dl_list_init(&wpa_s->bss_tmp_disallowed);
4472*a1157835SDaniel Fojt dl_list_init(&wpa_s->fils_hlp_req);
4473*a1157835SDaniel Fojt
44746d49e1aeSJan Lentfer return wpa_s;
44756d49e1aeSJan Lentfer }
44766d49e1aeSJan Lentfer
44776d49e1aeSJan Lentfer
44783ff40c12SJohn Marino #ifdef CONFIG_HT_OVERRIDES
44793ff40c12SJohn Marino
wpa_set_htcap_mcs(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,const char * ht_mcs)44803ff40c12SJohn Marino static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
44813ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps,
44823ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps_mask,
44833ff40c12SJohn Marino const char *ht_mcs)
44843ff40c12SJohn Marino {
44853ff40c12SJohn Marino /* parse ht_mcs into hex array */
44863ff40c12SJohn Marino int i;
44873ff40c12SJohn Marino const char *tmp = ht_mcs;
44883ff40c12SJohn Marino char *end = NULL;
44893ff40c12SJohn Marino
44903ff40c12SJohn Marino /* If ht_mcs is null, do not set anything */
44913ff40c12SJohn Marino if (!ht_mcs)
44923ff40c12SJohn Marino return 0;
44933ff40c12SJohn Marino
44943ff40c12SJohn Marino /* This is what we are setting in the kernel */
44953ff40c12SJohn Marino os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
44963ff40c12SJohn Marino
44973ff40c12SJohn Marino wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
44983ff40c12SJohn Marino
44993ff40c12SJohn Marino for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
4500*a1157835SDaniel Fojt long v;
4501*a1157835SDaniel Fojt
45023ff40c12SJohn Marino errno = 0;
4503*a1157835SDaniel Fojt v = strtol(tmp, &end, 16);
4504*a1157835SDaniel Fojt
45053ff40c12SJohn Marino if (errno == 0) {
45063ff40c12SJohn Marino wpa_msg(wpa_s, MSG_DEBUG,
45073ff40c12SJohn Marino "htcap value[%i]: %ld end: %p tmp: %p",
45083ff40c12SJohn Marino i, v, end, tmp);
45093ff40c12SJohn Marino if (end == tmp)
45103ff40c12SJohn Marino break;
45113ff40c12SJohn Marino
45123ff40c12SJohn Marino htcaps->supported_mcs_set[i] = v;
45133ff40c12SJohn Marino tmp = end;
45143ff40c12SJohn Marino } else {
45153ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR,
45163ff40c12SJohn Marino "Failed to parse ht-mcs: %s, error: %s\n",
45173ff40c12SJohn Marino ht_mcs, strerror(errno));
45183ff40c12SJohn Marino return -1;
45193ff40c12SJohn Marino }
45203ff40c12SJohn Marino }
45213ff40c12SJohn Marino
45223ff40c12SJohn Marino /*
45233ff40c12SJohn Marino * If we were able to parse any values, then set mask for the MCS set.
45243ff40c12SJohn Marino */
45253ff40c12SJohn Marino if (i) {
45263ff40c12SJohn Marino os_memset(&htcaps_mask->supported_mcs_set, 0xff,
45273ff40c12SJohn Marino IEEE80211_HT_MCS_MASK_LEN - 1);
45283ff40c12SJohn Marino /* skip the 3 reserved bits */
45293ff40c12SJohn Marino htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
45303ff40c12SJohn Marino 0x1f;
45313ff40c12SJohn Marino }
45323ff40c12SJohn Marino
45333ff40c12SJohn Marino return 0;
45343ff40c12SJohn Marino }
45353ff40c12SJohn Marino
45363ff40c12SJohn Marino
wpa_disable_max_amsdu(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int disabled)45373ff40c12SJohn Marino static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
45383ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps,
45393ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps_mask,
45403ff40c12SJohn Marino int disabled)
45413ff40c12SJohn Marino {
4542*a1157835SDaniel Fojt le16 msk;
45433ff40c12SJohn Marino
45443ff40c12SJohn Marino if (disabled == -1)
45453ff40c12SJohn Marino return 0;
45463ff40c12SJohn Marino
4547*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
4548*a1157835SDaniel Fojt
45493ff40c12SJohn Marino msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
45503ff40c12SJohn Marino htcaps_mask->ht_capabilities_info |= msk;
45513ff40c12SJohn Marino if (disabled)
45523ff40c12SJohn Marino htcaps->ht_capabilities_info &= msk;
45533ff40c12SJohn Marino else
45543ff40c12SJohn Marino htcaps->ht_capabilities_info |= msk;
45553ff40c12SJohn Marino
45563ff40c12SJohn Marino return 0;
45573ff40c12SJohn Marino }
45583ff40c12SJohn Marino
45593ff40c12SJohn Marino
wpa_set_ampdu_factor(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int factor)45603ff40c12SJohn Marino static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
45613ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps,
45623ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps_mask,
45633ff40c12SJohn Marino int factor)
45643ff40c12SJohn Marino {
45653ff40c12SJohn Marino if (factor == -1)
45663ff40c12SJohn Marino return 0;
45673ff40c12SJohn Marino
4568*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
4569*a1157835SDaniel Fojt
45703ff40c12SJohn Marino if (factor < 0 || factor > 3) {
45713ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
45723ff40c12SJohn Marino "Must be 0-3 or -1", factor);
45733ff40c12SJohn Marino return -EINVAL;
45743ff40c12SJohn Marino }
45753ff40c12SJohn Marino
45763ff40c12SJohn Marino htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
45773ff40c12SJohn Marino htcaps->a_mpdu_params &= ~0x3;
45783ff40c12SJohn Marino htcaps->a_mpdu_params |= factor & 0x3;
45793ff40c12SJohn Marino
45803ff40c12SJohn Marino return 0;
45813ff40c12SJohn Marino }
45823ff40c12SJohn Marino
45833ff40c12SJohn Marino
wpa_set_ampdu_density(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int density)45843ff40c12SJohn Marino static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
45853ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps,
45863ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps_mask,
45873ff40c12SJohn Marino int density)
45883ff40c12SJohn Marino {
45893ff40c12SJohn Marino if (density == -1)
45903ff40c12SJohn Marino return 0;
45913ff40c12SJohn Marino
4592*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
4593*a1157835SDaniel Fojt
45943ff40c12SJohn Marino if (density < 0 || density > 7) {
45953ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR,
45963ff40c12SJohn Marino "ampdu_density: %d out of range. Must be 0-7 or -1.",
45973ff40c12SJohn Marino density);
45983ff40c12SJohn Marino return -EINVAL;
45993ff40c12SJohn Marino }
46003ff40c12SJohn Marino
46013ff40c12SJohn Marino htcaps_mask->a_mpdu_params |= 0x1C;
46023ff40c12SJohn Marino htcaps->a_mpdu_params &= ~(0x1C);
46033ff40c12SJohn Marino htcaps->a_mpdu_params |= (density << 2) & 0x1C;
46043ff40c12SJohn Marino
46053ff40c12SJohn Marino return 0;
46063ff40c12SJohn Marino }
46073ff40c12SJohn Marino
46083ff40c12SJohn Marino
wpa_set_disable_ht40(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int disabled)46093ff40c12SJohn Marino static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
46103ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps,
46113ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps_mask,
46123ff40c12SJohn Marino int disabled)
46133ff40c12SJohn Marino {
4614*a1157835SDaniel Fojt if (disabled)
4615*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
4616*a1157835SDaniel Fojt
4617*a1157835SDaniel Fojt set_disable_ht40(htcaps, disabled);
4618*a1157835SDaniel Fojt set_disable_ht40(htcaps_mask, 0);
4619*a1157835SDaniel Fojt
4620*a1157835SDaniel Fojt return 0;
4621*a1157835SDaniel Fojt }
4622*a1157835SDaniel Fojt
4623*a1157835SDaniel Fojt
wpa_set_disable_sgi(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int disabled)4624*a1157835SDaniel Fojt static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
4625*a1157835SDaniel Fojt struct ieee80211_ht_capabilities *htcaps,
4626*a1157835SDaniel Fojt struct ieee80211_ht_capabilities *htcaps_mask,
4627*a1157835SDaniel Fojt int disabled)
4628*a1157835SDaniel Fojt {
4629*a1157835SDaniel Fojt /* Masking these out disables SGI */
4630*a1157835SDaniel Fojt le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
46313ff40c12SJohn Marino HT_CAP_INFO_SHORT_GI40MHZ);
46323ff40c12SJohn Marino
4633*a1157835SDaniel Fojt if (disabled)
4634*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
46353ff40c12SJohn Marino
46363ff40c12SJohn Marino if (disabled)
46373ff40c12SJohn Marino htcaps->ht_capabilities_info &= ~msk;
46383ff40c12SJohn Marino else
46393ff40c12SJohn Marino htcaps->ht_capabilities_info |= msk;
46403ff40c12SJohn Marino
46413ff40c12SJohn Marino htcaps_mask->ht_capabilities_info |= msk;
46423ff40c12SJohn Marino
46433ff40c12SJohn Marino return 0;
46443ff40c12SJohn Marino }
46453ff40c12SJohn Marino
46463ff40c12SJohn Marino
wpa_set_disable_ldpc(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int disabled)4647*a1157835SDaniel Fojt static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
46483ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps,
46493ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps_mask,
46503ff40c12SJohn Marino int disabled)
46513ff40c12SJohn Marino {
4652*a1157835SDaniel Fojt /* Masking these out disables LDPC */
4653*a1157835SDaniel Fojt le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
46543ff40c12SJohn Marino
4655*a1157835SDaniel Fojt if (disabled)
4656*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
46573ff40c12SJohn Marino
46583ff40c12SJohn Marino if (disabled)
46593ff40c12SJohn Marino htcaps->ht_capabilities_info &= ~msk;
46603ff40c12SJohn Marino else
46613ff40c12SJohn Marino htcaps->ht_capabilities_info |= msk;
46623ff40c12SJohn Marino
46633ff40c12SJohn Marino htcaps_mask->ht_capabilities_info |= msk;
46643ff40c12SJohn Marino
46653ff40c12SJohn Marino return 0;
46663ff40c12SJohn Marino }
46673ff40c12SJohn Marino
46683ff40c12SJohn Marino
wpa_set_tx_stbc(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int tx_stbc)4669*a1157835SDaniel Fojt static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s,
4670*a1157835SDaniel Fojt struct ieee80211_ht_capabilities *htcaps,
4671*a1157835SDaniel Fojt struct ieee80211_ht_capabilities *htcaps_mask,
4672*a1157835SDaniel Fojt int tx_stbc)
4673*a1157835SDaniel Fojt {
4674*a1157835SDaniel Fojt le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC);
4675*a1157835SDaniel Fojt
4676*a1157835SDaniel Fojt if (tx_stbc == -1)
4677*a1157835SDaniel Fojt return 0;
4678*a1157835SDaniel Fojt
4679*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
4680*a1157835SDaniel Fojt
4681*a1157835SDaniel Fojt if (tx_stbc < 0 || tx_stbc > 1) {
4682*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_ERROR,
4683*a1157835SDaniel Fojt "tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc);
4684*a1157835SDaniel Fojt return -EINVAL;
4685*a1157835SDaniel Fojt }
4686*a1157835SDaniel Fojt
4687*a1157835SDaniel Fojt htcaps_mask->ht_capabilities_info |= msk;
4688*a1157835SDaniel Fojt htcaps->ht_capabilities_info &= ~msk;
4689*a1157835SDaniel Fojt htcaps->ht_capabilities_info |= (tx_stbc << 7) & msk;
4690*a1157835SDaniel Fojt
4691*a1157835SDaniel Fojt return 0;
4692*a1157835SDaniel Fojt }
4693*a1157835SDaniel Fojt
4694*a1157835SDaniel Fojt
wpa_set_rx_stbc(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int rx_stbc)4695*a1157835SDaniel Fojt static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s,
4696*a1157835SDaniel Fojt struct ieee80211_ht_capabilities *htcaps,
4697*a1157835SDaniel Fojt struct ieee80211_ht_capabilities *htcaps_mask,
4698*a1157835SDaniel Fojt int rx_stbc)
4699*a1157835SDaniel Fojt {
4700*a1157835SDaniel Fojt le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK);
4701*a1157835SDaniel Fojt
4702*a1157835SDaniel Fojt if (rx_stbc == -1)
4703*a1157835SDaniel Fojt return 0;
4704*a1157835SDaniel Fojt
4705*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
4706*a1157835SDaniel Fojt
4707*a1157835SDaniel Fojt if (rx_stbc < 0 || rx_stbc > 3) {
4708*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_ERROR,
4709*a1157835SDaniel Fojt "rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc);
4710*a1157835SDaniel Fojt return -EINVAL;
4711*a1157835SDaniel Fojt }
4712*a1157835SDaniel Fojt
4713*a1157835SDaniel Fojt htcaps_mask->ht_capabilities_info |= msk;
4714*a1157835SDaniel Fojt htcaps->ht_capabilities_info &= ~msk;
4715*a1157835SDaniel Fojt htcaps->ht_capabilities_info |= (rx_stbc << 8) & msk;
4716*a1157835SDaniel Fojt
4717*a1157835SDaniel Fojt return 0;
4718*a1157835SDaniel Fojt }
4719*a1157835SDaniel Fojt
4720*a1157835SDaniel Fojt
wpa_supplicant_apply_ht_overrides(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_driver_associate_params * params)47213ff40c12SJohn Marino void wpa_supplicant_apply_ht_overrides(
47223ff40c12SJohn Marino struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
47233ff40c12SJohn Marino struct wpa_driver_associate_params *params)
47243ff40c12SJohn Marino {
47253ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps;
47263ff40c12SJohn Marino struct ieee80211_ht_capabilities *htcaps_mask;
47273ff40c12SJohn Marino
47283ff40c12SJohn Marino if (!ssid)
47293ff40c12SJohn Marino return;
47303ff40c12SJohn Marino
47313ff40c12SJohn Marino params->disable_ht = ssid->disable_ht;
47323ff40c12SJohn Marino if (!params->htcaps || !params->htcaps_mask)
47333ff40c12SJohn Marino return;
47343ff40c12SJohn Marino
47353ff40c12SJohn Marino htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
47363ff40c12SJohn Marino htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
47373ff40c12SJohn Marino wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
47383ff40c12SJohn Marino wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
47393ff40c12SJohn Marino ssid->disable_max_amsdu);
47403ff40c12SJohn Marino wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
47413ff40c12SJohn Marino wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
47423ff40c12SJohn Marino wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
47433ff40c12SJohn Marino wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
4744*a1157835SDaniel Fojt wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
4745*a1157835SDaniel Fojt wpa_set_rx_stbc(wpa_s, htcaps, htcaps_mask, ssid->rx_stbc);
4746*a1157835SDaniel Fojt wpa_set_tx_stbc(wpa_s, htcaps, htcaps_mask, ssid->tx_stbc);
4747*a1157835SDaniel Fojt
4748*a1157835SDaniel Fojt if (ssid->ht40_intolerant) {
4749*a1157835SDaniel Fojt le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
4750*a1157835SDaniel Fojt htcaps->ht_capabilities_info |= bit;
4751*a1157835SDaniel Fojt htcaps_mask->ht_capabilities_info |= bit;
4752*a1157835SDaniel Fojt }
47533ff40c12SJohn Marino }
47543ff40c12SJohn Marino
47553ff40c12SJohn Marino #endif /* CONFIG_HT_OVERRIDES */
47563ff40c12SJohn Marino
47573ff40c12SJohn Marino
47583ff40c12SJohn Marino #ifdef CONFIG_VHT_OVERRIDES
wpa_supplicant_apply_vht_overrides(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_driver_associate_params * params)47593ff40c12SJohn Marino void wpa_supplicant_apply_vht_overrides(
47603ff40c12SJohn Marino struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
47613ff40c12SJohn Marino struct wpa_driver_associate_params *params)
47623ff40c12SJohn Marino {
47633ff40c12SJohn Marino struct ieee80211_vht_capabilities *vhtcaps;
47643ff40c12SJohn Marino struct ieee80211_vht_capabilities *vhtcaps_mask;
47653ff40c12SJohn Marino
47663ff40c12SJohn Marino if (!ssid)
47673ff40c12SJohn Marino return;
47683ff40c12SJohn Marino
47693ff40c12SJohn Marino params->disable_vht = ssid->disable_vht;
47703ff40c12SJohn Marino
47713ff40c12SJohn Marino vhtcaps = (void *) params->vhtcaps;
47723ff40c12SJohn Marino vhtcaps_mask = (void *) params->vhtcaps_mask;
47733ff40c12SJohn Marino
47743ff40c12SJohn Marino if (!vhtcaps || !vhtcaps_mask)
47753ff40c12SJohn Marino return;
47763ff40c12SJohn Marino
4777*a1157835SDaniel Fojt vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
4778*a1157835SDaniel Fojt vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
4779*a1157835SDaniel Fojt
4780*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
4781*a1157835SDaniel Fojt if (ssid->disable_sgi) {
4782*a1157835SDaniel Fojt vhtcaps_mask->vht_capabilities_info |= (VHT_CAP_SHORT_GI_80 |
4783*a1157835SDaniel Fojt VHT_CAP_SHORT_GI_160);
4784*a1157835SDaniel Fojt vhtcaps->vht_capabilities_info &= ~(VHT_CAP_SHORT_GI_80 |
4785*a1157835SDaniel Fojt VHT_CAP_SHORT_GI_160);
4786*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_DEBUG,
4787*a1157835SDaniel Fojt "disable-sgi override specified, vht-caps: 0x%x",
4788*a1157835SDaniel Fojt vhtcaps->vht_capabilities_info);
4789*a1157835SDaniel Fojt }
4790*a1157835SDaniel Fojt
4791*a1157835SDaniel Fojt /* if max ampdu is <= 3, we have to make the HT cap the same */
4792*a1157835SDaniel Fojt if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
4793*a1157835SDaniel Fojt int max_ampdu;
4794*a1157835SDaniel Fojt
4795*a1157835SDaniel Fojt max_ampdu = (ssid->vht_capa &
4796*a1157835SDaniel Fojt VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
4797*a1157835SDaniel Fojt VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT;
4798*a1157835SDaniel Fojt
4799*a1157835SDaniel Fojt max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
4800*a1157835SDaniel Fojt wpa_set_ampdu_factor(wpa_s,
4801*a1157835SDaniel Fojt (void *) params->htcaps,
4802*a1157835SDaniel Fojt (void *) params->htcaps_mask,
4803*a1157835SDaniel Fojt max_ampdu);
4804*a1157835SDaniel Fojt }
4805*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
48063ff40c12SJohn Marino
48073ff40c12SJohn Marino #define OVERRIDE_MCS(i) \
48083ff40c12SJohn Marino if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
48093ff40c12SJohn Marino vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
4810*a1157835SDaniel Fojt host_to_le16(3 << 2 * (i - 1)); \
48113ff40c12SJohn Marino vhtcaps->vht_supported_mcs_set.tx_map |= \
4812*a1157835SDaniel Fojt host_to_le16(ssid->vht_tx_mcs_nss_ ##i << \
4813*a1157835SDaniel Fojt 2 * (i - 1)); \
48143ff40c12SJohn Marino } \
48153ff40c12SJohn Marino if (ssid->vht_rx_mcs_nss_ ##i >= 0) { \
48163ff40c12SJohn Marino vhtcaps_mask->vht_supported_mcs_set.rx_map |= \
4817*a1157835SDaniel Fojt host_to_le16(3 << 2 * (i - 1)); \
48183ff40c12SJohn Marino vhtcaps->vht_supported_mcs_set.rx_map |= \
4819*a1157835SDaniel Fojt host_to_le16(ssid->vht_rx_mcs_nss_ ##i << \
4820*a1157835SDaniel Fojt 2 * (i - 1)); \
48213ff40c12SJohn Marino }
48223ff40c12SJohn Marino
48233ff40c12SJohn Marino OVERRIDE_MCS(1);
48243ff40c12SJohn Marino OVERRIDE_MCS(2);
48253ff40c12SJohn Marino OVERRIDE_MCS(3);
48263ff40c12SJohn Marino OVERRIDE_MCS(4);
48273ff40c12SJohn Marino OVERRIDE_MCS(5);
48283ff40c12SJohn Marino OVERRIDE_MCS(6);
48293ff40c12SJohn Marino OVERRIDE_MCS(7);
48303ff40c12SJohn Marino OVERRIDE_MCS(8);
48313ff40c12SJohn Marino }
48323ff40c12SJohn Marino #endif /* CONFIG_VHT_OVERRIDES */
48333ff40c12SJohn Marino
48343ff40c12SJohn Marino
pcsc_reader_init(struct wpa_supplicant * wpa_s)48353ff40c12SJohn Marino static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
48363ff40c12SJohn Marino {
48373ff40c12SJohn Marino #ifdef PCSC_FUNCS
48383ff40c12SJohn Marino size_t len;
48393ff40c12SJohn Marino
48403ff40c12SJohn Marino if (!wpa_s->conf->pcsc_reader)
48413ff40c12SJohn Marino return 0;
48423ff40c12SJohn Marino
48433ff40c12SJohn Marino wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
48443ff40c12SJohn Marino if (!wpa_s->scard)
48453ff40c12SJohn Marino return 1;
48463ff40c12SJohn Marino
48473ff40c12SJohn Marino if (wpa_s->conf->pcsc_pin &&
48483ff40c12SJohn Marino scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
48493ff40c12SJohn Marino scard_deinit(wpa_s->scard);
48503ff40c12SJohn Marino wpa_s->scard = NULL;
48513ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
48523ff40c12SJohn Marino return -1;
48533ff40c12SJohn Marino }
48543ff40c12SJohn Marino
48553ff40c12SJohn Marino len = sizeof(wpa_s->imsi) - 1;
48563ff40c12SJohn Marino if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
48573ff40c12SJohn Marino scard_deinit(wpa_s->scard);
48583ff40c12SJohn Marino wpa_s->scard = NULL;
48593ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
48603ff40c12SJohn Marino return -1;
48613ff40c12SJohn Marino }
48623ff40c12SJohn Marino wpa_s->imsi[len] = '\0';
48633ff40c12SJohn Marino
48643ff40c12SJohn Marino wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
48653ff40c12SJohn Marino
48663ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
48673ff40c12SJohn Marino wpa_s->imsi, wpa_s->mnc_len);
48683ff40c12SJohn Marino
48693ff40c12SJohn Marino wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
48703ff40c12SJohn Marino eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
48713ff40c12SJohn Marino #endif /* PCSC_FUNCS */
48723ff40c12SJohn Marino
48733ff40c12SJohn Marino return 0;
48743ff40c12SJohn Marino }
48753ff40c12SJohn Marino
48763ff40c12SJohn Marino
wpas_init_ext_pw(struct wpa_supplicant * wpa_s)48773ff40c12SJohn Marino int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
48783ff40c12SJohn Marino {
48793ff40c12SJohn Marino char *val, *pos;
48803ff40c12SJohn Marino
48813ff40c12SJohn Marino ext_password_deinit(wpa_s->ext_pw);
48823ff40c12SJohn Marino wpa_s->ext_pw = NULL;
48833ff40c12SJohn Marino eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
48843ff40c12SJohn Marino
48853ff40c12SJohn Marino if (!wpa_s->conf->ext_password_backend)
48863ff40c12SJohn Marino return 0;
48873ff40c12SJohn Marino
48883ff40c12SJohn Marino val = os_strdup(wpa_s->conf->ext_password_backend);
48893ff40c12SJohn Marino if (val == NULL)
48903ff40c12SJohn Marino return -1;
48913ff40c12SJohn Marino pos = os_strchr(val, ':');
48923ff40c12SJohn Marino if (pos)
48933ff40c12SJohn Marino *pos++ = '\0';
48943ff40c12SJohn Marino
48953ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
48963ff40c12SJohn Marino
48973ff40c12SJohn Marino wpa_s->ext_pw = ext_password_init(val, pos);
48983ff40c12SJohn Marino os_free(val);
48993ff40c12SJohn Marino if (wpa_s->ext_pw == NULL) {
49003ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
49013ff40c12SJohn Marino return -1;
49023ff40c12SJohn Marino }
49033ff40c12SJohn Marino eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
49043ff40c12SJohn Marino
49053ff40c12SJohn Marino return 0;
49063ff40c12SJohn Marino }
49073ff40c12SJohn Marino
49083ff40c12SJohn Marino
4909*a1157835SDaniel Fojt #ifdef CONFIG_FST
4910*a1157835SDaniel Fojt
wpas_fst_get_bssid_cb(void * ctx)4911*a1157835SDaniel Fojt static const u8 * wpas_fst_get_bssid_cb(void *ctx)
4912*a1157835SDaniel Fojt {
4913*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
4914*a1157835SDaniel Fojt
4915*a1157835SDaniel Fojt return (is_zero_ether_addr(wpa_s->bssid) ||
4916*a1157835SDaniel Fojt wpa_s->wpa_state != WPA_COMPLETED) ? NULL : wpa_s->bssid;
4917*a1157835SDaniel Fojt }
4918*a1157835SDaniel Fojt
4919*a1157835SDaniel Fojt
wpas_fst_get_channel_info_cb(void * ctx,enum hostapd_hw_mode * hw_mode,u8 * channel)4920*a1157835SDaniel Fojt static void wpas_fst_get_channel_info_cb(void *ctx,
4921*a1157835SDaniel Fojt enum hostapd_hw_mode *hw_mode,
4922*a1157835SDaniel Fojt u8 *channel)
4923*a1157835SDaniel Fojt {
4924*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
4925*a1157835SDaniel Fojt
4926*a1157835SDaniel Fojt if (wpa_s->current_bss) {
4927*a1157835SDaniel Fojt *hw_mode = ieee80211_freq_to_chan(wpa_s->current_bss->freq,
4928*a1157835SDaniel Fojt channel);
4929*a1157835SDaniel Fojt } else if (wpa_s->hw.num_modes) {
4930*a1157835SDaniel Fojt *hw_mode = wpa_s->hw.modes[0].mode;
4931*a1157835SDaniel Fojt } else {
4932*a1157835SDaniel Fojt WPA_ASSERT(0);
4933*a1157835SDaniel Fojt *hw_mode = 0;
4934*a1157835SDaniel Fojt }
4935*a1157835SDaniel Fojt }
4936*a1157835SDaniel Fojt
4937*a1157835SDaniel Fojt
wpas_fst_get_hw_modes(void * ctx,struct hostapd_hw_modes ** modes)4938*a1157835SDaniel Fojt static int wpas_fst_get_hw_modes(void *ctx, struct hostapd_hw_modes **modes)
4939*a1157835SDaniel Fojt {
4940*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
4941*a1157835SDaniel Fojt
4942*a1157835SDaniel Fojt *modes = wpa_s->hw.modes;
4943*a1157835SDaniel Fojt return wpa_s->hw.num_modes;
4944*a1157835SDaniel Fojt }
4945*a1157835SDaniel Fojt
4946*a1157835SDaniel Fojt
wpas_fst_set_ies_cb(void * ctx,const struct wpabuf * fst_ies)4947*a1157835SDaniel Fojt static void wpas_fst_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
4948*a1157835SDaniel Fojt {
4949*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
4950*a1157835SDaniel Fojt
4951*a1157835SDaniel Fojt wpa_hexdump_buf(MSG_DEBUG, "FST: Set IEs", fst_ies);
4952*a1157835SDaniel Fojt wpa_s->fst_ies = fst_ies;
4953*a1157835SDaniel Fojt }
4954*a1157835SDaniel Fojt
4955*a1157835SDaniel Fojt
wpas_fst_send_action_cb(void * ctx,const u8 * da,struct wpabuf * data)4956*a1157835SDaniel Fojt static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data)
4957*a1157835SDaniel Fojt {
4958*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
4959*a1157835SDaniel Fojt
4960*a1157835SDaniel Fojt if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) {
4961*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
4962*a1157835SDaniel Fojt __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
4963*a1157835SDaniel Fojt return -1;
4964*a1157835SDaniel Fojt }
4965*a1157835SDaniel Fojt return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
4966*a1157835SDaniel Fojt wpa_s->own_addr, wpa_s->bssid,
4967*a1157835SDaniel Fojt wpabuf_head(data), wpabuf_len(data),
4968*a1157835SDaniel Fojt 0);
4969*a1157835SDaniel Fojt }
4970*a1157835SDaniel Fojt
4971*a1157835SDaniel Fojt
wpas_fst_get_mb_ie_cb(void * ctx,const u8 * addr)4972*a1157835SDaniel Fojt static const struct wpabuf * wpas_fst_get_mb_ie_cb(void *ctx, const u8 *addr)
4973*a1157835SDaniel Fojt {
4974*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
4975*a1157835SDaniel Fojt
4976*a1157835SDaniel Fojt WPA_ASSERT(os_memcmp(wpa_s->bssid, addr, ETH_ALEN) == 0);
4977*a1157835SDaniel Fojt return wpa_s->received_mb_ies;
4978*a1157835SDaniel Fojt }
4979*a1157835SDaniel Fojt
4980*a1157835SDaniel Fojt
wpas_fst_update_mb_ie_cb(void * ctx,const u8 * addr,const u8 * buf,size_t size)4981*a1157835SDaniel Fojt static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
4982*a1157835SDaniel Fojt const u8 *buf, size_t size)
4983*a1157835SDaniel Fojt {
4984*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
4985*a1157835SDaniel Fojt struct mb_ies_info info;
4986*a1157835SDaniel Fojt
4987*a1157835SDaniel Fojt WPA_ASSERT(os_memcmp(wpa_s->bssid, addr, ETH_ALEN) == 0);
4988*a1157835SDaniel Fojt
4989*a1157835SDaniel Fojt if (!mb_ies_info_by_ies(&info, buf, size)) {
4990*a1157835SDaniel Fojt wpabuf_free(wpa_s->received_mb_ies);
4991*a1157835SDaniel Fojt wpa_s->received_mb_ies = mb_ies_by_info(&info);
4992*a1157835SDaniel Fojt }
4993*a1157835SDaniel Fojt }
4994*a1157835SDaniel Fojt
4995*a1157835SDaniel Fojt
wpas_fst_get_peer_first(void * ctx,struct fst_get_peer_ctx ** get_ctx,Boolean mb_only)4996*a1157835SDaniel Fojt static const u8 * wpas_fst_get_peer_first(void *ctx,
4997*a1157835SDaniel Fojt struct fst_get_peer_ctx **get_ctx,
4998*a1157835SDaniel Fojt Boolean mb_only)
4999*a1157835SDaniel Fojt {
5000*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
5001*a1157835SDaniel Fojt
5002*a1157835SDaniel Fojt *get_ctx = NULL;
5003*a1157835SDaniel Fojt if (!is_zero_ether_addr(wpa_s->bssid))
5004*a1157835SDaniel Fojt return (wpa_s->received_mb_ies || !mb_only) ?
5005*a1157835SDaniel Fojt wpa_s->bssid : NULL;
5006*a1157835SDaniel Fojt return NULL;
5007*a1157835SDaniel Fojt }
5008*a1157835SDaniel Fojt
5009*a1157835SDaniel Fojt
wpas_fst_get_peer_next(void * ctx,struct fst_get_peer_ctx ** get_ctx,Boolean mb_only)5010*a1157835SDaniel Fojt static const u8 * wpas_fst_get_peer_next(void *ctx,
5011*a1157835SDaniel Fojt struct fst_get_peer_ctx **get_ctx,
5012*a1157835SDaniel Fojt Boolean mb_only)
5013*a1157835SDaniel Fojt {
5014*a1157835SDaniel Fojt return NULL;
5015*a1157835SDaniel Fojt }
5016*a1157835SDaniel Fojt
fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant * wpa_s,struct fst_wpa_obj * iface_obj)5017*a1157835SDaniel Fojt void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
5018*a1157835SDaniel Fojt struct fst_wpa_obj *iface_obj)
5019*a1157835SDaniel Fojt {
5020*a1157835SDaniel Fojt iface_obj->ctx = wpa_s;
5021*a1157835SDaniel Fojt iface_obj->get_bssid = wpas_fst_get_bssid_cb;
5022*a1157835SDaniel Fojt iface_obj->get_channel_info = wpas_fst_get_channel_info_cb;
5023*a1157835SDaniel Fojt iface_obj->get_hw_modes = wpas_fst_get_hw_modes;
5024*a1157835SDaniel Fojt iface_obj->set_ies = wpas_fst_set_ies_cb;
5025*a1157835SDaniel Fojt iface_obj->send_action = wpas_fst_send_action_cb;
5026*a1157835SDaniel Fojt iface_obj->get_mb_ie = wpas_fst_get_mb_ie_cb;
5027*a1157835SDaniel Fojt iface_obj->update_mb_ie = wpas_fst_update_mb_ie_cb;
5028*a1157835SDaniel Fojt iface_obj->get_peer_first = wpas_fst_get_peer_first;
5029*a1157835SDaniel Fojt iface_obj->get_peer_next = wpas_fst_get_peer_next;
5030*a1157835SDaniel Fojt }
5031*a1157835SDaniel Fojt #endif /* CONFIG_FST */
5032*a1157835SDaniel Fojt
wpas_set_wowlan_triggers(struct wpa_supplicant * wpa_s,const struct wpa_driver_capa * capa)5033*a1157835SDaniel Fojt static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
5034*a1157835SDaniel Fojt const struct wpa_driver_capa *capa)
5035*a1157835SDaniel Fojt {
5036*a1157835SDaniel Fojt struct wowlan_triggers *triggers;
5037*a1157835SDaniel Fojt int ret = 0;
5038*a1157835SDaniel Fojt
5039*a1157835SDaniel Fojt if (!wpa_s->conf->wowlan_triggers)
5040*a1157835SDaniel Fojt return 0;
5041*a1157835SDaniel Fojt
5042*a1157835SDaniel Fojt triggers = wpa_get_wowlan_triggers(wpa_s->conf->wowlan_triggers, capa);
5043*a1157835SDaniel Fojt if (triggers) {
5044*a1157835SDaniel Fojt ret = wpa_drv_wowlan(wpa_s, triggers);
5045*a1157835SDaniel Fojt os_free(triggers);
5046*a1157835SDaniel Fojt }
5047*a1157835SDaniel Fojt return ret;
5048*a1157835SDaniel Fojt }
5049*a1157835SDaniel Fojt
5050*a1157835SDaniel Fojt
wpas_freq_to_band(int freq)5051*a1157835SDaniel Fojt enum wpa_radio_work_band wpas_freq_to_band(int freq)
5052*a1157835SDaniel Fojt {
5053*a1157835SDaniel Fojt if (freq < 3000)
5054*a1157835SDaniel Fojt return BAND_2_4_GHZ;
5055*a1157835SDaniel Fojt if (freq > 50000)
5056*a1157835SDaniel Fojt return BAND_60_GHZ;
5057*a1157835SDaniel Fojt return BAND_5_GHZ;
5058*a1157835SDaniel Fojt }
5059*a1157835SDaniel Fojt
5060*a1157835SDaniel Fojt
wpas_get_bands(struct wpa_supplicant * wpa_s,const int * freqs)5061*a1157835SDaniel Fojt unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs)
5062*a1157835SDaniel Fojt {
5063*a1157835SDaniel Fojt int i;
5064*a1157835SDaniel Fojt unsigned int band = 0;
5065*a1157835SDaniel Fojt
5066*a1157835SDaniel Fojt if (freqs) {
5067*a1157835SDaniel Fojt /* freqs are specified for the radio work */
5068*a1157835SDaniel Fojt for (i = 0; freqs[i]; i++)
5069*a1157835SDaniel Fojt band |= wpas_freq_to_band(freqs[i]);
5070*a1157835SDaniel Fojt } else {
5071*a1157835SDaniel Fojt /*
5072*a1157835SDaniel Fojt * freqs are not specified, implies all
5073*a1157835SDaniel Fojt * the supported freqs by HW
5074*a1157835SDaniel Fojt */
5075*a1157835SDaniel Fojt for (i = 0; i < wpa_s->hw.num_modes; i++) {
5076*a1157835SDaniel Fojt if (wpa_s->hw.modes[i].num_channels != 0) {
5077*a1157835SDaniel Fojt if (wpa_s->hw.modes[i].mode ==
5078*a1157835SDaniel Fojt HOSTAPD_MODE_IEEE80211B ||
5079*a1157835SDaniel Fojt wpa_s->hw.modes[i].mode ==
5080*a1157835SDaniel Fojt HOSTAPD_MODE_IEEE80211G)
5081*a1157835SDaniel Fojt band |= BAND_2_4_GHZ;
5082*a1157835SDaniel Fojt else if (wpa_s->hw.modes[i].mode ==
5083*a1157835SDaniel Fojt HOSTAPD_MODE_IEEE80211A)
5084*a1157835SDaniel Fojt band |= BAND_5_GHZ;
5085*a1157835SDaniel Fojt else if (wpa_s->hw.modes[i].mode ==
5086*a1157835SDaniel Fojt HOSTAPD_MODE_IEEE80211AD)
5087*a1157835SDaniel Fojt band |= BAND_60_GHZ;
5088*a1157835SDaniel Fojt else if (wpa_s->hw.modes[i].mode ==
5089*a1157835SDaniel Fojt HOSTAPD_MODE_IEEE80211ANY)
5090*a1157835SDaniel Fojt band = BAND_2_4_GHZ | BAND_5_GHZ |
5091*a1157835SDaniel Fojt BAND_60_GHZ;
5092*a1157835SDaniel Fojt }
5093*a1157835SDaniel Fojt }
5094*a1157835SDaniel Fojt }
5095*a1157835SDaniel Fojt
5096*a1157835SDaniel Fojt return band;
5097*a1157835SDaniel Fojt }
5098*a1157835SDaniel Fojt
5099*a1157835SDaniel Fojt
radio_add_interface(struct wpa_supplicant * wpa_s,const char * rn)51003ff40c12SJohn Marino static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
51013ff40c12SJohn Marino const char *rn)
51023ff40c12SJohn Marino {
51033ff40c12SJohn Marino struct wpa_supplicant *iface = wpa_s->global->ifaces;
51043ff40c12SJohn Marino struct wpa_radio *radio;
51053ff40c12SJohn Marino
51063ff40c12SJohn Marino while (rn && iface) {
51073ff40c12SJohn Marino radio = iface->radio;
51083ff40c12SJohn Marino if (radio && os_strcmp(rn, radio->name) == 0) {
51093ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Add interface %s to existing radio %s",
51103ff40c12SJohn Marino wpa_s->ifname, rn);
51113ff40c12SJohn Marino dl_list_add(&radio->ifaces, &wpa_s->radio_list);
51123ff40c12SJohn Marino return radio;
51133ff40c12SJohn Marino }
51143ff40c12SJohn Marino
51153ff40c12SJohn Marino iface = iface->next;
51163ff40c12SJohn Marino }
51173ff40c12SJohn Marino
51183ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Add interface %s to a new radio %s",
51193ff40c12SJohn Marino wpa_s->ifname, rn ? rn : "N/A");
51203ff40c12SJohn Marino radio = os_zalloc(sizeof(*radio));
51213ff40c12SJohn Marino if (radio == NULL)
51223ff40c12SJohn Marino return NULL;
51233ff40c12SJohn Marino
51243ff40c12SJohn Marino if (rn)
51253ff40c12SJohn Marino os_strlcpy(radio->name, rn, sizeof(radio->name));
51263ff40c12SJohn Marino dl_list_init(&radio->ifaces);
51273ff40c12SJohn Marino dl_list_init(&radio->work);
51283ff40c12SJohn Marino dl_list_add(&radio->ifaces, &wpa_s->radio_list);
51293ff40c12SJohn Marino
51303ff40c12SJohn Marino return radio;
51313ff40c12SJohn Marino }
51323ff40c12SJohn Marino
51333ff40c12SJohn Marino
radio_work_free(struct wpa_radio_work * work)51343ff40c12SJohn Marino static void radio_work_free(struct wpa_radio_work *work)
51353ff40c12SJohn Marino {
51363ff40c12SJohn Marino if (work->wpa_s->scan_work == work) {
51373ff40c12SJohn Marino /* This should not really happen. */
51383ff40c12SJohn Marino wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work",
51393ff40c12SJohn Marino work->type, work, work->started);
51403ff40c12SJohn Marino work->wpa_s->scan_work = NULL;
51413ff40c12SJohn Marino }
51423ff40c12SJohn Marino
51433ff40c12SJohn Marino #ifdef CONFIG_P2P
51443ff40c12SJohn Marino if (work->wpa_s->p2p_scan_work == work) {
51453ff40c12SJohn Marino /* This should not really happen. */
51463ff40c12SJohn Marino wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work",
51473ff40c12SJohn Marino work->type, work, work->started);
51483ff40c12SJohn Marino work->wpa_s->p2p_scan_work = NULL;
51493ff40c12SJohn Marino }
51503ff40c12SJohn Marino #endif /* CONFIG_P2P */
51513ff40c12SJohn Marino
5152*a1157835SDaniel Fojt if (work->started) {
5153*a1157835SDaniel Fojt work->wpa_s->radio->num_active_works--;
5154*a1157835SDaniel Fojt wpa_dbg(work->wpa_s, MSG_DEBUG,
5155*a1157835SDaniel Fojt "radio_work_free('%s'@%p): num_active_works --> %u",
5156*a1157835SDaniel Fojt work->type, work,
5157*a1157835SDaniel Fojt work->wpa_s->radio->num_active_works);
5158*a1157835SDaniel Fojt }
5159*a1157835SDaniel Fojt
51603ff40c12SJohn Marino dl_list_del(&work->list);
51613ff40c12SJohn Marino os_free(work);
51623ff40c12SJohn Marino }
51633ff40c12SJohn Marino
51643ff40c12SJohn Marino
radio_work_is_connect(struct wpa_radio_work * work)5165*a1157835SDaniel Fojt static int radio_work_is_connect(struct wpa_radio_work *work)
5166*a1157835SDaniel Fojt {
5167*a1157835SDaniel Fojt return os_strcmp(work->type, "sme-connect") == 0 ||
5168*a1157835SDaniel Fojt os_strcmp(work->type, "connect") == 0;
5169*a1157835SDaniel Fojt }
5170*a1157835SDaniel Fojt
5171*a1157835SDaniel Fojt
radio_work_is_scan(struct wpa_radio_work * work)5172*a1157835SDaniel Fojt static int radio_work_is_scan(struct wpa_radio_work *work)
5173*a1157835SDaniel Fojt {
5174*a1157835SDaniel Fojt return os_strcmp(work->type, "scan") == 0 ||
5175*a1157835SDaniel Fojt os_strcmp(work->type, "p2p-scan") == 0;
5176*a1157835SDaniel Fojt }
5177*a1157835SDaniel Fojt
5178*a1157835SDaniel Fojt
radio_work_get_next_work(struct wpa_radio * radio)5179*a1157835SDaniel Fojt static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
5180*a1157835SDaniel Fojt {
5181*a1157835SDaniel Fojt struct wpa_radio_work *active_work = NULL;
5182*a1157835SDaniel Fojt struct wpa_radio_work *tmp;
5183*a1157835SDaniel Fojt
5184*a1157835SDaniel Fojt /* Get the active work to know the type and band. */
5185*a1157835SDaniel Fojt dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
5186*a1157835SDaniel Fojt if (tmp->started) {
5187*a1157835SDaniel Fojt active_work = tmp;
5188*a1157835SDaniel Fojt break;
5189*a1157835SDaniel Fojt }
5190*a1157835SDaniel Fojt }
5191*a1157835SDaniel Fojt
5192*a1157835SDaniel Fojt if (!active_work) {
5193*a1157835SDaniel Fojt /* No active work, start one */
5194*a1157835SDaniel Fojt radio->num_active_works = 0;
5195*a1157835SDaniel Fojt dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
5196*a1157835SDaniel Fojt list) {
5197*a1157835SDaniel Fojt if (os_strcmp(tmp->type, "scan") == 0 &&
5198*a1157835SDaniel Fojt radio->external_scan_running &&
5199*a1157835SDaniel Fojt (((struct wpa_driver_scan_params *)
5200*a1157835SDaniel Fojt tmp->ctx)->only_new_results ||
5201*a1157835SDaniel Fojt tmp->wpa_s->clear_driver_scan_cache))
5202*a1157835SDaniel Fojt continue;
5203*a1157835SDaniel Fojt return tmp;
5204*a1157835SDaniel Fojt }
5205*a1157835SDaniel Fojt return NULL;
5206*a1157835SDaniel Fojt }
5207*a1157835SDaniel Fojt
5208*a1157835SDaniel Fojt if (radio_work_is_connect(active_work)) {
5209*a1157835SDaniel Fojt /*
5210*a1157835SDaniel Fojt * If the active work is either connect or sme-connect,
5211*a1157835SDaniel Fojt * do not parallelize them with other radio works.
5212*a1157835SDaniel Fojt */
5213*a1157835SDaniel Fojt wpa_dbg(active_work->wpa_s, MSG_DEBUG,
5214*a1157835SDaniel Fojt "Do not parallelize radio work with %s",
5215*a1157835SDaniel Fojt active_work->type);
5216*a1157835SDaniel Fojt return NULL;
5217*a1157835SDaniel Fojt }
5218*a1157835SDaniel Fojt
5219*a1157835SDaniel Fojt dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
5220*a1157835SDaniel Fojt if (tmp->started)
5221*a1157835SDaniel Fojt continue;
5222*a1157835SDaniel Fojt
5223*a1157835SDaniel Fojt /*
5224*a1157835SDaniel Fojt * If connect or sme-connect are enqueued, parallelize only
5225*a1157835SDaniel Fojt * those operations ahead of them in the queue.
5226*a1157835SDaniel Fojt */
5227*a1157835SDaniel Fojt if (radio_work_is_connect(tmp))
5228*a1157835SDaniel Fojt break;
5229*a1157835SDaniel Fojt
5230*a1157835SDaniel Fojt /* Serialize parallel scan and p2p_scan operations on the same
5231*a1157835SDaniel Fojt * interface since the driver_nl80211 mechanism for tracking
5232*a1157835SDaniel Fojt * scan cookies does not yet have support for this. */
5233*a1157835SDaniel Fojt if (active_work->wpa_s == tmp->wpa_s &&
5234*a1157835SDaniel Fojt radio_work_is_scan(active_work) &&
5235*a1157835SDaniel Fojt radio_work_is_scan(tmp)) {
5236*a1157835SDaniel Fojt wpa_dbg(active_work->wpa_s, MSG_DEBUG,
5237*a1157835SDaniel Fojt "Do not start work '%s' when another work '%s' is already scheduled",
5238*a1157835SDaniel Fojt tmp->type, active_work->type);
5239*a1157835SDaniel Fojt continue;
5240*a1157835SDaniel Fojt }
5241*a1157835SDaniel Fojt /*
5242*a1157835SDaniel Fojt * Check that the radio works are distinct and
5243*a1157835SDaniel Fojt * on different bands.
5244*a1157835SDaniel Fojt */
5245*a1157835SDaniel Fojt if (os_strcmp(active_work->type, tmp->type) != 0 &&
5246*a1157835SDaniel Fojt (active_work->bands != tmp->bands)) {
5247*a1157835SDaniel Fojt /*
5248*a1157835SDaniel Fojt * If a scan has to be scheduled through nl80211 scan
5249*a1157835SDaniel Fojt * interface and if an external scan is already running,
5250*a1157835SDaniel Fojt * do not schedule the scan since it is likely to get
5251*a1157835SDaniel Fojt * rejected by kernel.
5252*a1157835SDaniel Fojt */
5253*a1157835SDaniel Fojt if (os_strcmp(tmp->type, "scan") == 0 &&
5254*a1157835SDaniel Fojt radio->external_scan_running &&
5255*a1157835SDaniel Fojt (((struct wpa_driver_scan_params *)
5256*a1157835SDaniel Fojt tmp->ctx)->only_new_results ||
5257*a1157835SDaniel Fojt tmp->wpa_s->clear_driver_scan_cache))
5258*a1157835SDaniel Fojt continue;
5259*a1157835SDaniel Fojt
5260*a1157835SDaniel Fojt wpa_dbg(active_work->wpa_s, MSG_DEBUG,
5261*a1157835SDaniel Fojt "active_work:%s new_work:%s",
5262*a1157835SDaniel Fojt active_work->type, tmp->type);
5263*a1157835SDaniel Fojt return tmp;
5264*a1157835SDaniel Fojt }
5265*a1157835SDaniel Fojt }
5266*a1157835SDaniel Fojt
5267*a1157835SDaniel Fojt /* Did not find a radio work to schedule in parallel. */
5268*a1157835SDaniel Fojt return NULL;
5269*a1157835SDaniel Fojt }
5270*a1157835SDaniel Fojt
5271*a1157835SDaniel Fojt
radio_start_next_work(void * eloop_ctx,void * timeout_ctx)52723ff40c12SJohn Marino static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
52733ff40c12SJohn Marino {
52743ff40c12SJohn Marino struct wpa_radio *radio = eloop_ctx;
52753ff40c12SJohn Marino struct wpa_radio_work *work;
52763ff40c12SJohn Marino struct os_reltime now, diff;
52773ff40c12SJohn Marino struct wpa_supplicant *wpa_s;
52783ff40c12SJohn Marino
52793ff40c12SJohn Marino work = dl_list_first(&radio->work, struct wpa_radio_work, list);
5280*a1157835SDaniel Fojt if (work == NULL) {
5281*a1157835SDaniel Fojt radio->num_active_works = 0;
52823ff40c12SJohn Marino return;
5283*a1157835SDaniel Fojt }
52843ff40c12SJohn Marino
52853ff40c12SJohn Marino wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
52863ff40c12SJohn Marino radio_list);
5287*a1157835SDaniel Fojt
5288*a1157835SDaniel Fojt if (!(wpa_s &&
5289*a1157835SDaniel Fojt wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) {
5290*a1157835SDaniel Fojt if (work->started)
5291*a1157835SDaniel Fojt return; /* already started and still in progress */
5292*a1157835SDaniel Fojt
5293*a1157835SDaniel Fojt if (wpa_s && wpa_s->radio->external_scan_running) {
52943ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
52953ff40c12SJohn Marino return;
52963ff40c12SJohn Marino }
5297*a1157835SDaniel Fojt } else {
5298*a1157835SDaniel Fojt work = NULL;
5299*a1157835SDaniel Fojt if (radio->num_active_works < MAX_ACTIVE_WORKS) {
5300*a1157835SDaniel Fojt /* get the work to schedule next */
5301*a1157835SDaniel Fojt work = radio_work_get_next_work(radio);
5302*a1157835SDaniel Fojt }
5303*a1157835SDaniel Fojt if (!work)
5304*a1157835SDaniel Fojt return;
5305*a1157835SDaniel Fojt }
53063ff40c12SJohn Marino
5307*a1157835SDaniel Fojt wpa_s = work->wpa_s;
53083ff40c12SJohn Marino os_get_reltime(&now);
53093ff40c12SJohn Marino os_reltime_sub(&now, &work->time, &diff);
5310*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
5311*a1157835SDaniel Fojt "Starting radio work '%s'@%p after %ld.%06ld second wait",
53123ff40c12SJohn Marino work->type, work, diff.sec, diff.usec);
53133ff40c12SJohn Marino work->started = 1;
53143ff40c12SJohn Marino work->time = now;
5315*a1157835SDaniel Fojt radio->num_active_works++;
5316*a1157835SDaniel Fojt
53173ff40c12SJohn Marino work->cb(work, 0);
5318*a1157835SDaniel Fojt
5319*a1157835SDaniel Fojt if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) &&
5320*a1157835SDaniel Fojt radio->num_active_works < MAX_ACTIVE_WORKS)
5321*a1157835SDaniel Fojt radio_work_check_next(wpa_s);
53223ff40c12SJohn Marino }
53233ff40c12SJohn Marino
53243ff40c12SJohn Marino
5325*a1157835SDaniel Fojt /*
5326*a1157835SDaniel Fojt * This function removes both started and pending radio works running on
5327*a1157835SDaniel Fojt * the provided interface's radio.
5328*a1157835SDaniel Fojt * Prior to the removal of the radio work, its callback (cb) is called with
5329*a1157835SDaniel Fojt * deinit set to be 1. Each work's callback is responsible for clearing its
5330*a1157835SDaniel Fojt * internal data and restoring to a correct state.
5331*a1157835SDaniel Fojt * @wpa_s: wpa_supplicant data
5332*a1157835SDaniel Fojt * @type: type of works to be removed
5333*a1157835SDaniel Fojt * @remove_all: 1 to remove all the works on this radio, 0 to remove only
5334*a1157835SDaniel Fojt * this interface's works.
5335*a1157835SDaniel Fojt */
radio_remove_works(struct wpa_supplicant * wpa_s,const char * type,int remove_all)5336*a1157835SDaniel Fojt void radio_remove_works(struct wpa_supplicant *wpa_s,
5337*a1157835SDaniel Fojt const char *type, int remove_all)
53383ff40c12SJohn Marino {
53393ff40c12SJohn Marino struct wpa_radio_work *work, *tmp;
53403ff40c12SJohn Marino struct wpa_radio *radio = wpa_s->radio;
53413ff40c12SJohn Marino
53423ff40c12SJohn Marino dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work,
53433ff40c12SJohn Marino list) {
5344*a1157835SDaniel Fojt if (type && os_strcmp(type, work->type) != 0)
53453ff40c12SJohn Marino continue;
5346*a1157835SDaniel Fojt
5347*a1157835SDaniel Fojt /* skip other ifaces' works */
5348*a1157835SDaniel Fojt if (!remove_all && work->wpa_s != wpa_s)
53493ff40c12SJohn Marino continue;
5350*a1157835SDaniel Fojt
5351*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s",
5352*a1157835SDaniel Fojt work->type, work, work->started ? " (started)" : "");
53533ff40c12SJohn Marino work->cb(work, 1);
53543ff40c12SJohn Marino radio_work_free(work);
53553ff40c12SJohn Marino }
5356*a1157835SDaniel Fojt
5357*a1157835SDaniel Fojt /* in case we removed the started work */
5358*a1157835SDaniel Fojt radio_work_check_next(wpa_s);
5359*a1157835SDaniel Fojt }
5360*a1157835SDaniel Fojt
5361*a1157835SDaniel Fojt
radio_remove_pending_work(struct wpa_supplicant * wpa_s,void * ctx)5362*a1157835SDaniel Fojt void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx)
5363*a1157835SDaniel Fojt {
5364*a1157835SDaniel Fojt struct wpa_radio_work *work;
5365*a1157835SDaniel Fojt struct wpa_radio *radio = wpa_s->radio;
5366*a1157835SDaniel Fojt
5367*a1157835SDaniel Fojt dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
5368*a1157835SDaniel Fojt if (work->ctx != ctx)
5369*a1157835SDaniel Fojt continue;
5370*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s",
5371*a1157835SDaniel Fojt work->type, work, work->started ? " (started)" : "");
5372*a1157835SDaniel Fojt radio_work_free(work);
5373*a1157835SDaniel Fojt break;
5374*a1157835SDaniel Fojt }
53753ff40c12SJohn Marino }
53763ff40c12SJohn Marino
53773ff40c12SJohn Marino
radio_remove_interface(struct wpa_supplicant * wpa_s)53783ff40c12SJohn Marino static void radio_remove_interface(struct wpa_supplicant *wpa_s)
53793ff40c12SJohn Marino {
53803ff40c12SJohn Marino struct wpa_radio *radio = wpa_s->radio;
53813ff40c12SJohn Marino
53823ff40c12SJohn Marino if (!radio)
53833ff40c12SJohn Marino return;
53843ff40c12SJohn Marino
53853ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s",
53863ff40c12SJohn Marino wpa_s->ifname, radio->name);
53873ff40c12SJohn Marino dl_list_del(&wpa_s->radio_list);
5388*a1157835SDaniel Fojt radio_remove_works(wpa_s, NULL, 0);
53893ff40c12SJohn Marino wpa_s->radio = NULL;
5390*a1157835SDaniel Fojt if (!dl_list_empty(&radio->ifaces))
53913ff40c12SJohn Marino return; /* Interfaces remain for this radio */
53923ff40c12SJohn Marino
53933ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
53943ff40c12SJohn Marino eloop_cancel_timeout(radio_start_next_work, radio, NULL);
53953ff40c12SJohn Marino os_free(radio);
53963ff40c12SJohn Marino }
53973ff40c12SJohn Marino
53983ff40c12SJohn Marino
radio_work_check_next(struct wpa_supplicant * wpa_s)53993ff40c12SJohn Marino void radio_work_check_next(struct wpa_supplicant *wpa_s)
54003ff40c12SJohn Marino {
54013ff40c12SJohn Marino struct wpa_radio *radio = wpa_s->radio;
54023ff40c12SJohn Marino
54033ff40c12SJohn Marino if (dl_list_empty(&radio->work))
54043ff40c12SJohn Marino return;
5405*a1157835SDaniel Fojt if (wpa_s->ext_work_in_progress) {
5406*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
5407*a1157835SDaniel Fojt "External radio work in progress - delay start of pending item");
5408*a1157835SDaniel Fojt return;
5409*a1157835SDaniel Fojt }
54103ff40c12SJohn Marino eloop_cancel_timeout(radio_start_next_work, radio, NULL);
54113ff40c12SJohn Marino eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
54123ff40c12SJohn Marino }
54133ff40c12SJohn Marino
54143ff40c12SJohn Marino
54153ff40c12SJohn Marino /**
54163ff40c12SJohn Marino * radio_add_work - Add a radio work item
54173ff40c12SJohn Marino * @wpa_s: Pointer to wpa_supplicant data
54183ff40c12SJohn Marino * @freq: Frequency of the offchannel operation in MHz or 0
54193ff40c12SJohn Marino * @type: Unique identifier for each type of work
54203ff40c12SJohn Marino * @next: Force as the next work to be executed
54213ff40c12SJohn Marino * @cb: Callback function for indicating when radio is available
54223ff40c12SJohn Marino * @ctx: Context pointer for the work (work->ctx in cb())
54233ff40c12SJohn Marino * Returns: 0 on success, -1 on failure
54243ff40c12SJohn Marino *
54253ff40c12SJohn Marino * This function is used to request time for an operation that requires
54263ff40c12SJohn Marino * exclusive radio control. Once the radio is available, the registered callback
54273ff40c12SJohn Marino * function will be called. radio_work_done() must be called once the exclusive
54283ff40c12SJohn Marino * radio operation has been completed, so that the radio is freed for other
54293ff40c12SJohn Marino * operations. The special case of deinit=1 is used to free the context data
54303ff40c12SJohn Marino * during interface removal. That does not allow the callback function to start
54313ff40c12SJohn Marino * the radio operation, i.e., it must free any resources allocated for the radio
54323ff40c12SJohn Marino * work and return.
54333ff40c12SJohn Marino *
54343ff40c12SJohn Marino * The @freq parameter can be used to indicate a single channel on which the
54353ff40c12SJohn Marino * offchannel operation will occur. This may allow multiple radio work
54363ff40c12SJohn Marino * operations to be performed in parallel if they apply for the same channel.
54373ff40c12SJohn Marino * Setting this to 0 indicates that the work item may use multiple channels or
54383ff40c12SJohn Marino * requires exclusive control of the radio.
54393ff40c12SJohn Marino */
radio_add_work(struct wpa_supplicant * wpa_s,unsigned int freq,const char * type,int next,void (* cb)(struct wpa_radio_work * work,int deinit),void * ctx)54403ff40c12SJohn Marino int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
54413ff40c12SJohn Marino const char *type, int next,
54423ff40c12SJohn Marino void (*cb)(struct wpa_radio_work *work, int deinit),
54433ff40c12SJohn Marino void *ctx)
54443ff40c12SJohn Marino {
5445*a1157835SDaniel Fojt struct wpa_radio *radio = wpa_s->radio;
54463ff40c12SJohn Marino struct wpa_radio_work *work;
54473ff40c12SJohn Marino int was_empty;
54483ff40c12SJohn Marino
54493ff40c12SJohn Marino work = os_zalloc(sizeof(*work));
54503ff40c12SJohn Marino if (work == NULL)
54513ff40c12SJohn Marino return -1;
54523ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work);
54533ff40c12SJohn Marino os_get_reltime(&work->time);
54543ff40c12SJohn Marino work->freq = freq;
54553ff40c12SJohn Marino work->type = type;
54563ff40c12SJohn Marino work->wpa_s = wpa_s;
54573ff40c12SJohn Marino work->cb = cb;
54583ff40c12SJohn Marino work->ctx = ctx;
54593ff40c12SJohn Marino
5460*a1157835SDaniel Fojt if (freq)
5461*a1157835SDaniel Fojt work->bands = wpas_freq_to_band(freq);
5462*a1157835SDaniel Fojt else if (os_strcmp(type, "scan") == 0 ||
5463*a1157835SDaniel Fojt os_strcmp(type, "p2p-scan") == 0)
5464*a1157835SDaniel Fojt work->bands = wpas_get_bands(wpa_s,
5465*a1157835SDaniel Fojt ((struct wpa_driver_scan_params *)
5466*a1157835SDaniel Fojt ctx)->freqs);
5467*a1157835SDaniel Fojt else
5468*a1157835SDaniel Fojt work->bands = wpas_get_bands(wpa_s, NULL);
5469*a1157835SDaniel Fojt
54703ff40c12SJohn Marino was_empty = dl_list_empty(&wpa_s->radio->work);
54713ff40c12SJohn Marino if (next)
54723ff40c12SJohn Marino dl_list_add(&wpa_s->radio->work, &work->list);
54733ff40c12SJohn Marino else
54743ff40c12SJohn Marino dl_list_add_tail(&wpa_s->radio->work, &work->list);
54753ff40c12SJohn Marino if (was_empty) {
54763ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
54773ff40c12SJohn Marino radio_work_check_next(wpa_s);
5478*a1157835SDaniel Fojt } else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)
5479*a1157835SDaniel Fojt && radio->num_active_works < MAX_ACTIVE_WORKS) {
5480*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
5481*a1157835SDaniel Fojt "Try to schedule a radio work (num_active_works=%u)",
5482*a1157835SDaniel Fojt radio->num_active_works);
5483*a1157835SDaniel Fojt radio_work_check_next(wpa_s);
54843ff40c12SJohn Marino }
54853ff40c12SJohn Marino
54863ff40c12SJohn Marino return 0;
54873ff40c12SJohn Marino }
54883ff40c12SJohn Marino
54893ff40c12SJohn Marino
54903ff40c12SJohn Marino /**
54913ff40c12SJohn Marino * radio_work_done - Indicate that a radio work item has been completed
54923ff40c12SJohn Marino * @work: Completed work
54933ff40c12SJohn Marino *
54943ff40c12SJohn Marino * This function is called once the callback function registered with
54953ff40c12SJohn Marino * radio_add_work() has completed its work.
54963ff40c12SJohn Marino */
radio_work_done(struct wpa_radio_work * work)54973ff40c12SJohn Marino void radio_work_done(struct wpa_radio_work *work)
54983ff40c12SJohn Marino {
54993ff40c12SJohn Marino struct wpa_supplicant *wpa_s = work->wpa_s;
55003ff40c12SJohn Marino struct os_reltime now, diff;
55013ff40c12SJohn Marino unsigned int started = work->started;
55023ff40c12SJohn Marino
55033ff40c12SJohn Marino os_get_reltime(&now);
55043ff40c12SJohn Marino os_reltime_sub(&now, &work->time, &diff);
55053ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds",
55063ff40c12SJohn Marino work->type, work, started ? "done" : "canceled",
55073ff40c12SJohn Marino diff.sec, diff.usec);
55083ff40c12SJohn Marino radio_work_free(work);
55093ff40c12SJohn Marino if (started)
55103ff40c12SJohn Marino radio_work_check_next(wpa_s);
55113ff40c12SJohn Marino }
55123ff40c12SJohn Marino
55133ff40c12SJohn Marino
5514*a1157835SDaniel Fojt struct wpa_radio_work *
radio_work_pending(struct wpa_supplicant * wpa_s,const char * type)5515*a1157835SDaniel Fojt radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
5516*a1157835SDaniel Fojt {
5517*a1157835SDaniel Fojt struct wpa_radio_work *work;
5518*a1157835SDaniel Fojt struct wpa_radio *radio = wpa_s->radio;
5519*a1157835SDaniel Fojt
5520*a1157835SDaniel Fojt dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
5521*a1157835SDaniel Fojt if (work->wpa_s == wpa_s && os_strcmp(work->type, type) == 0)
5522*a1157835SDaniel Fojt return work;
5523*a1157835SDaniel Fojt }
5524*a1157835SDaniel Fojt
5525*a1157835SDaniel Fojt return NULL;
5526*a1157835SDaniel Fojt }
5527*a1157835SDaniel Fojt
5528*a1157835SDaniel Fojt
wpas_init_driver(struct wpa_supplicant * wpa_s,const struct wpa_interface * iface)55293ff40c12SJohn Marino static int wpas_init_driver(struct wpa_supplicant *wpa_s,
5530*a1157835SDaniel Fojt const struct wpa_interface *iface)
55313ff40c12SJohn Marino {
55323ff40c12SJohn Marino const char *ifname, *driver, *rn;
55333ff40c12SJohn Marino
55343ff40c12SJohn Marino driver = iface->driver;
55353ff40c12SJohn Marino next_driver:
55363ff40c12SJohn Marino if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
55373ff40c12SJohn Marino return -1;
55383ff40c12SJohn Marino
55393ff40c12SJohn Marino wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
55403ff40c12SJohn Marino if (wpa_s->drv_priv == NULL) {
55413ff40c12SJohn Marino const char *pos;
55423ff40c12SJohn Marino pos = driver ? os_strchr(driver, ',') : NULL;
55433ff40c12SJohn Marino if (pos) {
55443ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
55453ff40c12SJohn Marino "driver interface - try next driver wrapper");
55463ff40c12SJohn Marino driver = pos + 1;
55473ff40c12SJohn Marino goto next_driver;
55483ff40c12SJohn Marino }
55493ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
55503ff40c12SJohn Marino "interface");
55513ff40c12SJohn Marino return -1;
55523ff40c12SJohn Marino }
55533ff40c12SJohn Marino if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
55543ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
55553ff40c12SJohn Marino "driver_param '%s'", wpa_s->conf->driver_param);
55563ff40c12SJohn Marino return -1;
55573ff40c12SJohn Marino }
55583ff40c12SJohn Marino
55593ff40c12SJohn Marino ifname = wpa_drv_get_ifname(wpa_s);
55603ff40c12SJohn Marino if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
55613ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
55623ff40c12SJohn Marino "interface name with '%s'", ifname);
55633ff40c12SJohn Marino os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
55643ff40c12SJohn Marino }
55653ff40c12SJohn Marino
5566*a1157835SDaniel Fojt rn = wpa_driver_get_radio_name(wpa_s);
55673ff40c12SJohn Marino if (rn && rn[0] == '\0')
55683ff40c12SJohn Marino rn = NULL;
55693ff40c12SJohn Marino
55703ff40c12SJohn Marino wpa_s->radio = radio_add_interface(wpa_s, rn);
55713ff40c12SJohn Marino if (wpa_s->radio == NULL)
55723ff40c12SJohn Marino return -1;
55733ff40c12SJohn Marino
55743ff40c12SJohn Marino return 0;
55753ff40c12SJohn Marino }
55763ff40c12SJohn Marino
55773ff40c12SJohn Marino
5578*a1157835SDaniel Fojt #ifdef CONFIG_GAS_SERVER
5579*a1157835SDaniel Fojt
wpas_gas_server_tx_status(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * data,size_t data_len,enum offchannel_send_action_result result)5580*a1157835SDaniel Fojt static void wpas_gas_server_tx_status(struct wpa_supplicant *wpa_s,
5581*a1157835SDaniel Fojt unsigned int freq, const u8 *dst,
5582*a1157835SDaniel Fojt const u8 *src, const u8 *bssid,
5583*a1157835SDaniel Fojt const u8 *data, size_t data_len,
5584*a1157835SDaniel Fojt enum offchannel_send_action_result result)
5585*a1157835SDaniel Fojt {
5586*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
5587*a1157835SDaniel Fojt " result=%s",
5588*a1157835SDaniel Fojt freq, MAC2STR(dst),
5589*a1157835SDaniel Fojt result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
5590*a1157835SDaniel Fojt (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
5591*a1157835SDaniel Fojt "FAILED"));
5592*a1157835SDaniel Fojt gas_server_tx_status(wpa_s->gas_server, dst, data, data_len,
5593*a1157835SDaniel Fojt result == OFFCHANNEL_SEND_ACTION_SUCCESS);
5594*a1157835SDaniel Fojt }
5595*a1157835SDaniel Fojt
5596*a1157835SDaniel Fojt
wpas_gas_server_tx(void * ctx,int freq,const u8 * da,struct wpabuf * buf,unsigned int wait_time)5597*a1157835SDaniel Fojt static void wpas_gas_server_tx(void *ctx, int freq, const u8 *da,
5598*a1157835SDaniel Fojt struct wpabuf *buf, unsigned int wait_time)
5599*a1157835SDaniel Fojt {
5600*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = ctx;
5601*a1157835SDaniel Fojt const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
5602*a1157835SDaniel Fojt
5603*a1157835SDaniel Fojt if (wait_time > wpa_s->max_remain_on_chan)
5604*a1157835SDaniel Fojt wait_time = wpa_s->max_remain_on_chan;
5605*a1157835SDaniel Fojt
5606*a1157835SDaniel Fojt offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, broadcast,
5607*a1157835SDaniel Fojt wpabuf_head(buf), wpabuf_len(buf),
5608*a1157835SDaniel Fojt wait_time, wpas_gas_server_tx_status, 0);
5609*a1157835SDaniel Fojt }
5610*a1157835SDaniel Fojt
5611*a1157835SDaniel Fojt #endif /* CONFIG_GAS_SERVER */
5612*a1157835SDaniel Fojt
wpa_supplicant_init_iface(struct wpa_supplicant * wpa_s,const struct wpa_interface * iface)56136d49e1aeSJan Lentfer static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
5614*a1157835SDaniel Fojt const struct wpa_interface *iface)
56156d49e1aeSJan Lentfer {
56163ff40c12SJohn Marino struct wpa_driver_capa capa;
5617*a1157835SDaniel Fojt int capa_res;
5618*a1157835SDaniel Fojt u8 dfs_domain;
56193ff40c12SJohn Marino
56206d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
56216d49e1aeSJan Lentfer "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
56226d49e1aeSJan Lentfer iface->confname ? iface->confname : "N/A",
56236d49e1aeSJan Lentfer iface->driver ? iface->driver : "default",
56246d49e1aeSJan Lentfer iface->ctrl_interface ? iface->ctrl_interface : "N/A",
56256d49e1aeSJan Lentfer iface->bridge_ifname ? iface->bridge_ifname : "N/A");
56266d49e1aeSJan Lentfer
56276d49e1aeSJan Lentfer if (iface->confname) {
56286d49e1aeSJan Lentfer #ifdef CONFIG_BACKEND_FILE
56296d49e1aeSJan Lentfer wpa_s->confname = os_rel2abs_path(iface->confname);
56306d49e1aeSJan Lentfer if (wpa_s->confname == NULL) {
56316d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "Failed to get absolute path "
56326d49e1aeSJan Lentfer "for configuration file '%s'.",
56336d49e1aeSJan Lentfer iface->confname);
56346d49e1aeSJan Lentfer return -1;
56356d49e1aeSJan Lentfer }
56366d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
56376d49e1aeSJan Lentfer iface->confname, wpa_s->confname);
56386d49e1aeSJan Lentfer #else /* CONFIG_BACKEND_FILE */
56396d49e1aeSJan Lentfer wpa_s->confname = os_strdup(iface->confname);
56406d49e1aeSJan Lentfer #endif /* CONFIG_BACKEND_FILE */
56413ff40c12SJohn Marino wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
56426d49e1aeSJan Lentfer if (wpa_s->conf == NULL) {
56436d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "Failed to read or parse "
56446d49e1aeSJan Lentfer "configuration '%s'.", wpa_s->confname);
56456d49e1aeSJan Lentfer return -1;
56466d49e1aeSJan Lentfer }
56473ff40c12SJohn Marino wpa_s->confanother = os_rel2abs_path(iface->confanother);
5648*a1157835SDaniel Fojt if (wpa_s->confanother &&
5649*a1157835SDaniel Fojt !wpa_config_read(wpa_s->confanother, wpa_s->conf)) {
5650*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
5651*a1157835SDaniel Fojt "Failed to read or parse configuration '%s'.",
5652*a1157835SDaniel Fojt wpa_s->confanother);
5653*a1157835SDaniel Fojt return -1;
5654*a1157835SDaniel Fojt }
56556d49e1aeSJan Lentfer
56566d49e1aeSJan Lentfer /*
56576d49e1aeSJan Lentfer * Override ctrl_interface and driver_param if set on command
56586d49e1aeSJan Lentfer * line.
56596d49e1aeSJan Lentfer */
56606d49e1aeSJan Lentfer if (iface->ctrl_interface) {
56616d49e1aeSJan Lentfer os_free(wpa_s->conf->ctrl_interface);
56626d49e1aeSJan Lentfer wpa_s->conf->ctrl_interface =
56636d49e1aeSJan Lentfer os_strdup(iface->ctrl_interface);
56646d49e1aeSJan Lentfer }
56656d49e1aeSJan Lentfer
56666d49e1aeSJan Lentfer if (iface->driver_param) {
56676d49e1aeSJan Lentfer os_free(wpa_s->conf->driver_param);
56686d49e1aeSJan Lentfer wpa_s->conf->driver_param =
56696d49e1aeSJan Lentfer os_strdup(iface->driver_param);
56706d49e1aeSJan Lentfer }
56713ff40c12SJohn Marino
56723ff40c12SJohn Marino if (iface->p2p_mgmt && !iface->ctrl_interface) {
56733ff40c12SJohn Marino os_free(wpa_s->conf->ctrl_interface);
56743ff40c12SJohn Marino wpa_s->conf->ctrl_interface = NULL;
56753ff40c12SJohn Marino }
56766d49e1aeSJan Lentfer } else
56776d49e1aeSJan Lentfer wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
56786d49e1aeSJan Lentfer iface->driver_param);
56796d49e1aeSJan Lentfer
56806d49e1aeSJan Lentfer if (wpa_s->conf == NULL) {
56816d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "\nNo configuration found.");
56826d49e1aeSJan Lentfer return -1;
56836d49e1aeSJan Lentfer }
56846d49e1aeSJan Lentfer
56856d49e1aeSJan Lentfer if (iface->ifname == NULL) {
56866d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "\nInterface name is required.");
56876d49e1aeSJan Lentfer return -1;
56886d49e1aeSJan Lentfer }
56896d49e1aeSJan Lentfer if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
56906d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
56916d49e1aeSJan Lentfer iface->ifname);
56926d49e1aeSJan Lentfer return -1;
56936d49e1aeSJan Lentfer }
56946d49e1aeSJan Lentfer os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
56956d49e1aeSJan Lentfer
56966d49e1aeSJan Lentfer if (iface->bridge_ifname) {
56976d49e1aeSJan Lentfer if (os_strlen(iface->bridge_ifname) >=
56986d49e1aeSJan Lentfer sizeof(wpa_s->bridge_ifname)) {
56996d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "\nToo long bridge interface "
57006d49e1aeSJan Lentfer "name '%s'.", iface->bridge_ifname);
57016d49e1aeSJan Lentfer return -1;
57026d49e1aeSJan Lentfer }
57036d49e1aeSJan Lentfer os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
57046d49e1aeSJan Lentfer sizeof(wpa_s->bridge_ifname));
57056d49e1aeSJan Lentfer }
57066d49e1aeSJan Lentfer
57076d49e1aeSJan Lentfer /* RSNA Supplicant Key Management - INITIALIZE */
57086d49e1aeSJan Lentfer eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
57096d49e1aeSJan Lentfer eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
57106d49e1aeSJan Lentfer
57116d49e1aeSJan Lentfer /* Initialize driver interface and register driver event handler before
57126d49e1aeSJan Lentfer * L2 receive handler so that association events are processed before
57136d49e1aeSJan Lentfer * EAPOL-Key packets if both become available for the same select()
57146d49e1aeSJan Lentfer * call. */
57153ff40c12SJohn Marino if (wpas_init_driver(wpa_s, iface) < 0)
57166d49e1aeSJan Lentfer return -1;
57176d49e1aeSJan Lentfer
57186d49e1aeSJan Lentfer if (wpa_supplicant_init_wpa(wpa_s) < 0)
57196d49e1aeSJan Lentfer return -1;
57206d49e1aeSJan Lentfer
57216d49e1aeSJan Lentfer wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
57226d49e1aeSJan Lentfer wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
57236d49e1aeSJan Lentfer NULL);
57246d49e1aeSJan Lentfer wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
57256d49e1aeSJan Lentfer
57266d49e1aeSJan Lentfer if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
57276d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
57286d49e1aeSJan Lentfer wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
57293ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
57306d49e1aeSJan Lentfer "dot11RSNAConfigPMKLifetime");
57316d49e1aeSJan Lentfer return -1;
57326d49e1aeSJan Lentfer }
57336d49e1aeSJan Lentfer
57346d49e1aeSJan Lentfer if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
57356d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
57366d49e1aeSJan Lentfer wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
57373ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
57386d49e1aeSJan Lentfer "dot11RSNAConfigPMKReauthThreshold");
57396d49e1aeSJan Lentfer return -1;
57406d49e1aeSJan Lentfer }
57416d49e1aeSJan Lentfer
57426d49e1aeSJan Lentfer if (wpa_s->conf->dot11RSNAConfigSATimeout &&
57436d49e1aeSJan Lentfer wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
57446d49e1aeSJan Lentfer wpa_s->conf->dot11RSNAConfigSATimeout)) {
57453ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
57466d49e1aeSJan Lentfer "dot11RSNAConfigSATimeout");
57476d49e1aeSJan Lentfer return -1;
57486d49e1aeSJan Lentfer }
57496d49e1aeSJan Lentfer
57503ff40c12SJohn Marino wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
57513ff40c12SJohn Marino &wpa_s->hw.num_modes,
5752*a1157835SDaniel Fojt &wpa_s->hw.flags,
5753*a1157835SDaniel Fojt &dfs_domain);
5754*a1157835SDaniel Fojt if (wpa_s->hw.modes) {
5755*a1157835SDaniel Fojt u16 i;
57563ff40c12SJohn Marino
5757*a1157835SDaniel Fojt for (i = 0; i < wpa_s->hw.num_modes; i++) {
5758*a1157835SDaniel Fojt if (wpa_s->hw.modes[i].vht_capab) {
5759*a1157835SDaniel Fojt wpa_s->hw_capab = CAPAB_VHT;
5760*a1157835SDaniel Fojt break;
5761*a1157835SDaniel Fojt }
5762*a1157835SDaniel Fojt
5763*a1157835SDaniel Fojt if (wpa_s->hw.modes[i].ht_capab &
5764*a1157835SDaniel Fojt HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
5765*a1157835SDaniel Fojt wpa_s->hw_capab = CAPAB_HT40;
5766*a1157835SDaniel Fojt else if (wpa_s->hw.modes[i].ht_capab &&
5767*a1157835SDaniel Fojt wpa_s->hw_capab == CAPAB_NO_HT_VHT)
5768*a1157835SDaniel Fojt wpa_s->hw_capab = CAPAB_HT;
5769*a1157835SDaniel Fojt }
5770*a1157835SDaniel Fojt }
5771*a1157835SDaniel Fojt
5772*a1157835SDaniel Fojt capa_res = wpa_drv_get_capa(wpa_s, &capa);
5773*a1157835SDaniel Fojt if (capa_res == 0) {
57743ff40c12SJohn Marino wpa_s->drv_capa_known = 1;
57753ff40c12SJohn Marino wpa_s->drv_flags = capa.flags;
57763ff40c12SJohn Marino wpa_s->drv_enc = capa.enc;
5777*a1157835SDaniel Fojt wpa_s->drv_smps_modes = capa.smps_modes;
5778*a1157835SDaniel Fojt wpa_s->drv_rrm_flags = capa.rrm_flags;
57793ff40c12SJohn Marino wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
57803ff40c12SJohn Marino wpa_s->max_scan_ssids = capa.max_scan_ssids;
57813ff40c12SJohn Marino wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
5782*a1157835SDaniel Fojt wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;
5783*a1157835SDaniel Fojt wpa_s->max_sched_scan_plan_interval =
5784*a1157835SDaniel Fojt capa.max_sched_scan_plan_interval;
5785*a1157835SDaniel Fojt wpa_s->max_sched_scan_plan_iterations =
5786*a1157835SDaniel Fojt capa.max_sched_scan_plan_iterations;
57873ff40c12SJohn Marino wpa_s->sched_scan_supported = capa.sched_scan_supported;
57883ff40c12SJohn Marino wpa_s->max_match_sets = capa.max_match_sets;
57893ff40c12SJohn Marino wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
57903ff40c12SJohn Marino wpa_s->max_stations = capa.max_stations;
57913ff40c12SJohn Marino wpa_s->extended_capa = capa.extended_capa;
57923ff40c12SJohn Marino wpa_s->extended_capa_mask = capa.extended_capa_mask;
57933ff40c12SJohn Marino wpa_s->extended_capa_len = capa.extended_capa_len;
57943ff40c12SJohn Marino wpa_s->num_multichan_concurrent =
57953ff40c12SJohn Marino capa.num_multichan_concurrent;
5796*a1157835SDaniel Fojt wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
5797*a1157835SDaniel Fojt
5798*a1157835SDaniel Fojt if (capa.mac_addr_rand_scan_supported)
5799*a1157835SDaniel Fojt wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
5800*a1157835SDaniel Fojt if (wpa_s->sched_scan_supported &&
5801*a1157835SDaniel Fojt capa.mac_addr_rand_sched_scan_supported)
5802*a1157835SDaniel Fojt wpa_s->mac_addr_rand_supported |=
5803*a1157835SDaniel Fojt (MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
5804*a1157835SDaniel Fojt
5805*a1157835SDaniel Fojt wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
5806*a1157835SDaniel Fojt if (wpa_s->extended_capa &&
5807*a1157835SDaniel Fojt wpa_s->extended_capa_len >= 3 &&
5808*a1157835SDaniel Fojt wpa_s->extended_capa[2] & 0x40)
5809*a1157835SDaniel Fojt wpa_s->multi_bss_support = 1;
58103ff40c12SJohn Marino }
58113ff40c12SJohn Marino if (wpa_s->max_remain_on_chan == 0)
58123ff40c12SJohn Marino wpa_s->max_remain_on_chan = 1000;
58133ff40c12SJohn Marino
58143ff40c12SJohn Marino /*
58153ff40c12SJohn Marino * Only take p2p_mgmt parameters when P2P Device is supported.
58163ff40c12SJohn Marino * Doing it here as it determines whether l2_packet_init() will be done
58173ff40c12SJohn Marino * during wpa_supplicant_driver_init().
58183ff40c12SJohn Marino */
58193ff40c12SJohn Marino if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
58203ff40c12SJohn Marino wpa_s->p2p_mgmt = iface->p2p_mgmt;
58213ff40c12SJohn Marino
58223ff40c12SJohn Marino if (wpa_s->num_multichan_concurrent == 0)
58233ff40c12SJohn Marino wpa_s->num_multichan_concurrent = 1;
58243ff40c12SJohn Marino
58256d49e1aeSJan Lentfer if (wpa_supplicant_driver_init(wpa_s) < 0)
58266d49e1aeSJan Lentfer return -1;
58276d49e1aeSJan Lentfer
58283ff40c12SJohn Marino #ifdef CONFIG_TDLS
5829*a1157835SDaniel Fojt if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
58303ff40c12SJohn Marino return -1;
58313ff40c12SJohn Marino #endif /* CONFIG_TDLS */
58323ff40c12SJohn Marino
58336d49e1aeSJan Lentfer if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
58346d49e1aeSJan Lentfer wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
58353ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
58366d49e1aeSJan Lentfer return -1;
58376d49e1aeSJan Lentfer }
58386d49e1aeSJan Lentfer
5839*a1157835SDaniel Fojt #ifdef CONFIG_FST
5840*a1157835SDaniel Fojt if (wpa_s->conf->fst_group_id) {
5841*a1157835SDaniel Fojt struct fst_iface_cfg cfg;
5842*a1157835SDaniel Fojt struct fst_wpa_obj iface_obj;
5843*a1157835SDaniel Fojt
5844*a1157835SDaniel Fojt fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
5845*a1157835SDaniel Fojt os_strlcpy(cfg.group_id, wpa_s->conf->fst_group_id,
5846*a1157835SDaniel Fojt sizeof(cfg.group_id));
5847*a1157835SDaniel Fojt cfg.priority = wpa_s->conf->fst_priority;
5848*a1157835SDaniel Fojt cfg.llt = wpa_s->conf->fst_llt;
5849*a1157835SDaniel Fojt
5850*a1157835SDaniel Fojt wpa_s->fst = fst_attach(wpa_s->ifname, wpa_s->own_addr,
5851*a1157835SDaniel Fojt &iface_obj, &cfg);
5852*a1157835SDaniel Fojt if (!wpa_s->fst) {
5853*a1157835SDaniel Fojt wpa_msg(wpa_s, MSG_ERROR,
5854*a1157835SDaniel Fojt "FST: Cannot attach iface %s to group %s",
5855*a1157835SDaniel Fojt wpa_s->ifname, cfg.group_id);
5856*a1157835SDaniel Fojt return -1;
5857*a1157835SDaniel Fojt }
5858*a1157835SDaniel Fojt }
5859*a1157835SDaniel Fojt #endif /* CONFIG_FST */
5860*a1157835SDaniel Fojt
58616d49e1aeSJan Lentfer if (wpas_wps_init(wpa_s))
58626d49e1aeSJan Lentfer return -1;
58636d49e1aeSJan Lentfer
5864*a1157835SDaniel Fojt #ifdef CONFIG_GAS_SERVER
5865*a1157835SDaniel Fojt wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);
5866*a1157835SDaniel Fojt if (!wpa_s->gas_server) {
5867*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "Failed to initialize GAS server");
5868*a1157835SDaniel Fojt return -1;
5869*a1157835SDaniel Fojt }
5870*a1157835SDaniel Fojt #endif /* CONFIG_GAS_SERVER */
5871*a1157835SDaniel Fojt
5872*a1157835SDaniel Fojt #ifdef CONFIG_DPP
5873*a1157835SDaniel Fojt if (wpas_dpp_init(wpa_s) < 0)
5874*a1157835SDaniel Fojt return -1;
5875*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
5876*a1157835SDaniel Fojt
58776d49e1aeSJan Lentfer if (wpa_supplicant_init_eapol(wpa_s) < 0)
58786d49e1aeSJan Lentfer return -1;
58796d49e1aeSJan Lentfer wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
58806d49e1aeSJan Lentfer
58816d49e1aeSJan Lentfer wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
58826d49e1aeSJan Lentfer if (wpa_s->ctrl_iface == NULL) {
58836d49e1aeSJan Lentfer wpa_printf(MSG_ERROR,
58846d49e1aeSJan Lentfer "Failed to initialize control interface '%s'.\n"
58856d49e1aeSJan Lentfer "You may have another wpa_supplicant process "
58866d49e1aeSJan Lentfer "already running or the file was\n"
58876d49e1aeSJan Lentfer "left by an unclean termination of wpa_supplicant "
58886d49e1aeSJan Lentfer "in which case you will need\n"
58896d49e1aeSJan Lentfer "to manually remove this file before starting "
58906d49e1aeSJan Lentfer "wpa_supplicant again.\n",
58916d49e1aeSJan Lentfer wpa_s->conf->ctrl_interface);
58926d49e1aeSJan Lentfer return -1;
58936d49e1aeSJan Lentfer }
58946d49e1aeSJan Lentfer
58953ff40c12SJohn Marino wpa_s->gas = gas_query_init(wpa_s);
58963ff40c12SJohn Marino if (wpa_s->gas == NULL) {
58973ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
58986d49e1aeSJan Lentfer return -1;
58996d49e1aeSJan Lentfer }
59003ff40c12SJohn Marino
5901*a1157835SDaniel Fojt if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||
5902*a1157835SDaniel Fojt wpa_s->p2p_mgmt) &&
5903*a1157835SDaniel Fojt wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
59043ff40c12SJohn Marino wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
59053ff40c12SJohn Marino return -1;
59066d49e1aeSJan Lentfer }
59073ff40c12SJohn Marino
59083ff40c12SJohn Marino if (wpa_bss_init(wpa_s) < 0)
59093ff40c12SJohn Marino return -1;
59103ff40c12SJohn Marino
5911*a1157835SDaniel Fojt #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
5912*a1157835SDaniel Fojt #ifdef CONFIG_MESH
5913*a1157835SDaniel Fojt dl_list_init(&wpa_s->mesh_external_pmksa_cache);
5914*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
5915*a1157835SDaniel Fojt #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
5916*a1157835SDaniel Fojt
5917*a1157835SDaniel Fojt /*
5918*a1157835SDaniel Fojt * Set Wake-on-WLAN triggers, if configured.
5919*a1157835SDaniel Fojt * Note: We don't restore/remove the triggers on shutdown (it doesn't
5920*a1157835SDaniel Fojt * have effect anyway when the interface is down).
5921*a1157835SDaniel Fojt */
5922*a1157835SDaniel Fojt if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
5923*a1157835SDaniel Fojt return -1;
5924*a1157835SDaniel Fojt
59253ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
59263ff40c12SJohn Marino {
59273ff40c12SJohn Marino size_t len;
5928*a1157835SDaniel Fojt wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
5929*a1157835SDaniel Fojt wpa_s->imsi, &len);
59303ff40c12SJohn Marino if (wpa_s->mnc_len > 0) {
59313ff40c12SJohn Marino wpa_s->imsi[len] = '\0';
59323ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
59333ff40c12SJohn Marino wpa_s->imsi, wpa_s->mnc_len);
59343ff40c12SJohn Marino } else {
59353ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
59363ff40c12SJohn Marino }
59373ff40c12SJohn Marino }
59383ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
59393ff40c12SJohn Marino
59403ff40c12SJohn Marino if (pcsc_reader_init(wpa_s) < 0)
59413ff40c12SJohn Marino return -1;
59423ff40c12SJohn Marino
59433ff40c12SJohn Marino if (wpas_init_ext_pw(wpa_s) < 0)
59443ff40c12SJohn Marino return -1;
59456d49e1aeSJan Lentfer
5946*a1157835SDaniel Fojt wpas_rrm_reset(wpa_s);
5947*a1157835SDaniel Fojt
5948*a1157835SDaniel Fojt wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
5949*a1157835SDaniel Fojt
5950*a1157835SDaniel Fojt #ifdef CONFIG_HS20
5951*a1157835SDaniel Fojt hs20_init(wpa_s);
5952*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
5953*a1157835SDaniel Fojt #ifdef CONFIG_MBO
5954*a1157835SDaniel Fojt if (wpa_s->conf->oce) {
5955*a1157835SDaniel Fojt if ((wpa_s->conf->oce & OCE_STA) &&
5956*a1157835SDaniel Fojt (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
5957*a1157835SDaniel Fojt wpa_s->enable_oce = OCE_STA;
5958*a1157835SDaniel Fojt if ((wpa_s->conf->oce & OCE_STA_CFON) &&
5959*a1157835SDaniel Fojt (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
5960*a1157835SDaniel Fojt /* TODO: Need to add STA-CFON support */
5961*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
5962*a1157835SDaniel Fojt "OCE STA-CFON feature is not yet supported");
5963*a1157835SDaniel Fojt }
5964*a1157835SDaniel Fojt }
5965*a1157835SDaniel Fojt wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
5966*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
5967*a1157835SDaniel Fojt
5968*a1157835SDaniel Fojt wpa_supplicant_set_default_scan_ies(wpa_s);
5969*a1157835SDaniel Fojt
59706d49e1aeSJan Lentfer return 0;
59716d49e1aeSJan Lentfer }
59726d49e1aeSJan Lentfer
59736d49e1aeSJan Lentfer
wpa_supplicant_deinit_iface(struct wpa_supplicant * wpa_s,int notify,int terminate)59743ff40c12SJohn Marino static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
59753ff40c12SJohn Marino int notify, int terminate)
59766d49e1aeSJan Lentfer {
5977*a1157835SDaniel Fojt struct wpa_global *global = wpa_s->global;
5978*a1157835SDaniel Fojt struct wpa_supplicant *iface, *prev;
5979*a1157835SDaniel Fojt
5980*a1157835SDaniel Fojt if (wpa_s == wpa_s->parent)
5981*a1157835SDaniel Fojt wpas_p2p_group_remove(wpa_s, "*");
5982*a1157835SDaniel Fojt
5983*a1157835SDaniel Fojt iface = global->ifaces;
5984*a1157835SDaniel Fojt while (iface) {
5985*a1157835SDaniel Fojt if (iface->p2pdev == wpa_s)
5986*a1157835SDaniel Fojt iface->p2pdev = iface->parent;
5987*a1157835SDaniel Fojt if (iface == wpa_s || iface->parent != wpa_s) {
5988*a1157835SDaniel Fojt iface = iface->next;
5989*a1157835SDaniel Fojt continue;
5990*a1157835SDaniel Fojt }
5991*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
5992*a1157835SDaniel Fojt "Remove remaining child interface %s from parent %s",
5993*a1157835SDaniel Fojt iface->ifname, wpa_s->ifname);
5994*a1157835SDaniel Fojt prev = iface;
5995*a1157835SDaniel Fojt iface = iface->next;
5996*a1157835SDaniel Fojt wpa_supplicant_remove_iface(global, prev, terminate);
5997*a1157835SDaniel Fojt }
5998*a1157835SDaniel Fojt
59993ff40c12SJohn Marino wpa_s->disconnected = 1;
60006d49e1aeSJan Lentfer if (wpa_s->drv_priv) {
60016d49e1aeSJan Lentfer wpa_supplicant_deauthenticate(wpa_s,
60026d49e1aeSJan Lentfer WLAN_REASON_DEAUTH_LEAVING);
60036d49e1aeSJan Lentfer
60046d49e1aeSJan Lentfer wpa_drv_set_countermeasures(wpa_s, 0);
60056d49e1aeSJan Lentfer wpa_clear_keys(wpa_s, NULL);
60066d49e1aeSJan Lentfer }
60076d49e1aeSJan Lentfer
60086d49e1aeSJan Lentfer wpa_supplicant_cleanup(wpa_s);
6009*a1157835SDaniel Fojt wpas_p2p_deinit_iface(wpa_s);
60103ff40c12SJohn Marino
60113ff40c12SJohn Marino wpas_ctrl_radio_work_flush(wpa_s);
60123ff40c12SJohn Marino radio_remove_interface(wpa_s);
60133ff40c12SJohn Marino
6014*a1157835SDaniel Fojt #ifdef CONFIG_FST
6015*a1157835SDaniel Fojt if (wpa_s->fst) {
6016*a1157835SDaniel Fojt fst_detach(wpa_s->fst);
6017*a1157835SDaniel Fojt wpa_s->fst = NULL;
6018*a1157835SDaniel Fojt }
6019*a1157835SDaniel Fojt if (wpa_s->received_mb_ies) {
6020*a1157835SDaniel Fojt wpabuf_free(wpa_s->received_mb_ies);
6021*a1157835SDaniel Fojt wpa_s->received_mb_ies = NULL;
6022*a1157835SDaniel Fojt }
6023*a1157835SDaniel Fojt #endif /* CONFIG_FST */
6024*a1157835SDaniel Fojt
60256d49e1aeSJan Lentfer if (wpa_s->drv_priv)
60266d49e1aeSJan Lentfer wpa_drv_deinit(wpa_s);
60273ff40c12SJohn Marino
60283ff40c12SJohn Marino if (notify)
60293ff40c12SJohn Marino wpas_notify_iface_removed(wpa_s);
60303ff40c12SJohn Marino
60313ff40c12SJohn Marino if (terminate)
60323ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
60333ff40c12SJohn Marino
60343ff40c12SJohn Marino if (wpa_s->ctrl_iface) {
60353ff40c12SJohn Marino wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
60363ff40c12SJohn Marino wpa_s->ctrl_iface = NULL;
60373ff40c12SJohn Marino }
60383ff40c12SJohn Marino
6039*a1157835SDaniel Fojt #ifdef CONFIG_MESH
6040*a1157835SDaniel Fojt if (wpa_s->ifmsh) {
6041*a1157835SDaniel Fojt wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
6042*a1157835SDaniel Fojt wpa_s->ifmsh = NULL;
6043*a1157835SDaniel Fojt }
6044*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
6045*a1157835SDaniel Fojt
60463ff40c12SJohn Marino if (wpa_s->conf != NULL) {
60473ff40c12SJohn Marino wpa_config_free(wpa_s->conf);
60483ff40c12SJohn Marino wpa_s->conf = NULL;
60493ff40c12SJohn Marino }
60503ff40c12SJohn Marino
6051*a1157835SDaniel Fojt os_free(wpa_s->ssids_from_scan_req);
6052*a1157835SDaniel Fojt
60533ff40c12SJohn Marino os_free(wpa_s);
60546d49e1aeSJan Lentfer }
60556d49e1aeSJan Lentfer
60566d49e1aeSJan Lentfer
6057*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
6058*a1157835SDaniel Fojt
6059*a1157835SDaniel Fojt /**
6060*a1157835SDaniel Fojt * wpa_supplicant_match_iface - Match an interface description to a name
6061*a1157835SDaniel Fojt * @global: Pointer to global data from wpa_supplicant_init()
6062*a1157835SDaniel Fojt * @ifname: Name of the interface to match
6063*a1157835SDaniel Fojt * Returns: Pointer to the created interface description or %NULL on failure
6064*a1157835SDaniel Fojt */
wpa_supplicant_match_iface(struct wpa_global * global,const char * ifname)6065*a1157835SDaniel Fojt struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
6066*a1157835SDaniel Fojt const char *ifname)
6067*a1157835SDaniel Fojt {
6068*a1157835SDaniel Fojt int i;
6069*a1157835SDaniel Fojt struct wpa_interface *iface, *miface;
6070*a1157835SDaniel Fojt
6071*a1157835SDaniel Fojt for (i = 0; i < global->params.match_iface_count; i++) {
6072*a1157835SDaniel Fojt miface = &global->params.match_ifaces[i];
6073*a1157835SDaniel Fojt if (!miface->ifname ||
6074*a1157835SDaniel Fojt fnmatch(miface->ifname, ifname, 0) == 0) {
6075*a1157835SDaniel Fojt iface = os_zalloc(sizeof(*iface));
6076*a1157835SDaniel Fojt if (!iface)
6077*a1157835SDaniel Fojt return NULL;
6078*a1157835SDaniel Fojt *iface = *miface;
6079*a1157835SDaniel Fojt iface->ifname = ifname;
6080*a1157835SDaniel Fojt return iface;
6081*a1157835SDaniel Fojt }
6082*a1157835SDaniel Fojt }
6083*a1157835SDaniel Fojt
6084*a1157835SDaniel Fojt return NULL;
6085*a1157835SDaniel Fojt }
6086*a1157835SDaniel Fojt
6087*a1157835SDaniel Fojt
6088*a1157835SDaniel Fojt /**
6089*a1157835SDaniel Fojt * wpa_supplicant_match_existing - Match existing interfaces
6090*a1157835SDaniel Fojt * @global: Pointer to global data from wpa_supplicant_init()
6091*a1157835SDaniel Fojt * Returns: 0 on success, -1 on failure
6092*a1157835SDaniel Fojt */
wpa_supplicant_match_existing(struct wpa_global * global)6093*a1157835SDaniel Fojt static int wpa_supplicant_match_existing(struct wpa_global *global)
6094*a1157835SDaniel Fojt {
6095*a1157835SDaniel Fojt struct if_nameindex *ifi, *ifp;
6096*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s;
6097*a1157835SDaniel Fojt struct wpa_interface *iface;
6098*a1157835SDaniel Fojt
6099*a1157835SDaniel Fojt ifp = if_nameindex();
6100*a1157835SDaniel Fojt if (!ifp) {
6101*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
6102*a1157835SDaniel Fojt return -1;
6103*a1157835SDaniel Fojt }
6104*a1157835SDaniel Fojt
6105*a1157835SDaniel Fojt for (ifi = ifp; ifi->if_name; ifi++) {
6106*a1157835SDaniel Fojt wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
6107*a1157835SDaniel Fojt if (wpa_s)
6108*a1157835SDaniel Fojt continue;
6109*a1157835SDaniel Fojt iface = wpa_supplicant_match_iface(global, ifi->if_name);
6110*a1157835SDaniel Fojt if (iface) {
6111*a1157835SDaniel Fojt wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
6112*a1157835SDaniel Fojt os_free(iface);
6113*a1157835SDaniel Fojt if (wpa_s)
6114*a1157835SDaniel Fojt wpa_s->matched = 1;
6115*a1157835SDaniel Fojt }
6116*a1157835SDaniel Fojt }
6117*a1157835SDaniel Fojt
6118*a1157835SDaniel Fojt if_freenameindex(ifp);
6119*a1157835SDaniel Fojt return 0;
6120*a1157835SDaniel Fojt }
6121*a1157835SDaniel Fojt
6122*a1157835SDaniel Fojt #endif /* CONFIG_MATCH_IFACE */
6123*a1157835SDaniel Fojt
6124*a1157835SDaniel Fojt
61256d49e1aeSJan Lentfer /**
61266d49e1aeSJan Lentfer * wpa_supplicant_add_iface - Add a new network interface
61276d49e1aeSJan Lentfer * @global: Pointer to global data from wpa_supplicant_init()
61286d49e1aeSJan Lentfer * @iface: Interface configuration options
6129*a1157835SDaniel Fojt * @parent: Parent interface or %NULL to assign new interface as parent
61306d49e1aeSJan Lentfer * Returns: Pointer to the created interface or %NULL on failure
61316d49e1aeSJan Lentfer *
61326d49e1aeSJan Lentfer * This function is used to add new network interfaces for %wpa_supplicant.
61336d49e1aeSJan Lentfer * This can be called before wpa_supplicant_run() to add interfaces before the
61346d49e1aeSJan Lentfer * main event loop has been started. In addition, new interfaces can be added
61356d49e1aeSJan Lentfer * dynamically while %wpa_supplicant is already running. This could happen,
61366d49e1aeSJan Lentfer * e.g., when a hotplug network adapter is inserted.
61376d49e1aeSJan Lentfer */
wpa_supplicant_add_iface(struct wpa_global * global,struct wpa_interface * iface,struct wpa_supplicant * parent)61386d49e1aeSJan Lentfer struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
6139*a1157835SDaniel Fojt struct wpa_interface *iface,
6140*a1157835SDaniel Fojt struct wpa_supplicant *parent)
61416d49e1aeSJan Lentfer {
61426d49e1aeSJan Lentfer struct wpa_supplicant *wpa_s;
61433ff40c12SJohn Marino struct wpa_interface t_iface;
61443ff40c12SJohn Marino struct wpa_ssid *ssid;
61456d49e1aeSJan Lentfer
61466d49e1aeSJan Lentfer if (global == NULL || iface == NULL)
61476d49e1aeSJan Lentfer return NULL;
61486d49e1aeSJan Lentfer
6149*a1157835SDaniel Fojt wpa_s = wpa_supplicant_alloc(parent);
61506d49e1aeSJan Lentfer if (wpa_s == NULL)
61516d49e1aeSJan Lentfer return NULL;
61526d49e1aeSJan Lentfer
61536d49e1aeSJan Lentfer wpa_s->global = global;
61546d49e1aeSJan Lentfer
61553ff40c12SJohn Marino t_iface = *iface;
61563ff40c12SJohn Marino if (global->params.override_driver) {
61573ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
61583ff40c12SJohn Marino "('%s' -> '%s')",
61593ff40c12SJohn Marino iface->driver, global->params.override_driver);
61603ff40c12SJohn Marino t_iface.driver = global->params.override_driver;
61613ff40c12SJohn Marino }
61623ff40c12SJohn Marino if (global->params.override_ctrl_interface) {
61633ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Override interface parameter: "
61643ff40c12SJohn Marino "ctrl_interface ('%s' -> '%s')",
61653ff40c12SJohn Marino iface->ctrl_interface,
61663ff40c12SJohn Marino global->params.override_ctrl_interface);
61673ff40c12SJohn Marino t_iface.ctrl_interface =
61683ff40c12SJohn Marino global->params.override_ctrl_interface;
61693ff40c12SJohn Marino }
61703ff40c12SJohn Marino if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
61716d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Failed to add interface %s",
61726d49e1aeSJan Lentfer iface->ifname);
61733ff40c12SJohn Marino wpa_supplicant_deinit_iface(wpa_s, 0, 0);
61746d49e1aeSJan Lentfer return NULL;
61756d49e1aeSJan Lentfer }
61766d49e1aeSJan Lentfer
6177*a1157835SDaniel Fojt if (iface->p2p_mgmt == 0) {
61783ff40c12SJohn Marino /* Notify the control interfaces about new iface */
61793ff40c12SJohn Marino if (wpas_notify_iface_added(wpa_s)) {
61803ff40c12SJohn Marino wpa_supplicant_deinit_iface(wpa_s, 1, 0);
61816d49e1aeSJan Lentfer return NULL;
61826d49e1aeSJan Lentfer }
61836d49e1aeSJan Lentfer
61843ff40c12SJohn Marino for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
61853ff40c12SJohn Marino wpas_notify_network_added(wpa_s, ssid);
6186*a1157835SDaniel Fojt }
61873ff40c12SJohn Marino
61886d49e1aeSJan Lentfer wpa_s->next = global->ifaces;
61896d49e1aeSJan Lentfer global->ifaces = wpa_s;
61906d49e1aeSJan Lentfer
61913ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
61923ff40c12SJohn Marino wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
61936d49e1aeSJan Lentfer
6194*a1157835SDaniel Fojt #ifdef CONFIG_P2P
6195*a1157835SDaniel Fojt if (wpa_s->global->p2p == NULL &&
6196*a1157835SDaniel Fojt !wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled &&
6197*a1157835SDaniel Fojt (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
6198*a1157835SDaniel Fojt wpas_p2p_add_p2pdev_interface(
6199*a1157835SDaniel Fojt wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
6200*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
6201*a1157835SDaniel Fojt "P2P: Failed to enable P2P Device interface");
6202*a1157835SDaniel Fojt /* Try to continue without. P2P will be disabled. */
6203*a1157835SDaniel Fojt }
6204*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
6205*a1157835SDaniel Fojt
62066d49e1aeSJan Lentfer return wpa_s;
62076d49e1aeSJan Lentfer }
62086d49e1aeSJan Lentfer
62096d49e1aeSJan Lentfer
62106d49e1aeSJan Lentfer /**
62116d49e1aeSJan Lentfer * wpa_supplicant_remove_iface - Remove a network interface
62126d49e1aeSJan Lentfer * @global: Pointer to global data from wpa_supplicant_init()
62136d49e1aeSJan Lentfer * @wpa_s: Pointer to the network interface to be removed
62146d49e1aeSJan Lentfer * Returns: 0 if interface was removed, -1 if interface was not found
62156d49e1aeSJan Lentfer *
62166d49e1aeSJan Lentfer * This function can be used to dynamically remove network interfaces from
62176d49e1aeSJan Lentfer * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
62186d49e1aeSJan Lentfer * addition, this function is used to remove all remaining interfaces when
62196d49e1aeSJan Lentfer * %wpa_supplicant is terminated.
62206d49e1aeSJan Lentfer */
wpa_supplicant_remove_iface(struct wpa_global * global,struct wpa_supplicant * wpa_s,int terminate)62216d49e1aeSJan Lentfer int wpa_supplicant_remove_iface(struct wpa_global *global,
62223ff40c12SJohn Marino struct wpa_supplicant *wpa_s,
62233ff40c12SJohn Marino int terminate)
62246d49e1aeSJan Lentfer {
62256d49e1aeSJan Lentfer struct wpa_supplicant *prev;
6226*a1157835SDaniel Fojt #ifdef CONFIG_MESH
6227*a1157835SDaniel Fojt unsigned int mesh_if_created = wpa_s->mesh_if_created;
6228*a1157835SDaniel Fojt char *ifname = NULL;
6229*a1157835SDaniel Fojt struct wpa_supplicant *parent = wpa_s->parent;
6230*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
62316d49e1aeSJan Lentfer
62326d49e1aeSJan Lentfer /* Remove interface from the global list of interfaces */
62336d49e1aeSJan Lentfer prev = global->ifaces;
62346d49e1aeSJan Lentfer if (prev == wpa_s) {
62356d49e1aeSJan Lentfer global->ifaces = wpa_s->next;
62366d49e1aeSJan Lentfer } else {
62376d49e1aeSJan Lentfer while (prev && prev->next != wpa_s)
62386d49e1aeSJan Lentfer prev = prev->next;
62396d49e1aeSJan Lentfer if (prev == NULL)
62406d49e1aeSJan Lentfer return -1;
62416d49e1aeSJan Lentfer prev->next = wpa_s->next;
62426d49e1aeSJan Lentfer }
62436d49e1aeSJan Lentfer
62443ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
62456d49e1aeSJan Lentfer
6246*a1157835SDaniel Fojt #ifdef CONFIG_MESH
6247*a1157835SDaniel Fojt if (mesh_if_created) {
6248*a1157835SDaniel Fojt ifname = os_strdup(wpa_s->ifname);
6249*a1157835SDaniel Fojt if (ifname == NULL) {
6250*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_ERROR,
6251*a1157835SDaniel Fojt "mesh: Failed to malloc ifname");
6252*a1157835SDaniel Fojt return -1;
6253*a1157835SDaniel Fojt }
6254*a1157835SDaniel Fojt }
6255*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
6256*a1157835SDaniel Fojt
62573ff40c12SJohn Marino if (global->p2p_group_formation == wpa_s)
62583ff40c12SJohn Marino global->p2p_group_formation = NULL;
62593ff40c12SJohn Marino if (global->p2p_invite_group == wpa_s)
62603ff40c12SJohn Marino global->p2p_invite_group = NULL;
62613ff40c12SJohn Marino wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
62626d49e1aeSJan Lentfer
6263*a1157835SDaniel Fojt #ifdef CONFIG_MESH
6264*a1157835SDaniel Fojt if (mesh_if_created) {
6265*a1157835SDaniel Fojt wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
6266*a1157835SDaniel Fojt os_free(ifname);
6267*a1157835SDaniel Fojt }
6268*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
6269*a1157835SDaniel Fojt
62706d49e1aeSJan Lentfer return 0;
62716d49e1aeSJan Lentfer }
62726d49e1aeSJan Lentfer
62736d49e1aeSJan Lentfer
62746d49e1aeSJan Lentfer /**
62753ff40c12SJohn Marino * wpa_supplicant_get_eap_mode - Get the current EAP mode
62763ff40c12SJohn Marino * @wpa_s: Pointer to the network interface
62773ff40c12SJohn Marino * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
62783ff40c12SJohn Marino */
wpa_supplicant_get_eap_mode(struct wpa_supplicant * wpa_s)62793ff40c12SJohn Marino const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
62803ff40c12SJohn Marino {
62813ff40c12SJohn Marino const char *eapol_method;
62823ff40c12SJohn Marino
62833ff40c12SJohn Marino if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
62843ff40c12SJohn Marino wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
62853ff40c12SJohn Marino return "NO-EAP";
62863ff40c12SJohn Marino }
62873ff40c12SJohn Marino
62883ff40c12SJohn Marino eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
62893ff40c12SJohn Marino if (eapol_method == NULL)
62903ff40c12SJohn Marino return "UNKNOWN-EAP";
62913ff40c12SJohn Marino
62923ff40c12SJohn Marino return eapol_method;
62933ff40c12SJohn Marino }
62943ff40c12SJohn Marino
62953ff40c12SJohn Marino
62963ff40c12SJohn Marino /**
62976d49e1aeSJan Lentfer * wpa_supplicant_get_iface - Get a new network interface
62986d49e1aeSJan Lentfer * @global: Pointer to global data from wpa_supplicant_init()
62996d49e1aeSJan Lentfer * @ifname: Interface name
63006d49e1aeSJan Lentfer * Returns: Pointer to the interface or %NULL if not found
63016d49e1aeSJan Lentfer */
wpa_supplicant_get_iface(struct wpa_global * global,const char * ifname)63026d49e1aeSJan Lentfer struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
63036d49e1aeSJan Lentfer const char *ifname)
63046d49e1aeSJan Lentfer {
63056d49e1aeSJan Lentfer struct wpa_supplicant *wpa_s;
63066d49e1aeSJan Lentfer
63076d49e1aeSJan Lentfer for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
63086d49e1aeSJan Lentfer if (os_strcmp(wpa_s->ifname, ifname) == 0)
63096d49e1aeSJan Lentfer return wpa_s;
63106d49e1aeSJan Lentfer }
63116d49e1aeSJan Lentfer return NULL;
63126d49e1aeSJan Lentfer }
63136d49e1aeSJan Lentfer
63146d49e1aeSJan Lentfer
63153ff40c12SJohn Marino #ifndef CONFIG_NO_WPA_MSG
wpa_supplicant_msg_ifname_cb(void * ctx)63163ff40c12SJohn Marino static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
63173ff40c12SJohn Marino {
63183ff40c12SJohn Marino struct wpa_supplicant *wpa_s = ctx;
63193ff40c12SJohn Marino if (wpa_s == NULL)
63203ff40c12SJohn Marino return NULL;
63213ff40c12SJohn Marino return wpa_s->ifname;
63223ff40c12SJohn Marino }
63233ff40c12SJohn Marino #endif /* CONFIG_NO_WPA_MSG */
63243ff40c12SJohn Marino
63253ff40c12SJohn Marino
6326*a1157835SDaniel Fojt #ifndef WPA_SUPPLICANT_CLEANUP_INTERVAL
6327*a1157835SDaniel Fojt #define WPA_SUPPLICANT_CLEANUP_INTERVAL 10
6328*a1157835SDaniel Fojt #endif /* WPA_SUPPLICANT_CLEANUP_INTERVAL */
6329*a1157835SDaniel Fojt
6330*a1157835SDaniel Fojt /* Periodic cleanup tasks */
wpas_periodic(void * eloop_ctx,void * timeout_ctx)6331*a1157835SDaniel Fojt static void wpas_periodic(void *eloop_ctx, void *timeout_ctx)
6332*a1157835SDaniel Fojt {
6333*a1157835SDaniel Fojt struct wpa_global *global = eloop_ctx;
6334*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s;
6335*a1157835SDaniel Fojt
6336*a1157835SDaniel Fojt eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
6337*a1157835SDaniel Fojt wpas_periodic, global, NULL);
6338*a1157835SDaniel Fojt
6339*a1157835SDaniel Fojt #ifdef CONFIG_P2P
6340*a1157835SDaniel Fojt if (global->p2p)
6341*a1157835SDaniel Fojt p2p_expire_peers(global->p2p);
6342*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
6343*a1157835SDaniel Fojt
6344*a1157835SDaniel Fojt for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
6345*a1157835SDaniel Fojt wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
6346*a1157835SDaniel Fojt #ifdef CONFIG_AP
6347*a1157835SDaniel Fojt ap_periodic(wpa_s);
6348*a1157835SDaniel Fojt #endif /* CONFIG_AP */
6349*a1157835SDaniel Fojt }
6350*a1157835SDaniel Fojt }
6351*a1157835SDaniel Fojt
6352*a1157835SDaniel Fojt
63536d49e1aeSJan Lentfer /**
63546d49e1aeSJan Lentfer * wpa_supplicant_init - Initialize %wpa_supplicant
63556d49e1aeSJan Lentfer * @params: Parameters for %wpa_supplicant
63566d49e1aeSJan Lentfer * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
63576d49e1aeSJan Lentfer *
63586d49e1aeSJan Lentfer * This function is used to initialize %wpa_supplicant. After successful
63596d49e1aeSJan Lentfer * initialization, the returned data pointer can be used to add and remove
63606d49e1aeSJan Lentfer * network interfaces, and eventually, to deinitialize %wpa_supplicant.
63616d49e1aeSJan Lentfer */
wpa_supplicant_init(struct wpa_params * params)63626d49e1aeSJan Lentfer struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
63636d49e1aeSJan Lentfer {
63646d49e1aeSJan Lentfer struct wpa_global *global;
63656d49e1aeSJan Lentfer int ret, i;
63666d49e1aeSJan Lentfer
63676d49e1aeSJan Lentfer if (params == NULL)
63686d49e1aeSJan Lentfer return NULL;
63696d49e1aeSJan Lentfer
63703ff40c12SJohn Marino #ifdef UNMASK__CONFIG_DRIVER_NDIS
63713ff40c12SJohn Marino {
63723ff40c12SJohn Marino void driver_ndis_init_ops(void);
63733ff40c12SJohn Marino driver_ndis_init_ops();
63743ff40c12SJohn Marino }
63753ff40c12SJohn Marino #endif /* CONFIG_DRIVER_NDIS */
63766d49e1aeSJan Lentfer
63773ff40c12SJohn Marino #ifndef CONFIG_NO_WPA_MSG
63783ff40c12SJohn Marino wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
63793ff40c12SJohn Marino #endif /* CONFIG_NO_WPA_MSG */
63803ff40c12SJohn Marino
6381*a1157835SDaniel Fojt if (params->wpa_debug_file_path)
63823ff40c12SJohn Marino wpa_debug_open_file(params->wpa_debug_file_path);
6383*a1157835SDaniel Fojt else
6384*a1157835SDaniel Fojt wpa_debug_setup_stdout();
63853ff40c12SJohn Marino if (params->wpa_debug_syslog)
63863ff40c12SJohn Marino wpa_debug_open_syslog();
63873ff40c12SJohn Marino if (params->wpa_debug_tracing) {
63883ff40c12SJohn Marino ret = wpa_debug_open_linux_tracing();
63893ff40c12SJohn Marino if (ret) {
63903ff40c12SJohn Marino wpa_printf(MSG_ERROR,
63913ff40c12SJohn Marino "Failed to enable trace logging");
63923ff40c12SJohn Marino return NULL;
63933ff40c12SJohn Marino }
63943ff40c12SJohn Marino }
63953ff40c12SJohn Marino
63963ff40c12SJohn Marino ret = eap_register_methods();
63976d49e1aeSJan Lentfer if (ret) {
63986d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "Failed to register EAP methods");
63996d49e1aeSJan Lentfer if (ret == -2)
64006d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "Two or more EAP methods used "
64016d49e1aeSJan Lentfer "the same EAP type.");
64026d49e1aeSJan Lentfer return NULL;
64036d49e1aeSJan Lentfer }
64046d49e1aeSJan Lentfer
64056d49e1aeSJan Lentfer global = os_zalloc(sizeof(*global));
64066d49e1aeSJan Lentfer if (global == NULL)
64076d49e1aeSJan Lentfer return NULL;
64083ff40c12SJohn Marino dl_list_init(&global->p2p_srv_bonjour);
64093ff40c12SJohn Marino dl_list_init(&global->p2p_srv_upnp);
64106d49e1aeSJan Lentfer global->params.daemonize = params->daemonize;
64116d49e1aeSJan Lentfer global->params.wait_for_monitor = params->wait_for_monitor;
64126d49e1aeSJan Lentfer global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
64136d49e1aeSJan Lentfer if (params->pid_file)
64146d49e1aeSJan Lentfer global->params.pid_file = os_strdup(params->pid_file);
64156d49e1aeSJan Lentfer if (params->ctrl_interface)
64166d49e1aeSJan Lentfer global->params.ctrl_interface =
64176d49e1aeSJan Lentfer os_strdup(params->ctrl_interface);
64183ff40c12SJohn Marino if (params->ctrl_interface_group)
64193ff40c12SJohn Marino global->params.ctrl_interface_group =
64203ff40c12SJohn Marino os_strdup(params->ctrl_interface_group);
64213ff40c12SJohn Marino if (params->override_driver)
64223ff40c12SJohn Marino global->params.override_driver =
64233ff40c12SJohn Marino os_strdup(params->override_driver);
64243ff40c12SJohn Marino if (params->override_ctrl_interface)
64253ff40c12SJohn Marino global->params.override_ctrl_interface =
64263ff40c12SJohn Marino os_strdup(params->override_ctrl_interface);
6427*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
6428*a1157835SDaniel Fojt global->params.match_iface_count = params->match_iface_count;
6429*a1157835SDaniel Fojt if (params->match_iface_count) {
6430*a1157835SDaniel Fojt global->params.match_ifaces =
6431*a1157835SDaniel Fojt os_calloc(params->match_iface_count,
6432*a1157835SDaniel Fojt sizeof(struct wpa_interface));
6433*a1157835SDaniel Fojt os_memcpy(global->params.match_ifaces,
6434*a1157835SDaniel Fojt params->match_ifaces,
6435*a1157835SDaniel Fojt params->match_iface_count *
6436*a1157835SDaniel Fojt sizeof(struct wpa_interface));
6437*a1157835SDaniel Fojt }
6438*a1157835SDaniel Fojt #endif /* CONFIG_MATCH_IFACE */
6439*a1157835SDaniel Fojt #ifdef CONFIG_P2P
6440*a1157835SDaniel Fojt if (params->conf_p2p_dev)
6441*a1157835SDaniel Fojt global->params.conf_p2p_dev =
6442*a1157835SDaniel Fojt os_strdup(params->conf_p2p_dev);
6443*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
64446d49e1aeSJan Lentfer wpa_debug_level = global->params.wpa_debug_level =
64456d49e1aeSJan Lentfer params->wpa_debug_level;
64466d49e1aeSJan Lentfer wpa_debug_show_keys = global->params.wpa_debug_show_keys =
64476d49e1aeSJan Lentfer params->wpa_debug_show_keys;
64486d49e1aeSJan Lentfer wpa_debug_timestamp = global->params.wpa_debug_timestamp =
64496d49e1aeSJan Lentfer params->wpa_debug_timestamp;
64506d49e1aeSJan Lentfer
64513ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
64523ff40c12SJohn Marino
64533ff40c12SJohn Marino if (eloop_init()) {
64546d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "Failed to initialize event loop");
64556d49e1aeSJan Lentfer wpa_supplicant_deinit(global);
64566d49e1aeSJan Lentfer return NULL;
64576d49e1aeSJan Lentfer }
64586d49e1aeSJan Lentfer
64593ff40c12SJohn Marino random_init(params->entropy_file);
64603ff40c12SJohn Marino
64616d49e1aeSJan Lentfer global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
64626d49e1aeSJan Lentfer if (global->ctrl_iface == NULL) {
64636d49e1aeSJan Lentfer wpa_supplicant_deinit(global);
64646d49e1aeSJan Lentfer return NULL;
64656d49e1aeSJan Lentfer }
64666d49e1aeSJan Lentfer
64673ff40c12SJohn Marino if (wpas_notify_supplicant_initialized(global)) {
64686d49e1aeSJan Lentfer wpa_supplicant_deinit(global);
64696d49e1aeSJan Lentfer return NULL;
64706d49e1aeSJan Lentfer }
64716d49e1aeSJan Lentfer
64723ff40c12SJohn Marino for (i = 0; wpa_drivers[i]; i++)
64736d49e1aeSJan Lentfer global->drv_count++;
64746d49e1aeSJan Lentfer if (global->drv_count == 0) {
64756d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "No drivers enabled");
64766d49e1aeSJan Lentfer wpa_supplicant_deinit(global);
64776d49e1aeSJan Lentfer return NULL;
64786d49e1aeSJan Lentfer }
6479*a1157835SDaniel Fojt global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
64806d49e1aeSJan Lentfer if (global->drv_priv == NULL) {
64816d49e1aeSJan Lentfer wpa_supplicant_deinit(global);
64826d49e1aeSJan Lentfer return NULL;
64836d49e1aeSJan Lentfer }
64843ff40c12SJohn Marino
64853ff40c12SJohn Marino #ifdef CONFIG_WIFI_DISPLAY
64863ff40c12SJohn Marino if (wifi_display_init(global) < 0) {
64873ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
64886d49e1aeSJan Lentfer wpa_supplicant_deinit(global);
64896d49e1aeSJan Lentfer return NULL;
64906d49e1aeSJan Lentfer }
64913ff40c12SJohn Marino #endif /* CONFIG_WIFI_DISPLAY */
64926d49e1aeSJan Lentfer
6493*a1157835SDaniel Fojt eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
6494*a1157835SDaniel Fojt wpas_periodic, global, NULL);
6495*a1157835SDaniel Fojt
64966d49e1aeSJan Lentfer return global;
64976d49e1aeSJan Lentfer }
64986d49e1aeSJan Lentfer
64996d49e1aeSJan Lentfer
65006d49e1aeSJan Lentfer /**
65016d49e1aeSJan Lentfer * wpa_supplicant_run - Run the %wpa_supplicant main event loop
65026d49e1aeSJan Lentfer * @global: Pointer to global data from wpa_supplicant_init()
65036d49e1aeSJan Lentfer * Returns: 0 after successful event loop run, -1 on failure
65046d49e1aeSJan Lentfer *
65056d49e1aeSJan Lentfer * This function starts the main event loop and continues running as long as
65066d49e1aeSJan Lentfer * there are any remaining events. In most cases, this function is running as
65076d49e1aeSJan Lentfer * long as the %wpa_supplicant process in still in use.
65086d49e1aeSJan Lentfer */
wpa_supplicant_run(struct wpa_global * global)65096d49e1aeSJan Lentfer int wpa_supplicant_run(struct wpa_global *global)
65106d49e1aeSJan Lentfer {
65116d49e1aeSJan Lentfer struct wpa_supplicant *wpa_s;
65126d49e1aeSJan Lentfer
65136d49e1aeSJan Lentfer if (global->params.daemonize &&
6514*a1157835SDaniel Fojt (wpa_supplicant_daemon(global->params.pid_file) ||
6515*a1157835SDaniel Fojt eloop_sock_requeue()))
65166d49e1aeSJan Lentfer return -1;
65176d49e1aeSJan Lentfer
6518*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
6519*a1157835SDaniel Fojt if (wpa_supplicant_match_existing(global))
6520*a1157835SDaniel Fojt return -1;
6521*a1157835SDaniel Fojt #endif
6522*a1157835SDaniel Fojt
65236d49e1aeSJan Lentfer if (global->params.wait_for_monitor) {
65246d49e1aeSJan Lentfer for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
6525*a1157835SDaniel Fojt if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
65266d49e1aeSJan Lentfer wpa_supplicant_ctrl_iface_wait(
65276d49e1aeSJan Lentfer wpa_s->ctrl_iface);
65286d49e1aeSJan Lentfer }
65296d49e1aeSJan Lentfer
65303ff40c12SJohn Marino eloop_register_signal_terminate(wpa_supplicant_terminate, global);
65313ff40c12SJohn Marino eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
65326d49e1aeSJan Lentfer
65336d49e1aeSJan Lentfer eloop_run();
65346d49e1aeSJan Lentfer
65356d49e1aeSJan Lentfer return 0;
65366d49e1aeSJan Lentfer }
65376d49e1aeSJan Lentfer
65386d49e1aeSJan Lentfer
65396d49e1aeSJan Lentfer /**
65406d49e1aeSJan Lentfer * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
65416d49e1aeSJan Lentfer * @global: Pointer to global data from wpa_supplicant_init()
65426d49e1aeSJan Lentfer *
65436d49e1aeSJan Lentfer * This function is called to deinitialize %wpa_supplicant and to free all
65446d49e1aeSJan Lentfer * allocated resources. Remaining network interfaces will also be removed.
65456d49e1aeSJan Lentfer */
wpa_supplicant_deinit(struct wpa_global * global)65466d49e1aeSJan Lentfer void wpa_supplicant_deinit(struct wpa_global *global)
65476d49e1aeSJan Lentfer {
65486d49e1aeSJan Lentfer int i;
65496d49e1aeSJan Lentfer
65506d49e1aeSJan Lentfer if (global == NULL)
65516d49e1aeSJan Lentfer return;
65526d49e1aeSJan Lentfer
6553*a1157835SDaniel Fojt eloop_cancel_timeout(wpas_periodic, global, NULL);
6554*a1157835SDaniel Fojt
65553ff40c12SJohn Marino #ifdef CONFIG_WIFI_DISPLAY
65563ff40c12SJohn Marino wifi_display_deinit(global);
65573ff40c12SJohn Marino #endif /* CONFIG_WIFI_DISPLAY */
65583ff40c12SJohn Marino
65596d49e1aeSJan Lentfer while (global->ifaces)
65603ff40c12SJohn Marino wpa_supplicant_remove_iface(global, global->ifaces, 1);
65616d49e1aeSJan Lentfer
65626d49e1aeSJan Lentfer if (global->ctrl_iface)
65636d49e1aeSJan Lentfer wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
65643ff40c12SJohn Marino
65653ff40c12SJohn Marino wpas_notify_supplicant_deinitialized(global);
65666d49e1aeSJan Lentfer
65676d49e1aeSJan Lentfer eap_peer_unregister_methods();
65683ff40c12SJohn Marino #ifdef CONFIG_AP
65693ff40c12SJohn Marino eap_server_unregister_methods();
65703ff40c12SJohn Marino #endif /* CONFIG_AP */
65716d49e1aeSJan Lentfer
65723ff40c12SJohn Marino for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
65736d49e1aeSJan Lentfer if (!global->drv_priv[i])
65746d49e1aeSJan Lentfer continue;
65753ff40c12SJohn Marino wpa_drivers[i]->global_deinit(global->drv_priv[i]);
65766d49e1aeSJan Lentfer }
65776d49e1aeSJan Lentfer os_free(global->drv_priv);
65786d49e1aeSJan Lentfer
65793ff40c12SJohn Marino random_deinit();
65803ff40c12SJohn Marino
65816d49e1aeSJan Lentfer eloop_destroy();
65826d49e1aeSJan Lentfer
65836d49e1aeSJan Lentfer if (global->params.pid_file) {
65846d49e1aeSJan Lentfer os_daemonize_terminate(global->params.pid_file);
65856d49e1aeSJan Lentfer os_free(global->params.pid_file);
65866d49e1aeSJan Lentfer }
65876d49e1aeSJan Lentfer os_free(global->params.ctrl_interface);
65883ff40c12SJohn Marino os_free(global->params.ctrl_interface_group);
65893ff40c12SJohn Marino os_free(global->params.override_driver);
65903ff40c12SJohn Marino os_free(global->params.override_ctrl_interface);
6591*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
6592*a1157835SDaniel Fojt os_free(global->params.match_ifaces);
6593*a1157835SDaniel Fojt #endif /* CONFIG_MATCH_IFACE */
6594*a1157835SDaniel Fojt #ifdef CONFIG_P2P
6595*a1157835SDaniel Fojt os_free(global->params.conf_p2p_dev);
6596*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
65973ff40c12SJohn Marino
65983ff40c12SJohn Marino os_free(global->p2p_disallow_freq.range);
65993ff40c12SJohn Marino os_free(global->p2p_go_avoid_freq.range);
66003ff40c12SJohn Marino os_free(global->add_psk);
66016d49e1aeSJan Lentfer
66026d49e1aeSJan Lentfer os_free(global);
66033ff40c12SJohn Marino wpa_debug_close_syslog();
66046d49e1aeSJan Lentfer wpa_debug_close_file();
66053ff40c12SJohn Marino wpa_debug_close_linux_tracing();
66063ff40c12SJohn Marino }
66073ff40c12SJohn Marino
66083ff40c12SJohn Marino
wpa_supplicant_update_config(struct wpa_supplicant * wpa_s)66093ff40c12SJohn Marino void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
66103ff40c12SJohn Marino {
66113ff40c12SJohn Marino if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
66123ff40c12SJohn Marino wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
66133ff40c12SJohn Marino char country[3];
66143ff40c12SJohn Marino country[0] = wpa_s->conf->country[0];
66153ff40c12SJohn Marino country[1] = wpa_s->conf->country[1];
66163ff40c12SJohn Marino country[2] = '\0';
66173ff40c12SJohn Marino if (wpa_drv_set_country(wpa_s, country) < 0) {
66183ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Failed to set country code "
66193ff40c12SJohn Marino "'%s'", country);
66203ff40c12SJohn Marino }
66213ff40c12SJohn Marino }
66223ff40c12SJohn Marino
66233ff40c12SJohn Marino if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
66243ff40c12SJohn Marino wpas_init_ext_pw(wpa_s);
66253ff40c12SJohn Marino
6626*a1157835SDaniel Fojt if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS)
6627*a1157835SDaniel Fojt wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
6628*a1157835SDaniel Fojt
6629*a1157835SDaniel Fojt if (wpa_s->conf->changed_parameters & CFG_CHANGED_WOWLAN_TRIGGERS) {
6630*a1157835SDaniel Fojt struct wpa_driver_capa capa;
6631*a1157835SDaniel Fojt int res = wpa_drv_get_capa(wpa_s, &capa);
6632*a1157835SDaniel Fojt
6633*a1157835SDaniel Fojt if (res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
6634*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
6635*a1157835SDaniel Fojt "Failed to update wowlan_triggers to '%s'",
6636*a1157835SDaniel Fojt wpa_s->conf->wowlan_triggers);
6637*a1157835SDaniel Fojt }
6638*a1157835SDaniel Fojt
6639*a1157835SDaniel Fojt if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
6640*a1157835SDaniel Fojt wpa_supplicant_set_default_scan_ies(wpa_s);
6641*a1157835SDaniel Fojt
66423ff40c12SJohn Marino #ifdef CONFIG_WPS
66433ff40c12SJohn Marino wpas_wps_update_config(wpa_s);
66443ff40c12SJohn Marino #endif /* CONFIG_WPS */
66453ff40c12SJohn Marino wpas_p2p_update_config(wpa_s);
66463ff40c12SJohn Marino wpa_s->conf->changed_parameters = 0;
66473ff40c12SJohn Marino }
66483ff40c12SJohn Marino
66493ff40c12SJohn Marino
add_freq(int * freqs,int * num_freqs,int freq)6650*a1157835SDaniel Fojt void add_freq(int *freqs, int *num_freqs, int freq)
66513ff40c12SJohn Marino {
66523ff40c12SJohn Marino int i;
66533ff40c12SJohn Marino
66543ff40c12SJohn Marino for (i = 0; i < *num_freqs; i++) {
66553ff40c12SJohn Marino if (freqs[i] == freq)
66563ff40c12SJohn Marino return;
66573ff40c12SJohn Marino }
66583ff40c12SJohn Marino
66593ff40c12SJohn Marino freqs[*num_freqs] = freq;
66603ff40c12SJohn Marino (*num_freqs)++;
66613ff40c12SJohn Marino }
66623ff40c12SJohn Marino
66633ff40c12SJohn Marino
get_bss_freqs_in_ess(struct wpa_supplicant * wpa_s)66643ff40c12SJohn Marino static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
66653ff40c12SJohn Marino {
66663ff40c12SJohn Marino struct wpa_bss *bss, *cbss;
66673ff40c12SJohn Marino const int max_freqs = 10;
66683ff40c12SJohn Marino int *freqs;
66693ff40c12SJohn Marino int num_freqs = 0;
66703ff40c12SJohn Marino
6671*a1157835SDaniel Fojt freqs = os_calloc(max_freqs + 1, sizeof(int));
66723ff40c12SJohn Marino if (freqs == NULL)
66733ff40c12SJohn Marino return NULL;
66743ff40c12SJohn Marino
66753ff40c12SJohn Marino cbss = wpa_s->current_bss;
66763ff40c12SJohn Marino
66773ff40c12SJohn Marino dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
66783ff40c12SJohn Marino if (bss == cbss)
66793ff40c12SJohn Marino continue;
66803ff40c12SJohn Marino if (bss->ssid_len == cbss->ssid_len &&
66813ff40c12SJohn Marino os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
66823ff40c12SJohn Marino wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
66833ff40c12SJohn Marino add_freq(freqs, &num_freqs, bss->freq);
66843ff40c12SJohn Marino if (num_freqs == max_freqs)
66853ff40c12SJohn Marino break;
66863ff40c12SJohn Marino }
66873ff40c12SJohn Marino }
66883ff40c12SJohn Marino
66893ff40c12SJohn Marino if (num_freqs == 0) {
66903ff40c12SJohn Marino os_free(freqs);
66913ff40c12SJohn Marino freqs = NULL;
66923ff40c12SJohn Marino }
66933ff40c12SJohn Marino
66943ff40c12SJohn Marino return freqs;
66953ff40c12SJohn Marino }
66963ff40c12SJohn Marino
66973ff40c12SJohn Marino
wpas_connection_failed(struct wpa_supplicant * wpa_s,const u8 * bssid)66983ff40c12SJohn Marino void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
66993ff40c12SJohn Marino {
67003ff40c12SJohn Marino int timeout;
67013ff40c12SJohn Marino int count;
67023ff40c12SJohn Marino int *freqs = NULL;
67033ff40c12SJohn Marino
67043ff40c12SJohn Marino wpas_connect_work_done(wpa_s);
67053ff40c12SJohn Marino
67063ff40c12SJohn Marino /*
67073ff40c12SJohn Marino * Remove possible authentication timeout since the connection failed.
67083ff40c12SJohn Marino */
67093ff40c12SJohn Marino eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
67103ff40c12SJohn Marino
67113ff40c12SJohn Marino /*
67123ff40c12SJohn Marino * There is no point in blacklisting the AP if this event is
67133ff40c12SJohn Marino * generated based on local request to disconnect.
67143ff40c12SJohn Marino */
6715*a1157835SDaniel Fojt if (wpa_s->own_disconnect_req) {
6716*a1157835SDaniel Fojt wpa_s->own_disconnect_req = 0;
6717*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
6718*a1157835SDaniel Fojt "Ignore connection failure due to local request to disconnect");
6719*a1157835SDaniel Fojt return;
6720*a1157835SDaniel Fojt }
6721*a1157835SDaniel Fojt if (wpa_s->disconnected) {
67223ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
67233ff40c12SJohn Marino "indication since interface has been put into "
67243ff40c12SJohn Marino "disconnected state");
67253ff40c12SJohn Marino return;
67263ff40c12SJohn Marino }
67273ff40c12SJohn Marino
67283ff40c12SJohn Marino /*
67293ff40c12SJohn Marino * Add the failed BSSID into the blacklist and speed up next scan
67303ff40c12SJohn Marino * attempt if there could be other APs that could accept association.
67313ff40c12SJohn Marino * The current blacklist count indicates how many times we have tried
67323ff40c12SJohn Marino * connecting to this AP and multiple attempts mean that other APs are
67333ff40c12SJohn Marino * either not available or has already been tried, so that we can start
67343ff40c12SJohn Marino * increasing the delay here to avoid constant scanning.
67353ff40c12SJohn Marino */
67363ff40c12SJohn Marino count = wpa_blacklist_add(wpa_s, bssid);
67373ff40c12SJohn Marino if (count == 1 && wpa_s->current_bss) {
67383ff40c12SJohn Marino /*
67393ff40c12SJohn Marino * This BSS was not in the blacklist before. If there is
67403ff40c12SJohn Marino * another BSS available for the same ESS, we should try that
67413ff40c12SJohn Marino * next. Otherwise, we may as well try this one once more
67423ff40c12SJohn Marino * before allowing other, likely worse, ESSes to be considered.
67433ff40c12SJohn Marino */
67443ff40c12SJohn Marino freqs = get_bss_freqs_in_ess(wpa_s);
67453ff40c12SJohn Marino if (freqs) {
67463ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
67473ff40c12SJohn Marino "has been seen; try it next");
67483ff40c12SJohn Marino wpa_blacklist_add(wpa_s, bssid);
67493ff40c12SJohn Marino /*
67503ff40c12SJohn Marino * On the next scan, go through only the known channels
67513ff40c12SJohn Marino * used in this ESS based on previous scans to speed up
67523ff40c12SJohn Marino * common load balancing use case.
67533ff40c12SJohn Marino */
67543ff40c12SJohn Marino os_free(wpa_s->next_scan_freqs);
67553ff40c12SJohn Marino wpa_s->next_scan_freqs = freqs;
67563ff40c12SJohn Marino }
67573ff40c12SJohn Marino }
67583ff40c12SJohn Marino
67593ff40c12SJohn Marino /*
67603ff40c12SJohn Marino * Add previous failure count in case the temporary blacklist was
67613ff40c12SJohn Marino * cleared due to no other BSSes being available.
67623ff40c12SJohn Marino */
67633ff40c12SJohn Marino count += wpa_s->extra_blacklist_count;
67643ff40c12SJohn Marino
67653ff40c12SJohn Marino if (count > 3 && wpa_s->current_ssid) {
67663ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Continuous association failures - "
67673ff40c12SJohn Marino "consider temporary network disabling");
6768*a1157835SDaniel Fojt wpas_auth_failed(wpa_s, "CONN_FAILED");
67693ff40c12SJohn Marino }
67703ff40c12SJohn Marino
67713ff40c12SJohn Marino switch (count) {
67723ff40c12SJohn Marino case 1:
67733ff40c12SJohn Marino timeout = 100;
67743ff40c12SJohn Marino break;
67753ff40c12SJohn Marino case 2:
67763ff40c12SJohn Marino timeout = 500;
67773ff40c12SJohn Marino break;
67783ff40c12SJohn Marino case 3:
67793ff40c12SJohn Marino timeout = 1000;
67803ff40c12SJohn Marino break;
67813ff40c12SJohn Marino case 4:
67823ff40c12SJohn Marino timeout = 5000;
67833ff40c12SJohn Marino break;
67843ff40c12SJohn Marino default:
67853ff40c12SJohn Marino timeout = 10000;
67863ff40c12SJohn Marino break;
67873ff40c12SJohn Marino }
67883ff40c12SJohn Marino
67893ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
67903ff40c12SJohn Marino "ms", count, timeout);
67913ff40c12SJohn Marino
67923ff40c12SJohn Marino /*
67933ff40c12SJohn Marino * TODO: if more than one possible AP is available in scan results,
67943ff40c12SJohn Marino * could try the other ones before requesting a new scan.
67953ff40c12SJohn Marino */
6796*a1157835SDaniel Fojt
6797*a1157835SDaniel Fojt /* speed up the connection attempt with normal scan */
6798*a1157835SDaniel Fojt wpa_s->normal_scans = 0;
67993ff40c12SJohn Marino wpa_supplicant_req_scan(wpa_s, timeout / 1000,
68003ff40c12SJohn Marino 1000 * (timeout % 1000));
68013ff40c12SJohn Marino }
68023ff40c12SJohn Marino
68033ff40c12SJohn Marino
6804*a1157835SDaniel Fojt #ifdef CONFIG_FILS
fils_connection_failure(struct wpa_supplicant * wpa_s)6805*a1157835SDaniel Fojt void fils_connection_failure(struct wpa_supplicant *wpa_s)
6806*a1157835SDaniel Fojt {
6807*a1157835SDaniel Fojt struct wpa_ssid *ssid = wpa_s->current_ssid;
6808*a1157835SDaniel Fojt const u8 *realm, *username, *rrk;
6809*a1157835SDaniel Fojt size_t realm_len, username_len, rrk_len;
6810*a1157835SDaniel Fojt u16 next_seq_num;
6811*a1157835SDaniel Fojt
6812*a1157835SDaniel Fojt if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) ||
6813*a1157835SDaniel Fojt eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
6814*a1157835SDaniel Fojt &username, &username_len,
6815*a1157835SDaniel Fojt &realm, &realm_len, &next_seq_num,
6816*a1157835SDaniel Fojt &rrk, &rrk_len) != 0 ||
6817*a1157835SDaniel Fojt !realm)
6818*a1157835SDaniel Fojt return;
6819*a1157835SDaniel Fojt
6820*a1157835SDaniel Fojt wpa_hexdump_ascii(MSG_DEBUG,
6821*a1157835SDaniel Fojt "FILS: Store last connection failure realm",
6822*a1157835SDaniel Fojt realm, realm_len);
6823*a1157835SDaniel Fojt os_free(wpa_s->last_con_fail_realm);
6824*a1157835SDaniel Fojt wpa_s->last_con_fail_realm = os_malloc(realm_len);
6825*a1157835SDaniel Fojt if (wpa_s->last_con_fail_realm) {
6826*a1157835SDaniel Fojt wpa_s->last_con_fail_realm_len = realm_len;
6827*a1157835SDaniel Fojt os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len);
6828*a1157835SDaniel Fojt }
6829*a1157835SDaniel Fojt }
6830*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
6831*a1157835SDaniel Fojt
6832*a1157835SDaniel Fojt
wpas_driver_bss_selection(struct wpa_supplicant * wpa_s)68333ff40c12SJohn Marino int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
68343ff40c12SJohn Marino {
68353ff40c12SJohn Marino return wpa_s->conf->ap_scan == 2 ||
68363ff40c12SJohn Marino (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
68373ff40c12SJohn Marino }
68383ff40c12SJohn Marino
68393ff40c12SJohn Marino
68403ff40c12SJohn Marino #if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,const char * field,const char * value)68413ff40c12SJohn Marino int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
68423ff40c12SJohn Marino struct wpa_ssid *ssid,
68433ff40c12SJohn Marino const char *field,
68443ff40c12SJohn Marino const char *value)
68453ff40c12SJohn Marino {
68463ff40c12SJohn Marino #ifdef IEEE8021X_EAPOL
68473ff40c12SJohn Marino struct eap_peer_config *eap = &ssid->eap;
68483ff40c12SJohn Marino
68493ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
68503ff40c12SJohn Marino wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
68513ff40c12SJohn Marino (const u8 *) value, os_strlen(value));
68523ff40c12SJohn Marino
68533ff40c12SJohn Marino switch (wpa_supplicant_ctrl_req_from_string(field)) {
68543ff40c12SJohn Marino case WPA_CTRL_REQ_EAP_IDENTITY:
68553ff40c12SJohn Marino os_free(eap->identity);
68563ff40c12SJohn Marino eap->identity = (u8 *) os_strdup(value);
68573ff40c12SJohn Marino eap->identity_len = os_strlen(value);
68583ff40c12SJohn Marino eap->pending_req_identity = 0;
68593ff40c12SJohn Marino if (ssid == wpa_s->current_ssid)
68603ff40c12SJohn Marino wpa_s->reassociate = 1;
68613ff40c12SJohn Marino break;
68623ff40c12SJohn Marino case WPA_CTRL_REQ_EAP_PASSWORD:
6863*a1157835SDaniel Fojt bin_clear_free(eap->password, eap->password_len);
68643ff40c12SJohn Marino eap->password = (u8 *) os_strdup(value);
68653ff40c12SJohn Marino eap->password_len = os_strlen(value);
68663ff40c12SJohn Marino eap->pending_req_password = 0;
68673ff40c12SJohn Marino if (ssid == wpa_s->current_ssid)
68683ff40c12SJohn Marino wpa_s->reassociate = 1;
68693ff40c12SJohn Marino break;
68703ff40c12SJohn Marino case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
6871*a1157835SDaniel Fojt bin_clear_free(eap->new_password, eap->new_password_len);
68723ff40c12SJohn Marino eap->new_password = (u8 *) os_strdup(value);
68733ff40c12SJohn Marino eap->new_password_len = os_strlen(value);
68743ff40c12SJohn Marino eap->pending_req_new_password = 0;
68753ff40c12SJohn Marino if (ssid == wpa_s->current_ssid)
68763ff40c12SJohn Marino wpa_s->reassociate = 1;
68773ff40c12SJohn Marino break;
68783ff40c12SJohn Marino case WPA_CTRL_REQ_EAP_PIN:
6879*a1157835SDaniel Fojt str_clear_free(eap->pin);
68803ff40c12SJohn Marino eap->pin = os_strdup(value);
68813ff40c12SJohn Marino eap->pending_req_pin = 0;
68823ff40c12SJohn Marino if (ssid == wpa_s->current_ssid)
68833ff40c12SJohn Marino wpa_s->reassociate = 1;
68843ff40c12SJohn Marino break;
68853ff40c12SJohn Marino case WPA_CTRL_REQ_EAP_OTP:
6886*a1157835SDaniel Fojt bin_clear_free(eap->otp, eap->otp_len);
68873ff40c12SJohn Marino eap->otp = (u8 *) os_strdup(value);
68883ff40c12SJohn Marino eap->otp_len = os_strlen(value);
68893ff40c12SJohn Marino os_free(eap->pending_req_otp);
68903ff40c12SJohn Marino eap->pending_req_otp = NULL;
68913ff40c12SJohn Marino eap->pending_req_otp_len = 0;
68923ff40c12SJohn Marino break;
68933ff40c12SJohn Marino case WPA_CTRL_REQ_EAP_PASSPHRASE:
6894*a1157835SDaniel Fojt str_clear_free(eap->private_key_passwd);
6895*a1157835SDaniel Fojt eap->private_key_passwd = os_strdup(value);
68963ff40c12SJohn Marino eap->pending_req_passphrase = 0;
68973ff40c12SJohn Marino if (ssid == wpa_s->current_ssid)
68983ff40c12SJohn Marino wpa_s->reassociate = 1;
68993ff40c12SJohn Marino break;
69003ff40c12SJohn Marino case WPA_CTRL_REQ_SIM:
6901*a1157835SDaniel Fojt str_clear_free(eap->external_sim_resp);
69023ff40c12SJohn Marino eap->external_sim_resp = os_strdup(value);
6903*a1157835SDaniel Fojt eap->pending_req_sim = 0;
6904*a1157835SDaniel Fojt break;
6905*a1157835SDaniel Fojt case WPA_CTRL_REQ_PSK_PASSPHRASE:
6906*a1157835SDaniel Fojt if (wpa_config_set(ssid, "psk", value, 0) < 0)
6907*a1157835SDaniel Fojt return -1;
6908*a1157835SDaniel Fojt ssid->mem_only_psk = 1;
6909*a1157835SDaniel Fojt if (ssid->passphrase)
6910*a1157835SDaniel Fojt wpa_config_update_psk(ssid);
6911*a1157835SDaniel Fojt if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
6912*a1157835SDaniel Fojt wpa_supplicant_req_scan(wpa_s, 0, 0);
6913*a1157835SDaniel Fojt break;
6914*a1157835SDaniel Fojt case WPA_CTRL_REQ_EXT_CERT_CHECK:
6915*a1157835SDaniel Fojt if (eap->pending_ext_cert_check != PENDING_CHECK)
6916*a1157835SDaniel Fojt return -1;
6917*a1157835SDaniel Fojt if (os_strcmp(value, "good") == 0)
6918*a1157835SDaniel Fojt eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
6919*a1157835SDaniel Fojt else if (os_strcmp(value, "bad") == 0)
6920*a1157835SDaniel Fojt eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
6921*a1157835SDaniel Fojt else
6922*a1157835SDaniel Fojt return -1;
69233ff40c12SJohn Marino break;
69243ff40c12SJohn Marino default:
69253ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
69263ff40c12SJohn Marino return -1;
69273ff40c12SJohn Marino }
69283ff40c12SJohn Marino
69293ff40c12SJohn Marino return 0;
69303ff40c12SJohn Marino #else /* IEEE8021X_EAPOL */
69313ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
69323ff40c12SJohn Marino return -1;
69333ff40c12SJohn Marino #endif /* IEEE8021X_EAPOL */
69343ff40c12SJohn Marino }
69353ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
69363ff40c12SJohn Marino
69373ff40c12SJohn Marino
wpas_network_disabled(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)69383ff40c12SJohn Marino int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
69393ff40c12SJohn Marino {
69403ff40c12SJohn Marino int i;
69413ff40c12SJohn Marino unsigned int drv_enc;
69423ff40c12SJohn Marino
6943*a1157835SDaniel Fojt if (wpa_s->p2p_mgmt)
6944*a1157835SDaniel Fojt return 1; /* no normal network profiles on p2p_mgmt interface */
6945*a1157835SDaniel Fojt
69463ff40c12SJohn Marino if (ssid == NULL)
69473ff40c12SJohn Marino return 1;
69483ff40c12SJohn Marino
69493ff40c12SJohn Marino if (ssid->disabled)
69503ff40c12SJohn Marino return 1;
69513ff40c12SJohn Marino
6952*a1157835SDaniel Fojt if (wpa_s->drv_capa_known)
69533ff40c12SJohn Marino drv_enc = wpa_s->drv_enc;
69543ff40c12SJohn Marino else
69553ff40c12SJohn Marino drv_enc = (unsigned int) -1;
69563ff40c12SJohn Marino
69573ff40c12SJohn Marino for (i = 0; i < NUM_WEP_KEYS; i++) {
69583ff40c12SJohn Marino size_t len = ssid->wep_key_len[i];
69593ff40c12SJohn Marino if (len == 0)
69603ff40c12SJohn Marino continue;
69613ff40c12SJohn Marino if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
69623ff40c12SJohn Marino continue;
69633ff40c12SJohn Marino if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
69643ff40c12SJohn Marino continue;
69653ff40c12SJohn Marino if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
69663ff40c12SJohn Marino continue;
69673ff40c12SJohn Marino return 1; /* invalid WEP key */
69683ff40c12SJohn Marino }
69693ff40c12SJohn Marino
69703ff40c12SJohn Marino if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
6971*a1157835SDaniel Fojt (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
6972*a1157835SDaniel Fojt !(wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password) &&
6973*a1157835SDaniel Fojt !ssid->mem_only_psk)
69743ff40c12SJohn Marino return 1;
69753ff40c12SJohn Marino
69763ff40c12SJohn Marino return 0;
69773ff40c12SJohn Marino }
69783ff40c12SJohn Marino
69793ff40c12SJohn Marino
wpas_get_ssid_pmf(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)6980*a1157835SDaniel Fojt int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
6981*a1157835SDaniel Fojt {
6982*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211W
6983*a1157835SDaniel Fojt if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
6984*a1157835SDaniel Fojt if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
6985*a1157835SDaniel Fojt !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
6986*a1157835SDaniel Fojt /*
6987*a1157835SDaniel Fojt * Driver does not support BIP -- ignore pmf=1 default
6988*a1157835SDaniel Fojt * since the connection with PMF would fail and the
6989*a1157835SDaniel Fojt * configuration does not require PMF to be enabled.
6990*a1157835SDaniel Fojt */
6991*a1157835SDaniel Fojt return NO_MGMT_FRAME_PROTECTION;
6992*a1157835SDaniel Fojt }
6993*a1157835SDaniel Fojt
6994*a1157835SDaniel Fojt if (ssid &&
6995*a1157835SDaniel Fojt (ssid->key_mgmt &
6996*a1157835SDaniel Fojt ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
6997*a1157835SDaniel Fojt WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
6998*a1157835SDaniel Fojt /*
6999*a1157835SDaniel Fojt * Do not use the default PMF value for non-RSN networks
7000*a1157835SDaniel Fojt * since PMF is available only with RSN and pmf=2
7001*a1157835SDaniel Fojt * configuration would otherwise prevent connections to
7002*a1157835SDaniel Fojt * all open networks.
7003*a1157835SDaniel Fojt */
7004*a1157835SDaniel Fojt return NO_MGMT_FRAME_PROTECTION;
7005*a1157835SDaniel Fojt }
7006*a1157835SDaniel Fojt
7007*a1157835SDaniel Fojt return wpa_s->conf->pmf;
7008*a1157835SDaniel Fojt }
7009*a1157835SDaniel Fojt
7010*a1157835SDaniel Fojt return ssid->ieee80211w;
7011*a1157835SDaniel Fojt #else /* CONFIG_IEEE80211W */
7012*a1157835SDaniel Fojt return NO_MGMT_FRAME_PROTECTION;
7013*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211W */
7014*a1157835SDaniel Fojt }
7015*a1157835SDaniel Fojt
7016*a1157835SDaniel Fojt
wpas_is_p2p_prioritized(struct wpa_supplicant * wpa_s)70173ff40c12SJohn Marino int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
70183ff40c12SJohn Marino {
70193ff40c12SJohn Marino if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
70203ff40c12SJohn Marino return 1;
70213ff40c12SJohn Marino if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
70223ff40c12SJohn Marino return 0;
70233ff40c12SJohn Marino return -1;
70243ff40c12SJohn Marino }
70253ff40c12SJohn Marino
70263ff40c12SJohn Marino
wpas_auth_failed(struct wpa_supplicant * wpa_s,char * reason)7027*a1157835SDaniel Fojt void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason)
70283ff40c12SJohn Marino {
70293ff40c12SJohn Marino struct wpa_ssid *ssid = wpa_s->current_ssid;
70303ff40c12SJohn Marino int dur;
70313ff40c12SJohn Marino struct os_reltime now;
70323ff40c12SJohn Marino
70333ff40c12SJohn Marino if (ssid == NULL) {
70343ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Authentication failure but no known "
70353ff40c12SJohn Marino "SSID block");
70363ff40c12SJohn Marino return;
70373ff40c12SJohn Marino }
70383ff40c12SJohn Marino
70393ff40c12SJohn Marino if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
70403ff40c12SJohn Marino return;
70413ff40c12SJohn Marino
70423ff40c12SJohn Marino ssid->auth_failures++;
70433ff40c12SJohn Marino
70443ff40c12SJohn Marino #ifdef CONFIG_P2P
70453ff40c12SJohn Marino if (ssid->p2p_group &&
70463ff40c12SJohn Marino (wpa_s->p2p_in_provisioning || wpa_s->show_group_started)) {
70473ff40c12SJohn Marino /*
70483ff40c12SJohn Marino * Skip the wait time since there is a short timeout on the
70493ff40c12SJohn Marino * connection to a P2P group.
70503ff40c12SJohn Marino */
70513ff40c12SJohn Marino return;
70523ff40c12SJohn Marino }
70533ff40c12SJohn Marino #endif /* CONFIG_P2P */
70543ff40c12SJohn Marino
70553ff40c12SJohn Marino if (ssid->auth_failures > 50)
70563ff40c12SJohn Marino dur = 300;
70573ff40c12SJohn Marino else if (ssid->auth_failures > 10)
7058*a1157835SDaniel Fojt dur = 120;
70593ff40c12SJohn Marino else if (ssid->auth_failures > 5)
7060*a1157835SDaniel Fojt dur = 90;
7061*a1157835SDaniel Fojt else if (ssid->auth_failures > 3)
7062*a1157835SDaniel Fojt dur = 60;
7063*a1157835SDaniel Fojt else if (ssid->auth_failures > 2)
70643ff40c12SJohn Marino dur = 30;
70653ff40c12SJohn Marino else if (ssid->auth_failures > 1)
70663ff40c12SJohn Marino dur = 20;
70673ff40c12SJohn Marino else
70683ff40c12SJohn Marino dur = 10;
70693ff40c12SJohn Marino
7070*a1157835SDaniel Fojt if (ssid->auth_failures > 1 &&
7071*a1157835SDaniel Fojt wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt))
7072*a1157835SDaniel Fojt dur += os_random() % (ssid->auth_failures * 10);
7073*a1157835SDaniel Fojt
70743ff40c12SJohn Marino os_get_reltime(&now);
70753ff40c12SJohn Marino if (now.sec + dur <= ssid->disabled_until.sec)
70763ff40c12SJohn Marino return;
70773ff40c12SJohn Marino
70783ff40c12SJohn Marino ssid->disabled_until.sec = now.sec + dur;
70793ff40c12SJohn Marino
70803ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
7081*a1157835SDaniel Fojt "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s",
70823ff40c12SJohn Marino ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
7083*a1157835SDaniel Fojt ssid->auth_failures, dur, reason);
70843ff40c12SJohn Marino }
70853ff40c12SJohn Marino
70863ff40c12SJohn Marino
wpas_clear_temp_disabled(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,int clear_failures)70873ff40c12SJohn Marino void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
70883ff40c12SJohn Marino struct wpa_ssid *ssid, int clear_failures)
70893ff40c12SJohn Marino {
70903ff40c12SJohn Marino if (ssid == NULL)
70913ff40c12SJohn Marino return;
70923ff40c12SJohn Marino
70933ff40c12SJohn Marino if (ssid->disabled_until.sec) {
70943ff40c12SJohn Marino wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
70953ff40c12SJohn Marino "id=%d ssid=\"%s\"",
70963ff40c12SJohn Marino ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
70973ff40c12SJohn Marino }
70983ff40c12SJohn Marino ssid->disabled_until.sec = 0;
70993ff40c12SJohn Marino ssid->disabled_until.usec = 0;
71003ff40c12SJohn Marino if (clear_failures)
71013ff40c12SJohn Marino ssid->auth_failures = 0;
71023ff40c12SJohn Marino }
71033ff40c12SJohn Marino
71043ff40c12SJohn Marino
disallowed_bssid(struct wpa_supplicant * wpa_s,const u8 * bssid)71053ff40c12SJohn Marino int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
71063ff40c12SJohn Marino {
71073ff40c12SJohn Marino size_t i;
71083ff40c12SJohn Marino
71093ff40c12SJohn Marino if (wpa_s->disallow_aps_bssid == NULL)
71103ff40c12SJohn Marino return 0;
71113ff40c12SJohn Marino
71123ff40c12SJohn Marino for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
71133ff40c12SJohn Marino if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
71143ff40c12SJohn Marino bssid, ETH_ALEN) == 0)
71153ff40c12SJohn Marino return 1;
71163ff40c12SJohn Marino }
71173ff40c12SJohn Marino
71183ff40c12SJohn Marino return 0;
71193ff40c12SJohn Marino }
71203ff40c12SJohn Marino
71213ff40c12SJohn Marino
disallowed_ssid(struct wpa_supplicant * wpa_s,const u8 * ssid,size_t ssid_len)71223ff40c12SJohn Marino int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
71233ff40c12SJohn Marino size_t ssid_len)
71243ff40c12SJohn Marino {
71253ff40c12SJohn Marino size_t i;
71263ff40c12SJohn Marino
71273ff40c12SJohn Marino if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
71283ff40c12SJohn Marino return 0;
71293ff40c12SJohn Marino
71303ff40c12SJohn Marino for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
71313ff40c12SJohn Marino struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
71323ff40c12SJohn Marino if (ssid_len == s->ssid_len &&
71333ff40c12SJohn Marino os_memcmp(ssid, s->ssid, ssid_len) == 0)
71343ff40c12SJohn Marino return 1;
71353ff40c12SJohn Marino }
71363ff40c12SJohn Marino
71373ff40c12SJohn Marino return 0;
71383ff40c12SJohn Marino }
71393ff40c12SJohn Marino
71403ff40c12SJohn Marino
71413ff40c12SJohn Marino /**
71423ff40c12SJohn Marino * wpas_request_connection - Request a new connection
71433ff40c12SJohn Marino * @wpa_s: Pointer to the network interface
71443ff40c12SJohn Marino *
71453ff40c12SJohn Marino * This function is used to request a new connection to be found. It will mark
71463ff40c12SJohn Marino * the interface to allow reassociation and request a new scan to find a
71473ff40c12SJohn Marino * suitable network to connect to.
71483ff40c12SJohn Marino */
wpas_request_connection(struct wpa_supplicant * wpa_s)71493ff40c12SJohn Marino void wpas_request_connection(struct wpa_supplicant *wpa_s)
71503ff40c12SJohn Marino {
71513ff40c12SJohn Marino wpa_s->normal_scans = 0;
7152*a1157835SDaniel Fojt wpa_s->scan_req = NORMAL_SCAN_REQ;
71533ff40c12SJohn Marino wpa_supplicant_reinit_autoscan(wpa_s);
71543ff40c12SJohn Marino wpa_s->extra_blacklist_count = 0;
71553ff40c12SJohn Marino wpa_s->disconnected = 0;
71563ff40c12SJohn Marino wpa_s->reassociate = 1;
7157*a1157835SDaniel Fojt wpa_s->last_owe_group = 0;
71583ff40c12SJohn Marino
71593ff40c12SJohn Marino if (wpa_supplicant_fast_associate(wpa_s) != 1)
71603ff40c12SJohn Marino wpa_supplicant_req_scan(wpa_s, 0, 0);
7161*a1157835SDaniel Fojt else
7162*a1157835SDaniel Fojt wpa_s->reattach = 0;
71633ff40c12SJohn Marino }
71643ff40c12SJohn Marino
71653ff40c12SJohn Marino
7166*a1157835SDaniel Fojt /**
7167*a1157835SDaniel Fojt * wpas_request_disconnection - Request disconnection
7168*a1157835SDaniel Fojt * @wpa_s: Pointer to the network interface
7169*a1157835SDaniel Fojt *
7170*a1157835SDaniel Fojt * This function is used to request disconnection from the currently connected
7171*a1157835SDaniel Fojt * network. This will stop any ongoing scans and initiate deauthentication.
7172*a1157835SDaniel Fojt */
wpas_request_disconnection(struct wpa_supplicant * wpa_s)7173*a1157835SDaniel Fojt void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
7174*a1157835SDaniel Fojt {
7175*a1157835SDaniel Fojt #ifdef CONFIG_SME
7176*a1157835SDaniel Fojt wpa_s->sme.prev_bssid_set = 0;
7177*a1157835SDaniel Fojt #endif /* CONFIG_SME */
7178*a1157835SDaniel Fojt wpa_s->reassociate = 0;
7179*a1157835SDaniel Fojt wpa_s->disconnected = 1;
7180*a1157835SDaniel Fojt wpa_supplicant_cancel_sched_scan(wpa_s);
7181*a1157835SDaniel Fojt wpa_supplicant_cancel_scan(wpa_s);
7182*a1157835SDaniel Fojt wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
7183*a1157835SDaniel Fojt eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
7184*a1157835SDaniel Fojt radio_remove_works(wpa_s, "connect", 0);
7185*a1157835SDaniel Fojt radio_remove_works(wpa_s, "sme-connect", 0);
7186*a1157835SDaniel Fojt }
7187*a1157835SDaniel Fojt
7188*a1157835SDaniel Fojt
dump_freq_data(struct wpa_supplicant * wpa_s,const char * title,struct wpa_used_freq_data * freqs_data,unsigned int len)7189*a1157835SDaniel Fojt void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
7190*a1157835SDaniel Fojt struct wpa_used_freq_data *freqs_data,
7191*a1157835SDaniel Fojt unsigned int len)
71923ff40c12SJohn Marino {
71933ff40c12SJohn Marino unsigned int i;
71943ff40c12SJohn Marino
71953ff40c12SJohn Marino wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
71963ff40c12SJohn Marino len, title);
7197*a1157835SDaniel Fojt for (i = 0; i < len; i++) {
7198*a1157835SDaniel Fojt struct wpa_used_freq_data *cur = &freqs_data[i];
7199*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d, flags=0x%X",
7200*a1157835SDaniel Fojt i, cur->freq, cur->flags);
7201*a1157835SDaniel Fojt }
7202*a1157835SDaniel Fojt }
7203*a1157835SDaniel Fojt
7204*a1157835SDaniel Fojt
7205*a1157835SDaniel Fojt /*
7206*a1157835SDaniel Fojt * Find the operating frequencies of any of the virtual interfaces that
7207*a1157835SDaniel Fojt * are using the same radio as the current interface, and in addition, get
7208*a1157835SDaniel Fojt * information about the interface types that are using the frequency.
7209*a1157835SDaniel Fojt */
get_shared_radio_freqs_data(struct wpa_supplicant * wpa_s,struct wpa_used_freq_data * freqs_data,unsigned int len)7210*a1157835SDaniel Fojt int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
7211*a1157835SDaniel Fojt struct wpa_used_freq_data *freqs_data,
7212*a1157835SDaniel Fojt unsigned int len)
7213*a1157835SDaniel Fojt {
7214*a1157835SDaniel Fojt struct wpa_supplicant *ifs;
7215*a1157835SDaniel Fojt u8 bssid[ETH_ALEN];
7216*a1157835SDaniel Fojt int freq;
7217*a1157835SDaniel Fojt unsigned int idx = 0, i;
7218*a1157835SDaniel Fojt
7219*a1157835SDaniel Fojt wpa_dbg(wpa_s, MSG_DEBUG,
7220*a1157835SDaniel Fojt "Determining shared radio frequencies (max len %u)", len);
7221*a1157835SDaniel Fojt os_memset(freqs_data, 0, sizeof(struct wpa_used_freq_data) * len);
7222*a1157835SDaniel Fojt
7223*a1157835SDaniel Fojt dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
7224*a1157835SDaniel Fojt radio_list) {
7225*a1157835SDaniel Fojt if (idx == len)
7226*a1157835SDaniel Fojt break;
7227*a1157835SDaniel Fojt
7228*a1157835SDaniel Fojt if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
7229*a1157835SDaniel Fojt continue;
7230*a1157835SDaniel Fojt
7231*a1157835SDaniel Fojt if (ifs->current_ssid->mode == WPAS_MODE_AP ||
7232*a1157835SDaniel Fojt ifs->current_ssid->mode == WPAS_MODE_P2P_GO ||
7233*a1157835SDaniel Fojt ifs->current_ssid->mode == WPAS_MODE_MESH)
7234*a1157835SDaniel Fojt freq = ifs->current_ssid->frequency;
7235*a1157835SDaniel Fojt else if (wpa_drv_get_bssid(ifs, bssid) == 0)
7236*a1157835SDaniel Fojt freq = ifs->assoc_freq;
7237*a1157835SDaniel Fojt else
7238*a1157835SDaniel Fojt continue;
7239*a1157835SDaniel Fojt
7240*a1157835SDaniel Fojt /* Hold only distinct freqs */
7241*a1157835SDaniel Fojt for (i = 0; i < idx; i++)
7242*a1157835SDaniel Fojt if (freqs_data[i].freq == freq)
7243*a1157835SDaniel Fojt break;
7244*a1157835SDaniel Fojt
7245*a1157835SDaniel Fojt if (i == idx)
7246*a1157835SDaniel Fojt freqs_data[idx++].freq = freq;
7247*a1157835SDaniel Fojt
7248*a1157835SDaniel Fojt if (ifs->current_ssid->mode == WPAS_MODE_INFRA) {
7249*a1157835SDaniel Fojt freqs_data[i].flags |= ifs->current_ssid->p2p_group ?
7250*a1157835SDaniel Fojt WPA_FREQ_USED_BY_P2P_CLIENT :
7251*a1157835SDaniel Fojt WPA_FREQ_USED_BY_INFRA_STATION;
7252*a1157835SDaniel Fojt }
7253*a1157835SDaniel Fojt }
7254*a1157835SDaniel Fojt
7255*a1157835SDaniel Fojt dump_freq_data(wpa_s, "completed iteration", freqs_data, idx);
7256*a1157835SDaniel Fojt return idx;
72573ff40c12SJohn Marino }
72583ff40c12SJohn Marino
72593ff40c12SJohn Marino
72603ff40c12SJohn Marino /*
72613ff40c12SJohn Marino * Find the operating frequencies of any of the virtual interfaces that
72623ff40c12SJohn Marino * are using the same radio as the current interface.
72633ff40c12SJohn Marino */
get_shared_radio_freqs(struct wpa_supplicant * wpa_s,int * freq_array,unsigned int len)72643ff40c12SJohn Marino int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
72653ff40c12SJohn Marino int *freq_array, unsigned int len)
72663ff40c12SJohn Marino {
7267*a1157835SDaniel Fojt struct wpa_used_freq_data *freqs_data;
7268*a1157835SDaniel Fojt int num, i;
72693ff40c12SJohn Marino
72703ff40c12SJohn Marino os_memset(freq_array, 0, sizeof(int) * len);
72713ff40c12SJohn Marino
7272*a1157835SDaniel Fojt freqs_data = os_calloc(len, sizeof(struct wpa_used_freq_data));
7273*a1157835SDaniel Fojt if (!freqs_data)
7274*a1157835SDaniel Fojt return -1;
7275*a1157835SDaniel Fojt
7276*a1157835SDaniel Fojt num = get_shared_radio_freqs_data(wpa_s, freqs_data, len);
7277*a1157835SDaniel Fojt for (i = 0; i < num; i++)
7278*a1157835SDaniel Fojt freq_array[i] = freqs_data[i].freq;
7279*a1157835SDaniel Fojt
7280*a1157835SDaniel Fojt os_free(freqs_data);
7281*a1157835SDaniel Fojt
7282*a1157835SDaniel Fojt return num;
72833ff40c12SJohn Marino }
72843ff40c12SJohn Marino
7285*a1157835SDaniel Fojt
7286*a1157835SDaniel Fojt struct wpa_supplicant *
wpas_vendor_elem(struct wpa_supplicant * wpa_s,enum wpa_vendor_elem_frame frame)7287*a1157835SDaniel Fojt wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
7288*a1157835SDaniel Fojt {
7289*a1157835SDaniel Fojt switch (frame) {
7290*a1157835SDaniel Fojt #ifdef CONFIG_P2P
7291*a1157835SDaniel Fojt case VENDOR_ELEM_PROBE_REQ_P2P:
7292*a1157835SDaniel Fojt case VENDOR_ELEM_PROBE_RESP_P2P:
7293*a1157835SDaniel Fojt case VENDOR_ELEM_PROBE_RESP_P2P_GO:
7294*a1157835SDaniel Fojt case VENDOR_ELEM_BEACON_P2P_GO:
7295*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_PD_REQ:
7296*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_PD_RESP:
7297*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_GO_NEG_REQ:
7298*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_GO_NEG_RESP:
7299*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_GO_NEG_CONF:
7300*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_INV_REQ:
7301*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_INV_RESP:
7302*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_ASSOC_REQ:
7303*a1157835SDaniel Fojt case VENDOR_ELEM_P2P_ASSOC_RESP:
7304*a1157835SDaniel Fojt return wpa_s->p2pdev;
7305*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
7306*a1157835SDaniel Fojt default:
7307*a1157835SDaniel Fojt return wpa_s;
7308*a1157835SDaniel Fojt }
73093ff40c12SJohn Marino }
73103ff40c12SJohn Marino
73113ff40c12SJohn Marino
wpas_vendor_elem_update(struct wpa_supplicant * wpa_s)7312*a1157835SDaniel Fojt void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s)
7313*a1157835SDaniel Fojt {
7314*a1157835SDaniel Fojt unsigned int i;
7315*a1157835SDaniel Fojt char buf[30];
73163ff40c12SJohn Marino
7317*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "Update vendor elements");
73183ff40c12SJohn Marino
7319*a1157835SDaniel Fojt for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
7320*a1157835SDaniel Fojt if (wpa_s->vendor_elem[i]) {
7321*a1157835SDaniel Fojt int res;
7322*a1157835SDaniel Fojt
7323*a1157835SDaniel Fojt res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
7324*a1157835SDaniel Fojt if (!os_snprintf_error(sizeof(buf), res)) {
7325*a1157835SDaniel Fojt wpa_hexdump_buf(MSG_DEBUG, buf,
7326*a1157835SDaniel Fojt wpa_s->vendor_elem[i]);
7327*a1157835SDaniel Fojt }
7328*a1157835SDaniel Fojt }
7329*a1157835SDaniel Fojt }
7330*a1157835SDaniel Fojt
7331*a1157835SDaniel Fojt #ifdef CONFIG_P2P
7332*a1157835SDaniel Fojt if (wpa_s->parent == wpa_s &&
7333*a1157835SDaniel Fojt wpa_s->global->p2p &&
7334*a1157835SDaniel Fojt !wpa_s->global->p2p_disabled)
7335*a1157835SDaniel Fojt p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
7336*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
7337*a1157835SDaniel Fojt }
7338*a1157835SDaniel Fojt
7339*a1157835SDaniel Fojt
wpas_vendor_elem_remove(struct wpa_supplicant * wpa_s,int frame,const u8 * elem,size_t len)7340*a1157835SDaniel Fojt int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
7341*a1157835SDaniel Fojt const u8 *elem, size_t len)
7342*a1157835SDaniel Fojt {
7343*a1157835SDaniel Fojt u8 *ie, *end;
7344*a1157835SDaniel Fojt
7345*a1157835SDaniel Fojt ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
7346*a1157835SDaniel Fojt end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
7347*a1157835SDaniel Fojt
7348*a1157835SDaniel Fojt for (; ie + 1 < end; ie += 2 + ie[1]) {
7349*a1157835SDaniel Fojt if (ie + len > end)
73503ff40c12SJohn Marino break;
7351*a1157835SDaniel Fojt if (os_memcmp(ie, elem, len) != 0)
7352*a1157835SDaniel Fojt continue;
73533ff40c12SJohn Marino
7354*a1157835SDaniel Fojt if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
7355*a1157835SDaniel Fojt wpabuf_free(wpa_s->vendor_elem[frame]);
7356*a1157835SDaniel Fojt wpa_s->vendor_elem[frame] = NULL;
7357*a1157835SDaniel Fojt } else {
7358*a1157835SDaniel Fojt os_memmove(ie, ie + len, end - (ie + len));
7359*a1157835SDaniel Fojt wpa_s->vendor_elem[frame]->used -= len;
7360*a1157835SDaniel Fojt }
7361*a1157835SDaniel Fojt wpas_vendor_elem_update(wpa_s);
7362*a1157835SDaniel Fojt return 0;
73633ff40c12SJohn Marino }
73643ff40c12SJohn Marino
7365*a1157835SDaniel Fojt return -1;
7366*a1157835SDaniel Fojt }
7367*a1157835SDaniel Fojt
7368*a1157835SDaniel Fojt
get_mode(struct hostapd_hw_modes * modes,u16 num_modes,enum hostapd_hw_mode mode)7369*a1157835SDaniel Fojt struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
7370*a1157835SDaniel Fojt u16 num_modes, enum hostapd_hw_mode mode)
7371*a1157835SDaniel Fojt {
7372*a1157835SDaniel Fojt u16 i;
7373*a1157835SDaniel Fojt
7374*a1157835SDaniel Fojt for (i = 0; i < num_modes; i++) {
7375*a1157835SDaniel Fojt if (modes[i].mode == mode)
7376*a1157835SDaniel Fojt return &modes[i];
7377*a1157835SDaniel Fojt }
7378*a1157835SDaniel Fojt
7379*a1157835SDaniel Fojt return NULL;
7380*a1157835SDaniel Fojt }
7381*a1157835SDaniel Fojt
7382*a1157835SDaniel Fojt
7383*a1157835SDaniel Fojt static struct
wpas_get_disallowed_bss(struct wpa_supplicant * wpa_s,const u8 * bssid)7384*a1157835SDaniel Fojt wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
7385*a1157835SDaniel Fojt const u8 *bssid)
7386*a1157835SDaniel Fojt {
7387*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed *bss;
7388*a1157835SDaniel Fojt
7389*a1157835SDaniel Fojt dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
7390*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed, list) {
7391*a1157835SDaniel Fojt if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0)
7392*a1157835SDaniel Fojt return bss;
7393*a1157835SDaniel Fojt }
7394*a1157835SDaniel Fojt
7395*a1157835SDaniel Fojt return NULL;
7396*a1157835SDaniel Fojt }
7397*a1157835SDaniel Fojt
7398*a1157835SDaniel Fojt
wpa_set_driver_tmp_disallow_list(struct wpa_supplicant * wpa_s)7399*a1157835SDaniel Fojt static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
7400*a1157835SDaniel Fojt {
7401*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed *tmp;
7402*a1157835SDaniel Fojt unsigned int num_bssid = 0;
7403*a1157835SDaniel Fojt u8 *bssids;
7404*a1157835SDaniel Fojt int ret;
7405*a1157835SDaniel Fojt
7406*a1157835SDaniel Fojt bssids = os_malloc(dl_list_len(&wpa_s->bss_tmp_disallowed) * ETH_ALEN);
7407*a1157835SDaniel Fojt if (!bssids)
7408*a1157835SDaniel Fojt return -1;
7409*a1157835SDaniel Fojt dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
7410*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed, list) {
7411*a1157835SDaniel Fojt os_memcpy(&bssids[num_bssid * ETH_ALEN], tmp->bssid,
7412*a1157835SDaniel Fojt ETH_ALEN);
7413*a1157835SDaniel Fojt num_bssid++;
7414*a1157835SDaniel Fojt }
7415*a1157835SDaniel Fojt ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
7416*a1157835SDaniel Fojt os_free(bssids);
7417*a1157835SDaniel Fojt return ret;
7418*a1157835SDaniel Fojt }
7419*a1157835SDaniel Fojt
7420*a1157835SDaniel Fojt
wpa_bss_tmp_disallow_timeout(void * eloop_ctx,void * timeout_ctx)7421*a1157835SDaniel Fojt static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
7422*a1157835SDaniel Fojt {
7423*a1157835SDaniel Fojt struct wpa_supplicant *wpa_s = eloop_ctx;
7424*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx;
7425*a1157835SDaniel Fojt
7426*a1157835SDaniel Fojt /* Make sure the bss is not already freed */
7427*a1157835SDaniel Fojt dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
7428*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed, list) {
7429*a1157835SDaniel Fojt if (bss == tmp) {
7430*a1157835SDaniel Fojt dl_list_del(&tmp->list);
7431*a1157835SDaniel Fojt os_free(tmp);
7432*a1157835SDaniel Fojt wpa_set_driver_tmp_disallow_list(wpa_s);
7433*a1157835SDaniel Fojt break;
7434*a1157835SDaniel Fojt }
7435*a1157835SDaniel Fojt }
7436*a1157835SDaniel Fojt }
7437*a1157835SDaniel Fojt
7438*a1157835SDaniel Fojt
wpa_bss_tmp_disallow(struct wpa_supplicant * wpa_s,const u8 * bssid,unsigned int sec,int rssi_threshold)7439*a1157835SDaniel Fojt void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
7440*a1157835SDaniel Fojt unsigned int sec, int rssi_threshold)
7441*a1157835SDaniel Fojt {
7442*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed *bss;
7443*a1157835SDaniel Fojt
7444*a1157835SDaniel Fojt bss = wpas_get_disallowed_bss(wpa_s, bssid);
7445*a1157835SDaniel Fojt if (bss) {
7446*a1157835SDaniel Fojt eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
7447*a1157835SDaniel Fojt goto finish;
7448*a1157835SDaniel Fojt }
7449*a1157835SDaniel Fojt
7450*a1157835SDaniel Fojt bss = os_malloc(sizeof(*bss));
7451*a1157835SDaniel Fojt if (!bss) {
7452*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
7453*a1157835SDaniel Fojt "Failed to allocate memory for temp disallow BSS");
7454*a1157835SDaniel Fojt return;
7455*a1157835SDaniel Fojt }
7456*a1157835SDaniel Fojt
7457*a1157835SDaniel Fojt os_memcpy(bss->bssid, bssid, ETH_ALEN);
7458*a1157835SDaniel Fojt dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
7459*a1157835SDaniel Fojt wpa_set_driver_tmp_disallow_list(wpa_s);
7460*a1157835SDaniel Fojt
7461*a1157835SDaniel Fojt finish:
7462*a1157835SDaniel Fojt bss->rssi_threshold = rssi_threshold;
7463*a1157835SDaniel Fojt eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
7464*a1157835SDaniel Fojt wpa_s, bss);
7465*a1157835SDaniel Fojt }
7466*a1157835SDaniel Fojt
7467*a1157835SDaniel Fojt
wpa_is_bss_tmp_disallowed(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)7468*a1157835SDaniel Fojt int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
7469*a1157835SDaniel Fojt struct wpa_bss *bss)
7470*a1157835SDaniel Fojt {
7471*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
7472*a1157835SDaniel Fojt
7473*a1157835SDaniel Fojt dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
7474*a1157835SDaniel Fojt struct wpa_bss_tmp_disallowed, list) {
7475*a1157835SDaniel Fojt if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) {
7476*a1157835SDaniel Fojt disallowed = tmp;
7477*a1157835SDaniel Fojt break;
7478*a1157835SDaniel Fojt }
7479*a1157835SDaniel Fojt }
7480*a1157835SDaniel Fojt if (!disallowed)
7481*a1157835SDaniel Fojt return 0;
7482*a1157835SDaniel Fojt
7483*a1157835SDaniel Fojt if (disallowed->rssi_threshold != 0 &&
7484*a1157835SDaniel Fojt bss->level > disallowed->rssi_threshold)
7485*a1157835SDaniel Fojt return 0;
7486*a1157835SDaniel Fojt
7487*a1157835SDaniel Fojt return 1;
7488*a1157835SDaniel Fojt }
7489*a1157835SDaniel Fojt
7490*a1157835SDaniel Fojt
wpas_enable_mac_addr_randomization(struct wpa_supplicant * wpa_s,unsigned int type,const u8 * addr,const u8 * mask)7491*a1157835SDaniel Fojt int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
7492*a1157835SDaniel Fojt unsigned int type, const u8 *addr,
7493*a1157835SDaniel Fojt const u8 *mask)
7494*a1157835SDaniel Fojt {
7495*a1157835SDaniel Fojt if ((addr && !mask) || (!addr && mask)) {
7496*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
7497*a1157835SDaniel Fojt "MAC_ADDR_RAND_SCAN invalid addr/mask combination");
7498*a1157835SDaniel Fojt return -1;
7499*a1157835SDaniel Fojt }
7500*a1157835SDaniel Fojt
7501*a1157835SDaniel Fojt if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
7502*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
7503*a1157835SDaniel Fojt "MAC_ADDR_RAND_SCAN cannot allow multicast address");
7504*a1157835SDaniel Fojt return -1;
7505*a1157835SDaniel Fojt }
7506*a1157835SDaniel Fojt
7507*a1157835SDaniel Fojt if (type & MAC_ADDR_RAND_SCAN) {
7508*a1157835SDaniel Fojt if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
7509*a1157835SDaniel Fojt addr, mask))
7510*a1157835SDaniel Fojt return -1;
7511*a1157835SDaniel Fojt }
7512*a1157835SDaniel Fojt
7513*a1157835SDaniel Fojt if (type & MAC_ADDR_RAND_SCHED_SCAN) {
7514*a1157835SDaniel Fojt if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
7515*a1157835SDaniel Fojt addr, mask))
7516*a1157835SDaniel Fojt return -1;
7517*a1157835SDaniel Fojt
7518*a1157835SDaniel Fojt if (wpa_s->sched_scanning && !wpa_s->pno)
7519*a1157835SDaniel Fojt wpas_scan_restart_sched_scan(wpa_s);
7520*a1157835SDaniel Fojt }
7521*a1157835SDaniel Fojt
7522*a1157835SDaniel Fojt if (type & MAC_ADDR_RAND_PNO) {
7523*a1157835SDaniel Fojt if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
7524*a1157835SDaniel Fojt addr, mask))
7525*a1157835SDaniel Fojt return -1;
7526*a1157835SDaniel Fojt
7527*a1157835SDaniel Fojt if (wpa_s->pno) {
7528*a1157835SDaniel Fojt wpas_stop_pno(wpa_s);
7529*a1157835SDaniel Fojt wpas_start_pno(wpa_s);
7530*a1157835SDaniel Fojt }
7531*a1157835SDaniel Fojt }
7532*a1157835SDaniel Fojt
7533*a1157835SDaniel Fojt return 0;
7534*a1157835SDaniel Fojt }
7535*a1157835SDaniel Fojt
7536*a1157835SDaniel Fojt
wpas_disable_mac_addr_randomization(struct wpa_supplicant * wpa_s,unsigned int type)7537*a1157835SDaniel Fojt int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
7538*a1157835SDaniel Fojt unsigned int type)
7539*a1157835SDaniel Fojt {
7540*a1157835SDaniel Fojt wpas_mac_addr_rand_scan_clear(wpa_s, type);
7541*a1157835SDaniel Fojt if (wpa_s->pno) {
7542*a1157835SDaniel Fojt if (type & MAC_ADDR_RAND_PNO) {
7543*a1157835SDaniel Fojt wpas_stop_pno(wpa_s);
7544*a1157835SDaniel Fojt wpas_start_pno(wpa_s);
7545*a1157835SDaniel Fojt }
7546*a1157835SDaniel Fojt } else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) {
7547*a1157835SDaniel Fojt wpas_scan_restart_sched_scan(wpa_s);
7548*a1157835SDaniel Fojt }
7549*a1157835SDaniel Fojt
7550*a1157835SDaniel Fojt return 0;
75516d49e1aeSJan Lentfer }
7552