aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--wpa_supplicant/events.c3
-rw-r--r--wpa_supplicant/wnm_sta.c133
-rw-r--r--wpa_supplicant/wnm_sta.h14
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h1
4 files changed, 88 insertions, 63 deletions
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index c404dd2..ee2801c 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 3052314..b64a411 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 = 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;
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index a118b01..a45a695 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 b0fd84d..a9f5d17 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