int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) { struct wpa_bss *bss; struct wpa_ssid *ssid = wpa_s->current_ssid; enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; enum mbo_transition_reject_reason reason = MBO_TRANSITION_REJECT_REASON_UNSPECIFIED; if (!wpa_s->wnm_neighbor_report_elements) return 0; wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Process scan results for BSS Transition Management"); if (os_reltime_before(&wpa_s->wnm_cand_valid_until, &wpa_s->scan_trigger_time)) { wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); wnm_deallocate_memory(wpa_s); return 0; } if (!wpa_s->current_bss || os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); return 0; } /* Compare the Neighbor Report and scan results */ bss = compare_scan_neighbor_results(wpa_s, 0, &reason); if (!bss) { wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; goto send_bss_resp_fail; } /* Associate to the network */ wnm_bss_tm_connect(wpa_s, bss, ssid, 1); return 1; send_bss_resp_fail: if (!reply_on_fail) return 0; /* Send reject response for all the failures */ if (wpa_s->wnm_reply) { wpa_s->wnm_reply = 0; wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, status, reason, 0, NULL); } wnm_deallocate_memory(wpa_s); return 0; }
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 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; }