X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=wpa_supplicant%2Fevents.c;h=76ee93b225d29a65c4eb5b7cd90dbe26eea32e05;hb=HEAD;hp=70dccace4d23cfab3579d5f2a29720035bb38322;hpb=b766a9a2938b555521b05eecb12685e73b29df1b;p=libeap.git diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 70dccac..76ee93b 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -30,11 +30,13 @@ #include "ap/hostapd.h" #include "notify.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "blacklist.h" #include "wpas_glue.h" #include "wps_supplicant.h" #include "ibss_rsn.h" #include "sme.h" +#include "p2p_supplicant.h" #include "bgscan.h" #include "ap.h" #include "bss.h" @@ -109,6 +111,9 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) { int bssid_changed; + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) + return; + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); bssid_changed = !is_zero_ether_addr(wpa_s->bssid); os_memset(wpa_s->bssid, 0, ETH_ALEN); @@ -408,238 +413,132 @@ static int freq_allowed(int *freqs, int freq) } -static struct wpa_bss * -wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *scan_res, - struct wpa_ssid *group, - struct wpa_ssid **selected_ssid) +static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, + int i, struct wpa_scan_res *bss, + struct wpa_ssid *group) { - struct wpa_ssid *ssid; - struct wpa_scan_res *bss; - size_t i; + const u8 *ssid_; + u8 wpa_ie_len, rsn_ie_len, ssid_len; + int wpa; struct wpa_blacklist *e; const u8 *ie; + struct wpa_ssid *ssid; - wpa_printf(MSG_DEBUG, "Try to find WPA-enabled AP"); - for (i = 0; i < scan_res->num; i++) { - const u8 *ssid_; - u8 wpa_ie_len, rsn_ie_len, ssid_len; - bss = scan_res->res[i]; + ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); + ssid_ = ie ? ie + 2 : (u8 *) ""; + ssid_len = ie ? ie[1] : 0; - ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); - ssid_ = ie ? ie + 2 : (u8 *) ""; - ssid_len = ie ? ie[1] : 0; + ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); + wpa_ie_len = ie ? ie[1] : 0; - ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); - wpa_ie_len = ie ? ie[1] : 0; + ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); + rsn_ie_len = ie ? ie[1] : 0; - ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); - rsn_ie_len = ie ? ie[1] : 0; + wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " + "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s", + i, MAC2STR(bss->bssid), wpa_ssid_txt(ssid_, ssid_len), + wpa_ie_len, rsn_ie_len, bss->caps, bss->level, + wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? + " wps" : ""); - wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " - "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x", - (int) i, MAC2STR(bss->bssid), - wpa_ssid_txt(ssid_, ssid_len), - wpa_ie_len, rsn_ie_len, bss->caps); + e = wpa_blacklist_get(wpa_s, bss->bssid); + if (e && e->count > 1) { + wpa_printf(MSG_DEBUG, " skip - blacklisted"); + return 0; + } - e = wpa_blacklist_get(wpa_s, bss->bssid); - if (e && e->count > 1) { - wpa_printf(MSG_DEBUG, " skip - blacklisted"); - continue; - } + if (ssid_len == 0) { + wpa_printf(MSG_DEBUG, " skip - SSID not known"); + return 0; + } - if (ssid_len == 0) { - wpa_printf(MSG_DEBUG, " skip - SSID not known"); + wpa = wpa_ie_len > 0 || rsn_ie_len > 0; + + for (ssid = group; ssid; ssid = ssid->pnext) { + int check_ssid = wpa ? 1 : (ssid->ssid_len != 0); + + if (ssid->disabled) { + wpa_printf(MSG_DEBUG, " skip - disabled"); continue; } - if (wpa_ie_len == 0 && rsn_ie_len == 0) { - wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE"); +#ifdef CONFIG_WPS + if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) { + wpa_printf(MSG_DEBUG, " skip - blacklisted (WPS)"); continue; } - for (ssid = group; ssid; ssid = ssid->pnext) { - int check_ssid = 1; + if (wpa && ssid->ssid_len == 0 && + wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) + check_ssid = 0; - if (ssid->disabled) { - wpa_printf(MSG_DEBUG, " skip - disabled"); - continue; - } - -#ifdef CONFIG_WPS + if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { + /* Only allow wildcard SSID match if an AP + * advertises active WPS operation that matches + * with our mode. */ + check_ssid = 1; if (ssid->ssid_len == 0 && wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) check_ssid = 0; + } #endif /* CONFIG_WPS */ - if (check_ssid && - (ssid_len != ssid->ssid_len || - os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) { - wpa_printf(MSG_DEBUG, " skip - " - "SSID mismatch"); - continue; - } - - if (ssid->bssid_set && - os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) - { - wpa_printf(MSG_DEBUG, " skip - " - "BSSID mismatch"); - continue; - } - - if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) - continue; - - if (!freq_allowed(ssid->freq_list, bss->freq)) { - wpa_printf(MSG_DEBUG, " skip - " - "frequency not allowed"); - continue; - } - - wpa_printf(MSG_DEBUG, " selected WPA AP " - MACSTR " ssid='%s'", - MAC2STR(bss->bssid), - wpa_ssid_txt(ssid_, ssid_len)); - *selected_ssid = ssid; - return wpa_bss_get(wpa_s, bss->bssid, ssid_, ssid_len); + if (check_ssid && + (ssid_len != ssid->ssid_len || + os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) { + wpa_printf(MSG_DEBUG, " skip - SSID mismatch"); + continue; } - } - - return NULL; -} - - -static struct wpa_bss * -wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *scan_res, - struct wpa_ssid *group, - struct wpa_ssid **selected_ssid) -{ - struct wpa_ssid *ssid; - struct wpa_scan_res *bss; - size_t i; - struct wpa_blacklist *e; - const u8 *ie; - wpa_printf(MSG_DEBUG, "Try to find non-WPA AP"); - for (i = 0; i < scan_res->num; i++) { - const u8 *ssid_; - u8 wpa_ie_len, rsn_ie_len, ssid_len; - bss = scan_res->res[i]; - - ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); - ssid_ = ie ? ie + 2 : (u8 *) ""; - ssid_len = ie ? ie[1] : 0; - - ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); - wpa_ie_len = ie ? ie[1] : 0; - - ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); - rsn_ie_len = ie ? ie[1] : 0; + if (ssid->bssid_set && + os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, " skip - BSSID mismatch"); + continue; + } - wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " - "wpa_ie_len=%u rsn_ie_len=%u caps=0x%x", - (int) i, MAC2STR(bss->bssid), - wpa_ssid_txt(ssid_, ssid_len), - wpa_ie_len, rsn_ie_len, bss->caps); + if (wpa && !wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) + continue; - e = wpa_blacklist_get(wpa_s, bss->bssid); - if (e && e->count > 1) { - wpa_printf(MSG_DEBUG, " skip - blacklisted"); + if (!wpa && + !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) && + !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) && + !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) { + wpa_printf(MSG_DEBUG, " skip - non-WPA network not " + "allowed"); continue; } - if (ssid_len == 0) { - wpa_printf(MSG_DEBUG, " skip - SSID not known"); + if (!wpa && !wpa_supplicant_match_privacy(bss, ssid)) { + wpa_printf(MSG_DEBUG, " skip - privacy mismatch"); continue; } - for (ssid = group; ssid; ssid = ssid->pnext) { - int check_ssid = ssid->ssid_len != 0; - - if (ssid->disabled) { - wpa_printf(MSG_DEBUG, " skip - disabled"); - continue; - } - -#ifdef CONFIG_WPS - if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) { - /* Only allow wildcard SSID match if an AP - * advertises active WPS operation that matches - * with our mode. */ - check_ssid = 1; - if (ssid->ssid_len == 0 && - wpas_wps_ssid_wildcard_ok(wpa_s, ssid, - bss)) - check_ssid = 0; - } -#endif /* CONFIG_WPS */ - - if (check_ssid && - (ssid_len != ssid->ssid_len || - os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) { - wpa_printf(MSG_DEBUG, " skip - " - "SSID mismatch"); - continue; - } - - if (ssid->bssid_set && - os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) - { - wpa_printf(MSG_DEBUG, " skip - " - "BSSID mismatch"); - continue; - } - - if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) && - !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) && - !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) - { - wpa_printf(MSG_DEBUG, " skip - " - "non-WPA network not allowed"); - continue; - } - - if ((ssid->key_mgmt & - (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK | - WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK | - WPA_KEY_MGMT_IEEE8021X_SHA256 | - WPA_KEY_MGMT_PSK_SHA256)) && - (wpa_ie_len != 0 || rsn_ie_len != 0)) { - wpa_printf(MSG_DEBUG, " skip - " - "WPA network"); - continue; - } - - if (!wpa_supplicant_match_privacy(bss, ssid)) { - wpa_printf(MSG_DEBUG, " skip - " - "privacy mismatch"); - continue; - } + if (!wpa && (bss->caps & IEEE80211_CAP_IBSS)) { + wpa_printf(MSG_DEBUG, " skip - IBSS (adhoc) " + "network"); + continue; + } - if (bss->caps & IEEE80211_CAP_IBSS) { - wpa_printf(MSG_DEBUG, " skip - " - "IBSS (adhoc) network"); - continue; - } + if (!freq_allowed(ssid->freq_list, bss->freq)) { + wpa_printf(MSG_DEBUG, " skip - frequency not " + "allowed"); + continue; + } - if (!freq_allowed(ssid->freq_list, bss->freq)) { - wpa_printf(MSG_DEBUG, " skip - " - "frequency not allowed"); - continue; - } +#ifdef CONFIG_P2P + /* + * TODO: skip the AP if its P2P IE has Group Formation + * bit set in the P2P Group Capability Bitmap and we + * are not in Group Formation with that device. + */ +#endif /* CONFIG_P2P */ - wpa_printf(MSG_DEBUG, " selected non-WPA AP " - MACSTR " ssid='%s'", - MAC2STR(bss->bssid), - wpa_ssid_txt(ssid_, ssid_len)); - *selected_ssid = ssid; - return wpa_bss_get(wpa_s, bss->bssid, ssid_, ssid_len); - } + /* Matching configuration found */ + return ssid; } - return NULL; + /* No matching configuration found */ + return 0; } @@ -649,21 +548,30 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group, struct wpa_ssid **selected_ssid) { - struct wpa_bss *selected; + size_t i; wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d", group->priority); - /* First, try to find WPA-enabled AP */ - selected = wpa_supplicant_select_bss_wpa(wpa_s, scan_res, group, - selected_ssid); - if (selected) - return selected; + for (i = 0; i < scan_res->num; i++) { + struct wpa_scan_res *bss = scan_res->res[i]; + const u8 *ie, *ssid; + u8 ssid_len; + + *selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group); + if (!*selected_ssid) + continue; + + ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); + ssid = ie ? ie + 2 : (u8 *) ""; + ssid_len = ie ? ie[1] : 0; + + wpa_printf(MSG_DEBUG, " selected BSS " MACSTR " ssid='%s'", + MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len)); + return wpa_bss_get(wpa_s, bss->bssid, ssid, ssid_len); + } - /* If no WPA-enabled AP found, try to find non-WPA AP, if configuration - * allows this. */ - return wpa_supplicant_select_bss_non_wpa(wpa_s, scan_res, group, - selected_ssid); + return NULL; } @@ -698,16 +606,9 @@ wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s, - int timeout) + int timeout_sec, int timeout_usec) { - if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1) { - /* - * Quick recovery if the initial scan results were not - * complete when fetched before the first scan request. - */ - wpa_s->scan_res_tried++; - timeout = 0; - } else if (!wpa_supplicant_enabled_networks(wpa_s->conf)) { + if (!wpa_supplicant_enabled_networks(wpa_s->conf)) { /* * No networks are enabled; short-circuit request so * we don't wait timeout seconds before transitioning @@ -716,18 +617,25 @@ static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s, wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); return; } - wpa_supplicant_req_scan(wpa_s, timeout, 0); + wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec); } -static void wpa_supplicant_connect(struct wpa_supplicant *wpa_s, - struct wpa_bss *selected, - struct wpa_ssid *ssid) +void wpa_supplicant_connect(struct wpa_supplicant *wpa_s, + struct wpa_bss *selected, + struct wpa_ssid *ssid) { if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) { wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP "PBC session overlap"); - wpa_supplicant_req_new_scan(wpa_s, 10); +#ifdef CONFIG_P2P + if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1) + return; +#endif /* CONFIG_P2P */ + +#ifdef CONFIG_WPS + wpas_wps_cancel(wpa_s); +#endif /* CONFIG_WPS */ return; } @@ -742,7 +650,7 @@ static void wpa_supplicant_connect(struct wpa_supplicant *wpa_s, os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) != 0))) { if (wpa_supplicant_scard_init(wpa_s, ssid)) { - wpa_supplicant_req_new_scan(wpa_s, 10); + wpa_supplicant_req_new_scan(wpa_s, 10, 0); return; } wpa_supplicant_associate(wpa_s, selected, ssid); @@ -883,6 +791,12 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, struct wpa_bss *selected; struct wpa_ssid *ssid = NULL; struct wpa_scan_results *scan_res; + int ap = 0; + +#ifdef CONFIG_AP + if (wpa_s->ap_iface) + ap = 1; +#endif /* CONFIG_AP */ wpa_supplicant_notify_scanning(wpa_s, 0); @@ -890,28 +804,31 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, data ? &data->scan_info : NULL, 1); if (scan_res == NULL) { - if (wpa_s->conf->ap_scan == 2) + if (wpa_s->conf->ap_scan == 2 || ap) return; wpa_printf(MSG_DEBUG, "Failed to get scan results - try " "scanning again"); - wpa_supplicant_req_new_scan(wpa_s, 1); + wpa_supplicant_req_new_scan(wpa_s, 1, 0); return; } - /* - * Don't post the results if this was the initial cached - * and there were no results. - */ - if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1 && - scan_res->num == 0) { - wpa_msg(wpa_s, MSG_DEBUG, "Cached scan results are " - "empty - not posting"); - } else { - wpa_printf(MSG_DEBUG, "New scan results available"); - wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); - wpas_notify_scan_results(wpa_s); + if (wpa_s->scan_res_handler) { + wpa_s->scan_res_handler(wpa_s, scan_res); + wpa_s->scan_res_handler = NULL; + wpa_scan_results_free(scan_res); + return; } + if (ap) { + wpa_printf(MSG_DEBUG, "Ignore scan results in AP mode"); + wpa_scan_results_free(scan_res); + return; + } + + wpa_printf(MSG_DEBUG, "New scan results available"); + wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS); + wpas_notify_scan_results(wpa_s); + wpas_notify_scan_done(wpa_s, 1); if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) { @@ -925,7 +842,7 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return; } - if (bgscan_notify_scan(wpa_s) == 1) { + if (bgscan_notify_scan(wpa_s, scan_res) == 1) { wpa_scan_results_free(scan_res); return; } @@ -949,65 +866,32 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, if (ssid) { wpa_printf(MSG_DEBUG, "Setup a new network"); wpa_supplicant_associate(wpa_s, NULL, ssid); - } else - wpa_supplicant_req_new_scan(wpa_s, 5); - } -} -#endif /* CONFIG_NO_SCAN_PROCESSING */ - - -#ifdef CONFIG_IEEE80211R -static void wpa_assoc_set_ft_params(struct wpa_supplicant *wpa_s, - const u8 *ftie, const u8 *mdie) -{ - const u8 *mobility_domain = NULL; - const u8 *r0kh_id = NULL; - size_t r0kh_id_len = 0; - const u8 *r1kh_id = NULL; - struct rsn_ftie *hdr; - const u8 *pos, *end; - - if (mdie == NULL || ftie == NULL) - return; - - if (mdie[1] >= MOBILITY_DOMAIN_ID_LEN) { - mobility_domain = mdie + 2; -#ifdef CONFIG_SME - wpa_s->sme.ft_used = 1; - os_memcpy(wpa_s->sme.mobility_domain, mobility_domain, 2); -#endif /* CONFIG_SME */ - } - if (ftie[1] >= sizeof(struct rsn_ftie)) { - end = ftie + 2 + ftie[1]; - hdr = (struct rsn_ftie *) (ftie + 2); - pos = (const u8 *) (hdr + 1); - while (pos + 1 < end) { - if (pos + 2 + pos[1] > end) - break; - if (pos[0] == FTIE_SUBELEM_R1KH_ID && - pos[1] == FT_R1KH_ID_LEN) - r1kh_id = pos + 2; - else if (pos[0] == FTIE_SUBELEM_R0KH_ID && - pos[1] >= 1 && pos[1] <= FT_R0KH_ID_MAX_LEN) { - r0kh_id = pos + 2; - r0kh_id_len = pos[1]; + } else { + int timeout_sec = 5; + int timeout_usec = 0; +#ifdef CONFIG_P2P + if (wpa_s->p2p_in_provisioning) { + /* + * Use shorter wait during P2P Provisioning + * state to speed up group formation. + */ + timeout_sec = 0; + timeout_usec = 250000; } - pos += 2 + pos[1]; +#endif /* CONFIG_P2P */ + wpa_supplicant_req_new_scan(wpa_s, timeout_sec, + timeout_usec); } } - wpa_sm_set_ft_params(wpa_s->wpa, mobility_domain, r0kh_id, - r0kh_id_len, r1kh_id); } -#endif /* CONFIG_IEEE80211R */ +#endif /* CONFIG_NO_SCAN_PROCESSING */ + -static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) +static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, + union wpa_event_data *data) { int l, len, found = 0, wpa_found, rsn_found; const u8 *p; -#ifdef CONFIG_IEEE80211R - const u8 *mdie = NULL, *ftie = NULL; -#endif /* CONFIG_IEEE80211R */ wpa_printf(MSG_DEBUG, "Association info event"); if (data->assoc_info.req_ies) @@ -1060,15 +944,37 @@ static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, bssid) < 0) { wpa_printf(MSG_DEBUG, "FT: Validation of " "Reassociation Response failed"); - /* TODO: force disconnection? */ + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_INVALID_IE); + return -1; } } -#endif /* CONFIG_SME */ p = data->assoc_info.resp_ies; l = data->assoc_info.resp_ies_len; - /* Go through the IEs and make a copy of the FT/MD IE, if present. */ +#ifdef CONFIG_WPS_STRICT + if (wpa_s->current_ssid && + wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_WPS) { + struct wpabuf *wps; + wps = ieee802_11_vendor_ie_concat(p, l, WPS_IE_VENDOR_TYPE); + if (wps == NULL) { + wpa_printf(MSG_INFO, "WPS-STRICT: AP did not include " + "WPS IE in (Re)Association Response"); + return -1; + } + + if (wps_validate_assoc_resp(wps) < 0) { + wpabuf_free(wps); + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_INVALID_IE); + return -1; + } + wpabuf_free(wps); + } +#endif /* CONFIG_WPS_STRICT */ + + /* Go through the IEs and make a copy of the MDIE, if present. */ while (p && l >= 2) { len = p[1] + 2; if (len > l) { @@ -1076,15 +982,20 @@ static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, p, l); break; } - if (p[0] == WLAN_EID_FAST_BSS_TRANSITION) - ftie = p; - else if (p[0] == WLAN_EID_MOBILITY_DOMAIN) - mdie = p; + if (p[0] == WLAN_EID_MOBILITY_DOMAIN && + p[1] >= MOBILITY_DOMAIN_ID_LEN) { + wpa_s->sme.ft_used = 1; + os_memcpy(wpa_s->sme.mobility_domain, p + 2, + MOBILITY_DOMAIN_ID_LEN); + break; + } l -= len; p += len; } +#endif /* CONFIG_SME */ - wpa_assoc_set_ft_params(wpa_s, ftie, mdie); + wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); #endif /* CONFIG_IEEE80211R */ /* WPA/RSN IE from Beacon/ProbeResp */ @@ -1126,6 +1037,8 @@ static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, wpa_s->ap_ies_from_associnfo = 1; wpa_s->assoc_freq = data->assoc_info.freq; + + return 0; } @@ -1148,8 +1061,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, #endif /* CONFIG_AP */ ft_completed = wpa_ft_is_completed(wpa_s->wpa); - if (data) - wpa_supplicant_event_associnfo(wpa_s, data); + if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0) + return; wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED); if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) @@ -1200,7 +1113,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid); } wpa_sm_notify_assoc(wpa_s->wpa, bssid); - l2_packet_notify_auth_start(wpa_s->l2); + if (wpa_s->l2) + l2_packet_notify_auth_start(wpa_s->l2); /* * Set portEnabled first to FALSE in order to get EAP state machine out @@ -1291,7 +1205,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, } -static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s) +static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s, + u16 reason_code) { const u8 *bssid; #ifdef CONFIG_SME @@ -1318,21 +1233,35 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s) wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - " "pre-shared key may be incorrect"); } - if (wpa_s->wpa_state >= WPA_ASSOCIATED) - wpa_supplicant_req_scan(wpa_s, 0, 100000); + if (!wpa_s->auto_reconnect_disabled || + wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) { + wpa_printf(MSG_DEBUG, "WPA: Auto connect enabled: try to " + "reconnect (wps=%d)", + wpa_s->key_mgmt == WPA_KEY_MGMT_WPS); + if (wpa_s->wpa_state >= WPA_ASSOCIATING) + wpa_supplicant_req_scan(wpa_s, 0, 100000); + } else { + wpa_printf(MSG_DEBUG, "WPA: Auto connect disabled: do not try " + "to re-connect"); + wpa_s->reassociate = 0; + wpa_s->disconnected = 1; + } bssid = wpa_s->bssid; if (is_zero_ether_addr(bssid)) bssid = wpa_s->pending_bssid; wpa_blacklist_add(wpa_s, bssid); wpa_sm_notify_disassoc(wpa_s->wpa); - wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "- Disconnect event - " - "remove keys"); + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR + " reason=%d", + MAC2STR(bssid), reason_code); if (wpa_supplicant_dynamic_keys(wpa_s)) { + wpa_printf(MSG_DEBUG, "Disconnect event - remove keys"); wpa_s->keys_cleared = 0; wpa_clear_keys(wpa_s, wpa_s->bssid); } wpa_supplicant_mark_disassoc(wpa_s); bgscan_deinit(wpa_s); + wpa_s->bgscan_ssid = NULL; #ifdef CONFIG_SME if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) { @@ -1605,6 +1534,18 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct wpa_supplicant *wpa_s = ctx; + u16 reason_code = 0; + + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED && + event != EVENT_INTERFACE_ENABLED && + event != EVENT_INTERFACE_STATUS) { + wpa_printf(MSG_DEBUG, "Ignore event %d while interface is " + "disabled", event); + return; + } + + wpa_printf(MSG_DEBUG, "Event %d received on interface %s", + event, wpa_s->ifname); switch (event) { case EVENT_AUTH: @@ -1615,27 +1556,69 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; case EVENT_DISASSOC: wpa_printf(MSG_DEBUG, "Disassociation notification"); + if (data) { + wpa_printf(MSG_DEBUG, " * reason %u", + data->disassoc_info.reason_code); + if (data->disassoc_info.addr) + wpa_printf(MSG_DEBUG, " * address " MACSTR, + MAC2STR(data->disassoc_info.addr)); + } #ifdef CONFIG_AP - if (wpa_s->ap_iface && data) { + if (wpa_s->ap_iface && data && data->disassoc_info.addr) { hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], data->disassoc_info.addr); break; } #endif /* CONFIG_AP */ + if (data) { + reason_code = data->disassoc_info.reason_code; + wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)", + data->disassoc_info.ie, + data->disassoc_info.ie_len); +#ifdef CONFIG_P2P + wpas_p2p_disassoc_notif( + wpa_s, data->disassoc_info.addr, reason_code, + data->disassoc_info.ie, + data->disassoc_info.ie_len); +#endif /* CONFIG_P2P */ + } if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) sme_event_disassoc(wpa_s, data); /* fall through */ case EVENT_DEAUTH: - if (event == EVENT_DEAUTH) + if (event == EVENT_DEAUTH) { wpa_printf(MSG_DEBUG, "Deauthentication notification"); + if (data) { + reason_code = data->deauth_info.reason_code; + wpa_printf(MSG_DEBUG, " * reason %u", + data->deauth_info.reason_code); + if (data->deauth_info.addr) { + wpa_printf(MSG_DEBUG, " * address " + MACSTR, + MAC2STR(data->deauth_info. + addr)); + } + wpa_hexdump(MSG_DEBUG, + "Deauthentication frame IE(s)", + data->deauth_info.ie, + data->deauth_info.ie_len); +#ifdef CONFIG_P2P + wpas_p2p_deauth_notif( + wpa_s, data->deauth_info.addr, + reason_code, + data->deauth_info.ie, + data->deauth_info.ie_len); +#endif /* CONFIG_P2P */ + } + } #ifdef CONFIG_AP - if (wpa_s->ap_iface && data) { + if (wpa_s->ap_iface && data && data->deauth_info.addr) { hostapd_notif_disassoc(wpa_s->ap_iface->bss[0], data->deauth_info.addr); break; } #endif /* CONFIG_AP */ - wpa_supplicant_event_disassoc(wpa_s); + wpa_supplicant_event_disassoc(wpa_s, reason_code); break; case EVENT_MICHAEL_MIC_FAILURE: wpa_supplicant_event_michael_mic_failure(wpa_s, data); @@ -1680,8 +1663,40 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; #ifdef CONFIG_AP case EVENT_TX_STATUS: - if (wpa_s->ap_iface == NULL) + wpa_printf(MSG_DEBUG, "EVENT_TX_STATUS on %s dst=" MACSTR + " type=%d stype=%d pending_dst=" MACSTR, + wpa_s->ifname, MAC2STR(data->tx_status.dst), + data->tx_status.type, data->tx_status.stype, + MAC2STR(wpa_s->parent->pending_action_dst)); + if (wpa_s->ap_iface == NULL) { +#ifdef CONFIG_P2P + if (data->tx_status.type == WLAN_FC_TYPE_MGMT && + data->tx_status.stype == WLAN_FC_STYPE_ACTION) + wpas_send_action_tx_status( + wpa_s, data->tx_status.dst, + data->tx_status.data, + data->tx_status.data_len, + data->tx_status.ack); +#endif /* CONFIG_P2P */ + break; + } +#ifdef CONFIG_P2P + /* + * Catch TX status events for Action frames we sent via group + * interface in GO mode. + */ + if (data->tx_status.type == WLAN_FC_TYPE_MGMT && + data->tx_status.stype == WLAN_FC_STYPE_ACTION && + os_memcmp(wpa_s->parent->pending_action_dst, + data->tx_status.dst, ETH_ALEN) == 0) { + wpas_send_action_tx_status( + wpa_s->parent, data->tx_status.dst, + data->tx_status.data, + data->tx_status.data_len, + data->tx_status.ack); break; + } +#endif /* CONFIG_P2P */ switch (data->tx_status.type) { case WLAN_FC_TYPE_MGMT: ap_mgmt_tx_cb(wpa_s, data->tx_status.data, @@ -1704,8 +1719,29 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->rx_from_unknown.len); break; case EVENT_RX_MGMT: - if (wpa_s->ap_iface == NULL) + if (wpa_s->ap_iface == NULL) { +#ifdef CONFIG_P2P + u16 fc, stype; + const struct ieee80211_mgmt *mgmt; + mgmt = (const struct ieee80211_mgmt *) + data->rx_mgmt.frame; + fc = le_to_host16(mgmt->frame_control); + stype = WLAN_FC_GET_STYPE(fc); + if (stype == WLAN_FC_STYPE_PROBE_REQ && + data->rx_mgmt.frame_len > 24) { + const u8 *src = mgmt->sa; + const u8 *ie = mgmt->u.probe_req.variable; + size_t ie_len = data->rx_mgmt.frame_len - + (mgmt->u.probe_req.variable - + data->rx_mgmt.frame); + wpas_p2p_probe_req_rx(wpa_s, src, ie, ie_len); + break; + } +#endif /* CONFIG_P2P */ + wpa_printf(MSG_DEBUG, "AP: ignore received management " + "frame in non-AP mode"); break; + } ap_mgmt_rx(wpa_s, &data->rx_mgmt); break; #endif /* CONFIG_AP */ @@ -1722,7 +1758,31 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, break; } #endif /* CONFIG_IEEE80211R */ +#ifdef CONFIG_P2P + wpas_p2p_rx_action(wpa_s, data->rx_action.da, + data->rx_action.sa, + data->rx_action.bssid, + data->rx_action.category, + data->rx_action.data, + data->rx_action.len, data->rx_action.freq); +#endif /* CONFIG_P2P */ + break; +#ifdef CONFIG_P2P + case EVENT_REMAIN_ON_CHANNEL: + wpas_p2p_remain_on_channel_cb( + wpa_s, data->remain_on_channel.freq, + data->remain_on_channel.duration); break; + case EVENT_CANCEL_REMAIN_ON_CHANNEL: + wpas_p2p_cancel_remain_on_channel_cb( + wpa_s, data->remain_on_channel.freq); + break; + case EVENT_RX_PROBE_REQ: + wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa, + data->rx_probe_req.ie, + data->rx_probe_req.ie_len); + break; +#endif /* CONFIG_P2P */ #ifdef CONFIG_CLIENT_MLME case EVENT_MLME_RX: { struct ieee80211_rx_status rx_status; @@ -1740,6 +1800,40 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->eapol_rx.data, data->eapol_rx.data_len); break; + case EVENT_SIGNAL_CHANGE: + bgscan_notify_signal_change( + wpa_s, data->signal_change.above_threshold, + data->signal_change.current_signal, + data->signal_change.current_noise, + data->signal_change.current_txrate); + break; + case EVENT_INTERFACE_ENABLED: + wpa_printf(MSG_DEBUG, "Interface was enabled"); + if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { +#ifdef CONFIG_AP + if (!wpa_s->ap_iface) { + wpa_supplicant_set_state(wpa_s, + WPA_DISCONNECTED); + wpa_supplicant_req_scan(wpa_s, 0, 0); + } else + wpa_supplicant_set_state(wpa_s, + WPA_COMPLETED); +#else /* CONFIG_AP */ + wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); + wpa_supplicant_req_scan(wpa_s, 0, 0); +#endif /* CONFIG_AP */ + } + break; + case EVENT_INTERFACE_DISABLED: + wpa_printf(MSG_DEBUG, "Interface was disabled"); + wpa_supplicant_mark_disassoc(wpa_s); + wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED); + break; + case EVENT_CHANNEL_LIST_CHANGED: +#ifdef CONFIG_P2P + wpas_p2p_update_channel_list(wpa_s); +#endif /* CONFIG_P2P */ + break; default: wpa_printf(MSG_INFO, "Unknown event %d", event); break;