3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-25 17:59:25 +01:00

station: add ANQP state watch API

This is to allow network to watch for ANQP activity in order to
fix the race condition between scanning finishing and ANQP finishing.
Without this it is possible for a DBus Connect() to come in before
ANQP has completed and causing the network to return NotConfigured,
when its actually in the process of obtaining all the network info.

The watch was made globally in station due to network not having
a station object until each individual network is created. Adding a
watch during network creation would result in many watchers as well
as a lot of removal/addition as networks are found and lost.
This commit is contained in:
James Prestwood 2020-06-12 12:14:11 -07:00 committed by Denis Kenzior
parent ecd39dcf0d
commit 60e2c4647c
2 changed files with 63 additions and 3 deletions

View File

@ -59,6 +59,7 @@ static uint32_t netdev_watch;
static uint32_t mfp_setting;
static bool anqp_disabled;
static bool netconfig_enabled;
static struct watchlist anqp_watches;
struct station {
enum station_state state;
@ -434,6 +435,32 @@ static void network_add_foreach(struct network *network, void *user_data)
station_add_autoconnect_bss(station, network, bss);
}
static bool match_pending(const void *a, const void *b)
{
const struct anqp_entry *entry = a;
return entry->pending != 0;
}
static void remove_anqp(void *data)
{
struct anqp_entry *entry = data;
l_free(entry);
}
static bool anqp_entry_foreach(void *data, void *user_data)
{
struct anqp_entry *e = data;
WATCHLIST_NOTIFY(&anqp_watches, station_anqp_watch_func_t,
STATION_ANQP_FINISHED, e->network);
remove_anqp(e);
return true;
}
static void station_anqp_response_cb(enum anqp_result result,
const void *anqp, size_t anqp_len,
void *user_data)
@ -487,12 +514,15 @@ static void station_anqp_response_cb(enum anqp_result result,
l_strv_free(realms);
request_done:
l_queue_remove(station->anqp_pending, entry);
entry->pending = 0;
/* If no more requests, resume scanning */
if (!l_queue_isempty(station->anqp_pending))
/* Return if there are other pending requests */
if (l_queue_find(station->anqp_pending, match_pending, NULL))
return;
/* Notify all watchers now that every ANQP request has finished */
l_queue_foreach_remove(station->anqp_pending, anqp_entry_foreach, NULL);
l_queue_destroy(station->autoconnect_list, l_free);
station->autoconnect_list = l_queue_new();
@ -564,6 +594,8 @@ static bool station_start_anqp(struct station *station, struct network *network,
l_queue_push_head(station->anqp_pending, entry);
WATCHLIST_NOTIFY(&anqp_watches, station_anqp_watch_func_t,
STATION_ANQP_STARTED, network);
return true;
}
@ -1217,6 +1249,18 @@ bool station_remove_state_watch(struct station *station, uint32_t id)
return watchlist_remove(&station->state_watches, id);
}
uint32_t station_add_anqp_watch(station_anqp_watch_func_t func,
void *user_data,
station_destroy_func_t destroy)
{
return watchlist_add(&anqp_watches, func, user_data, destroy);
}
void station_remove_anqp_watch(uint32_t id)
{
watchlist_remove(&anqp_watches, id);
}
bool station_set_autoconnect(struct station *station, bool autoconnect)
{
if (station->autoconnect == autoconnect)
@ -3270,6 +3314,8 @@ static int station_init(void)
if (!netconfig_enabled)
l_info("station: Network configuration is disabled.");
watchlist_init(&anqp_watches, NULL);
return 0;
}
@ -3279,6 +3325,7 @@ static void station_exit(void)
netdev_watch_remove(netdev_watch);
l_queue_destroy(station_list, NULL);
station_list = NULL;
watchlist_destroy(&anqp_watches);
}
IWD_MODULE(station, station_init, station_exit)

View File

@ -43,8 +43,16 @@ enum station_state {
STATION_STATE_ROAMING
};
enum station_anqp_state {
STATION_ANQP_STARTED,
STATION_ANQP_FINISHED,
};
typedef void (*station_foreach_func_t)(struct station *, void *data);
typedef void (*station_state_watch_func_t)(enum station_state, void *userdata);
typedef void (*station_anqp_watch_func_t)(enum station_anqp_state,
struct network *network,
void *user_data);
typedef void (*station_destroy_func_t)(void *userdata);
typedef void (*station_network_foreach_func_t)(struct network *, void *data);
@ -66,6 +74,11 @@ uint32_t station_add_state_watch(struct station *station,
station_destroy_func_t destroy);
bool station_remove_state_watch(struct station *station, uint32_t id);
uint32_t station_add_anqp_watch(station_anqp_watch_func_t func,
void *user_data,
station_destroy_func_t destroy);
void station_remove_anqp_watch(uint32_t id);
bool station_set_autoconnect(struct station *station, bool autoconnect);
void station_ap_directed_roam(struct station *station,