#include "offchannel.h"
#include "hs20_supplicant.h"
#include "wnm_sta.h"
+#include "wpas_kay.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
eapol_conf.external_sim = wpa_s->conf->external_sim;
eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
#endif /* IEEE8021X_EAPOL */
+
+ ieee802_1x_alloc_kay_sm(wpa_s, ssid);
}
os_free(wpa_s->confanother);
wpa_s->confanother = NULL;
+#ifdef CONFIG_P2P
+ os_free(wpa_s->conf_p2p_dev);
+ wpa_s->conf_p2p_dev = NULL;
+#endif /* CONFIG_P2P */
+
wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
wpa_supplicant_ap_deinit(wpa_s);
#endif /* CONFIG_AP */
-#ifdef CONFIG_P2P
wpas_p2p_deinit(wpa_s);
-#endif /* CONFIG_P2P */
#ifdef CONFIG_OFFCHANNEL
offchannel_deinit(wpa_s);
os_free(wpa_s->manual_scan_freqs);
wpa_s->manual_scan_freqs = NULL;
+ os_free(wpa_s->manual_sched_scan_freqs);
+ wpa_s->manual_sched_scan_freqs = NULL;
+
gas_query_deinit(wpa_s->gas);
wpa_s->gas = NULL;
free_hw_features(wpa_s);
+ ieee802_1x_dealloc_kay_sm(wpa_s);
+
os_free(wpa_s->bssid_filter);
wpa_s->bssid_filter = NULL;
os_free(wpa_s->last_scan_res);
wpa_s->last_scan_res = NULL;
+
+#ifdef CONFIG_HS20
+ hs20_deinit(wpa_s);
+#endif /* CONFIG_HS20 */
}
name = wpa_s->current_ssid->bgscan;
else
name = wpa_s->conf->bgscan;
- if (name == NULL)
+ if (name == NULL || name[0] == '\0')
return;
if (wpas_driver_bss_selection(wpa_s))
return;
if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
return;
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
+ return;
+#endif /* CONFIG_P2P */
bgscan_deinit(wpa_s);
if (wpa_s->current_ssid) {
wpa_s->normal_scans = 0;
}
- if (state == WPA_COMPLETED)
+ if (state == WPA_COMPLETED) {
wpas_connect_work_done(wpa_s);
+ /* Reinitialize normal_scan counter */
+ wpa_s->normal_scans = 0;
+ }
if (state != WPA_SCANNING)
wpa_supplicant_notify_scanning(wpa_s, 0);
#endif /* IEEE8021X_EAPOL */
wpa_s->after_wps = 0;
wpa_s->known_wps_freq = 0;
-#ifdef CONFIG_P2P
wpas_p2p_completed(wpa_s);
-#endif /* CONFIG_P2P */
sme_sched_obss_scan(wpa_s, 1);
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
if (wpa_s->wpa_state != old_state) {
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+ /*
+ * Notify the P2P Device interface about a state change in one
+ * of the interfaces.
+ */
+ wpas_p2p_indicate_state_change(wpa_s);
+
if (wpa_s->wpa_state == WPA_COMPLETED ||
old_state == WPA_COMPLETED)
wpas_notify_auth_changed(wpa_s);
struct wpa_supplicant *wpa_s = global->ifaces;
while (wpa_s) {
struct wpa_supplicant *next = wpa_s->next;
+ if (wpas_wps_terminate_pending(wpa_s) == 1)
+ pending = 1;
#ifdef CONFIG_P2P
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
(wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
wpas_p2p_disconnect(wpa_s);
#endif /* CONFIG_P2P */
- if (wpas_wps_terminate_pending(wpa_s) == 1)
- pending = 1;
wpa_s = next;
}
#endif /* CONFIG_WPS */
{
struct wpa_ie_data ie;
int sel, proto;
- const u8 *bss_wpa, *bss_rsn;
+ const u8 *bss_wpa, *bss_rsn, *bss_osen;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
} else
- bss_wpa = bss_rsn = NULL;
+ bss_wpa = bss_rsn = bss_osen = NULL;
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
(ie.key_mgmt & ssid->key_mgmt)) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
proto = WPA_PROTO_WPA;
+#ifdef CONFIG_HS20
+ } else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN");
+ /* TODO: parse OSEN element */
+ os_memset(&ie, 0, sizeof(ie));
+ ie.group_cipher = WPA_CIPHER_CCMP;
+ ie.pairwise_cipher = WPA_CIPHER_CCMP;
+ ie.key_mgmt = WPA_KEY_MGMT_OSEN;
+ proto = WPA_PROTO_OSEN;
+#endif /* CONFIG_HS20 */
} else if (bss) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
return -1;
} else {
- if (ssid->proto & WPA_PROTO_RSN)
+ if (ssid->proto & WPA_PROTO_OSEN)
+ proto = WPA_PROTO_OSEN;
+ else if (ssid->proto & WPA_PROTO_RSN)
proto = WPA_PROTO_RSN;
else
proto = WPA_PROTO_WPA;
wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
- !!(ssid->proto & WPA_PROTO_RSN));
+ !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
if (bss || !wpa_s->ap_ies_from_associnfo) {
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
+#ifdef CONFIG_HS20
+ } else if (sel & WPA_KEY_MGMT_OSEN) {
+ wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
+ wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
+#endif /* CONFIG_HS20 */
} else {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
"authenticated key management type");
wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
"AES-128-CMAC");
+ } else if (sel & WPA_CIPHER_BIP_GMAC_128) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+ "BIP-GMAC-128");
+ } else if (sel & WPA_CIPHER_BIP_GMAC_256) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+ "BIP-GMAC-256");
+ } else if (sel & WPA_CIPHER_BIP_CMAC_256) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+ "BIP-CMAC-256");
} else {
wpa_s->mgmt_group_cipher = 0;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
#endif /* CONFIG_INTERWORKING */
break;
case 5: /* Bits 40-47 */
+#ifdef CONFIG_HS20
+ if (wpa_s->conf->hs20)
+ *pos |= 0x40; /* Bit 46 - WNM-Notification */
+#endif /* CONFIG_HS20 */
break;
case 6: /* Bits 48-55 */
break;
}
-int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
{
u8 *pos = buf;
- u8 len = 4, i;
+ u8 len = 6, i;
if (len < wpa_s->extended_capa_len)
len = wpa_s->extended_capa_len;
+ if (buflen < (size_t) len + 2) {
+ wpa_printf(MSG_INFO,
+ "Not enough room for building extended capabilities element");
+ return -1;
+ }
*pos++ = WLAN_EID_EXT_CAPAB;
*pos++ = len;
return;
}
+ if (radio_work_pending(wpa_s, "connect")) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist");
+ return;
+ }
+
cwork = os_zalloc(sizeof(*cwork));
if (cwork == NULL)
return;
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ struct ieee80211_vht_capabilities vhtcaps;
+ struct ieee80211_vht_capabilities vhtcaps_mask;
+#endif /* CONFIG_VHT_OVERRIDES */
if (deinit) {
if (work->started) {
struct wpabuf *hs20;
hs20 = wpabuf_alloc(20);
if (hs20) {
- wpas_hs20_add_indication(hs20);
- os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
- wpabuf_len(hs20));
- wpa_ie_len += wpabuf_len(hs20);
+ int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
+ size_t len;
+
+ wpas_hs20_add_indication(hs20, pps_mo_id);
+ len = sizeof(wpa_ie) - wpa_ie_len;
+ if (wpabuf_len(hs20) <= len) {
+ os_memcpy(wpa_ie + wpa_ie_len,
+ wpabuf_head(hs20), wpabuf_len(hs20));
+ wpa_ie_len += wpabuf_len(hs20);
+ }
wpabuf_free(hs20);
}
}
* interoperability issues.
*/
if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
- u8 ext_capab[10];
+ u8 ext_capab[18];
int ext_capab_len;
- ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
+ sizeof(ext_capab));
if (ext_capab_len > 0) {
u8 *pos = wpa_ie;
if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
params.freq == 0)
params.freq = ssid->frequency; /* Initial channel for IBSS */
+
+ if (ssid->mode == WPAS_MODE_IBSS) {
+ if (ssid->beacon_int)
+ params.beacon_int = ssid->beacon_int;
+ else
+ params.beacon_int = wpa_s->conf->beacon_int;
+ }
+
params.wpa_ie = wpa_ie;
params.wpa_ie_len = wpa_ie_len;
params.pairwise_suite = cipher_pairwise;
params.htcaps_mask = (u8 *) &htcaps_mask;
wpa_supplicant_apply_ht_overrides(wpa_s, ssid, ¶ms);
#endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+ os_memset(&vhtcaps, 0, sizeof(vhtcaps));
+ os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
+ params.vhtcaps = &vhtcaps;
+ params.vhtcaps_mask = &vhtcaps_mask;
+ wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms);
+#endif /* CONFIG_VHT_OVERRIDES */
#ifdef CONFIG_P2P
/*
* least prioritized connection.
*/
if (wpa_s->num_multichan_concurrent < 2) {
- int freq = wpa_drv_shared_freq(wpa_s);
- if (freq > 0 && freq != params.freq) {
- wpa_printf(MSG_DEBUG, "Shared interface with conflicting frequency found (%d != %d)",
+ int freq, num;
+ num = get_shared_radio_freqs(wpa_s, &freq, 1);
+ if (num > 0 && freq > 0 && freq != params.freq) {
+ wpa_printf(MSG_DEBUG,
+ "Assoc conflicting freq found (%d != %d)",
freq, params.freq);
if (wpas_p2p_handle_frequency_conflicts(wpa_s,
params.freq,
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
interface_count = 0;
}
- if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+ if (!wpa_s->p2p_mgmt &&
+ wpa_supplicant_delayed_sched_scan(wpa_s,
+ interface_count % 3,
100000))
- wpa_supplicant_req_scan(wpa_s, interface_count,
+ wpa_supplicant_req_scan(wpa_s, interface_count % 3,
100000);
interface_count++;
} else
}
+static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ /* Masking these out disables LDPC */
+ u16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
+
+ if (disabled)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ htcaps_mask->ht_capabilities_info |= msk;
+
+ return 0;
+}
+
+
void wpa_supplicant_apply_ht_overrides(
struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_driver_associate_params *params)
wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
+ wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
+
+ if (ssid->ht40_intolerant) {
+ u16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
+ htcaps->ht_capabilities_info |= bit;
+ htcaps_mask->ht_capabilities_info |= bit;
+ }
}
#endif /* CONFIG_HT_OVERRIDES */
{
struct ieee80211_vht_capabilities *vhtcaps;
struct ieee80211_vht_capabilities *vhtcaps_mask;
+#ifdef CONFIG_HT_OVERRIDES
+ int max_ampdu;
+ const u32 max_ampdu_mask = VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX;
+#endif /* CONFIG_HT_OVERRIDES */
if (!ssid)
return;
vhtcaps->vht_capabilities_info = ssid->vht_capa;
vhtcaps_mask->vht_capabilities_info = ssid->vht_capa_mask;
+#ifdef CONFIG_HT_OVERRIDES
+ /* if max ampdu is <= 3, we have to make the HT cap the same */
+ if (ssid->vht_capa_mask & max_ampdu_mask) {
+ max_ampdu = (ssid->vht_capa & max_ampdu_mask) >>
+ find_first_bit(max_ampdu_mask);
+
+ max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
+ wpa_set_ampdu_factor(wpa_s,
+ (void *) params->htcaps,
+ (void *) params->htcaps_mask,
+ max_ampdu);
+ }
+#endif /* CONFIG_HT_OVERRIDES */
+
#define OVERRIDE_MCS(i) \
if (ssid->vht_tx_mcs_nss_ ##i >= 0) { \
vhtcaps_mask->vht_supported_mcs_set.tx_map |= \
}
+static int wpas_check_wowlan_trigger(const char *start, const char *trigger,
+ int capa_trigger, u8 *param_trigger)
+{
+ if (os_strcmp(start, trigger) != 0)
+ return 0;
+ if (!capa_trigger)
+ return 0;
+
+ *param_trigger = 1;
+ return 1;
+}
+
+
+int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_capa *capa)
+{
+ struct wowlan_triggers triggers;
+ char *start, *end, *buf;
+ int last, ret;
+
+ if (!wpa_s->conf->wowlan_triggers)
+ return 0;
+
+ buf = os_strdup(wpa_s->conf->wowlan_triggers);
+ if (buf == NULL)
+ return -1;
+
+ os_memset(&triggers, 0, sizeof(triggers));
+
+#define CHECK_TRIGGER(trigger) \
+ wpas_check_wowlan_trigger(start, #trigger, \
+ capa->wowlan_triggers.trigger, \
+ &triggers.trigger)
+
+ start = buf;
+ while (*start != '\0') {
+ while (isblank(*start))
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (!isblank(*end) && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+
+ if (!CHECK_TRIGGER(any) &&
+ !CHECK_TRIGGER(disconnect) &&
+ !CHECK_TRIGGER(magic_pkt) &&
+ !CHECK_TRIGGER(gtk_rekey_failure) &&
+ !CHECK_TRIGGER(eap_identity_req) &&
+ !CHECK_TRIGGER(four_way_handshake) &&
+ !CHECK_TRIGGER(rfkill_release)) {
+ wpa_printf(MSG_DEBUG,
+ "Unknown/unsupported wowlan trigger '%s'",
+ start);
+ ret = -1;
+ goto out;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+#undef CHECK_TRIGGER
+
+ ret = wpa_drv_wowlan(wpa_s, &triggers);
+out:
+ os_free(buf);
+ return ret;
+}
+
+
static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
const char *rn)
{
wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s",
wpa_s->ifname, radio->name);
dl_list_del(&wpa_s->radio_list);
- if (!dl_list_empty(&radio->ifaces)) {
- wpa_s->radio = NULL;
+ radio_remove_works(wpa_s, NULL, 0);
+ wpa_s->radio = NULL;
+ if (!dl_list_empty(&radio->ifaces))
return; /* Interfaces remain for this radio */
- }
wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
- radio_remove_works(wpa_s, NULL, 0);
eloop_cancel_timeout(radio_start_next_work, radio, NULL);
- wpa_s->radio = NULL;
os_free(radio);
}
}
+int radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
+{
+ struct wpa_radio_work *work;
+ struct wpa_radio *radio = wpa_s->radio;
+
+ dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
+ if (work->wpa_s == wpa_s && os_strcmp(work->type, type) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int wpas_init_driver(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
}
- if (wpa_s->driver->get_radio_name)
- rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
- else
- rn = NULL;
+ rn = wpa_driver_get_radio_name(wpa_s);
if (rn && rn[0] == '\0')
rn = NULL;
wpa_s->confanother = os_rel2abs_path(iface->confanother);
wpa_config_read(wpa_s->confanother, wpa_s->conf);
+#ifdef CONFIG_P2P
+ wpa_s->conf_p2p_dev = os_rel2abs_path(iface->conf_p2p_dev);
+ wpa_config_read(wpa_s->conf_p2p_dev, wpa_s->conf);
+#endif /* CONFIG_P2P */
+
/*
* Override ctrl_interface and driver_param if set on command
* line.
return -1;
}
-#ifdef CONFIG_P2P
if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
return -1;
}
-#endif /* CONFIG_P2P */
if (wpa_bss_init(wpa_s) < 0)
return -1;
+ /*
+ * Set Wake-on-WLAN triggers, if configured.
+ * Note: We don't restore/remove the triggers on shutdown (it doesn't
+ * have effect anyway when the interface is down).
+ */
+ if (wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
+ return -1;
+
#ifdef CONFIG_EAP_PROXY
{
size_t len;
}
wpa_supplicant_cleanup(wpa_s);
-
-#ifdef CONFIG_P2P
- if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
- wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
- "the management interface is being removed");
- wpas_p2p_deinit_global(wpa_s->global);
- }
-#endif /* CONFIG_P2P */
+ wpas_p2p_deinit_iface(wpa_s);
wpas_ctrl_radio_work_flush(wpa_s);
radio_remove_interface(wpa_s);
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
-
-#ifdef CONFIG_P2P
wpas_p2p_update_config(wpa_s);
-#endif /* CONFIG_P2P */
-
wpa_s->conf->changed_parameters = 0;
}
if (count > 3 && wpa_s->current_ssid) {
wpa_printf(MSG_DEBUG, "Continuous association failures - "
"consider temporary network disabling");
- wpas_auth_failed(wpa_s);
+ wpas_auth_failed(wpa_s, "CONN_FAILED");
}
switch (count) {
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PASSWORD:
- os_free(eap->password);
+ bin_clear_free(eap->password, eap->password_len);
eap->password = (u8 *) os_strdup(value);
eap->password_len = os_strlen(value);
eap->pending_req_password = 0;
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
- os_free(eap->new_password);
+ bin_clear_free(eap->new_password, eap->new_password_len);
eap->new_password = (u8 *) os_strdup(value);
eap->new_password_len = os_strlen(value);
eap->pending_req_new_password = 0;
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_PIN:
- os_free(eap->pin);
+ str_clear_free(eap->pin);
eap->pin = os_strdup(value);
eap->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_EAP_OTP:
- os_free(eap->otp);
+ bin_clear_free(eap->otp, eap->otp_len);
eap->otp = (u8 *) os_strdup(value);
eap->otp_len = os_strlen(value);
os_free(eap->pending_req_otp);
eap->pending_req_otp_len = 0;
break;
case WPA_CTRL_REQ_EAP_PASSPHRASE:
- os_free(eap->private_key_passwd);
- eap->private_key_passwd = (u8 *) os_strdup(value);
+ str_clear_free(eap->private_key_passwd);
+ eap->private_key_passwd = os_strdup(value);
eap->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
break;
case WPA_CTRL_REQ_SIM:
- os_free(eap->external_sim_resp);
+ str_clear_free(eap->external_sim_resp);
eap->external_sim_resp = os_strdup(value);
break;
default:
}
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
- !ssid->ext_psk)
+ (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk)
return 1;
return 0;
}
-void wpas_auth_failed(struct wpa_supplicant *wpa_s)
+void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason)
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
int dur;
if (ssid->auth_failures > 50)
dur = 300;
- else if (ssid->auth_failures > 20)
- dur = 120;
else if (ssid->auth_failures > 10)
- dur = 60;
+ dur = 120;
else if (ssid->auth_failures > 5)
+ dur = 90;
+ else if (ssid->auth_failures > 3)
+ dur = 60;
+ else if (ssid->auth_failures > 2)
dur = 30;
else if (ssid->auth_failures > 1)
dur = 20;
else
dur = 10;
+ if (ssid->auth_failures > 1 &&
+ wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt))
+ dur += os_random() % (ssid->auth_failures * 10);
+
os_get_reltime(&now);
if (now.sec + dur <= ssid->disabled_until.sec)
return;
ssid->disabled_until.sec = now.sec + dur;
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
- "id=%d ssid=\"%s\" auth_failures=%u duration=%d",
+ "id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s",
ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
- ssid->auth_failures, dur);
+ ssid->auth_failures, dur, reason);
}
}
-void dump_freq_array(struct wpa_supplicant *wpa_s, const char *title,
- int *freq_array, unsigned int len)
+void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
+ struct wpa_used_freq_data *freqs_data,
+ unsigned int len)
{
unsigned int i;
wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
len, title);
- for (i = 0; i < len; i++)
- wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d", i, freq_array[i]);
+ for (i = 0; i < len; i++) {
+ struct wpa_used_freq_data *cur = &freqs_data[i];
+ wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d, flags=0x%X",
+ i, cur->freq, cur->flags);
+ }
}
/*
* Find the operating frequencies of any of the virtual interfaces that
- * are using the same radio as the current interface.
+ * are using the same radio as the current interface, and in addition, get
+ * information about the interface types that are using the frequency.
*/
-int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
- int *freq_array, unsigned int len)
+int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
+ struct wpa_used_freq_data *freqs_data,
+ unsigned int len)
{
struct wpa_supplicant *ifs;
u8 bssid[ETH_ALEN];
wpa_dbg(wpa_s, MSG_DEBUG,
"Determining shared radio frequencies (max len %u)", len);
- os_memset(freq_array, 0, sizeof(int) * len);
-
- /* First add the frequency of the local interface */
- if (wpa_s->current_ssid != NULL && wpa_s->assoc_freq != 0) {
- if (wpa_s->current_ssid->mode == WPAS_MODE_AP ||
- wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO)
- freq_array[idx++] = wpa_s->current_ssid->frequency;
- else if (wpa_drv_get_bssid(wpa_s, bssid) == 0)
- freq_array[idx++] = wpa_s->assoc_freq;
- }
-
- /* If get_radio_name is not supported, use only the local freq */
- if (!wpa_s->driver->get_radio_name) {
- freq = wpa_drv_shared_freq(wpa_s);
- if (freq > 0 && idx < len &&
- (idx == 0 || freq_array[0] != freq))
- freq_array[idx++] = freq;
- dump_freq_array(wpa_s, "No get_radio_name", freq_array, idx);
- return idx;
- }
+ os_memset(freqs_data, 0, sizeof(struct wpa_used_freq_data) * len);
dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
radio_list) {
- if (wpa_s == ifs)
- continue;
+ if (idx == len)
+ break;
if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
continue;
/* Hold only distinct freqs */
for (i = 0; i < idx; i++)
- if (freq_array[i] == freq)
+ if (freqs_data[i].freq == freq)
break;
if (i == idx)
- freq_array[idx++] = freq;
+ freqs_data[idx++].freq = freq;
+
+ if (ifs->current_ssid->mode == WPAS_MODE_INFRA) {
+ freqs_data[i].flags = ifs->current_ssid->p2p_group ?
+ WPA_FREQ_USED_BY_P2P_CLIENT :
+ WPA_FREQ_USED_BY_INFRA_STATION;
+ }
}
- dump_freq_array(wpa_s, "completed iteration", freq_array, idx);
+ dump_freq_data(wpa_s, "completed iteration", freqs_data, idx);
return idx;
}
+
+
+/*
+ * Find the operating frequencies of any of the virtual interfaces that
+ * are using the same radio as the current interface.
+ */
+int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
+ int *freq_array, unsigned int len)
+{
+ struct wpa_used_freq_data *freqs_data;
+ int num, i;
+
+ os_memset(freq_array, 0, sizeof(int) * len);
+
+ freqs_data = os_calloc(len, sizeof(struct wpa_used_freq_data));
+ if (!freqs_data)
+ return -1;
+
+ num = get_shared_radio_freqs_data(wpa_s, freqs_data, len);
+ for (i = 0; i < num; i++)
+ freq_array[i] = freqs_data[i].freq;
+
+ os_free(freqs_data);
+
+ return num;
+}