From d0b9ab69f6b73d61fe7054ea98110015cf8dcf17 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 22 Nov 2014 18:04:21 +0200 Subject: [PATCH] WNM: Move transition candidate list processing to normal scan This makes it easier to optimize transition request processing. Signed-off-by: Jouni Malinen --- wpa_supplicant/events.c | 3 + wpa_supplicant/wnm_sta.c | 135 ++++++++++++++++-------------- wpa_supplicant/wnm_sta.h | 14 ++++ wpa_supplicant/wpa_supplicant_i.h | 1 + 4 files changed, 89 insertions(+), 64 deletions(-) diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index c404dd2b9..ee2801c45 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1314,6 +1314,9 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return 0; } + if (wnm_scan_process(wpa_s) > 0) + goto scan_work_done; + if (sme_proc_obss_scan(wpa_s) > 0) goto scan_work_done; diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 305231408..b64a411f3 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -445,41 +445,32 @@ static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, } -static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *scan_res, - struct neighbor_report *neigh_rep, - u8 num_neigh_rep, u8 *bssid_to_connect) +static struct wpa_bss * +compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) { - u8 i, j; - const u8 *ssid; + u8 i; struct wpa_bss *bss = wpa_s->current_bss; + struct wpa_bss *target; - if (scan_res == NULL || num_neigh_rep == 0 || !bss) + if (!bss) return 0; wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", MAC2STR(wpa_s->bssid), bss->level); - for (i = 0; i < num_neigh_rep; i++) { - struct neighbor_report *nei = &neigh_rep[i]; - struct wpa_scan_res *res = NULL; + 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; } - for (j = 0; j < scan_res->num; j++) { - if (os_memcmp(scan_res->res[j]->bssid, - neigh_rep[i].bssid, ETH_ALEN) == 0) { - res = scan_res->res[j]; - break; - } - } - - if (!res) { + 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), @@ -488,9 +479,8 @@ static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, continue; } - ssid = wpa_scan_get_ie(res, WLAN_EID_SSID); - if (ssid == NULL || bss->ssid_len != ssid[1] || - os_memcmp(bss->ssid, ssid + 2, ssid[1]) != 0) { + 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. @@ -503,25 +493,24 @@ static int compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, continue; } - if (res->level < bss->level && res->level < -80) { + 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, - res->level); + target->level); continue; } wpa_printf(MSG_DEBUG, - "WNM: Found an acceptable prefed transition candidate BSS " + "WNM: Found an acceptable preferred transition candidate BSS " MACSTR " (RSSI %d)", - MAC2STR(nei->bssid), res->level); - os_memcpy(bssid_to_connect, nei->bssid, ETH_ALEN); - return 1; + MAC2STR(nei->bssid), target->level); + return target; } - return 0; + return NULL; } @@ -537,6 +526,11 @@ static void wnm_send_bss_transition_mgmt_resp( wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " "to " MACSTR " dialog_token=%u status=%u delay=%d", MAC2STR(wpa_s->bssid), dialog_token, status, delay); + if (!wpa_s->current_bss) { + wpa_printf(MSG_DEBUG, + "WNM: Current BSS not known - drop response"); + return; + } mgmt = (struct ieee80211_mgmt *) buf; os_memset(&buf, 0, sizeof(buf)); @@ -572,56 +566,69 @@ static void wnm_send_bss_transition_mgmt_resp( } -static void wnm_scan_response(struct wpa_supplicant *wpa_s, - struct wpa_scan_results *scan_res) +int wnm_scan_process(struct wpa_supplicant *wpa_s) { - u8 bssid[ETH_ALEN]; + struct wpa_bss *bss; + struct wpa_ssid *ssid = wpa_s->current_ssid; + enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; - if (scan_res == NULL) { - wpa_printf(MSG_ERROR, "Scan result is NULL"); - goto send_bss_resp_fail; + if (!wpa_s->wnm_neighbor_report_elements) + return 0; + + 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 */ - 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 = compare_scan_neighbor_results(wpa_s); + 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; + } - 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, + /* Associate to the network */ + /* Send the BSS Management Response - Accept */ + if (wpa_s->wnm_reply) { + wpa_s->wnm_reply = 0; + 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; + 0, bss->bssid); } + if (bss == wpa_s->current_bss) { + wpa_printf(MSG_DEBUG, + "WNM: Already associated with the preferred candidate"); + return 1; + } + + wpa_s->reassociate = 1; + wpa_supplicant_connect(wpa_s, bss, ssid); + wnm_deallocate_memory(wpa_s); + return 1; + /* Send reject response for all the failures */ send_bss_resp_fail: - wnm_deallocate_memory(wpa_s); if (wpa_s->wnm_reply) { + wpa_s->wnm_reply = 0; wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, - WNM_BSS_TM_REJECT_UNSPECIFIED, - 0, NULL); + status, 0, NULL); } - return; + wnm_deallocate_memory(wpa_s); + + return 0; } @@ -785,8 +792,8 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, wpa_s->wnm_cand_valid_until.sec += wpa_s->wnm_cand_valid_until.usec / 1000000; wpa_s->wnm_cand_valid_until.usec %= 1000000; + os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); - wpa_s->scan_res_handler = wnm_scan_response; wpa_supplicant_req_scan(wpa_s, 0, 0); } else if (reply) { enum bss_trans_mgmt_status_code status; diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h index a118b016d..a45a6957e 100644 --- a/wpa_supplicant/wnm_sta.h +++ b/wpa_supplicant/wnm_sta.h @@ -58,4 +58,18 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, u8 query_reason); void wnm_deallocate_memory(struct wpa_supplicant *wpa_s); + +#ifdef CONFIG_WNM + +int wnm_scan_process(struct wpa_supplicant *wpa_s); + +#else /* CONFIG_WNM */ + +static inline int wnm_scan_process(struct wpa_supplicant *wpa_s) +{ + return 0; +} + +#endif /* CONFIG_WNM */ + #endif /* WNM_STA_H */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index b0fd84d1a..a9f5d17b7 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -872,6 +872,7 @@ struct wpa_supplicant { u8 wnm_bss_termination_duration[12]; struct neighbor_report *wnm_neighbor_report_elements; struct os_reltime wnm_cand_valid_until; + u8 wnm_cand_from_bss[ETH_ALEN]; #endif /* CONFIG_WNM */ #ifdef CONFIG_TESTING_GET_GTK