+struct auto_connect_cb_data {
+ char *path;
+ bool auto_connect;
+};
+
+static void auto_connect_cb_free(struct auto_connect_cb_data *cbd)
+{
+ g_free(cbd->path);
+ g_free(cbd);
+}
+
+static void auto_connect_cb(const DBusError *error, void *user_data)
+{
+ struct auto_connect_cb_data *cbd = user_data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, cbd->path);
+ if (!iwdkn)
+ goto out;
+
+ if (dbus_error_is_set(error))
+ connman_warn("WiFi known network %s property auto connect %s",
+ cbd->path, error->message);
+
+ /* property is updated via watch known_network_property_change() */
+out:
+ auto_connect_cb_free(cbd);
+}
+
+static int set_auto_connect(struct iwd_known_network *iwdkn, bool auto_connect)
+{
+ dbus_bool_t dbus_auto_connect = auto_connect;
+ struct auto_connect_cb_data *cbd;
+
+ if (proxy_get_bool(iwdkn->proxy, "AutoConnect") == auto_connect)
+ return -EALREADY;
+
+ cbd = g_new(struct auto_connect_cb_data, 1);
+ cbd->path = g_strdup(iwdkn->path);
+ cbd->auto_connect = auto_connect;
+
+ if (!g_dbus_proxy_set_property_basic(iwdkn->proxy, "AutoConnect",
+ DBUS_TYPE_BOOLEAN,
+ &dbus_auto_connect,
+ auto_connect_cb, cbd, NULL)) {
+ auto_connect_cb_free(cbd);
+ return -EIO;
+ }
+
+ return -EINPROGRESS;
+}
+
+static gboolean disable_auto_connect_cb(gpointer data)
+{
+ char *path = data;
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return FALSE;
+
+ if (set_auto_connect(iwdkn, false) != -EINPROGRESS)
+ connman_warn("Failed to disable auto connect");
+
+ iwdkn->auto_connect_id = 0;
+ return FALSE;
+}
+
+static void disable_auto_connect(struct iwd_known_network *iwdkn)
+{
+ if (iwdkn->auto_connect_id)
+ return;
+
+ iwdkn->auto_connect_id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ 0,
+ disable_auto_connect_cb,
+ g_strdup(iwdkn->path),
+ g_free);
+}
+
+static void known_network_property_change(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct iwd_known_network *iwdkn;
+ const char *path;
+
+ path = g_dbus_proxy_get_path(proxy);
+ iwdkn = g_hash_table_lookup(known_networks, path);
+ if (!iwdkn)
+ return;
+
+ if (!strcmp(name, "AutoConnect")) {
+ dbus_bool_t auto_connect;
+
+ dbus_message_iter_get_basic(iter, &auto_connect);
+ iwdkn->auto_connect = auto_connect;
+
+ DBG("%p auto_connect %d", path, iwdkn->auto_connect);
+
+ if (iwdkn->auto_connect)
+ disable_auto_connect(iwdkn);
+ }
+}
+
+static void create_know_network(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_known_network *iwdkn;
+
+ iwdkn = g_try_new0(struct iwd_known_network, 1);
+ if (!iwdkn) {
+ connman_error("Out of memory creating IWD known network");
+ return;
+ }
+
+ iwdkn->path = g_strdup(path);
+ g_hash_table_replace(known_networks, iwdkn->path, iwdkn);
+
+ iwdkn->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwdkn->proxy) {
+ connman_error("Cannot create IWD known network watcher %s", path);
+ g_hash_table_remove(known_networks, path);
+ return;
+ }
+
+ iwdkn->name = g_strdup(proxy_get_string(proxy, "Name"));
+ iwdkn->type = g_strdup(proxy_get_string(proxy, "Type"));
+ iwdkn->hidden = proxy_get_bool(proxy, "Hidden");
+ iwdkn->last_connected_time =
+ g_strdup(proxy_get_string(proxy, "LastConnectedTime"));
+ iwdkn->auto_connect = proxy_get_bool(proxy, "AutoConnect");
+
+ DBG("name '%s' type %s hidden %d, last_connection_time %s auto_connect %d",
+ iwdkn->name, iwdkn->type, iwdkn->hidden,
+ iwdkn->last_connected_time, iwdkn->auto_connect);
+
+ g_dbus_proxy_set_property_watch(iwdkn->proxy,
+ known_network_property_change, NULL);
+
+ if (iwdkn->auto_connect)
+ disable_auto_connect(iwdkn);
+}
+
+static void create_station(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_station *iwds;
+
+ iwds = g_try_new0(struct iwd_station, 1);
+ if (!iwds) {
+ connman_error("Out of memory creating IWD station");
+ return;
+ }
+
+ iwds->path = g_strdup(path);
+ g_hash_table_replace(stations, iwds->path, iwds);
+
+ iwds->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwds->proxy) {
+ connman_error("Cannot create IWD station watcher %s", path);
+ g_hash_table_remove(stations, path);
+ return;
+ }
+
+ iwds->state = g_strdup(proxy_get_string(proxy, "State"));
+ iwds->connected_network = g_strdup(proxy_get_string(proxy, "ConnectedNetwork"));
+ iwds->scanning = proxy_get_bool(proxy, "Scanning");
+
+ DBG("state '%s' connected_network %s scanning %d",
+ iwds->state, iwds->connected_network, iwds->scanning);
+
+ g_dbus_proxy_set_property_watch(iwds->proxy,
+ station_property_change, NULL);
+}
+
+static void create_ap(GDBusProxy *proxy)
+{
+ const char *path = g_dbus_proxy_get_path(proxy);
+ struct iwd_ap *iwdap;
+
+ iwdap = g_try_new0(struct iwd_ap, 1);
+ if (!iwdap) {
+ connman_error("Out of memory creating IWD access point");
+ return;
+ }
+ iwdap->index = -1;
+
+ iwdap->path = g_strdup(path);
+ g_hash_table_replace(access_points, iwdap->path, iwdap);
+
+ iwdap->proxy = g_dbus_proxy_ref(proxy);
+
+ if (!iwdap->proxy) {
+ connman_error("Cannot create IWD access point watcher %s", path);
+ g_hash_table_remove(access_points, path);
+ return;
+ }
+
+ iwdap->started = proxy_get_bool(proxy, "Started");
+
+ DBG("started %d", iwdap->started);
+
+ g_dbus_proxy_set_property_watch(iwdap->proxy,
+ ap_property_change, NULL);
+}
+