wpa_supplicant: Call frequency conflict handling during auth
[mech_eap.git] / wpa_supplicant / wpa_supplicant.c
index 187e5d9..af7b847 100644 (file)
@@ -397,6 +397,11 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
        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;
@@ -455,6 +460,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *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;
 
@@ -483,6 +491,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 
        os_free(wpa_s->last_scan_res);
        wpa_s->last_scan_res = NULL;
+
+#ifdef CONFIG_HS20
+       hs20_free_osu_prov(wpa_s);
+#endif /* CONFIG_HS20 */
 }
 
 
@@ -569,12 +581,16 @@ static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
                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) {
@@ -652,8 +668,16 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpa_supplicant_state_txt(wpa_s->wpa_state),
                wpa_supplicant_state_txt(state));
 
-       if (state == WPA_COMPLETED)
+       if (state == WPA_INTERFACE_DISABLED) {
+               /* Assure normal scan when interface is restored */
+               wpa_s->normal_scans = 0;
+       }
+
+       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);
@@ -928,13 +952,14 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 {
        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 &&
@@ -950,11 +975,22 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                   (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 */
+               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;
@@ -987,7 +1023,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        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,
@@ -1058,6 +1094,11 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
        } 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");
@@ -1079,6 +1120,18 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
                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");
@@ -1203,6 +1256,10 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
 #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;
@@ -1213,7 +1270,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
 {
        u8 *pos = buf;
-       u8 len = 4, i;
+       u8 len = 6, i;
 
        if (len < wpa_s->extended_capa_len)
                len = wpa_s->extended_capa_len;
@@ -1361,6 +1418,11 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                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;
@@ -1394,8 +1456,19 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        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) {
+                       wpa_s->connect_work = NULL;
+
+                       /* cancel possible auth. timeout */
+                       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
+                                            NULL);
+               }
                wpas_connect_work_free(cwork);
                return;
        }
@@ -1410,6 +1483,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
 
        os_memset(&params, 0, sizeof(params));
        wpa_s->reassociate = 0;
+       wpa_s->eap_expected_failure = 0;
        if (bss && !wpas_driver_bss_selection(wpa_s)) {
 #ifdef CONFIG_IEEE80211R
                const u8 *ie, *md = NULL;
@@ -1559,6 +1633,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                                "disallows" : "allows");
                }
        }
+
+       os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_HS20
@@ -1566,7 +1642,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                struct wpabuf *hs20;
                hs20 = wpabuf_alloc(20);
                if (hs20) {
-                       wpas_hs20_add_indication(hs20);
+                       int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
+                       wpas_hs20_add_indication(hs20, pps_mo_id);
                        os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
                                  wpabuf_len(hs20));
                        wpa_ie_len += wpabuf_len(hs20);
@@ -1648,6 +1725,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
                        params.bssid = bss->bssid;
                        params.freq = bss->freq;
                }
