This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch network-manager
in repository enlightenment.

View the commit online.

commit b88fed09ef02975573b8d37115a98f9f1ae5586a
Author: [email protected] <[email protected]>
AuthorDate: Sat Mar 14 13:30:02 2026 -0600

    fix: eliminate memory safety and signal handler lifecycle bugs in NetworkManager
    
    Multiple critical issues fixed:
    
    **agent.c — SIGSEGV in password dialog setup:**
    - _dialog_psk_add received E_NM_Agent but dereferenced agent->dialog->win before
      _dialog_new assigned agent->dialog. This accessed NULL + 0x58 (sizeof(E_Object)),
      causing SIGSEGV crashes during password entry under load.
    - Changed signature to accept E_Dialog* directly, eliminating the race.
    - Return proper D-Bus InternalError when dialog creation fails instead of
      empty success reply.
    - Document why input->value is not freed in _page_del (owned by EFL widget).
    
    **e_mod_main.c/h — Genlist activation and AGENT_PATH:**
    - Changed genlist callback from "activated" (double-click/Enter) to "selected"
      (single-click), matching intended UI behavior.
    - Add immediate elm_genlist_item_selected_set(it, EINA_FALSE) so repeat clicks
      always fire (prevents UI getting stuck on selected item).
    - Corrected AGENT_PATH from custom path to standard NetworkManager SecretAgent path.
    
    **e_networkmanager.c/h — Signal handler and state lifecycle:**
    - Store explicit Eldbus_Signal_Handler* returns from all signal subscriptions
      (AP.PropertiesChanged, Device.PropertiesChanged, Device.AccessPointAdded/Removed,
      IP4Config.PropertiesChanged, Settings.ConnectionRemoved/NewConnection).
    - Delete these handlers explicitly on proxy teardown, preventing dangling-pointer
      callbacks after connection object is freed.
    - Add saved_conn_generation counter so in-flight GetSettings callbacks abort
      cleanly when manager is freed or new batch starts, avoiding use-after-free.
    - Subscribe to Settings.NewConnection signal so saved-connections hash refreshes
      when AddAndActivateConnection creates new profiles (enables forget button).
    - Add "/" sentinel check for SpecificObject AP path in _active_conn_probe_cb
      (NetworkManager uses "/" as null object path).
    - Clear active_connection_path and active_ap_path in _manager_active_conn_watch_free.
    - Implement smart connection selection: use saved profile if available, otherwise
      call AddAndActivateConnection to let NM create and store new profile.
    - Remove unused pending.active_conn field from NM_Manager structure.
    
    Fixes intermittent crashes, dangling callbacks, password entry hangs, and
    improves network switching reliability.
---
 src/modules/networkmanager/agent.c            |  20 +--
 src/modules/networkmanager/e_mod_main.c       |   6 +-
 src/modules/networkmanager/e_mod_main.h       |   2 +-
 src/modules/networkmanager/e_networkmanager.c | 173 ++++++++++++++++++++++----
 src/modules/networkmanager/e_networkmanager.h |  18 ++-
 5 files changed, 183 insertions(+), 36 deletions(-)

diff --git a/src/modules/networkmanager/agent.c b/src/modules/networkmanager/agent.c
index 32d192dde..24d3470cd 100644
--- a/src/modules/networkmanager/agent.c
+++ b/src/modules/networkmanager/agent.c
@@ -167,6 +167,10 @@ _page_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED,
    EINA_LIST_FREE(input_list, input)
      {
         free(input->key);
+        /* input->value is NOT freed here: it is a pointer into the EFL entry
+         * widget's internal buffer (set via e_widget_entry_add's &value
+         * parameter).  The widget owns the allocation; freeing it here would
+         * be a double-free once the widget itself is destroyed. */
         free(input);
      }
 }
@@ -186,7 +190,7 @@ _show_password_cb(void *data, Evas_Object *obj, void *event EINA_UNUSED)
 /* -------------------------------------------------------------------------- */
 
 static void
