summaryrefslogtreecommitdiff
path: root/src/nm-netlink-monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-netlink-monitor.c')
-rw-r--r--src/nm-netlink-monitor.c943
1 files changed, 0 insertions, 943 deletions
diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c
deleted file mode 100644
index ba8053e93..000000000
--- a/src/nm-netlink-monitor.c
+++ /dev/null
@@ -1,943 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2005 - 2010 Red Hat, Inc.
- * Copyright (C) 2005 - 2008 Novell, Inc.
- * Copyright (C) 2005 Ray Strode
- *
- * Some code borrowed from HAL:
- *
- * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
- * Copyright (C) 2004 Novell, Inc.
- */
-
-/* for struct ucred and LIBNL_NEEDS_ADDR_CACHING_WORKAROUND */
-#include <config.h>
-
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <linux/types.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/if.h>
-#include <linux/unistd.h>
-#include <unistd.h>
-#include <netlink/netlink.h>
-#include <netlink/object.h>
-#include <netlink/route/addr.h>
-#include <netlink/route/rtnl.h>
-
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#include "nm-netlink-compat.h"
-#include "nm-netlink-monitor.h"
-#include "nm-logging.h"
-
-#define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI))
-#define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL))
-#define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP))
-
-#define NM_NETLINK_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
- NM_TYPE_NETLINK_MONITOR, \
- NMNetlinkMonitorPrivate))
-
-typedef struct {
- /* Async event listener connection */
- struct nl_sock *nlh_event;
- GIOChannel * io_channel;
- guint event_id;
-
- /* Sync/blocking request/response connection */
- struct nl_sock *nlh_sync;
- struct nl_cache * link_cache;
-
- guint request_status_id;
-
- GHashTable *subscriptions;
-} NMNetlinkMonitorPrivate;
-
-enum {
- NOTIFICATION = 0,
- CARRIER_ON,
- CARRIER_OFF,
- LAST_SIGNAL
-};
-static guint signals[LAST_SIGNAL] = { 0 };
-
-
-G_DEFINE_TYPE (NMNetlinkMonitor, nm_netlink_monitor, G_TYPE_OBJECT);
-
-/****************************************************************/
-
-static gboolean
-detach_monitor (gpointer data)
-{
- nm_log_warn (LOGD_HW, "detaching netlink event monitor");
- nm_netlink_monitor_detach (NM_NETLINK_MONITOR (data));
- return FALSE;
-}
-
-static void
-log_error_limited (NMNetlinkMonitor *monitor, guint32 code, const char *fmt, ...)
-{
- static time_t rl_time = 0;
- static guint32 rl_code = 0;
- static guint32 rl_count = 0;
- va_list args;
- char *msg;
- time_t now;
-
- g_return_if_fail (monitor != NULL);
-
- now = time (NULL);
-
- if ((code != rl_code) || (now > rl_time + 10)) {
- va_start (args, fmt);
- msg = g_strdup_vprintf (fmt, args);
- va_end (args);
-
- nm_log_warn (LOGD_HW, "error monitoring device for netlink events: %s\n", msg);
- g_free (msg);
-
- rl_time = now;
- rl_code = code;
- rl_count = 0;
- }
-
- rl_count++;
- if (rl_count > 100) {
- /* Broken drivers will sometimes cause a flood of netlink errors.
- * rh #459205, novell #443429, lp #284507
- */
- nm_log_warn (LOGD_HW, "excessive netlink errors ocurred, disabling netlink monitor.");
- nm_log_warn (LOGD_HW, "link change events will not be processed.");
- g_idle_add_full (G_PRIORITY_HIGH, detach_monitor, monitor, NULL);
- }
-}
-
-/****************************************************************/
-
-static void
-link_msg_handler (struct nl_object *obj, void *arg)
-{
- NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg);
- struct rtnl_link *filter;
- struct rtnl_link *link_obj;
- guint flags;
- guint ifidx;
-
- filter = rtnl_link_alloc ();
- if (!filter) {
- log_error_limited (self, NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
- _("error processing netlink message: %s"),
- nl_geterror (ENOMEM));
- return;
- }
-
- /* Ensure it's a link object */
- if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) {
- rtnl_link_put (filter);
- return;
- }
-
- link_obj = (struct rtnl_link *) obj;
- flags = rtnl_link_get_flags (link_obj);
- ifidx = rtnl_link_get_ifindex (link_obj);
-
- nm_log_dbg (LOGD_HW, "netlink link message: iface idx %d flags 0x%X", ifidx, flags);
-
- /* IFF_LOWER_UP is the indicator of carrier status since kernel commit
- * b00055aacdb172c05067612278ba27265fcd05ce in 2.6.17.
- */
- if (flags & IFF_LOWER_UP)
- g_signal_emit (self, signals[CARRIER_ON], 0, ifidx);
- else
- g_signal_emit (self, signals[CARRIER_OFF], 0, ifidx);
-
- rtnl_link_put (filter);
-}
-
-static int
-event_msg_recv (struct nl_msg *msg, void *arg)
-{
- struct nl_sock *nlh = arg;
- struct nlmsghdr *hdr = nlmsg_hdr (msg);
- struct ucred *creds = nlmsg_get_creds (msg);
- const struct sockaddr_nl *snl;
- guint32 local_port;
- gboolean accept_msg = FALSE;
-
- /* Only messages sent from the kernel */
- if (!creds || creds->uid != 0) {
- nm_log_dbg (LOGD_HW, "ignoring netlink message from UID %d",
- creds ? creds->uid : -1);
- return NL_SKIP;
- }
-
- snl = nlmsg_get_src (msg);
- g_assert (snl);
-
- /* Accept any messages from the kernel */
- if (hdr->nlmsg_pid == 0 || snl->nl_pid == 0)
- accept_msg = TRUE;
-
- /* And any multicast message directed to our netlink PID, since multicast
- * currently requires CAP_ADMIN to use.
- */
- local_port = nl_socket_get_local_port (nlh);
- if ((hdr->nlmsg_pid == local_port) && snl->nl_groups)
- accept_msg = TRUE;
-
- if (accept_msg == FALSE) {
- nm_log_dbg (LOGD_HW, "ignoring netlink message from PID %d (local PID %d, multicast %d)",
- hdr->nlmsg_pid,
- local_port,
- (hdr->nlmsg_flags & NLM_F_MULTI));
- return NL_SKIP;
- }
-
- return NL_OK;
-}
-
-static int
-event_msg_ready (struct nl_msg *msg, void *arg)
-{
- NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg);
-
- /* By the time the message gets here we've already checked the sender
- * and we're sure it's safe to parse this message.
- */
-
- /* Let clients handle generic messages */
- g_signal_emit (self, signals[NOTIFICATION], 0, msg);
-
- /* Parse carrier messages */
- nl_msg_parse (msg, &link_msg_handler, self);
-
- return NL_OK;
-}
-
-static gboolean
-event_handler (GIOChannel *channel,
- GIOCondition io_condition,
- gpointer user_data)
-{
- NMNetlinkMonitor *self = (NMNetlinkMonitor *) user_data;
- NMNetlinkMonitorPrivate *priv;
- int err;
-
- g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), TRUE);
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
- g_return_val_if_fail (priv->event_id > 0, TRUE);
-
- if (io_condition & ERROR_CONDITIONS) {
- const char *err_msg = _("error occurred while waiting for data on socket");
- int err_code = 0;
- socklen_t err_len = sizeof (err_code);
-
- /* Grab error information */
- if (getsockopt (g_io_channel_unix_get_fd (channel),
- SOL_SOCKET, SO_ERROR,
- (void *) &err_code, &err_len) == 0)
- err_msg = strerror (err_code);
-
- log_error_limited (self, NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA, "%s", err_msg);
- return TRUE;
- } else if (io_condition & DISCONNECT_CONDITIONS)
- return FALSE;
-
- g_return_val_if_fail (!(io_condition & ~EVENT_CONDITIONS), FALSE);
-
- /* Process the netlink messages */
- err = nl_recvmsgs_default (priv->nlh_event);
- if (err < 0) {
- log_error_limited (self, NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE,
- _("error processing netlink message: %s"),
- nl_geterror (err));
- }
-
- return TRUE;
-}
-
-static gboolean
-nlh_setup (struct nl_sock *nlh,
- nl_recvmsg_msg_cb_t valid_func,
- gpointer cb_data,
- GError **error)
-{
- int err;
-
- nl_socket_modify_cb (nlh, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, cb_data);
-
- if (valid_func)
- nl_socket_modify_cb (nlh, NL_CB_VALID, NL_CB_CUSTOM, valid_func, cb_data);
-
- err = nl_connect (nlh, NETLINK_ROUTE);
- if (err < 0) {
- g_set_error (error, NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
- _("unable to connect to netlink for monitoring link status: %s"),
- nl_geterror (err));
- return FALSE;
- }
-
- /* Enable unix socket peer credentials which we use for verifying that the
- * sender of the message is actually the kernel.
- */
- if (nl_socket_set_passcred (nlh, 1) < 0) {
- g_set_error (error, NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
- _("unable to enable netlink handle credential passing: %s"),
- nl_geterror (err));
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-event_connection_setup (NMNetlinkMonitor *self, GError **error)
-{
- NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
- GError *channel_error = NULL;
- GIOFlags channel_flags;
- int fd;
-
- g_return_val_if_fail (priv->io_channel == NULL, FALSE);
-
- /* Set up the event listener connection */
- priv->nlh_event = nl_socket_alloc ();
- if (!priv->nlh_event) {
- g_set_error (error, NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
- _("unable to allocate netlink handle for monitoring link status: %s"),
- nl_geterror (ENOMEM));
- goto error;
- }
-
- if (!nlh_setup (priv->nlh_event, event_msg_ready, self, error))
- goto error;
-
- nl_socket_disable_seq_check (priv->nlh_event);
-
- /* Subscribe to the LINK group for internal carrier signals */
- if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error))
- goto error;
-
- fd = nl_socket_get_fd (priv->nlh_event);
- priv->io_channel = g_io_channel_unix_new (fd);
-
- g_io_channel_set_encoding (priv->io_channel, NULL, &channel_error);
- /* Encoding is NULL, so no conversion error can possibly occur */
- g_assert (channel_error == NULL);
-
- g_io_channel_set_close_on_unref (priv->io_channel, TRUE);
- channel_flags = g_io_channel_get_flags (priv->io_channel);
- channel_error = NULL;
- g_io_channel_set_flags (priv->io_channel,
- channel_flags | G_IO_FLAG_NONBLOCK,
- &channel_error);
- if (channel_error != NULL) {
- g_propagate_error (error, channel_error);
- goto error;
- }
-
- return TRUE;
-
-error:
- if (priv->io_channel)
- nm_netlink_monitor_close_connection (self);
-
- if (priv->nlh_event) {
- nl_socket_free (priv->nlh_event);
- priv->nlh_event = NULL;
- }
-
- return FALSE;
-}
-
-static gboolean
-sync_connection_setup (NMNetlinkMonitor *self, GError **error)
-{
- NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
- struct nl_cache *addr_cache;
-#endif
- int err;
-
- /* Set up the event listener connection */
- priv->nlh_sync = nl_socket_alloc ();
- if (!priv->nlh_sync) {
- g_set_error (error, NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
- _("unable to allocate netlink handle for monitoring link status: %s"),
- nl_geterror (ENOMEM));
- goto error;
- }
-
- if (!nlh_setup (priv->nlh_sync, NULL, self, error))
- goto error;
-
-#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
- /* Work around apparent libnl bug; rtnl_addr requires that all
- * addresses have the "peer" attribute set in order to be compared
- * for equality, but this attribute is not normally set. As a
- * result, most addresses will not compare as equal even to
- * themselves, busting caching.
- */
- rtnl_addr_alloc_cache (priv->nlh_sync, &addr_cache);
- g_warn_if_fail (addr_cache != NULL);
- nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80;
- nl_cache_free (addr_cache);
-#endif
-
- err = rtnl_link_alloc_cache (priv->nlh_sync, AF_UNSPEC, &priv->link_cache);
- if (err < 0) {
- g_set_error (error, NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE,
- _("unable to allocate netlink link cache for monitoring link status: %s"),
- nl_geterror (err));
- goto error;
- }
- nl_cache_mngt_provide (priv->link_cache);
-
- return TRUE;
-
-error:
- if (priv->link_cache) {
- nl_cache_free (priv->link_cache);
- priv->link_cache = NULL;
- }
-
- if (priv->nlh_sync) {
- nl_socket_free (priv->nlh_sync);
- priv->nlh_sync = NULL;
- }
-
- return FALSE;
-}
-
-gboolean
-nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error)
-{
- g_return_val_if_fail (self != NULL, FALSE);
- g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
-
- if (!event_connection_setup (self, error))
- return FALSE;
-
- if (!sync_connection_setup (self, error))
- return FALSE;
-
- return TRUE;
-}
-
-void
-nm_netlink_monitor_close_connection (NMNetlinkMonitor *self)
-{
- NMNetlinkMonitorPrivate *priv;
-
- g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
- g_return_if_fail (priv->io_channel != NULL);
-
- if (priv->event_id)
- nm_netlink_monitor_detach (self);
-
- g_io_channel_shutdown (priv->io_channel,
- TRUE /* flush pending data */,
- NULL);
- g_io_channel_unref (priv->io_channel);
- priv->io_channel = NULL;
-}
-
-void
-nm_netlink_monitor_attach (NMNetlinkMonitor *self)
-{
- NMNetlinkMonitorPrivate *priv;
-
- g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
- g_return_if_fail (priv->nlh_event != NULL);
- g_return_if_fail (priv->event_id == 0);
-
- priv->event_id = g_io_add_watch (priv->io_channel,
- (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS),
- event_handler, self);
-}
-
-void
-nm_netlink_monitor_detach (NMNetlinkMonitor *self)
-{
- NMNetlinkMonitorPrivate *priv;
-
- g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
- g_return_if_fail (priv->event_id > 0);
-
- g_source_remove (priv->event_id);
- 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, err;
-
- g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- if (!priv->nlh_event) {
- if (!nm_netlink_monitor_open_connection (self, error))
- return FALSE;
- }
-
- subs = get_subs (self, group) + 1;
- if (subs == 1) {
- err = nl_socket_add_membership (priv->nlh_event, group);
- if (err < 0) {
- g_set_error (error, NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP,
- _("unable to join netlink group: %s"),
- nl_geterror (err));
- 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_event != NULL);
-
- subs = get_subs (self, group) - 1;
- if (subs == 0)
- nl_socket_drop_membership (priv->nlh_event, group);
-
- /* Update # of subscriptions for this group */
- set_subs (self, group, subs);
-}
-
-/***************************************************************/
-
-gboolean
-nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *self, GError **error)
-{
- NMNetlinkMonitorPrivate *priv;
-
- g_return_val_if_fail (self != NULL, FALSE);
- g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- /* FIXME: nl_rtgen_request() gets the return value screwed up with
- * libnl-1.1; revisit this and return a proper error when we port to
- * a later libnl.
- */
- nl_rtgen_request (priv->nlh_event, RTM_GETLINK, AF_INET6, NLM_F_DUMP);
-
- return TRUE;
-}
-
-gboolean
-nm_netlink_monitor_request_bridge_info (NMNetlinkMonitor *self, GError **error)
-{
- NMNetlinkMonitorPrivate *priv;
-
- g_return_val_if_fail (self != NULL, FALSE);
- g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- /* FIXME: nl_rtgen_request() gets the return value screwed up with
- * libnl-1.1; revisit this and return a proper error when we port to
- * a later libnl.
- */
- nl_rtgen_request (priv->nlh_event, RTM_GETLINK, AF_BRIDGE, NLM_F_DUMP);
-
- return TRUE;
-}
-
-static gboolean
-deferred_emit_carrier_state (gpointer user_data)
-{
- NMNetlinkMonitor *self = NM_NETLINK_MONITOR (user_data);
- NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
- int err;
-
- priv->request_status_id = 0;
-
- /* Update the link cache with latest state, and if there are no errors
- * emit the link states for all the interfaces in the cache.
- */
- err = nl_cache_refill (priv->nlh_sync, priv->link_cache);
- if (err < 0)
- nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror (err));
- else
- nl_cache_foreach_filter (priv->link_cache, NULL, link_msg_handler, self);
-
- return FALSE;
-}
-
-void
-nm_netlink_monitor_request_status (NMNetlinkMonitor *self)
-{
- NMNetlinkMonitorPrivate *priv;
-
- g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- /* Schedule the carrier state emission */
- if (!priv->request_status_id)
- priv->request_status_id = g_idle_add (deferred_emit_carrier_state, self);
-}
-
-typedef struct {
- NMNetlinkMonitor *self;
- struct rtnl_link *filter;
- GError *error;
- guint32 flags;
-} GetFlagsInfo;
-
-static void
-get_flags_sync_cb (struct nl_object *obj, void *arg)
-{
- GetFlagsInfo *info = arg;
-
- /* Ensure this cache item matches our filter */
- if (nl_object_match_filter (obj, OBJ_CAST (info->filter)) != 0)
- info->flags = rtnl_link_get_flags ((struct rtnl_link *) obj);
-}
-
-gboolean
-nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
- guint32 ifindex,
- guint32 *ifflags,
- GError **error)
-{
- NMNetlinkMonitorPrivate *priv;
- GetFlagsInfo info;
- struct rtnl_link *filter;
- int err;
-
- g_return_val_if_fail (self != NULL, FALSE);
- g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
- g_return_val_if_fail (ifflags != NULL, FALSE);
-
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- /* Update the link cache with the latest information */
- err = nl_cache_refill (priv->nlh_sync, priv->link_cache);
- if (err < 0) {
- g_set_error (error,
- NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE,
- _("error updating link cache: %s"),
- nl_geterror (err));
- return FALSE;
- }
-
- /* HACK: Apparently to get it working we have to refill the cache twice;
- * otherwise some kernels (or maybe libnl?) only send a few of the
- * interfaces in the refill request.
- */
- if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) {
- g_set_error (error,
- NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE,
- _("error updating link cache: %s"),
- nl_geterror (err));
- return FALSE;
- }
-
- /* Set up the filter */
- filter = rtnl_link_alloc ();
- if (!filter) {
- g_set_error (error,
- NM_NETLINK_MONITOR_ERROR,
- NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
- _("error processing netlink message: %s"),
- nl_geterror (err));
- return FALSE;
- }
- rtnl_link_set_ifindex (filter, ifindex);
-
- memset (&info, 0, sizeof (info));
- info.self = self;
- info.filter = filter;
- info.error = NULL;
- nl_cache_foreach_filter (priv->link_cache, NULL, get_flags_sync_cb, &info);
-
- rtnl_link_put (filter);
-
- if (info.error) {
- if (error)
- *error = info.error;
- else
- g_error_free (info.error);
- return FALSE;
- } else
- *ifflags = info.flags;
-
- return TRUE; /* success */
-}
-
-/***************************************************************/
-
-struct nl_sock *
-nm_netlink_get_default_handle (void)
-{
- NMNetlinkMonitor *self;
- struct nl_sock *nlh;
-
- self = nm_netlink_monitor_get ();
- nlh = NM_NETLINK_MONITOR_GET_PRIVATE (self)->nlh_sync;
- g_object_unref (self);
-
- return nlh;
-}
-
-int
-nm_netlink_iface_to_index (const char *iface)
-{
- NMNetlinkMonitor *self;
- NMNetlinkMonitorPrivate *priv;
- int idx;
-
- g_return_val_if_fail (iface != NULL, -1);
-
- self = nm_netlink_monitor_get ();
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- nl_cache_refill (priv->nlh_sync, priv->link_cache);
- idx = rtnl_link_name2i (priv->link_cache, iface);
- g_object_unref (self);
-
- return idx;
-}
-
-/**
- * nm_netlink_index_to_iface:
- * @idx: kernel interface index
- *
- * Returns: the device name corresponding to the kernel interface index; caller
- * owns returned value and must free it when it is no longer required
- **/
-#define MAX_IFACE_LEN 33
-char *
-nm_netlink_index_to_iface (int idx)
-{
- NMNetlinkMonitor *self;
- NMNetlinkMonitorPrivate *priv;
- char *buf = NULL;
-
- g_return_val_if_fail (idx >= 0, NULL);
-
- self = nm_netlink_monitor_get ();
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- buf = g_malloc0 (MAX_IFACE_LEN);
- g_assert (buf);
-
- nl_cache_refill (priv->nlh_sync, priv->link_cache);
- if (!rtnl_link_i2name (priv->link_cache, idx, buf, MAX_IFACE_LEN - 1)) {
- nm_log_warn (LOGD_HW, "(%d) failed to find interface name for index", idx);
- g_free (buf);
- buf = NULL;
- }
-
- g_object_unref (self);
- return buf;
-}
-
-struct rtnl_link *
-nm_netlink_index_to_rtnl_link (int idx)
-{
- NMNetlinkMonitor *self;
- NMNetlinkMonitorPrivate *priv;
- struct rtnl_link *ret = NULL;
-
- if (idx <= 0)
- return NULL;
-
- self = nm_netlink_monitor_get ();
- priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- nl_cache_refill (priv->nlh_sync, priv->link_cache);
- ret = rtnl_link_get (priv->link_cache, idx);
- g_object_unref (self);
-
- return ret;
-}
-
-/***************************************************************/
-
-NMNetlinkMonitor *
-nm_netlink_monitor_get (void)
-{
- static NMNetlinkMonitor *singleton = NULL;
- GError *error = NULL;
-
- if (!singleton) {
- singleton = (NMNetlinkMonitor *) g_object_new (NM_TYPE_NETLINK_MONITOR, NULL);
- g_return_val_if_fail (singleton != NULL, NULL);
-
- if (nm_netlink_monitor_open_connection (singleton, &error)) {
- nm_netlink_monitor_attach (singleton);
- /* Request initial status of cards */
- nm_netlink_monitor_request_status (singleton);
- } else {
- nm_log_warn (LOGD_HW, "Failed to connect to netlink: (%d) %s",
- error ? error->code : 0,
- (error && error->message) ? error->message : "(unknown)");
- g_clear_error (&error);
-
- g_object_unref (singleton);
- singleton = NULL;
- }
- } else
- g_object_ref (singleton);
-
- return singleton;
-}
-
-static void
-nm_netlink_monitor_init (NMNetlinkMonitor *self)
-{
- NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
-
- priv->subscriptions = g_hash_table_new (g_direct_hash, g_direct_equal);
-}
-
-static void
-finalize (GObject *object)
-{
- NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (object);
-
- if (priv->request_status_id)
- g_source_remove (priv->request_status_id);
-
- if (priv->io_channel)
- nm_netlink_monitor_close_connection (NM_NETLINK_MONITOR (object));
-
- if (priv->link_cache) {
- nl_cache_free (priv->link_cache);
- priv->link_cache = NULL;
- }
-
- if (priv->nlh_event) {
- nl_socket_free (priv->nlh_event);
- priv->nlh_event = NULL;
- }
-
- if (priv->nlh_sync) {
- nl_socket_free (priv->nlh_sync);
- priv->nlh_sync = NULL;
- }
-
- g_hash_table_destroy (priv->subscriptions);
-
- G_OBJECT_CLASS (nm_netlink_monitor_parent_class)->finalize (object);
-}
-
-static void
-nm_netlink_monitor_class_init (NMNetlinkMonitorClass *monitor_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (monitor_class);
-
- g_type_class_add_private (monitor_class, sizeof (NMNetlinkMonitorPrivate));
-
- /* Virtual methods */
- object_class->finalize = finalize;
-
- /* Signals */
- signals[NOTIFICATION] =
- g_signal_new ("notification",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NMNetlinkMonitorClass, notification),
- NULL, NULL, g_cclosure_marshal_VOID__POINTER,
- G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- signals[CARRIER_ON] =
- g_signal_new ("carrier-on",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_on),
- NULL, NULL, g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-
- signals[CARRIER_OFF] =
- g_signal_new ("carrier-off",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_off),
- NULL, NULL, g_cclosure_marshal_VOID__INT,
- G_TYPE_NONE, 1, G_TYPE_INT);
-}
-
-GQuark
-nm_netlink_monitor_error_quark (void)
-{
- static GQuark error_quark = 0;
-
- if (G_UNLIKELY (error_quark == 0))
- error_quark = g_quark_from_static_string ("nm-netlink-monitor-error-quark");
- return error_quark;
-}
-