+               params.bssid_hint = bss->bssid;
+               params.freq_hint = bss->freq;
        } else {
                params.ssid = ssid->ssid;
                params.ssid_len = ssid->ssid_len;
@@ -1662,6 +1741,14 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        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;
@@ -1720,6 +1807,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
        params.htcaps_mask = (u8 *) &htcaps_mask;
        wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
 #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, &params);
+#endif /* CONFIG_VHT_OVERRIDES */
 
 #ifdef CONFIG_P2P
        /*
@@ -1728,9 +1822,11 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
         * 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,
@@ -2075,7 +2171,7 @@ int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
        }
        if (pkcs11_module_path != NULL) {
                pkcs11_module_path_copy = os_strdup(pkcs11_module_path);
-               if (pkcs11_engine_path_copy == NULL) {
+               if (pkcs11_module_path_copy == NULL) {
                        os_free(pkcs11_engine_path_copy);
                        return -1;
                }
@@ -2617,9 +2713,15 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
        wpa_s->prev_scan_wildcard = 0;
 
        if (wpa_supplicant_enabled_networks(wpa_s)) {
-               if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+               if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+                       wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+                       interface_count = 0;
+               }
+               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
@@ -2825,6 +2927,27 @@ static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
 }
 
 
+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)
@@ -2848,6 +2971,13 @@ void wpa_supplicant_apply_ht_overrides(
        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 */
@@ -2860,6 +2990,10 @@ void wpa_supplicant_apply_vht_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;
@@ -2875,6 +3009,20 @@ void wpa_supplicant_apply_vht_overrides(
        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 |=           \
@@ -3063,25 +3211,40 @@ static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
 }
 
 
-void radio_remove_unstarted_work(struct wpa_supplicant *wpa_s, const char *type)
+/*
+ * This function removes both started and pending radio works running on
+ * the provided interface's radio.
+ * Prior to the removal of the radio work, its callback (cb) is called with
+ * deinit set to be 1. Each work's callback is responsible for clearing its
+ * internal data and restoring to a correct state.
+ * @wpa_s: wpa_supplicant data
+ * @type: type of works to be removed
+ * @remove_all: 1 to remove all the works on this radio, 0 to remove only
+ * this interface's works.
+ */
+void radio_remove_works(struct wpa_supplicant *wpa_s,
+                       const char *type, int remove_all)
 {
        struct wpa_radio_work *work, *tmp;
        struct wpa_radio *radio = wpa_s->radio;
 
        dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work,
                              list) {
-               if (type && (work->started || os_strcmp(type, work->type) != 0))
+               if (type && os_strcmp(type, work->type) != 0)
                        continue;
-               if (work->started) {
-                       wpa_dbg(wpa_s, MSG_DEBUG, "Leaving started radio work '%s'@%p in the list",
-                               work->type, work);
+
+               /* skip other ifaces' works */
+               if (!remove_all && work->wpa_s != wpa_s)
                        continue;
-               }
-               wpa_dbg(wpa_s, MSG_DEBUG, "Remove unstarted radio work '%s'@%p",
-                       work->type, work);
+
+               wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s",
+                       work->type, work, work->started ? " (started)" : "");
                work->cb(work, 1);
                radio_work_free(work);
        }
+
+       /* in case we removed the started work */
+       radio_work_check_next(wpa_s);
 }
 
 
@@ -3095,15 +3258,13 @@ static void radio_remove_interface(struct wpa_supplicant *wpa_s)
        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_unstarted_work(wpa_s, NULL);
        eloop_cancel_timeout(radio_start_next_work, radio, NULL);
-       wpa_s->radio = NULL;
        os_free(radio);
 }
 
@@ -3201,6 +3362,20 @@ void radio_work_done(struct wpa_radio_work *work)
 }
 
 
+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)
 {
@@ -3238,10 +3413,7 @@ next_driver:
                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;
 
@@ -3288,6 +3460,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
                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.
@@ -3513,6 +3690,8 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
        wpa_supplicant_cleanup(wpa_s);
 
 #ifdef CONFIG_P2P
+       if (wpa_s == wpa_s->parent)
+               wpas_p2p_group_remove(wpa_s, "*");
        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");
@@ -3917,6 +4096,7 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        os_free(global->params.override_ctrl_interface);
 
        os_free(global->p2p_disallow_freq.range);
+       os_free(global->p2p_go_avoid_freq.range);
        os_free(global->add_psk);
 
        os_free(global);
@@ -4215,7 +4395,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
        }
 
        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;
@@ -4262,17 +4442,23 @@ void wpas_auth_failed(struct wpa_supplicant *wpa_s)
 
        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;
@@ -4399,7 +4585,7 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
        }
 
        /* If get_radio_name is not supported, use only the local freq */
-       if (!wpa_s->driver->get_radio_name) {
+       if (!wpa_driver_get_radio_name(wpa_s)) {
                freq = wpa_drv_shared_freq(wpa_s);
                if (freq > 0 && idx < len &&
                    (idx == 0 || freq_array[0] != freq))