summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/iwd.c87
1 files changed, 84 insertions, 3 deletions
diff --git a/plugins/iwd.c b/plugins/iwd.c
index 9d437b3d..2fe49a23 100644
--- a/plugins/iwd.c
+++ b/plugins/iwd.c
@@ -41,7 +41,15 @@ static GDBusClient *client;
static GDBusProxy *agent_proxy;
static GHashTable *adapters;
static GHashTable *devices;
+/*
+ * Mapping from dbus path -> struct iwd_network, tracking the set of Network
+ * objects seen by iwd.
+ */
static GHashTable *networks;
+/*
+ * Mapping from dbus path -> struct iwd_network, tracking the set of iwd
+ * KnownNetwork objects.
+ */
static GHashTable *known_networks;
static GHashTable *stations;
static GHashTable *access_points;
@@ -84,6 +92,11 @@ struct iwd_device {
struct connman_device *device;
};
+/*
+ * Structure tracking an net.connman.iwd.Network D-Bus object.
+ *
+ * This is mapped one-to-one to a connman_network object.
+ */
struct iwd_network {
GDBusProxy *proxy;
char *path;
@@ -95,10 +108,17 @@ struct iwd_network {
struct iwd_device *iwdd;
struct connman_network *network;
- /* service's autoconnect */
+ /*
+ * connman_service's autoconnect.
+ *
+ * See Note [Managing autoconnect state] for more details.
+ */
bool cm_autoconnect;
};
+/*
+ * Structure tracking a net.connman.iwd.KnownNetwork D-Bus object.
+ */
struct iwd_known_network {
GDBusProxy *proxy;
char *path;
@@ -109,7 +129,11 @@ struct iwd_known_network {
bool iwd_auto_connect;
int auto_connect_id;
- /* service's autoconnect */
+ /*
+ * connman_service's autoconnect.
+ *
+ * See Note [Managing autoconnect state] for more details.
+ */
bool cm_autoconnect;
};
@@ -1153,11 +1177,58 @@ static void network_property_change(GDBusProxy *proxy, const char *name,
iwdkn = g_hash_table_lookup(known_networks,
iwdn->known_network);
- if (iwdkn)
+ if (iwdkn) {
+ /* See Note [Managing autoconnect state] */
+ iwdkn->cm_autoconnect = iwdn->cm_autoconnect;
update_auto_connect(iwdkn);
+ }
}
}
+/*
+ * Note [Managing autoconnect state]:
+ *
+ * We need to set the iwd_known_network's cm_autoconnect status from the
+ * iwd_network, which has in turn been set to the corresponding
+ * connman_service's state when it first appeared (due to
+ * __connman_service_create_from_network).
+ *
+ * The management of the autoconnect state between ConnMan and its plugins and
+ * iwd is rather subtle and prone to bugs:
+ * - ConnMan itself determines the autoconnect state in struct connman_service,
+ * which we cannot directly see; we only see cm_network_set_autoconnect
+ * callbacks.
+ *
+ * - The iwd plugin maintains an independent state machine tracking iwd's view of
+ * the world, which processes events in a non atomic fashion; for
+ * instance, a iwd.KnownNetwork created event will appear before the
+ * corresponding PropertyChanged setting the KnownNetwork property of the
+ * iwd.Network corresponding to the created iwd.KnownNetwork.
+ *
+ * A typical flow of a network being newly connected to looks like so:
+ * - An iwd.Network appears, and add_network registers a connman_network
+ * structure with ConnMan. ConnMan then in turn creates a service via
+ * __connman_service_create_from_network.
+ *
+ * - The iwd plugin receives a callback from ConnMan to set the autoconnect
+ * state, setting the cm_autoconnect state of the iwd_network. At this point,
+ * there is no iwd_known_network yet.
+ *
+ * - ConnMan receives a Connect() request on the connman.Service, which is
+ * forwarded to the iwd plugin via cm_network_connect. The iwd plugin calls
+ * Connect() on the corresponding iwd.Network (possibly using the iwd
+ * plugin's agent to get credentials if necessary).
+ *
+ * - Around the time that the connection completes, a iwd.KnownNetwork created
+ * event appears, followed by a PropertyChanged event noting the change in
+ * the iwd.Network's KnownNetwork property.
+ *
+ * This is the first time that we can associate the iwd.KnownNetwork with the
+ * corresponding iwd.Network and iwd_network. We have the ConnMan-side
+ * autoconnect status in the iwd_network structure at this point, so we
+ * synchronize the autoconnect state with iwd here.
+ */
+
static unsigned char calculate_strength(int strength)
{
unsigned char res;
@@ -1742,6 +1813,16 @@ static void create_known_network(GDBusProxy *proxy)
iwdkn->name, iwdkn->type, iwdkn->hidden,
iwdkn->last_connected_time, iwdkn->iwd_auto_connect);
+ /*
+ * Although we initialize the autoconnect state of this
+ * iwd_known_network here, it is only initialized in the case of
+ * networks that already existed prior to startup: in the
+ * case of a new iwd.KnownNetwork appearing, we are called before the
+ * iwd_network.known_network field is initialized by a subsequent
+ * PropertyChanged event.
+ *
+ * See Note [Managing autoconnect state].
+ */
init_auto_connect(iwdkn);
g_dbus_proxy_set_property_watch(iwdkn->proxy,