network: delay connect if ANQP has not completed

Using the new station ANQP watch network can delay the connection
request until after ANQP has finished. Since station may be
autoconnecting we must also add a check in network_autoconnect
which prevents it from autoconnecting if we have a pending Connect
request.
This commit is contained in:
James Prestwood 2020-06-12 12:14:12 -07:00 committed by Denis Kenzior
parent 60e2c4647c
commit 248190b0ed
1 changed files with 58 additions and 0 deletions

View File

@ -52,6 +52,7 @@
#include "src/util.h"
static uint32_t known_networks_watch;
static uint32_t anqp_watch;
struct network {
char ssid[33];
@ -72,7 +73,10 @@ struct network {
bool update_psk:1; /* Whether PSK should be written to storage */
bool ask_passphrase:1; /* Whether we should force-ask agent */
bool is_hs20:1;
bool anqp_pending:1; /* Set if there is a pending ANQP request */
int rank;
/* Holds DBus Connect() message if it comes in before ANQP finishes */
struct l_dbus_message *connect_after_anqp;
};
static bool network_settings_load(struct network *network)
@ -521,6 +525,10 @@ int network_autoconnect(struct network *network, struct scan_bss *bss)
bool is_rsn;
int ret;
/* already waiting for an agent request, connect in progress */
if (network->agent_request)
return -EALREADY;
switch (security) {
case SECURITY_NONE:
is_rsn = false;
@ -1156,6 +1164,22 @@ static struct l_dbus_message *network_connect(struct l_dbus *dbus,
station_connect_network(station, network, bss, message);
return NULL;
case SECURITY_8021X:
if (network->connect_after_anqp)
return dbus_error_busy(message);
/*
* If there is an ongoing ANQP request we must wait for that to
* finish. Save the message and wait for the ANQP watch to
* fire
*/
if (network->anqp_pending) {
network->connect_after_anqp =
l_dbus_message_ref(message);
l_debug("Pending ANQP request, delaying connect to %s",
network->ssid);
return NULL;
}
if (!network_settings_load(network))
return dbus_error_not_configured(message);
@ -1484,6 +1508,35 @@ static void known_networks_changed(enum known_networks_event event,
}
}
static void anqp_watch_changed(enum station_anqp_state state,
struct network *network, void *user_data)
{
network->anqp_pending = state == STATION_ANQP_STARTED;
if (state == STATION_ANQP_FINISHED && network->connect_after_anqp) {
struct l_dbus_message *reply;
l_debug("ANQP complete, resuming connect to %s", network->ssid);
if (!network_settings_load(network)) {
reply = dbus_error_not_configured(
network->connect_after_anqp);
dbus_pending_reply(&network->connect_after_anqp, reply);
return;
}
reply = network_connect_8021x(network,
network_bss_select(network, true),
network->connect_after_anqp);
if (reply)
l_dbus_send(dbus_get_bus(), reply);
l_dbus_message_unref(network->connect_after_anqp);
network->connect_after_anqp = NULL;
}
}
static void setup_network_interface(struct l_dbus_interface *interface)
{
l_dbus_interface_method(interface, "Connect", 0,
@ -1517,6 +1570,8 @@ static int network_init(void)
known_networks_watch =
known_networks_watch_add(known_networks_changed, NULL, NULL);
anqp_watch = station_add_anqp_watch(anqp_watch_changed, NULL, NULL);
return 0;
}
@ -1525,6 +1580,9 @@ static void network_exit(void)
known_networks_watch_remove(known_networks_watch);
known_networks_watch = 0;
station_remove_anqp_watch(anqp_watch);
anqp_watch = 0;
l_dbus_unregister_interface(dbus_get_bus(), IWD_NETWORK_INTERFACE);
}