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:
parent
2ffe0fb7db
commit
04f4e8e0a3
66
src/device.c
66
src/device.c
@ -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;
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user