@@ -3162,12 +3162,10 @@ static void station_ap_directed_roam(struct station *station,
uint8_t req_mode;
uint16_t dtimer;
uint8_t valid_interval;
+ bool can_roam = !station_cannot_roam(station);
l_debug("ifindex: %u", netdev_get_ifindex(station->netdev));
- if (station_cannot_roam(station))
- return;
-
if (station->state != STATION_STATE_CONNECTED) {
l_debug("roam: unexpected AP directed roam -- ignore");
return;
@@ -3231,8 +3229,13 @@ static void station_ap_directed_roam(struct station *station,
* disassociating us. If either of these bits are set, set the
* ap_directed_roaming flag. Otherwise still try roaming but don't
* treat it any different than a normal roam.
+ *
+ * The only exception here is if we are in the middle of roaming
+ * (can_roam == false) since we cannot reliably know if the roam scan
+ * included frequencies from potential candidates in this request,
+ * forcing a roam in this case might result in unintended behavior.
*/
- if (req_mode & (WNM_REQUEST_MODE_DISASSOCIATION_IMMINENT |
+ if (can_roam && req_mode & (WNM_REQUEST_MODE_DISASSOCIATION_IMMINENT |
WNM_REQUEST_MODE_TERMINATION_IMMINENT |
WNM_REQUEST_MODE_ESS_DISASSOCIATION_IMMINENT))
station->ap_directed_roaming = true;
@@ -3259,15 +3262,24 @@ static void station_ap_directed_roam(struct station *station,
pos += url_len;
}
+ blacklist_add_bss(station->connected_bss->addr,
+ BLACKLIST_REASON_ROAM_REQUESTED);
+ station_debug_event(station, "ap-roam-blacklist-added");
+
+ /*
+ * Validating the frame and blacklisting should still be done even if
+ * we are mid-roam. Its important to track the BSS requesting the
+ * transition so when the current roam completes IWD will be less likely
+ * to roam back to the current BSS.
+ */
+ if (!can_roam)
+ return;
+
station->preparing_roam = true;
l_timeout_remove(station->roam_trigger_timeout);
station->roam_trigger_timeout = NULL;
- blacklist_add_bss(station->connected_bss->addr,
- BLACKLIST_REASON_ROAM_REQUESTED);
- station_debug_event(station, "ap-roam-blacklist-added");
-
if (req_mode & WNM_REQUEST_MODE_PREFERRED_CANDIDATE_LIST) {
l_debug("roam: AP sent a preferred candidate list");
station_neighbor_report_cb(station->netdev, 0, body + pos,