3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-19 02:39:29 +01:00

device: Ratelimit roam attempts and retry periodically

Define minimum delay between roam attempts and add automatic retries.
This handles a few situations:
 * roam attempt failing, then RSSI going above the threshold and below
   again -- in that case we don't want to reattempt too soon, we'll only
   reattempt after 60s.
 * roam attempt failing then RSSI staying low for longer than 60 -- in
   that case we want to reattempt after 60s too.
 * signal being low from the moment we connected -- in that case we also
   want to attempt a roam every some time.
This commit is contained in:
Andrew Zaborowski 2017-02-18 03:30:49 +01:00 committed by Denis Kenzior
parent 2ffe0fb7db
commit 04f4e8e0a3

View File

@ -73,6 +73,7 @@ struct device {
struct l_dbus_message *disconnect_pending;
uint32_t netdev_watch_id;
struct watchlist state_watches;
struct timespec roam_min_time;
struct l_timeout *roam_trigger_timeout;
uint32_t roam_scan_id;
@ -82,11 +83,14 @@ struct device {
bool scanning : 1;
bool autoconnect : 1;
bool preparing_roam : 1;
bool signal_low : 1;
};
static struct watchlist device_watches;
static struct l_queue *device_list;
static void device_roam_timeout_rearm(struct device *device, int seconds);
uint32_t device_watch_add(device_watch_func_t func,
void *userdata, device_destroy_func_t destroy)
{
@ -511,6 +515,8 @@ static void device_reset_connection_state(struct device *device)
l_timeout_remove(device->roam_trigger_timeout);
device->roam_trigger_timeout = NULL;
device->preparing_roam = false;
device->signal_low = false;
device->roam_min_time.tv_sec = 0;
if (device->roam_scan_id)
scan_cancel(device->index, device->roam_scan_id);
@ -566,10 +572,11 @@ static void device_disconnect_by_ap(struct device *device)
static void device_roam_failed(struct device *device)
{
/*
* If we're still connected to the old BSS, only clear preparing_roam,
* otherwise (we'd already started negotiating with the transition
* target, preparing_roam is false, state is roaming) we are now
* disconnected.
* If we're still connected to the old BSS, only clear preparing_roam
* and reattempt in 60 seconds if signal level is still low at that
* time. Otherwise (we'd already started negotiating with the
* transition target, preparing_roam is false, state is roaming) we
* are now disconnected.
*/
l_debug("%d", device->index);
@ -578,6 +585,8 @@ static void device_roam_failed(struct device *device)
if (device->state == DEVICE_STATE_ROAMING)
device_disassociated(device);
else if (device->signal_low)
device_roam_timeout_rearm(device, 60);
}
static void device_fast_transition_cb(struct netdev *netdev,
@ -591,9 +600,16 @@ static void device_fast_transition_cb(struct netdev *netdev,
if (device->state != DEVICE_STATE_ROAMING)
return;
if (result == NETDEV_RESULT_OK)
if (result == NETDEV_RESULT_OK) {
/*
* New signal high/low notification should occur on the next
* beacon from new AP.
*/
device->signal_low = false;
device->roam_min_time.tv_sec = 0;
device_enter_state(device, DEVICE_STATE_CONNECTED);
else
} else
device_roam_failed(device);
}
@ -952,6 +968,27 @@ static void device_roam_trigger_cb(struct l_timeout *timeout, void *user_data)
device_roam_scan(device, NULL);
}
static void device_roam_timeout_rearm(struct device *device, int seconds)
{
struct timespec now, min_timeout;
clock_gettime(CLOCK_MONOTONIC, &now);
min_timeout = now;
min_timeout.tv_sec += seconds;
if (device->roam_min_time.tv_sec < min_timeout.tv_sec ||
(device->roam_min_time.tv_sec == min_timeout.tv_sec &&
device->roam_min_time.tv_nsec < min_timeout.tv_nsec))
device->roam_min_time = min_timeout;
seconds = device->roam_min_time.tv_sec - now.tv_sec +
(device->roam_min_time.tv_nsec > now.tv_nsec ? 1 : 0);
device->roam_trigger_timeout =
l_timeout_create(seconds, device_roam_trigger_cb, device, NULL);
}
static void device_connect_cb(struct netdev *netdev, enum netdev_result result,
void *user_data)
{
@ -1026,20 +1063,25 @@ static void device_netdev_event(struct netdev *netdev, enum netdev_event event,
device_disassociated(device);
break;
case NETDEV_EVENT_RSSI_THRESHOLD_LOW:
if (device->roam_trigger_timeout ||
device->preparing_roam ||
if (device->signal_low)
break;
device->signal_low = true;
if (device->preparing_roam ||
device->state == DEVICE_STATE_ROAMING)
break;
/* Set a 5-second timeout */
device->roam_trigger_timeout =
l_timeout_create(5, device_roam_trigger_cb,
device, NULL);
/* Set a 5-second initial timeout */
device_roam_timeout_rearm(device, 5);
break;
case NETDEV_EVENT_RSSI_THRESHOLD_HIGH:
l_timeout_remove(device->roam_trigger_timeout);
device->roam_trigger_timeout = NULL;
device->signal_low = false;
break;
};
}