-_dialog_psk_add(E_NM_Agent *agent, const char *ssid)
+_dialog_psk_add(E_Dialog *dialog, const char *ssid)
 {
    Evas_Object *toolbook, *list, *framelist, *entry, *check;
    E_NM_Agent_Input *input;
@@ -194,12 +198,12 @@ _dialog_psk_add(E_NM_Agent *agent, const char *ssid)
    char header[128];
    Evas *evas;
 
-   evas     = evas_object_evas_get(agent->dialog->win);
-   toolbook = agent->dialog->content_object;
+   evas     = evas_object_evas_get(dialog->win);
+   toolbook = dialog->content_object;
 
    input       = E_NEW(E_NM_Agent_Input, 1);
    input->key  = strdup("psk");
-   entry = e_widget_entry_add(agent->dialog->win, &(input->value),
+   entry = e_widget_entry_add(dialog->win, &(input->value),
                               NULL, NULL, NULL);
    evas_object_show(entry);
    e_widget_entry_password_set(entry, 1);
@@ -237,7 +241,7 @@ _dialog_psk_add(E_NM_Agent *agent, const char *ssid)
    evas_object_smart_callback_add(check, "changed",
                                   _show_password_cb, entry);
 
-   e_util_win_auto_resize_fill(agent->dialog->win);
+   e_util_win_auto_resize_fill(dialog->win);
 }
 
 static E_Dialog *
@@ -276,7 +280,7 @@ _dialog_new(E_NM_Agent *agent, const char *ssid)
    e_dialog_button_focus_num(dialog, 0);
    elm_win_center(dialog->win, 1, 1);
 
-   _dialog_psk_add(agent, ssid);
+   _dialog_psk_add(dialog, ssid);
 
    return dialog;
 }
