/* TODO: move the rsn_preauth_scan_result*() to be called from notify.c based * on BSS added and BSS changed events */ static void wpa_supplicant_rsn_preauth_scan_results( struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { int i; if (rsn_preauth_scan_results(wpa_s->wpa) < 0) return; for (i = scan_res->num - 1; i >= 0; i--) { const u8 *ssid, *rsn; struct wpa_scan_res *r; r = scan_res->res[i]; ssid = wpa_scan_get_ie(r, WLAN_EID_SSID); if (ssid == NULL) continue; rsn = wpa_scan_get_ie(r, WLAN_EID_RSN); if (rsn == NULL) continue; rsn_preauth_scan_result(wpa_s->wpa, r->bssid, ssid, rsn); } }
/* Format one result on one text line into a buffer. */ static int wpa_supplicant_ctrl_iface_scan_result( const struct wpa_scan_res *res, char *buf, size_t buflen) { char *pos, *end; int ret; const u8 *ie, *ie2; pos = buf; end = buf + buflen; ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t", MAC2STR(res->bssid), res->freq, res->level); if (ret < 0 || ret >= end - pos) return -1; pos += ret; ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); if (ie) pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN); if (ie2) pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]); pos = wpa_supplicant_wps_ie_txt(pos, end, res); if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) { ret = os_snprintf(pos, end - pos, "[WEP]"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } /* Just to make the fields line up nicely when printed */ if (!ie && !ie2) { ret = os_snprintf(pos, end - pos, "\t"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; } ie = wpa_scan_get_ie(res, WLAN_EID_SSID); if (res->caps & IEEE80211_CAP_IBSS) ret = os_snprintf(pos, end - pos, "\t%s%s", "(*)", wpa_ssid_txt(ie + 2, ie[1])); else ret = os_snprintf(pos, end - pos, "\t%s", ie ? wpa_ssid_txt(ie + 2, ie[1]) : ""); if (ret < 0 || ret >= end - pos) return -1; pos += ret; ret = os_snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return -1; pos += ret; return pos - buf; }
/** * rsn_preauth_scan_results - Process scan results to find PMKSA candidates * @sm: Pointer to WPA state machine data from wpa_sm_init() * @results: Scan results * * This functions goes through the scan results and adds all suitable APs * (Authenticators) into PMKSA candidate list. */ void rsn_preauth_scan_results(struct wpa_sm *sm, struct wpa_scan_results *results) { struct wpa_scan_res *r; struct wpa_ie_data ie; int i; struct rsn_pmksa_cache_entry *pmksa; if (sm->ssid_len == 0) return; /* * TODO: is it ok to free all candidates? What about the entries * received from EVENT_PMKID_CANDIDATE? */ pmksa_candidate_free(sm); for (i = results->num - 1; i >= 0; i--) { const u8 *ssid, *rsn; r = results->res[i]; ssid = wpa_scan_get_ie(r, WLAN_EID_SSID); if (ssid == NULL || ssid[1] != sm->ssid_len || os_memcmp(ssid + 2, sm->ssid, ssid[1]) != 0) continue; if (os_memcmp(r->bssid, sm->bssid, ETH_ALEN) == 0) continue; rsn = wpa_scan_get_ie(r, WLAN_EID_RSN); if (rsn == NULL || wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie)) continue; pmksa = pmksa_cache_get(sm->pmksa, r->bssid, NULL); if (pmksa && (!pmksa->opportunistic || !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) continue; /* * Give less priority to candidates found from normal * scan results. */ pmksa_candidate_add(sm, r->bssid, PMKID_CANDIDATE_PRIO_SCAN, ie.capabilities & WPA_CAPABILITY_PREAUTH); } }
static struct wpa_bss * wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res, struct wpa_ssid *group, struct wpa_ssid **selected_ssid) { size_t i; wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d", group->priority); 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); } return NULL; }
/* Compare function for sorting scan results. Return >0 if @b is considered * better. */ static int wpa_scan_result_compar(const void *a, const void *b) { struct wpa_scan_res **_wa = (void *) a; struct wpa_scan_res **_wb = (void *) b; struct wpa_scan_res *wa = *_wa; struct wpa_scan_res *wb = *_wb; int wpa_a, wpa_b, maxrate_a, maxrate_b; /* WPA/WPA2 support preferred */ wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; if (wpa_b && !wpa_a) return 1; if (!wpa_b && wpa_a) return -1; /* privacy support preferred */ if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && (wb->caps & IEEE80211_CAP_PRIVACY)) return 1; if ((wa->caps & IEEE80211_CAP_PRIVACY) && (wb->caps & IEEE80211_CAP_PRIVACY) == 0) return -1; /* best/max rate preferred if signal level close enough XXX */ if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) || (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { maxrate_a = wpa_scan_get_max_rate(wa); maxrate_b = wpa_scan_get_max_rate(wb); if (maxrate_a != maxrate_b) return maxrate_b - maxrate_a; } /* use freq for channel preference */ /* all things being equal, use signal level; if signal levels are * identical, use quality values since some drivers may only report * that value and leave the signal level zero */ if (wb->level == wa->level) return wb->qual - wa->qual; return wb->level - wa->level; }
static int are_ies_equal(const struct wpa_bss *old, const struct wpa_scan_res *new_res, u32 ie) { const u8 *old_ie, *new_ie; struct wpabuf *old_ie_buff = NULL; struct wpabuf *new_ie_buff = NULL; int new_ie_len, old_ie_len, ret, is_multi; switch (ie) { case WPA_IE_VENDOR_TYPE: old_ie = wpa_bss_get_vendor_ie(old, ie); new_ie = wpa_scan_get_vendor_ie(new_res, ie); is_multi = 0; break; case WPS_IE_VENDOR_TYPE: old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie); new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie); is_multi = 1; break; case WLAN_EID_RSN: case WLAN_EID_SUPP_RATES: case WLAN_EID_EXT_SUPP_RATES: old_ie = wpa_bss_get_ie(old, ie); new_ie = wpa_scan_get_ie(new_res, ie); is_multi = 0; break; default: wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__); return 0; } if (is_multi) { /* in case of multiple IEs stored in buffer */ old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL; new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL; old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0; new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0; } else { /* in case of single IE */ old_ie_len = old_ie ? old_ie[1] + 2 : 0; new_ie_len = new_ie ? new_ie[1] + 2 : 0; } if (!old_ie || !new_ie) ret = !old_ie && !new_ie; else ret = (old_ie_len == new_ie_len && os_memcmp(old_ie, new_ie, old_ie_len) == 0); wpabuf_free(old_ie_buff); wpabuf_free(new_ie_buff); return ret; }
static int wpa_scan_get_max_rate(const struct wpa_scan_res *res) { int rate = 0; const u8 *ie; int i; ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES); for (i = 0; ie && i < ie[1]; i++) { if ((ie[i + 2] & 0x7f) > rate) rate = ie[i + 2] & 0x7f; } ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES); for (i = 0; ie && i < ie[1]; i++) { if ((ie[i + 2] & 0x7f) > rate) rate = ie[i + 2] & 0x7f; } return rate; }
static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s, int registrar, const u8 *bssid) { struct wpa_ssid *ssid; ssid = wpa_config_add_network(wpa_s->conf); if (ssid == NULL) return NULL; wpa_config_set_network_defaults(ssid); if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 || wpa_config_set(ssid, "eap", "WSC", 0) < 0 || wpa_config_set(ssid, "identity", registrar ? "\"" WSC_ID_REGISTRAR "\"" : "\"" WSC_ID_ENROLLEE "\"", 0) < 0) { wpa_config_remove_network(wpa_s->conf, ssid->id); return NULL; } if (bssid) { size_t i; struct wpa_scan_res *res; os_memcpy(ssid->bssid, bssid, ETH_ALEN); ssid->bssid_set = 1; /* Try to get SSID from scan results */ if (wpa_s->scan_res == NULL && wpa_supplicant_get_scan_results(wpa_s) < 0) return ssid; /* Could not find any scan results */ for (i = 0; i < wpa_s->scan_res->num; i++) { const u8 *ie; res = wpa_s->scan_res->res[i]; if (os_memcmp(bssid, res->bssid, ETH_ALEN) != 0) continue; ie = wpa_scan_get_ie(res, WLAN_EID_SSID); if (ie == NULL) break; os_free(ssid->ssid); ssid->ssid = os_malloc(ie[1]); if (ssid->ssid == NULL) break; os_memcpy(ssid->ssid, ie + 2, ie[1]); ssid->ssid_len = ie[1]; break; } } return ssid; }
static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) { size_t i; int ret = 0; struct wpa_scan_res *curr = NULL; struct wpa_ssid *ssid = wpa_s->current_ssid; const u8 *ie; if (wpa_s->scan_res == NULL) return -1; for (i = 0; i < wpa_s->scan_res->num; i++) { struct wpa_scan_res *r = wpa_s->scan_res->res[i]; if (os_memcmp(r->bssid, wpa_s->bssid, ETH_ALEN) != 0) continue; ie = wpa_scan_get_ie(r, WLAN_EID_SSID); if (ssid == NULL || ((ie && ie[1] == ssid->ssid_len && os_memcmp(ie + 2, ssid->ssid, ssid->ssid_len) == 0) || ssid->ssid_len == 0)) { curr = r; break; } } if (curr) { ie = wpa_scan_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE); if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) ret = -1; ie = wpa_scan_get_ie(curr, WLAN_EID_RSN); if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) ret = -1; } else { ret = -1; } return ret; }
static int wpa_supplicant_ssid_wapi_bss_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_scan_res *bss) { struct wpa_ie_data ie; int proto_match = 0; const u8 *wapi_ie; int ret; wapi_ie = wpa_scan_get_ie(bss, WAPI_INFO_ELEM); while ((ssid->proto & WPA_PROTO_WAPI) && wapi_ie) { proto_match++; if (wpa_parse_wapi_ie(wapi_ie, 2 + wapi_ie[1], &ie)) { wpa_printf(MSG_DEBUG, " skip WAPI IE - parse failed"); break; } if (!(ie.proto & ssid->proto)) { wpa_printf(MSG_DEBUG, " skip WAPI IE - proto " "mismatch"); break; } if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { wpa_printf(MSG_DEBUG, " skip WAPI IE - PTK cipher " "mismatch"); break; } if (!(ie.group_cipher & ssid->group_cipher)) { wpa_printf(MSG_DEBUG, " skip WAPI IE - GTK cipher " "mismatch"); break; } if (!(ie.key_mgmt & ssid->key_mgmt)) { wpa_printf(MSG_DEBUG, " skip WAPI IE - key mgmt " "mismatch"); break; } wpa_printf(MSG_DEBUG, " selected based on WAPI IE"); return 1; } if (proto_match == 0) wpa_printf(MSG_DEBUG, " skip - no WAPI proto match"); return 0; }
static int bgscan_learn_bss_match(struct bgscan_learn_data *data, struct wpa_scan_res *bss) { const u8 *ie; ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); if (ie == NULL) return 0; if (data->ssid->ssid_len != ie[1] || os_memcmp(data->ssid->ssid, ie + 2, ie[1]) != 0) return 0; /* SSID mismatch */ return 1; }
scan_ssid_t *scan_get_ssid( scan_result_t *res_ptr ) { static scan_ssid_t ssid_temp; #if defined WPA_SUPPLICANT_VER_0_6_X || defined WPA_SUPPLICANT_VER_0_8_X const u8 *res_ie; res_ie = wpa_scan_get_ie(res_ptr, WLAN_EID_SSID); if (!res_ie) return NULL; ssid_temp.ssid_len = (size_t)res_ie[1]; os_memcpy(ssid_temp.ssid, (res_ie + 2), ssid_temp.ssid_len); #else ssid_temp.ssid_len = res_ptr->ssid_len; os_memcpy(ssid_temp.ssid, res_ptr->ssid, ssid_temp.ssid_len); #endif return &ssid_temp; }
static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, const struct wps_credential *cred) { struct wpa_driver_capa capa; size_t i; struct wpa_scan_res *bss; const u8 *ie; struct wpa_ie_data adv; int wpa2 = 0, ccmp = 0; /* * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in * case they are configured for mixed mode operation (WPA+WPA2 and * TKIP+CCMP). Try to use scan results to figure out whether the AP * actually supports stronger security and select that if the client * has support for it, too. */ if (wpa_drv_get_capa(wpa_s, &capa)) return; /* Unknown what driver supports */ if (wpa_supplicant_get_scan_results(wpa_s) || wpa_s->scan_res == NULL) return; /* Could not get scan results for checking advertised * parameters */ for (i = 0; i < wpa_s->scan_res->num; i++) { bss = wpa_s->scan_res->res[i]; if (os_memcmp(bss->bssid, cred->mac_addr, ETH_ALEN) != 0) continue; ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); if (ie == NULL) continue; if (ie[1] != ssid->ssid_len || ssid->ssid == NULL || os_memcmp(ie + 2, ssid->ssid, ssid->ssid_len) != 0) continue; wpa_printf(MSG_DEBUG, "WPS: AP found from scan results"); break; } if (i == wpa_s->scan_res->num) { wpa_printf(MSG_DEBUG, "WPS: The AP was not found from scan " "results - use credential as-is"); return; } ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) { wpa2 = 1; if (adv.pairwise_cipher & WPA_CIPHER_CCMP) ccmp = 1; } else { ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 && adv.pairwise_cipher & WPA_CIPHER_CCMP) ccmp = 1; } if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) && (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) { /* * TODO: This could be the initial AP configuration and the * Beacon contents could change shortly. Should request a new * scan and delay addition of the network until the updated * scan results are available. */ wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA " "support - use credential as-is"); return; } if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) && (ssid->pairwise_cipher & WPA_CIPHER_TKIP) && (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) { wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential " "based on scan results"); if (wpa_s->conf->ap_scan == 1) ssid->pairwise_cipher |= WPA_CIPHER_CCMP; else ssid->pairwise_cipher = WPA_CIPHER_CCMP; } if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) && (ssid->proto & WPA_PROTO_WPA) && (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) { wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential " "based on scan results"); if (wpa_s->conf->ap_scan == 1) ssid->proto |= WPA_PROTO_RSN; else ssid->proto = WPA_PROTO_RSN; } }
/** * wpas_dbus_bssid_properties - Return the properties of a scanned network * @message: Pointer to incoming dbus message * @wpa_s: wpa_supplicant structure for a network interface * @res: wpa_supplicant scan result for which to get properties * Returns: a dbus message containing the properties for the requested network * * Handler function for "properties" method call of a scanned network. * Returns a dbus message containing the the properties. */ DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message, struct wpa_supplicant *wpa_s, struct wpa_scan_res *res) { DBusMessage *reply = NULL; DBusMessageIter iter, iter_dict; const u8 *ie; /* Dump the properties into a dbus message */ reply = dbus_message_new_method_return(message); dbus_message_iter_init_append(reply, &iter); if (!wpa_dbus_dict_open_write(&iter, &iter_dict)) goto error; if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid", (const char *) res->bssid, ETH_ALEN)) goto error; ie = wpa_scan_get_ie(res, WLAN_EID_SSID); if (ie) { if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid", (const char *) (ie + 2), ie[1])) goto error; } ie = wpa_scan_get_vendor_ie(res, WPA_IE_VENDOR_TYPE); if (ie) { if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie", (const char *) ie, ie[1] + 2)) goto error; } ie = wpa_scan_get_ie(res, WLAN_EID_RSN); if (ie) { if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie", (const char *) ie, ie[1] + 2)) goto error; } ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE); if (ie) { if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie", (const char *) ie, ie[1] + 2)) goto error; } if (res->freq) { if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency", res->freq)) goto error; } if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities", res->caps)) goto error; if (!wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual)) goto error; if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise)) goto error; if (!wpa_dbus_dict_append_int32(&iter_dict, "level", res->level)) goto error; if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate", wpa_scan_get_max_rate(res) * 500000)) goto error; if (!wpa_dbus_dict_close_write(&iter, &iter_dict)) goto error; return reply; error: if (reply) dbus_message_unref(reply); return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR, "an internal error occurred returning " "BSSID properties."); }
static struct wpa_scan_res * wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s, 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 WPA-enabled AP"); for (i = 0; i < wpa_s->scan_res->num; i++) { const u8 *ssid_; u8 wpa_ie_len, rsn_ie_len, ssid_len; bss = wpa_s->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; 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"); continue; } if (ssid_len == 0) { wpa_printf(MSG_DEBUG, " skip - SSID not known"); continue; } if (wpa_ie_len == 0 && rsn_ie_len == 0) { wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE"); continue; } for (ssid = group; ssid; ssid = ssid->pnext) { int check_ssid = 1; if (ssid->disabled) { wpa_printf(MSG_DEBUG, " skip - disabled"); continue; } #ifdef CONFIG_WPS 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; wpa_printf(MSG_DEBUG, " selected WPA AP " MACSTR " ssid='%s'", MAC2STR(bss->bssid), wpa_ssid_txt(ssid_, ssid_len)); *selected_ssid = ssid; return bss; } } return NULL; }
static struct wpa_scan_res * wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s, 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 < wpa_s->scan_res->num; i++) { const u8 *ssid_; u8 wpa_ie_len, rsn_ie_len, ssid_len; bss = wpa_s->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; 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"); continue; } if (ssid_len == 0) { wpa_printf(MSG_DEBUG, " skip - SSID not known"); 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 (bss->caps & IEEE80211_CAP_IBSS) { wpa_printf(MSG_DEBUG, " skip - " "IBSS (adhoc) network"); continue; } wpa_printf(MSG_DEBUG, " selected non-WPA AP " MACSTR " ssid='%s'", MAC2STR(bss->bssid), wpa_ssid_txt(ssid_, ssid_len)); *selected_ssid = ssid; return bss; } } return NULL; }
static struct wpa_scan_res * wpa_supplicant_select_bss_wapi(struct wpa_supplicant *wpa_s, 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 WAPI-enabled AP"); for (i = 0; i < wpa_s->scan_res->num; i++) { const u8 *ssid_; u8 wapi_ie_len, ssid_len; bss = wpa_s->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, WAPI_INFO_ELEM); wapi_ie_len = ie ? ie[1] : 0; wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' " "wapi_ie_len=%u caps=0x%x", (int) i, MAC2STR(bss->bssid), wpa_ssid_txt(ssid_, ssid_len), wapi_ie_len, bss->caps); 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"); continue; } if (wapi_ie_len == 0) { wpa_printf(MSG_DEBUG, " skip - no WAPI IE"); continue; } for (ssid = group; ssid; ssid = ssid->pnext) { int check_ssid = 1; if (ssid->disabled) { wpa_printf(MSG_DEBUG, " skip - disabled"); continue; } 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_wapi_bss_match(wpa_s, ssid, bss)) continue; { /* Record the WAPI AP's IE, will be reported to WAPI Module */ const u8* wapi_ie; wapi_ie = wpa_scan_get_ie(bss, WAPI_INFO_ELEM); wpa_s->bss_wapi_ie_len = 2 + wapi_ie[1]; os_memcpy(wpa_s->bss_wapi_ie, wapi_ie, wpa_s->bss_wapi_ie_len); wpa_printf(MSG_DEBUG, "[WAPI-Debug ^_^] selected WAPI AP !!!!!!! Ready to connect +_+"); } wpa_printf(MSG_DEBUG, " selected WAPI AP " MACSTR " ssid='%s'", MAC2STR(bss->bssid), wpa_ssid_txt(ssid_, ssid_len)); *selected_ssid = ssid; return bss; } } return NULL; }
static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_scan_res *bss) { struct wpa_ie_data ie; int proto_match = 0; const u8 *rsn_ie, *wpa_ie; int ret; ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); if (ret >= 0) return ret; rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN); while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) { proto_match++; if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) { wpa_printf(MSG_DEBUG, " skip RSN IE - parse failed"); break; } if (!(ie.proto & ssid->proto)) { wpa_printf(MSG_DEBUG, " skip RSN IE - proto " "mismatch"); break; } if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { wpa_printf(MSG_DEBUG, " skip RSN IE - PTK cipher " "mismatch"); break; } if (!(ie.group_cipher & ssid->group_cipher)) { wpa_printf(MSG_DEBUG, " skip RSN IE - GTK cipher " "mismatch"); break; } if (!(ie.key_mgmt & ssid->key_mgmt)) { wpa_printf(MSG_DEBUG, " skip RSN IE - key mgmt " "mismatch"); break; } #ifdef CONFIG_IEEE80211W if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && ssid->ieee80211w == IEEE80211W_REQUIRED) { wpa_printf(MSG_DEBUG, " skip RSN IE - no mgmt frame " "protection"); break; } #endif /* CONFIG_IEEE80211W */ wpa_printf(MSG_DEBUG, " selected based on RSN IE"); return 1; } wpa_ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) { proto_match++; if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) { wpa_printf(MSG_DEBUG, " skip WPA IE - parse failed"); break; } if (!(ie.proto & ssid->proto)) { wpa_printf(MSG_DEBUG, " skip WPA IE - proto " "mismatch"); break; } if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) { wpa_printf(MSG_DEBUG, " skip WPA IE - PTK cipher " "mismatch"); break; } if (!(ie.group_cipher & ssid->group_cipher)) { wpa_printf(MSG_DEBUG, " skip WPA IE - GTK cipher " "mismatch"); break; } if (!(ie.key_mgmt & ssid->key_mgmt)) { wpa_printf(MSG_DEBUG, " skip WPA IE - key mgmt " "mismatch"); break; } wpa_printf(MSG_DEBUG, " selected based on WPA IE"); return 1; } if (proto_match == 0) wpa_printf(MSG_DEBUG, " skip - no WPA/RSN proto match"); return 0; }
static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid, struct wpa_scan_results *scan_res) { size_t i; struct wpa_scan_res *current_bss = NULL; int min_diff; if (wpa_s->reassociate) return 1; /* explicit request to reassociate */ if (wpa_s->wpa_state < WPA_ASSOCIATED) return 1; /* we are not associated; continue */ if (wpa_s->current_ssid == NULL) return 1; /* unknown current SSID */ if (wpa_s->current_ssid != ssid) return 1; /* different network block */ for (i = 0; i < scan_res->num; i++) { struct wpa_scan_res *res = scan_res->res[i]; const u8 *ie; if (os_memcmp(res->bssid, wpa_s->bssid, ETH_ALEN) != 0) continue; ie = wpa_scan_get_ie(res, WLAN_EID_SSID); if (ie == NULL) continue; if (ie[1] != wpa_s->current_ssid->ssid_len || os_memcmp(ie + 2, wpa_s->current_ssid->ssid, ie[1]) != 0) continue; current_bss = res; break; } if (!current_bss) return 1; /* current BSS not seen in scan results */ wpa_printf(MSG_DEBUG, "Considering within-ESS reassociation"); wpa_printf(MSG_DEBUG, "Current BSS: " MACSTR " level=%d", MAC2STR(current_bss->bssid), current_bss->level); wpa_printf(MSG_DEBUG, "Selected BSS: " MACSTR " level=%d", MAC2STR(selected->bssid), selected->level); if (wpa_s->current_ssid->bssid_set && os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) == 0) { wpa_printf(MSG_DEBUG, "Allow reassociation - selected BSS has " "preferred BSSID"); return 1; } min_diff = 2; if (current_bss->level < 0) { if (current_bss->level < -85) min_diff = 1; else if (current_bss->level < -80) min_diff = 2; else if (current_bss->level < -75) min_diff = 3; else if (current_bss->level < -70) min_diff = 4; else min_diff = 5; } if (abs(current_bss->level - selected->level) < min_diff) { wpa_printf(MSG_DEBUG, "Skip roam - too small difference in " "signal level"); return 0; } return 1; }
static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s, const char *cmd, char *buf, size_t buflen) { u8 bssid[ETH_ALEN]; size_t i; struct wpa_scan_results *results; struct wpa_scan_res *bss; int ret; char *pos, *end; const u8 *ie, *ie2; results = wpa_s->scan_res; if (results == NULL) return 0; if (hwaddr_aton(cmd, bssid) == 0) { for (i = 0; i < results->num; i++) { if (os_memcmp(bssid, results->res[i]->bssid, ETH_ALEN) == 0) break; } } else i = atoi(cmd); if (i >= results->num || results->res[i] == NULL) return 0; /* no match found */ bss = results->res[i]; pos = buf; end = buf + buflen; ret = snprintf(pos, end - pos, "bssid=" MACSTR "\n" "freq=%d\n" "beacon_int=%d\n" "capabilities=0x%04x\n" "qual=%d\n" "noise=%d\n" "level=%d\n" "tsf=%016llu\n" "ie=", MAC2STR(bss->bssid), bss->freq, bss->beacon_int, bss->caps, bss->qual, bss->noise, bss->level, (unsigned long long) bss->tsf); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ie = (const u8 *) (bss + 1); for (i = 0; i < bss->ie_len; i++) { ret = snprintf(pos, end - pos, "%02x", *ie++); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } ret = snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ret = os_snprintf(pos, end - pos, "flags="); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE); if (ie) pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]); ie2 = wpa_scan_get_ie(bss, WLAN_EID_RSN); if (ie2) pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]); if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) { ret = os_snprintf(pos, end - pos, "[WEP]"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } if (bss->caps & IEEE80211_CAP_IBSS) { ret = os_snprintf(pos, end - pos, "[IBSS]"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; } ret = snprintf(pos, end - pos, "\n"); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; ie = wpa_scan_get_ie(bss, WLAN_EID_SSID); ret = os_snprintf(pos, end - pos, "ssid=%s\n", ie ? wpa_ssid_txt(ie + 2, ie[1]) : ""); if (ret < 0 || ret >= end - pos) return pos - buf; pos += ret; return pos - buf; }
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) { 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 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_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; 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) { int limit = 1; if (wpa_supplicant_enabled_networks(wpa_s->conf) == 1) { /* * When only a single network is enabled, we can * trigger blacklisting on the first failure. This * should not be done with multiple enabled networks to * avoid getting forced to move into a worse ESS on * single error if there are no other BSSes of the * current ESS. */ limit = 0; } if (e->count > limit) { wpa_printf(MSG_DEBUG, " skip - blacklisted " "(count=%d limit=%d)", e->count, limit); continue; } } if (ssid_len == 0) { wpa_printf(MSG_DEBUG, " skip - SSID not known"); continue; } if (wpa_ie_len == 0 && rsn_ie_len == 0) { wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE"); continue; } for (ssid = group; ssid; ssid = ssid->pnext) { int check_ssid = 1; if (ssid->disabled) { wpa_printf(MSG_DEBUG, " skip - disabled"); continue; } #ifdef CONFIG_WPS 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); } } return NULL; }
/** * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result * @wpa_s: Pointer to wpa_supplicant data * @res: Scan result * @fetch_time: Time when the result was fetched from the driver * * This function updates a BSS table entry (or adds one) based on a scan result. * This is called separately for each scan result between the calls to * wpa_bss_update_start() and wpa_bss_update_end(). */ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res, struct os_reltime *fetch_time) { const u8 *ssid, *p2p, *mesh; struct wpa_bss *bss; if (wpa_s->conf->ignore_old_scan_res) { struct os_reltime update; calculate_update_time(fetch_time, res->age, &update); if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) { struct os_reltime age; os_reltime_sub(&wpa_s->scan_trigger_time, &update, &age); wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS " "table entry that is %u.%06u seconds older " "than our scan trigger", (unsigned int) age.sec, (unsigned int) age.usec); return; } } ssid = wpa_scan_get_ie(res, WLAN_EID_SSID); if (ssid == NULL) { wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for " MACSTR, MAC2STR(res->bssid)); return; } if (ssid[1] > SSID_MAX_LEN) { wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for " MACSTR, MAC2STR(res->bssid)); return; } p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE); #ifdef CONFIG_P2P if (p2p == NULL && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) { /* * If it's a P2P specific interface, then don't update * the scan result without a P2P IE. */ wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR " update for P2P interface", MAC2STR(res->bssid)); return; } #endif /* CONFIG_P2P */ if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN && os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0) return; /* Skip P2P listen discovery results here */ /* TODO: add option for ignoring BSSes we are not interested in * (to save memory) */ mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID); if (mesh && mesh[1] <= SSID_MAX_LEN) ssid = mesh; bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]); if (bss == NULL) bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time); else { bss = wpa_bss_update(wpa_s, bss, res, fetch_time); if (wpa_s->last_scan_res) { unsigned int i; for (i = 0; i < wpa_s->last_scan_res_used; i++) { if (bss == wpa_s->last_scan_res[i]) { /* Already in the list */ return; } } } } if (bss == NULL) return; if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) { struct wpa_bss **n; unsigned int siz; if (wpa_s->last_scan_res_size == 0) siz = 32; else siz = wpa_s->last_scan_res_size * 2; n = os_realloc_array(wpa_s->last_scan_res, siz, sizeof(struct wpa_bss *)); if (n == NULL) return; wpa_s->last_scan_res = n; wpa_s->last_scan_res_size = siz; } if (wpa_s->last_scan_res) wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss; }
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int i, struct wpa_scan_res *bss, struct wpa_ssid *group) { 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; 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; 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" : ""); e = wpa_blacklist_get(wpa_s, bss->bssid); if (e && e->count > 1) { wpa_printf(MSG_DEBUG, " skip - blacklisted"); return 0; } if (ssid_len == 0) { wpa_printf(MSG_DEBUG, " skip - SSID not known"); return 0; } 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; } #ifdef CONFIG_WPS if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) { wpa_printf(MSG_DEBUG, " skip - blacklisted (WPS)"); continue; } if (wpa && ssid->ssid_len == 0 && wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss)) check_ssid = 0; 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 && !wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss)) continue; 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 (!wpa && !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 (!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 */ /* Matching configuration found */ return ssid; } /* No matching configuration found */ return 0; }
/* Compare function for sorting scan results. Return >0 if @b is considered * better. */ static int wpa_scan_result_compar(const void *a, const void *b) { #define IS_5GHZ(n) (n > 4000) #define MIN(a,b) a < b ? a : b struct wpa_scan_res **_wa = (void *) a; struct wpa_scan_res **_wb = (void *) b; struct wpa_scan_res *wa = *_wa; struct wpa_scan_res *wb = *_wb; int wpa_a, wpa_b, maxrate_a, maxrate_b; int snr_a, snr_b; /* WPA/WPA2 support preferred */ wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL || wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL; wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL || wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL; if (wpa_b && !wpa_a) return 1; if (!wpa_b && wpa_a) return -1; /* privacy support preferred */ if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 && (wb->caps & IEEE80211_CAP_PRIVACY)) return 1; if ((wa->caps & IEEE80211_CAP_PRIVACY) && (wb->caps & IEEE80211_CAP_PRIVACY) == 0) return -1; if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) && !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) { snr_a = MIN(wa->level - wa->noise, GREAT_SNR); snr_b = MIN(wb->level - wb->noise, GREAT_SNR); } else { /* Not suitable information to calculate SNR, so use level */ snr_a = wa->level; snr_b = wb->level; } /* best/max rate preferred if SNR close enough */ if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) || (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) { maxrate_a = wpa_scan_get_max_rate(wa); maxrate_b = wpa_scan_get_max_rate(wb); if (maxrate_a != maxrate_b) return maxrate_b - maxrate_a; if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq)) return IS_5GHZ(wa->freq) ? -1 : 1; } /* use freq for channel preference */ /* all things being equal, use SNR; if SNRs are * identical, use quality values since some drivers may only report * that value and leave the signal level zero */ if (snr_b == snr_a) return wb->qual - wa->qual; return snr_b - snr_a; #undef MIN #undef IS_5GHZ }
static int wnm_fetch_scan_results(struct wpa_supplicant *wpa_s) { struct wpa_scan_results *scan_res; struct wpa_bss *bss; struct wpa_ssid *ssid = wpa_s->current_ssid; u8 i, found = 0; size_t j; wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Fetch current scan results from the driver for checking transition candidates"); scan_res = wpa_drv_get_scan_results2(wpa_s); if (!scan_res) { wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Failed to get scan results"); return 0; } if (scan_res->fetch_time.sec == 0) os_get_reltime(&scan_res->fetch_time); filter_scan_res(wpa_s, scan_res); for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { struct neighbor_report *nei; nei = &wpa_s->wnm_neighbor_report_elements[i]; if (nei->preference_present && nei->preference == 0) continue; for (j = 0; j < scan_res->num; j++) { struct wpa_scan_res *res; const u8 *ssid_ie; res = scan_res->res[j]; if (os_memcmp(nei->bssid, res->bssid, ETH_ALEN) != 0 || res->age > WNM_SCAN_RESULT_AGE * 1000) continue; bss = wpa_s->current_bss; ssid_ie = wpa_scan_get_ie(res, WLAN_EID_SSID); if (bss && ssid_ie && (bss->ssid_len != ssid_ie[1] || os_memcmp(bss->ssid, ssid_ie + 2, bss->ssid_len) != 0)) continue; /* Potential candidate found */ found = 1; scan_snr(res); scan_est_throughput(wpa_s, res); wpa_bss_update_scan_res(wpa_s, res, &scan_res->fetch_time); } } wpa_scan_results_free(scan_res); if (!found) { wpa_dbg(wpa_s, MSG_DEBUG, "WNM: No transition candidate matches existing scan results"); return 0; } bss = compare_scan_neighbor_results(wpa_s, WNM_SCAN_RESULT_AGE, NULL); if (!bss) { wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Comparison of scan results against transition candidates did not find matches"); return 0; } /* Associate to the network */ wnm_bss_tm_connect(wpa_s, bss, ssid, 0); return 1; }