mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2024-12-27 19:22:34 +01:00
station: get neighbor reports early
Waiting to request neighbor reports until we are in need of a roam delays the roam time, and probably isn't as reliable since we are most likely in a low RSSI state. Instead the neighbor report can be requested immediately after connecting, saved, and used if/when a roam is needed. The existing behavior is maintained if the early neighbor report fails where a neighbor report is requested at the time of the roam. The code which parses the reports was factored out and shared between the existing (late) neighbor report callback and the early neighbor report callback.
This commit is contained in:
parent
a6808aa55a
commit
845658bd32
135
src/station.c
135
src/station.c
@ -95,6 +95,9 @@ struct station {
|
||||
|
||||
struct netconfig *netconfig;
|
||||
|
||||
/* Set of frequencies to scan first when attempting a roam */
|
||||
struct scan_freq_set *roam_freqs;
|
||||
|
||||
bool preparing_roam : 1;
|
||||
bool roam_scan_full : 1;
|
||||
bool signal_low : 1;
|
||||
@ -1306,6 +1309,11 @@ static void station_reset_connection_state(struct station *station)
|
||||
station->connected_bss = NULL;
|
||||
station->connected_network = NULL;
|
||||
|
||||
if (station->roam_freqs) {
|
||||
scan_freq_set_free(station->roam_freqs);
|
||||
station->roam_freqs = NULL;
|
||||
}
|
||||
|
||||
l_dbus_property_changed(dbus, netdev_get_path(station->netdev),
|
||||
IWD_STATION_INTERFACE, "ConnectedNetwork");
|
||||
l_dbus_property_changed(dbus, network_get_path(network),
|
||||
@ -1879,40 +1887,16 @@ static uint32_t station_freq_from_neighbor_report(const uint8_t *country,
|
||||
return freq;
|
||||
}
|
||||
|
||||
static void station_neighbor_report_cb(struct netdev *netdev, int err,
|
||||
static void parse_neighbor_report(struct station *station,
|
||||
const uint8_t *reports,
|
||||
size_t reports_len, void *user_data)
|
||||
size_t reports_len,
|
||||
struct scan_freq_set **set)
|
||||
{
|
||||
struct station *station = user_data;
|
||||
struct ie_tlv_iter iter;
|
||||
int count_md = 0, count_no_md = 0;
|
||||
struct scan_freq_set *freq_set_md, *freq_set_no_md;
|
||||
uint32_t current_freq = 0;
|
||||
struct handshake_state *hs = netdev_get_handshake(station->netdev);
|
||||
int r;
|
||||
|
||||
l_debug("ifindex: %u, error: %d(%s)",
|
||||
netdev_get_ifindex(station->netdev),
|
||||
err, err < 0 ? strerror(-err) : "");
|
||||
|
||||
/*
|
||||
* Check if we're still attempting to roam -- if dbus Disconnect
|
||||
* had been called in the meantime we just abort the attempt.
|
||||
*/
|
||||
if (!station->preparing_roam || err == -ENODEV)
|
||||
return;
|
||||
|
||||
if (!reports || err) {
|
||||
r = station_roam_scan_known_freqs(station);
|
||||
|
||||
if (r == -ENODATA)
|
||||
l_debug("no neighbor report results or known freqs");
|
||||
|
||||
if (r < 0)
|
||||
station_roam_failed(station);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
freq_set_md = scan_freq_set_new();
|
||||
freq_set_no_md = scan_freq_set_new();
|
||||
@ -2000,17 +1984,53 @@ static void station_neighbor_report_cb(struct netdev *netdev, int err,
|
||||
*/
|
||||
if (count_md) {
|
||||
scan_freq_set_add(freq_set_md, current_freq);
|
||||
|
||||
r = station_roam_scan(station, freq_set_md);
|
||||
*set = freq_set_md;
|
||||
scan_freq_set_free(freq_set_no_md);
|
||||
} else if (count_no_md) {
|
||||
scan_freq_set_add(freq_set_no_md, current_freq);
|
||||
|
||||
r = station_roam_scan(station, freq_set_no_md);
|
||||
*set = freq_set_no_md;
|
||||
scan_freq_set_free(freq_set_md);
|
||||
} else
|
||||
r = station_roam_scan(station, NULL);
|
||||
*set = NULL;
|
||||
}
|
||||
|
||||
scan_freq_set_free(freq_set_md);
|
||||
scan_freq_set_free(freq_set_no_md);
|
||||
static void station_neighbor_report_cb(struct netdev *netdev, int err,
|
||||
const uint8_t *reports,
|
||||
size_t reports_len, void *user_data)
|
||||
{
|
||||
struct station *station = user_data;
|
||||
struct scan_freq_set *freq_set;
|
||||
int r;
|
||||
|
||||
l_debug("ifindex: %u, error: %d(%s)",
|
||||
netdev_get_ifindex(station->netdev),
|
||||
err, err < 0 ? strerror(-err) : "");
|
||||
|
||||
/*
|
||||
* Check if we're still attempting to roam -- if dbus Disconnect
|
||||
* had been called in the meantime we just abort the attempt.
|
||||
*/
|
||||
if (!station->preparing_roam || err == -ENODEV)
|
||||
return;
|
||||
|
||||
if (!reports || err) {
|
||||
r = station_roam_scan_known_freqs(station);
|
||||
|
||||
if (r == -ENODATA)
|
||||
l_debug("no neighbor report results or known freqs");
|
||||
|
||||
if (r < 0)
|
||||
station_roam_failed(station);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
parse_neighbor_report(station, reports, reports_len, &freq_set);
|
||||
|
||||
r = station_roam_scan(station, freq_set);
|
||||
|
||||
if (freq_set)
|
||||
scan_freq_set_free(freq_set);
|
||||
|
||||
if (r < 0)
|
||||
station_roam_failed(station);
|
||||
@ -2029,18 +2049,27 @@ static void station_roam_trigger_cb(struct l_timeout *timeout, void *user_data)
|
||||
|
||||
/*
|
||||
* If current BSS supports Neighbor Reports, narrow the scan down
|
||||
* to channels occupied by known neighbors in the ESS. This isn't
|
||||
* to channels occupied by known neighbors in the ESS. If no neighbor
|
||||
* report was obtained upon connection, request one now. This isn't
|
||||
* 100% reliable as the neighbor lists are not required to be
|
||||
* complete or current. It is likely still better than doing a
|
||||
* full scan. 10.11.10.1: "A neighbor report may not be exhaustive
|
||||
* either by choice, or due to the fact that there may be neighbor
|
||||
* APs not known to the AP."
|
||||
*/
|
||||
if (station->connected_bss->cap_rm_neighbor_report &&
|
||||
!station->roam_no_orig_ap)
|
||||
if (!netdev_neighbor_report_req(station->netdev,
|
||||
station_neighbor_report_cb))
|
||||
if (station->roam_freqs) {
|
||||
if (station_roam_scan(station, station->roam_freqs) == 0) {
|
||||
l_debug("Using cached neighbor report for roam");
|
||||
return;
|
||||
}
|
||||
} else if (station->connected_bss->cap_rm_neighbor_report &&
|
||||
!station->roam_no_orig_ap) {
|
||||
if (netdev_neighbor_report_req(station->netdev,
|
||||
station_neighbor_report_cb) == 0) {
|
||||
l_debug("Requesting neighbor report for roam");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
r = station_roam_scan_known_freqs(station);
|
||||
if (r == -ENODATA)
|
||||
@ -2317,6 +2346,24 @@ static void station_connect_dbus_reply(struct station *station,
|
||||
dbus_pending_reply(&station->connect_pending, reply);
|
||||
}
|
||||
|
||||
static void station_early_neighbor_report_cb(struct netdev *netdev, int err,
|
||||
const uint8_t *reports,
|
||||
size_t reports_len,
|
||||
void *user_data)
|
||||
{
|
||||
struct station *station = user_data;
|
||||
|
||||
l_debug("ifindex: %u, error: %d(%s)",
|
||||
netdev_get_ifindex(station->netdev),
|
||||
err, err < 0 ? strerror(-err) : "");
|
||||
|
||||
if (!reports || err)
|
||||
return;
|
||||
|
||||
parse_neighbor_report(station, reports, reports_len,
|
||||
&station->roam_freqs);
|
||||
}
|
||||
|
||||
static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
|
||||
void *event_data, void *user_data)
|
||||
{
|
||||
@ -2361,6 +2408,16 @@ static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a neighbor report now so future roams can avoid waiting for
|
||||
* a report at that time
|
||||
*/
|
||||
if (station->connected_bss->cap_rm_neighbor_report) {
|
||||
if (netdev_neighbor_report_req(station->netdev,
|
||||
station_early_neighbor_report_cb) < 0)
|
||||
l_warn("Could not request neighbor report");
|
||||
}
|
||||
|
||||
network_connected(station->connected_network);
|
||||
|
||||
if (station->netconfig)
|
||||
|
Loading…
Reference in New Issue
Block a user