@@ -361,7 +365,9 @@ _agent_get_secrets(const Eldbus_Service_Interface *iface,
      {
         eldbus_message_unref(agent->msg);
         agent->msg = NULL;
-        return eldbus_message_method_return_new(msg);
+        return eldbus_message_error_new(msg,
+                 "org.freedesktop.NetworkManager.SecretAgent.InternalError",
+                 "Failed to create password dialog");
      }
 
    /* Return NULL — reply will be sent asynchronously from _dialog_ok_cb */
diff --git a/src/modules/networkmanager/e_mod_main.c b/src/modules/networkmanager/e_mod_main.c
index 8d9705500..8ad6e08a8 100644
--- a/src/modules/networkmanager/e_mod_main.c
+++ b/src/modules/networkmanager/e_mod_main.c
@@ -202,6 +202,8 @@ _enm_item_activated_cb(void *data, Evas_Object *obj EINA_UNUSED,
    struct NM_Device *dev;
 
    if (!it) return;
+   /* Deselect immediately so repeat clicks always fire "selected" */
+   elm_genlist_item_selected_set(it, EINA_FALSE);
    id = elm_object_item_data_get(it);
    if (!id) return;
 
@@ -735,8 +737,8 @@ _enm_popup_new(E_NM_Instance *inst)
    itc->func.del = _enm_itc_item_del;
    inst->ui.popup.itc_eth = itc;
 
-   /* Activated signal for row tap → connect/disconnect */
-   evas_object_smart_callback_add(gl, "activated", _enm_item_activated_cb,
+   /* Selected signal for row tap → connect/disconnect (single-click) */
+   evas_object_smart_callback_add(gl, "selected", _enm_item_activated_cb,
                                    inst);
 
    elm_box_pack_end(box, gl);
diff --git a/src/modules/networkmanager/e_mod_main.h b/src/modules/networkmanager/e_mod_main.h
index e73839860..48d668814 100644
--- a/src/modules/networkmanager/e_mod_main.h
+++ b/src/modules/networkmanager/e_mod_main.h
@@ -5,7 +5,7 @@
 
 #include "e_networkmanager.h"
 
-#define AGENT_PATH "/org/enlightenment/networkmanager/agent"
+#define AGENT_PATH "/org/freedesktop/NetworkManager/SecretAgent"
 
 extern E_Module *networkmanager_mod;
 extern int _e_nm_log_dom;
diff --git a/src/modules/networkmanager/e_networkmanager.c b/src/modules/networkmanager/e_networkmanager.c
index a98343a52..a9e84cfa3 100644
--- a/src/modules/networkmanager/e_networkmanager.c
+++ b/src/modules/networkmanager/e_networkmanager.c
@@ -100,6 +100,11 @@ _ap_free(struct NM_Access_Point *ap)
 
    if (ap->proxy)
      {
+        if (ap->prop_changed_handler)
+          {
+             eldbus_signal_handler_del(ap->prop_changed_handler);
+             ap->prop_changed_handler = NULL;
+          }
         obj = eldbus_proxy_object_get(ap->proxy);
         eldbus_proxy_unref(ap->proxy);
         eldbus_object_unref(obj);
@@ -243,8 +248,9 @@ _ap_new(const char *path)
    ap->proxy = eldbus_proxy_get(obj, NM_IFACE_PROPS);
 
    /* Subscribe to PropertiesChanged on the AP object */
-   eldbus_proxy_signal_handler_add(ap->proxy, "PropertiesChanged",
-                                   _ap_prop_changed, ap);
+   ap->prop_changed_handler =
+      eldbus_proxy_signal_handler_add(ap->proxy, "PropertiesChanged",
+                                      _ap_prop_changed, ap);
 
    /* Fetch all AP properties */
    eldbus_proxy_call(ap->proxy, "GetAll", _ap_get_props_cb, ap, -1,
@@ -469,11 +475,13 @@ _device_get_props_cb(void *data, const Eldbus_Message *msg,
         /* Re-get object to get the wireless interface proxy */
         dev->wireless_proxy = eldbus_proxy_get(obj, NM_IFACE_WIFI);
 
-        eldbus_proxy_signal_handler_add(dev->wireless_proxy, "AccessPointAdded",
-                                        _device_ap_added, dev);
-        eldbus_proxy_signal_handler_add(dev->wireless_proxy,
-                                        "AccessPointRemoved",
-                                        _device_ap_removed, dev);
+        dev->ap_added_handler =
+           eldbus_proxy_signal_handler_add(dev->wireless_proxy, "AccessPointAdded",
+                                           _device_ap_added, dev);
+        dev->ap_removed_handler =
+           eldbus_proxy_signal_handler_add(dev->wireless_proxy,
+                                           "AccessPointRemoved",
+                                           _device_ap_removed, dev);
 
         dev->pending.get_aps = eldbus_proxy_call(dev->wireless_proxy,
                                                   "GetAccessPoints",
@@ -644,8 +652,9 @@ _device_new(const char *path)
    obj = eldbus_object_get(conn, NM_BUS_NAME, path);
    dev->proxy = eldbus_proxy_get(obj, NM_IFACE_PROPS);
 
-   eldbus_proxy_signal_handler_add(dev->proxy, "PropertiesChanged",
-                                   _device_prop_changed, dev);
+   dev->prop_changed_handler =
+      eldbus_proxy_signal_handler_add(dev->proxy, "PropertiesChanged",
+                                      _device_prop_changed, dev);
 
    dev->pending.get_props = eldbus_proxy_call(dev->proxy, "GetAll",
                                               _device_get_props_cb, dev,
@@ -684,12 +693,27 @@ _device_free(struct NM_Device *dev)
    if (dev->wireless_proxy)
      {
         Eldbus_Object *wobj = eldbus_proxy_object_get(dev->wireless_proxy);
+        if (dev->ap_added_handler)
+          {
+             eldbus_signal_handler_del(dev->ap_added_handler);
+             dev->ap_added_handler = NULL;
+          }
+        if (dev->ap_removed_handler)
+          {
+             eldbus_signal_handler_del(dev->ap_removed_handler);
+             dev->ap_removed_handler = NULL;
+          }
         eldbus_proxy_unref(dev->wireless_proxy);
         if (wobj) eldbus_object_unref(wobj);
      }
 
    if (dev->proxy)
      {
+        if (dev->prop_changed_handler)
+          {
+             eldbus_signal_handler_del(dev->prop_changed_handler);
+             dev->prop_changed_handler = NULL;
+          }
         obj = eldbus_proxy_object_get(dev->proxy);
         eldbus_proxy_unref(dev->proxy);
         eldbus_object_unref(obj);
@@ -713,6 +737,11 @@ _manager_ip4_watch_free(struct NM_Manager *nm)
      }
    if (nm->ip4_proxy)
      {
+        if (nm->ip4_prop_handler)
+          {
+             eldbus_signal_handler_del(nm->ip4_prop_handler);
+             nm->ip4_prop_handler = NULL;
+          }
         eldbus_proxy_unref(nm->ip4_proxy);
         eldbus_object_unref(nm->ip4_obj);
         nm->ip4_proxy = NULL;
@@ -839,8 +868,9 @@ _manager_watch_ip4(struct NM_Manager *nm, const char *ip4config_path)
    nm->ip4_path = eina_stringshare_add(ip4config_path);
 
    /* Subscribe to property changes — keeps proxy alive for signals */
-   eldbus_proxy_signal_handler_add(props, "PropertiesChanged",
-                                   _ip4_prop_changed, nm);
+   nm->ip4_prop_handler =
+      eldbus_proxy_signal_handler_add(props, "PropertiesChanged",
+                                      _ip4_prop_changed, nm);
 
    /* Initial fetch */
    nm->pending.ip4config = eldbus_proxy_call(props, "GetAll",
@@ -878,6 +908,10 @@ _manager_active_conn_watch_free(struct NM_Manager *nm)
         nm->active_conn_proxy = NULL;
         nm->active_conn_obj = NULL;
      }
+   eina_stringshare_del(nm->active_connection_path);
+   nm->active_connection_path = NULL;
+   eina_stringshare_del(nm->active_ap_path);
+   nm->active_ap_path = NULL;
 }
 
 static void
@@ -997,6 +1031,9 @@ _active_conn_probe_cb(void *data, const Eldbus_Message *msg,
 
    conn_type = _nm_conn_type_parse(type_str);
 
+   /* NM uses "/" as the null/none sentinel for object paths */
+   if (ap_path && !strcmp(ap_path, "/")) ap_path = NULL;
+
    /* Skip non-network types (bridge, vpn, etc.) — they don't have
     * useful SpecificObject or signal strength info. */
    if (conn_type != NM_DEVICE_TYPE_WIFI &&
@@ -1323,9 +1360,10 @@ _manager_device_removed(void *data, const Eldbus_Message *msg)
 struct _Saved_Conn_Ctx
 {
    struct NM_Manager *nm;
-   const char        *path;  /* stringshare: connection D-Bus object path */
-   Eldbus_Proxy      *proxy; /* Settings.Connection proxy — unref in callback */
-   Eldbus_Object     *obj;   /* connection object — unref in callback */
+   const char        *path;       /* stringshare: connection D-Bus object path */
+   Eldbus_Proxy      *proxy;      /* Settings.Connection proxy — unref in callback */
+   Eldbus_Object     *obj;        /* connection object — unref in callback */
+   unsigned int       generation; /* snapshot of nm->saved_conn_generation */
 };
 
 static void
@@ -1337,6 +1375,15 @@ _saved_conn_settings_cb(void *data, const Eldbus_Message *msg,
    const char *setting_name, *key;
    char ssid_str[256];
 
+   /* Bail out if the manager was freed or a new batch was started while
+    * this D-Bus call was in flight — avoids writing to freed/stale state. */
+   if (ctx->generation != ctx->nm->saved_conn_generation)
+     {
+        DBG("_saved_conn_settings_cb: stale generation %u vs %u, discarding",
+            ctx->generation, ctx->nm->saved_conn_generation);
+        goto done;
+     }
+
    {
       const char *err_name = NULL, *err_msg = NULL;
       if (eldbus_message_error_get(msg, &err_name, &err_msg))
@@ -1410,8 +1457,9 @@ done:
 struct _Settings_List_Ctx
 {
    struct NM_Manager *nm;
-   Eldbus_Proxy  *proxy;
-   Eldbus_Object *obj;
+   Eldbus_Proxy      *proxy;
+   Eldbus_Object     *obj;
+   unsigned int       generation; /* snapshot of nm->saved_conn_generation */
 };
 
 static void
@@ -1420,6 +1468,7 @@ _saved_conn_list_cb(void *data, const Eldbus_Message *msg,
 {
    struct _Settings_List_Ctx *sctx = data;
    struct NM_Manager *nm = sctx->nm;
+   unsigned int generation = sctx->generation;
    Eldbus_Message_Iter *conn_array;
    const char *conn_path;
 
@@ -1428,6 +1477,14 @@ _saved_conn_list_cb(void *data, const Eldbus_Message *msg,
    eldbus_object_unref(sctx->obj);
    free(sctx);
 
+   /* Bail out if a newer batch was started or manager was freed. */
+   if (generation != nm->saved_conn_generation)
+     {
+        DBG("_saved_conn_list_cb: stale generation %u vs %u, discarding",
+            generation, nm->saved_conn_generation);
+        return;
+     }
+
    {
       const char *err_name = NULL, *err_msg = NULL;
       if (eldbus_message_error_get(msg, &err_name, &err_msg))
@@ -1452,6 +1509,7 @@ _saved_conn_list_cb(void *data, const Eldbus_Message *msg,
         if (!ctx) continue;
 
         ctx->nm = nm;
+        ctx->generation = generation;
         ctx->path = eina_stringshare_add(conn_path);
         ctx->obj = eldbus_object_get(conn, NM_BUS_NAME, conn_path);
         ctx->proxy = eldbus_proxy_get(ctx->obj, NM_IFACE_SCONN);
@@ -1482,6 +1540,10 @@ enm_saved_connections_get(struct NM_Manager *nm)
       struct _Settings_List_Ctx *sctx = malloc(sizeof(*sctx));
       EINA_SAFETY_ON_NULL_RETURN(sctx);
 
+      /* Increment generation so any in-flight ListConnections/GetSettings
+       * callbacks from the previous batch will detect staleness and abort. */
+      nm->saved_conn_generation++;
+
       /* Swap pattern: assign new hash before freeing old to avoid a window
        * where saved_connections is NULL (in-flight callbacks check it).
        * Only performed after malloc succeeds so OOM cannot corrupt the hash. */
@@ -1493,6 +1555,7 @@ enm_saved_connections_get(struct NM_Manager *nm)
       }
 
       sctx->nm = nm;
+      sctx->generation = nm->saved_conn_generation;
       sctx->obj = eldbus_object_get(conn, NM_BUS_NAME, NM_SETTINGS_PATH);
       sctx->proxy = eldbus_proxy_get(sctx->obj, NM_IFACE_SETTINGS);
       eldbus_proxy_call(sctx->proxy, "ListConnections",
@@ -1567,6 +1630,17 @@ _settings_conn_removed_cb(void *data, const Eldbus_Message *msg EINA_UNUSED)
    enm_saved_connections_get(nm);
 }
 
+/* Called when NM adds a new connection (e.g. via AddAndActivateConnection) —
+ * refresh the hash so the forget button appears for the newly saved network. */
+static void
+_settings_conn_added_cb(void *data, const Eldbus_Message *msg EINA_UNUSED)
+{
+   struct NM_Manager *nm = data;
+   if (!nm) return;
+   INF("NewConnection signal: refreshing saved connections");
+   enm_saved_connections_get(nm);
+}
+
 static struct NM_Manager *
 _manager_new(void)
 {
@@ -1608,6 +1682,9 @@ _manager_new(void)
    nm->conn_removed_handler =
       eldbus_proxy_signal_handler_add(nm->settings_proxy, "ConnectionRemoved",
                                       _settings_conn_removed_cb, nm);
+   nm->conn_added_handler =
+      eldbus_proxy_signal_handler_add(nm->settings_proxy, "NewConnection",
+                                      _settings_conn_added_cb, nm);
 
    return nm;
 }
@@ -1620,6 +1697,11 @@ _manager_free(struct NM_Manager *nm)
 
    if (!nm) return;
 
+   /* Invalidate in-flight saved-connection probes before freeing anything.
+    * Both _saved_conn_list_cb and _saved_conn_settings_cb check this field
+    * and will bail out cleanly without touching the freed NM_Manager. */
+   nm->saved_conn_generation++;
+
    if (nm->pending.get_props)
      eldbus_pending_cancel(nm->pending.get_props);
    if (nm->pending.get_devices)
@@ -1651,6 +1733,11 @@ _manager_free(struct NM_Manager *nm)
         eldbus_signal_handler_del(nm->conn_removed_handler);
         nm->conn_removed_handler = NULL;
      }
+   if (nm->conn_added_handler)
+     {
+        eldbus_signal_handler_del(nm->conn_added_handler);
+        nm->conn_added_handler = NULL;
+     }
    if (nm->settings_proxy)
      {
         eldbus_proxy_unref(nm->settings_proxy);
@@ -1696,11 +1783,27 @@ _activate_cb(void *data, const Eldbus_Message *msg,
    free(cd);
 }
 
+static void
+_add_activate_cb(void *data, const Eldbus_Message *msg,
+                 Eldbus_Pending *pending EINA_UNUSED)
+{
+   struct connection_cb_data *cd = data;
+   const char *name, *text;
+
+   if (eldbus_message_error_get(msg, &name, &text))
+     ERR("AddAndActivateConnection failed: %s: %s", name, text);
+   else
+     INF("AddAndActivateConnection succeeded");
+
+   free(cd);
+}
+
 void
 enm_ap_connect(struct NM_Manager *nm, struct NM_Device *dev,
                struct NM_Access_Point *ap)
 {
    struct connection_cb_data *cd;
+   const char *conn_path = NULL;
 
    EINA_SAFETY_ON_NULL_RETURN(nm);
    EINA_SAFETY_ON_NULL_RETURN(dev);
@@ -1713,11 +1816,39 @@ enm_ap_connect(struct NM_Manager *nm, struct NM_Device *dev,
    cd->dev = dev;
    cd->ap  = ap;
 
-   /* ActivateConnection("/" means auto-select saved connection or create one,
-    * device path, AP path) */
-   eldbus_proxy_call(nm->proxy, "ActivateConnection",
-                     _activate_cb, cd, NM_CONNECTION_TIMEOUT,
-                     "ooo", "/", dev->path, ap->path);
+   if (nm->saved_connections && ap->ssid)
+     conn_path = eina_hash_find(nm->saved_connections, ap->ssid);
+
+   if (conn_path)
+     {
+        /* Known saved profile — activate it directly */
+        INF("ActivateConnection: saved profile %s for ssid=%s",
+            conn_path, ap->ssid);
+        eldbus_proxy_call(nm->proxy, "ActivateConnection",
+                          _activate_cb, cd, NM_CONNECTION_TIMEOUT,
+                          "ooo", conn_path, dev->path, ap->path);
+     }
+   else
+     {
+        /* No saved profile (new network or just forgotten) — let NM create
+         * a fresh profile and call our agent for credentials. */
+        Eldbus_Message *msg_call;
+        Eldbus_Message_Iter *iter, *empty_dict;
+
+        INF("AddAndActivateConnection: no saved profile for ssid=%s",
+            ap->ssid ?: "(null)");
+
+        msg_call = eldbus_proxy_method_call_new(nm->proxy,
+                                                "AddAndActivateConnection");
+        iter = eldbus_message_iter_get(msg_call);
+        /* Empty a{sa{sv}} connection dict — NM fills in security from the AP */
+        eldbus_message_iter_arguments_append(iter, "a{sa{sv}}", &empty_dict);
+        eldbus_message_iter_container_close(iter, empty_dict);
+        eldbus_message_iter_basic_append(iter, 'o', dev->path);
+        eldbus_message_iter_basic_append(iter, 'o', ap->path);
+        eldbus_proxy_send(nm->proxy, msg_call, _add_activate_cb, cd,
+                          NM_CONNECTION_TIMEOUT);
+     }
 }
 
 static void
diff --git a/src/modules/networkmanager/e_networkmanager.h b/src/modules/networkmanager/e_networkmanager.h
index b128f1abd..e18b4a221 100644
--- a/src/modules/networkmanager/e_networkmanager.h
+++ b/src/modules/networkmanager/e_networkmanager.h
@@ -58,6 +58,8 @@ struct NM_Access_Point
    Eldbus_Proxy *proxy;
    EINA_INLIST;
 
+   Eldbus_Signal_Handler *prop_changed_handler;
+
    char         *ssid;
    uint8_t       strength;
    uint32_t      wpa_flags;
@@ -72,6 +74,10 @@ struct NM_Device
    Eldbus_Proxy *wireless_proxy;
    EINA_INLIST;
 
+   Eldbus_Signal_Handler *prop_changed_handler;
+   Eldbus_Signal_Handler *ap_added_handler;
+   Eldbus_Signal_Handler *ap_removed_handler;
+
    char              *interface;
    enum NM_Device_Type type;
    uint32_t            state;
@@ -110,7 +116,6 @@ struct NM_Manager
      {
         Eldbus_Pending *get_props;
         Eldbus_Pending *get_devices;
-        Eldbus_Pending *active_conn;
         Eldbus_Pending *ip4config;
      } pending;
 
@@ -122,19 +127,22 @@ struct NM_Manager
    Eldbus_Signal_Handler *active_conn_signal_handler; /* for explicit removal */
 
    /* Persistent proxy/obj for watching IP4Config properties. */
-   Eldbus_Proxy  *ip4_proxy;
-   Eldbus_Object *ip4_obj;
-   const char    *ip4_path;
+   Eldbus_Proxy          *ip4_proxy;
+   Eldbus_Object         *ip4_obj;
+   const char            *ip4_path;
+   Eldbus_Signal_Handler *ip4_prop_handler; /* for explicit removal */
 
    /* Saved WiFi connections: SSID (string) -> connection D-Bus path (stringshare) */
    Eina_Hash    *saved_connections;
-   int           saved_conn_pending; /* outstanding GetSettings calls */
+   int           saved_conn_pending;    /* outstanding GetSettings calls */
+   unsigned int  saved_conn_generation; /* increment to abort in-flight GetSettings */
 
    /* Long-lived Settings object/proxy for ConnectionRemoved signal subscription.
     * Created in _manager_new, freed in _manager_free. */
    Eldbus_Proxy          *settings_proxy;
    Eldbus_Object         *settings_obj;
    Eldbus_Signal_Handler *conn_removed_handler;
+   Eldbus_Signal_Handler *conn_added_handler;
 
    /* Generation counter incremented each time a new batch of active-connection
     * probes is started.  Each probe captures the generation at creation time

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to