int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u16 info_ids[], size_t num_ids) { struct wpabuf *buf; int ret = 0; int freq; struct wpa_bss *bss; int res; freq = wpa_s->assoc_freq; bss = wpa_bss_get_bssid(wpa_s, dst); if (bss) freq = bss->freq; if (freq <= 0) return -1; wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)", MAC2STR(dst), (unsigned int) num_ids); buf = anqp_build_req(info_ids, num_ids, NULL); if (buf == NULL) return -1; res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); ret = -1; } else wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " "%u", res); wpabuf_free(buf); return ret; }
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, const u8 *payload, size_t payload_len, int inmem) { struct wpabuf *buf; int ret = 0; int freq; struct wpa_bss *bss; int res; struct icon_entry *icon_entry; bss = wpa_bss_get_bssid(wpa_s, dst); if (!bss) { wpa_printf(MSG_WARNING, "ANQP: Cannot send query to unknown BSS " MACSTR, MAC2STR(dst)); return -1; } wpa_bss_anqp_unshare_alloc(bss); freq = bss->freq; wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for " "subtypes 0x%x", MAC2STR(dst), stypes); buf = hs20_build_anqp_req(stypes, payload, payload_len); if (buf == NULL) return -1; res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); return -1; } else wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " "%u", res); if (inmem) { icon_entry = os_zalloc(sizeof(struct icon_entry)); if (!icon_entry) return -1; os_memcpy(icon_entry->bssid, dst, ETH_ALEN); icon_entry->file_name = os_malloc(payload_len + 1); if (!icon_entry->file_name) { os_free(icon_entry); return -1; } os_memcpy(icon_entry->file_name, payload, payload_len); icon_entry->file_name[payload_len] = '\0'; icon_entry->dialog_token = res; dl_list_add(&wpa_s->icon_head, &icon_entry->list); } return ret; }
static struct wpa_bss * get_first_acceptable(struct wpa_supplicant *wpa_s) { unsigned int i; struct neighbor_report *nei; for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { nei = &wpa_s->wnm_neighbor_report_elements[i]; if (nei->acceptable) return wpa_bss_get_bssid(wpa_s, nei->bssid); } return NULL; }
void wnm_scan_response(struct wpa_supplicant *wpa_s, struct wpa_scan_results *scan_res) { u8 bssid[ETH_ALEN]; if (scan_res == NULL) { wpa_printf(MSG_ERROR, "Scan result is NULL"); goto send_bss_resp_fail; } /* Compare the Neighbor Report and scan results */ if (compare_scan_neighbor_results(wpa_s, scan_res, wpa_s->wnm_neighbor_report_elements, wpa_s->wnm_num_neighbor_report, bssid) == 1) { /* Associate to the network */ struct wpa_bss *bss; struct wpa_ssid *ssid = wpa_s->current_ssid; bss = wpa_bss_get_bssid(wpa_s, bssid); if (!bss) { wpa_printf(MSG_DEBUG, "WNM: Target AP not found from " "BSS table"); goto send_bss_resp_fail; } /* Send the BSS Management Response - Accept */ if (wpa_s->wnm_reply) { wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_ACCEPT, 0, bssid); } wpa_s->reassociate = 1; wpa_supplicant_connect(wpa_s, bss, ssid); wnm_deallocate_memory(wpa_s); return; } /* Send reject response for all the failures */ send_bss_resp_fail: wnm_deallocate_memory(wpa_s); if (wpa_s->wnm_reply) { wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_REJECT_UNSPECIFIED, 0, NULL); } return; }
static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data, size_t len) { const u8 *sta_addr, *target_ap_addr; u16 status; wpa_hexdump(MSG_MSGDUMP, "FT: RX Action", data, len); if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) return; /* only SME case supported for now */ if (len < 1 + 2 * ETH_ALEN + 2) return; if (data[0] != 2) return; /* Only FT Action Response is supported for now */ sta_addr = data + 1; target_ap_addr = data + 1 + ETH_ALEN; status = WPA_GET_LE16(data + 1 + 2 * ETH_ALEN); wpa_printf(MSG_DEBUG, "FT: Received FT Action Response: STA " MACSTR " TargetAP " MACSTR " status %u", MAC2STR(sta_addr), MAC2STR(target_ap_addr), status); if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Foreign STA Address " MACSTR " in FT Action Response", MAC2STR(sta_addr)); return; } if (status) { wpa_printf(MSG_DEBUG, "FT: FT Action Response indicates " "failure (status code %d)", status); /* TODO: report error to FT code(?) */ return; } if (wpa_ft_process_response(wpa_s->wpa, data + 1 + 2 * ETH_ALEN + 2, len - (1 + 2 * ETH_ALEN + 2), 1, target_ap_addr, NULL, 0) < 0) return; #ifdef CONFIG_SME { struct wpa_bss *bss; bss = wpa_bss_get_bssid(wpa_s, target_ap_addr); if (bss) wpa_s->sme.freq = bss->freq; wpa_s->sme.auth_alg = WPA_AUTH_ALG_FT; sme_associate(wpa_s, WPAS_MODE_INFRA, target_ap_addr, WLAN_AUTH_FT); } #endif /* CONFIG_SME */ }
static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s, struct wpa_ssid *selected, const u8 *bssid) { struct wpa_ssid *ssid; struct wpa_bss *bss; wpa_s->known_wps_freq = 0; if (bssid) { bss = wpa_bss_get_bssid(wpa_s, bssid); if (bss && bss->freq > 0) { wpa_s->known_wps_freq = 1; wpa_s->wps_freq = bss->freq; } } if (wpa_s->current_ssid) wpa_supplicant_deauthenticate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); /* Mark all other networks disabled and trigger reassociation */ ssid = wpa_s->conf->ssid; while (ssid) { int was_disabled = ssid->disabled; /* * In case the network object corresponds to a persistent group * then do not send out network disabled signal. In addition, * do not change disabled status of persistent network objects * from 2 to 1 should we connect to another network. */ if (was_disabled != 2) { ssid->disabled = ssid != selected; if (was_disabled != ssid->disabled) wpas_notify_network_enabled_changed(wpa_s, ssid); } ssid = ssid->next; } wpa_s->disconnected = 0; wpa_s->reassociate = 1; wpa_s->scan_runs = 0; wpa_s->normal_scans = 0; wpa_s->wps_success = 0; wpa_s->blacklist_cleared = 0; wpa_supplicant_req_scan(wpa_s, 0, 0); }
static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap) { struct wpa_supplicant *wpa_s = ctx; struct wpa_driver_auth_params params; struct wpa_bss *bss; bss = wpa_bss_get_bssid(wpa_s, target_ap); if (bss == NULL) return -1; os_memset(¶ms, 0, sizeof(params)); params.bssid = target_ap; params.freq = bss->freq; params.ssid = bss->ssid; params.ssid_len = bss->ssid_len; params.auth_alg = WPA_AUTH_ALG_FT; params.local_state_change = 1; return wpa_drv_authenticate(wpa_s, ¶ms); }
/** * wpas_dispatch_bssid_method - dispatch messages for scanned networks * @message: the incoming dbus message * @wpa_s: a network interface's data * @bssid: bssid of the scanned network we're interested in * Returns: a reply dbus message, or a dbus error message * * This function dispatches all incoming dbus messages for scanned networks. */ static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, struct wpa_supplicant *wpa_s, const char *bssid_txt) { u8 bssid[ETH_ALEN]; struct wpa_bss *bss; if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0) return wpas_dbus_new_invalid_bssid_error(message); bss = wpa_bss_get_bssid(wpa_s, bssid); if (bss == NULL) return wpas_dbus_new_invalid_bssid_error(message); /* Dispatch the method call against the scanned bssid */ if (os_strcmp(dbus_message_get_member(message), "properties") == 0) return wpas_dbus_bssid_properties(message, wpa_s, bss); return NULL; }
int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes, const u8 *payload, size_t payload_len) { struct wpabuf *buf; int ret = 0; int freq; struct wpa_bss *bss; int res; freq = wpa_s->assoc_freq; bss = wpa_bss_get_bssid(wpa_s, dst); if (bss) { wpa_bss_anqp_unshare_alloc(bss); freq = bss->freq; } if (freq <= 0) return -1; wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for " "subtypes 0x%x", MAC2STR(dst), stypes); buf = hs20_build_anqp_req(stypes, payload, payload_len); if (buf == NULL) return -1; res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s); if (res < 0) { wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request"); wpabuf_free(buf); ret = -1; } else wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token " "%u", res); return ret; }
static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, union wpa_event_data *data) { u8 bssid[ETH_ALEN]; int ft_completed; int bssid_changed; struct wpa_driver_capa capa; #ifdef CONFIG_AP if (wpa_s->ap_iface) { hostapd_notif_assoc(wpa_s->ap_iface->bss[0], data->assoc_info.addr, data->assoc_info.req_ies, data->assoc_info.req_ies_len); return; } #endif /* CONFIG_AP */ ft_completed = wpa_ft_is_completed(wpa_s->wpa); if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0) return; wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED); if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 && os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) { wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID=" MACSTR, MAC2STR(bssid)); bssid_changed = os_memcmp(wpa_s->bssid, bssid, ETH_ALEN); os_memcpy(wpa_s->bssid, bssid, ETH_ALEN); os_memset(wpa_s->pending_bssid, 0, ETH_ALEN); if (bssid_changed) wpas_notify_bssid_changed(wpa_s); if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) { wpa_clear_keys(wpa_s, bssid); } if (wpa_supplicant_select_config(wpa_s) < 0) { wpa_supplicant_disassociate( wpa_s, WLAN_REASON_DEAUTH_LEAVING); return; } if (wpa_s->current_ssid) { struct wpa_bss *bss = NULL; struct wpa_ssid *ssid = wpa_s->current_ssid; if (ssid->ssid_len > 0) bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len); if (!bss) bss = wpa_bss_get_bssid(wpa_s, bssid); if (bss) wpa_s->current_bss = bss; } } #ifdef CONFIG_SME os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN); wpa_s->sme.prev_bssid_set = 1; #endif /* CONFIG_SME */ wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid)); if (wpa_s->current_ssid) { /* When using scanning (ap_scan=1), SIM PC/SC interface can be * initialized before association, but for other modes, * initialize PC/SC here, if the current configuration needs * smartcard or SIM/USIM. */ wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid); } wpa_sm_notify_assoc(wpa_s->wpa, bssid); 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 * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE * state machine may transit to AUTHENTICATING state based on obsolete * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to * AUTHENTICATED without ever giving chance to EAP state machine to * reset the state. */ if (!ft_completed) { eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); eapol_sm_notify_portValid(wpa_s->eapol, FALSE); } if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed) eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); /* 802.1X::portControl = Auto */ eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE); wpa_s->eapol_received = 0; if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE || (wpa_s->current_ssid && wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) { wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); } else if (!ft_completed) { /* Timeout for receiving the first EAPOL packet */ wpa_supplicant_req_auth_timeout(wpa_s, 10, 0); } wpa_supplicant_cancel_scan(wpa_s); if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) && wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) { /* * We are done; the driver will take care of RSN 4-way * handshake. */ wpa_supplicant_cancel_auth_timeout(wpa_s); wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); eapol_sm_notify_portValid(wpa_s->eapol, TRUE); eapol_sm_notify_eap_success(wpa_s->eapol, TRUE); } if (wpa_s->pending_eapol_rx) { struct os_time now, age; os_get_time(&now); os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age); if (age.sec == 0 && age.usec < 100000 && os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) == 0) { wpa_printf(MSG_DEBUG, "Process pending EAPOL frame " "that was received just before association " "notification"); wpa_supplicant_rx_eapol( wpa_s, wpa_s->pending_eapol_rx_src, wpabuf_head(wpa_s->pending_eapol_rx), wpabuf_len(wpa_s->pending_eapol_rx)); } wpabuf_free(wpa_s->pending_eapol_rx); wpa_s->pending_eapol_rx = NULL; } if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) && wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 && capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE) { /* Set static WEP keys again */ wpa_set_wep_keys(wpa_s, wpa_s->current_ssid); } }
static struct wpa_bss * compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, enum mbo_transition_reject_reason *reason) { u8 i; struct wpa_bss *bss = wpa_s->current_bss; struct wpa_bss *target; if (!bss) return NULL; wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", MAC2STR(wpa_s->bssid), bss->level); wnm_clear_acceptable(wpa_s); 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) { wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, MAC2STR(nei->bssid)); continue; } target = wpa_bss_get_bssid(wpa_s, nei->bssid); if (!target) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) not found in scan results", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1); continue; } if (age_secs) { struct os_reltime now; if (os_get_reltime(&now) == 0 && os_reltime_expired(&now, &target->last_update, age_secs)) { wpa_printf(MSG_DEBUG, "Candidate BSS is more than %ld seconds old", age_secs); continue; } } if (bss->ssid_len != target->ssid_len || os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { /* * TODO: Could consider allowing transition to another * ESS if PMF was enabled for the association. */ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) in different ESS", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1); continue; } if (wpa_s->current_ssid && !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, 1, 0)) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) does not match the current network profile", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1); continue; } if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { wpa_printf(MSG_DEBUG, "MBO: Candidate BSS " MACSTR " retry delay is not over yet", MAC2STR(nei->bssid)); continue; } if (target->level < bss->level && target->level < -80) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) does not have sufficient signal level (%d)", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1, target->level); continue; } nei->acceptable = 1; } #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_trans_reason_present) target = get_mbo_transition_candidate(wpa_s, reason); else target = get_first_acceptable(wpa_s); #else /* CONFIG_MBO */ target = get_first_acceptable(wpa_s); #endif /* CONFIG_MBO */ if (target) { wpa_printf(MSG_DEBUG, "WNM: Found an acceptable preferred transition candidate BSS " MACSTR " (RSSI %d)", MAC2STR(target->bssid), target->level); } return target; }
static struct wpa_bss * get_mbo_transition_candidate(struct wpa_supplicant *wpa_s, enum mbo_transition_reject_reason *reason) { struct wpa_bss *target = NULL; struct wpa_bss_trans_info params; struct wpa_bss_candidate_info *info = NULL; struct neighbor_report *nei = wpa_s->wnm_neighbor_report_elements; u8 *first_candidate_bssid = NULL, *pos; unsigned int i; params.mbo_transition_reason = wpa_s->wnm_mbo_transition_reason; params.n_candidates = 0; params.bssid = os_calloc(wpa_s->wnm_num_neighbor_report, ETH_ALEN); if (!params.bssid) return NULL; pos = params.bssid; for (i = 0; i < wpa_s->wnm_num_neighbor_report; nei++, i++) { if (nei->is_first) first_candidate_bssid = nei->bssid; if (!nei->acceptable) continue; os_memcpy(pos, nei->bssid, ETH_ALEN); pos += ETH_ALEN; params.n_candidates++; } if (!params.n_candidates) goto end; info = wpa_drv_get_bss_trans_status(wpa_s, ¶ms); if (!info) { /* If failed to get candidate BSS transition status from driver, * get the first acceptable candidate from wpa_supplicant. */ target = wpa_bss_get_bssid(wpa_s, params.bssid); goto end; } /* Get the first acceptable candidate from driver */ for (i = 0; i < info->num; i++) { if (info->candidates[i].is_accept) { target = wpa_bss_get_bssid(wpa_s, info->candidates[i].bssid); goto end; } } /* If Disassociation Imminent is set and driver rejects all the * candidate select first acceptable candidate which has * rssi > disassoc_imminent_rssi_threshold */ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { for (i = 0; i < info->num; i++) { target = wpa_bss_get_bssid(wpa_s, info->candidates[i].bssid); if (target->level < wpa_s->conf->disassoc_imminent_rssi_threshold) continue; goto end; } } /* While sending BTM reject use reason code of the first candidate * received in BTM request frame */ if (reason) { for (i = 0; i < info->num; i++) { if (first_candidate_bssid && os_memcmp(first_candidate_bssid, info->candidates[i].bssid, ETH_ALEN) == 0) { *reason = info->candidates[i].reject_reason; break; } } } target = NULL; end: os_free(params.bssid); if (info) { os_free(info->candidates); os_free(info); } return target; }
static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s, const u8 *sa, u16 info_id, const u8 *data, size_t slen) { const u8 *pos = data; struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa); switch (info_id) { case ANQP_CAPABILITY_LIST: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " ANQP Capability list", MAC2STR(sa)); break; case ANQP_VENUE_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Venue Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen); if (bss) { wpabuf_free(bss->anqp_venue_name); bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen); } break; case ANQP_NETWORK_AUTH_TYPE: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Network Authentication Type information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication " "Type", pos, slen); if (bss) { wpabuf_free(bss->anqp_network_auth_type); bss->anqp_network_auth_type = wpabuf_alloc_copy(pos, slen); } break; case ANQP_ROAMING_CONSORTIUM: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Roaming Consortium list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium", pos, slen); if (bss) { wpabuf_free(bss->anqp_roaming_consortium); bss->anqp_roaming_consortium = wpabuf_alloc_copy(pos, slen); } break; case ANQP_IP_ADDR_TYPE_AVAILABILITY: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " IP Address Type Availability information", MAC2STR(sa)); wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability", pos, slen); if (bss) { wpabuf_free(bss->anqp_ip_addr_type_availability); bss->anqp_ip_addr_type_availability = wpabuf_alloc_copy(pos, slen); } break; case ANQP_NAI_REALM: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " NAI Realm list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen); if (bss) { wpabuf_free(bss->anqp_nai_realm); bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen); } break; case ANQP_3GPP_CELLULAR_NETWORK: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " 3GPP Cellular Network information", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network", pos, slen); if (bss) { wpabuf_free(bss->anqp_3gpp); bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen); } break; case ANQP_DOMAIN_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR " Domain Name list", MAC2STR(sa)); wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen); if (bss) { wpabuf_free(bss->anqp_domain_name); bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen); } break; case ANQP_VENDOR_SPECIFIC: if (slen < 3) return; switch (WPA_GET_BE24(pos)) { default: wpa_printf(MSG_DEBUG, "Interworking: Unsupported " "vendor-specific ANQP OUI %06x", WPA_GET_BE24(pos)); return; } break; default: wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID " "%u", info_id); break; } }
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *data, size_t slen) { const u8 *pos = data; u8 subtype; struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa); struct wpa_bss_anqp *anqp = NULL; int ret; if (slen < 2) return; if (bss) anqp = bss->anqp; subtype = *pos++; slen--; pos++; /* Reserved */ slen--; switch (subtype) { case HS20_STYPE_CAPABILITY_LIST: wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " HS Capability List", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen); break; case HS20_STYPE_OPERATOR_FRIENDLY_NAME: wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Operator Friendly Name", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_operator_friendly_name); anqp->hs20_operator_friendly_name = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_WAN_METRICS: wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen); if (slen < 13) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN " "Metrics value from " MACSTR, MAC2STR(sa)); break; } wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa), pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5), pos[9], pos[10], WPA_GET_LE16(pos + 11)); if (anqp) { wpabuf_free(anqp->hs20_wan_metrics); anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_CONNECTION_CAPABILITY: wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Connection Capability", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_connection_capability); anqp->hs20_connection_capability = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_OPERATING_CLASS: wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Operating Class", MAC2STR(sa)); wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen); if (anqp) { wpabuf_free(anqp->hs20_operating_class); anqp->hs20_operating_class = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_OSU_PROVIDERS_LIST: wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " OSU Providers list", MAC2STR(sa)); wpa_s->num_prov_found++; if (anqp) { wpabuf_free(anqp->hs20_osu_providers_list); anqp->hs20_osu_providers_list = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_ICON_BINARY_FILE: ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen); if (wpa_s->fetch_osu_icon_in_progress) { hs20_osu_icon_fetch_result(wpa_s, ret); eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL); eloop_register_timeout(0, 0, hs20_continue_icon_fetch, wpa_s, NULL); } break; default: wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype); break; } }
static struct wpa_bss * compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) { u8 i; struct wpa_bss *bss = wpa_s->current_bss; struct wpa_bss *target; if (!bss) return 0; wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", MAC2STR(wpa_s->bssid), bss->level); 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) { wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, MAC2STR(nei->bssid)); continue; } target = wpa_bss_get_bssid(wpa_s, nei->bssid); if (!target) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) not found in scan results", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1); continue; } if (bss->ssid_len != target->ssid_len || os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { /* * TODO: Could consider allowing transition to another * ESS if PMF was enabled for the association. */ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) in different ESS", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1); continue; } if (target->level < bss->level && target->level < -80) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) does not have sufficient signal level (%d)", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1, target->level); continue; } wpa_printf(MSG_DEBUG, "WNM: Found an acceptable preferred transition candidate BSS " MACSTR " (RSSI %d)", MAC2STR(nei->bssid), target->level); return target; } return NULL; }