]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/wnm_sta.c
WNM: Move transition candidate list processing to normal scan
[thirdparty/hostap.git] / wpa_supplicant / wnm_sta.c
index 305231408c6d4285340490789c87e12a5fb8bcda..b64a411f3bbbd4d2e984fb3ccfd5be5eeeaf1b54 100644 (file)
@@ -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 = 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;
-               }
+       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;
+       }
 
-               /* 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);
-               }
+                                                 0, bss->bssid);
+       }
 
-               wpa_s->reassociate = 1;
-               wpa_supplicant_connect(wpa_s, bss, ssid);
-               wnm_deallocate_memory(wpa_s);
-               return;
+       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;