diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 4a6818dc1..b807d5c37 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -66,6 +66,8 @@ typedef struct { guint event_id; guint request_status_id; + + GHashTable *subscriptions; } NMNetlinkMonitorPrivate; enum { @@ -263,13 +265,9 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error) goto error; } - if (nl_socket_add_membership (priv->nlh, RTNLGRP_LINK) < 0) { - g_set_error (error, NM_NETLINK_MONITOR_ERROR, - NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP, - _("unable to join netlink group for monitoring link status: %s"), - nl_geterror ()); + /* Subscribe to the LINK group for internal carrier signals */ + if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error)) goto error; - } if ((priv->nlh_link_cache = rtnl_link_alloc_cache (priv->nlh)) == NULL) { g_set_error (error, NM_NETLINK_MONITOR_ERROR, @@ -373,6 +371,77 @@ nm_netlink_monitor_detach (NMNetlinkMonitor *self) priv->event_id = 0; } +static int +get_subs (NMNetlinkMonitor *self, int group) +{ + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + return GPOINTER_TO_INT (g_hash_table_lookup (priv->subscriptions, + GINT_TO_POINTER (group))); +} + +static void +set_subs (NMNetlinkMonitor *self, int group, int new_subs) +{ + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + g_hash_table_insert (priv->subscriptions, + GINT_TO_POINTER (group), + GINT_TO_POINTER (new_subs)); +} + +gboolean +nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error) +{ + NMNetlinkMonitorPrivate *priv; + int subs; + + g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE); + + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + if (!priv->nlh) { + if (!nm_netlink_monitor_open_connection (self, error)) + return FALSE; + } + + subs = get_subs (self, group) + 1; + if (subs == 1) { + if (nl_socket_add_membership (priv->nlh, group) < 0) { + g_set_error (error, NM_NETLINK_MONITOR_ERROR, + NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP, + _("unable to join netlink group: %s"), + nl_geterror ()); + return FALSE; + } + } + + /* Update # of subscriptions for this group */ + set_subs (self, group, subs); + + return TRUE; +} + +void +nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *self, int group) +{ + NMNetlinkMonitorPrivate *priv; + int subs; + + g_return_if_fail (self != NULL); + g_return_if_fail (NM_IS_NETLINK_MONITOR (self)); + + priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + g_return_if_fail (priv->nlh != NULL); + + subs = get_subs (self, group) - 1; + if (subs == 0) + nl_socket_drop_membership (priv->nlh, group); + + /* Update # of subscriptions for this group */ + set_subs (self, group, subs); +} + static gboolean deferred_emit_carrier_state (gpointer user_data) { @@ -515,6 +584,9 @@ nm_netlink_monitor_get (void) static void nm_netlink_monitor_init (NMNetlinkMonitor *self) { + NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self); + + priv->subscriptions = g_hash_table_new (g_int_hash, g_int_equal); } static void @@ -543,6 +615,8 @@ finalize (GObject *object) priv->nlh_cb = NULL; } + g_hash_table_destroy (priv->subscriptions); + G_OBJECT_CLASS (nm_netlink_monitor_parent_class)->finalize (object); } diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h index 06bbe572d..1920704a7 100644 --- a/src/nm-netlink-monitor.h +++ b/src/nm-netlink-monitor.h @@ -67,11 +67,19 @@ GQuark nm_netlink_monitor_error_quark (void) G_GNUC_CONST; NMNetlinkMonitor *nm_netlink_monitor_get (void); -gboolean nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, - GError **error); +gboolean nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor, + GError **error); void nm_netlink_monitor_close_connection (NMNetlinkMonitor *monitor); void nm_netlink_monitor_attach (NMNetlinkMonitor *monitor); void nm_netlink_monitor_detach (NMNetlinkMonitor *monitor); + +gboolean nm_netlink_monitor_subscribe (NMNetlinkMonitor *monitor, + int group, + GError **error); +void nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *monitor, + int group); + + gboolean nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor, GError **error); gboolean nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *monitor,