netlink: fix IPv6 RA flag retrieval

The RA flags aren't in the link flags, they are in the special
PROTINFO flags that the IPv6 stack sends.  To get these, because
libnl doesn't have native support for them, we get to parse the
netlink messages directly.  Furthermore, the PROTINFO message
isn't sent unless it's explicitly requested with a
RTM_GETLINK/AF_INET6 message, meaning we get to poll for it
periodically.

So switch over to the netlink monitor object (killing a lot of
duplicate code) and start requesting the PROTINFO bits from
netlink.
This commit is contained in:
Dan Williams
2010-04-20 16:46:08 -07:00
parent 9476355be2
commit 5b8b9fc608
6 changed files with 103 additions and 515 deletions

View File

@@ -11,9 +11,7 @@ noinst_LTLIBRARIES = libip6-manager.la
libip6_manager_la_SOURCES = \ libip6_manager_la_SOURCES = \
nm-ip6-manager.c \ nm-ip6-manager.c \
nm-ip6-manager.h \ nm-ip6-manager.h
nm-netlink-listener.c \
nm-netlink-listener.h
libip6_manager_la_CPPFLAGS = \ libip6_manager_la_CPPFLAGS = \
$(DBUS_CFLAGS) \ $(DBUS_CFLAGS) \

View File

@@ -25,7 +25,8 @@
#include <netlink/route/route.h> #include <netlink/route/route.h>
#include "nm-ip6-manager.h" #include "nm-ip6-manager.h"
#include "nm-netlink-listener.h" #include "nm-netlink-monitor.h"
#include "nm-netlink.h"
#include "NetworkManagerUtils.h" #include "NetworkManagerUtils.h"
#include "nm-marshal.h" #include "nm-marshal.h"
#include "nm-logging.h" #include "nm-logging.h"
@@ -40,7 +41,7 @@
#define IF_RS_SENT 0x10 #define IF_RS_SENT 0x10
typedef struct { typedef struct {
NMNetlinkListener *netlink; NMNetlinkMonitor *monitor;
GHashTable *devices_by_iface, *devices_by_index; GHashTable *devices_by_iface, *devices_by_index;
struct nl_handle *nlh; struct nl_handle *nlh;
@@ -82,6 +83,8 @@ typedef struct {
GArray *rdnss_servers; GArray *rdnss_servers;
guint rdnss_timeout_id; guint rdnss_timeout_id;
guint32 ra_flags;
} NMIP6Device; } NMIP6Device;
G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT) G_DEFINE_TYPE (NMIP6Manager, nm_ip6_manager, G_TYPE_OBJECT)
@@ -96,7 +99,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
static NMIP6Manager *nm_ip6_manager_new (void); static NMIP6Manager *nm_ip6_manager_new (void);
static void netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer user_data); static void netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data);
static void nm_ip6_device_destroy (NMIP6Device *device); static void nm_ip6_device_destroy (NMIP6Device *device);
@@ -122,12 +125,14 @@ nm_ip6_manager_init (NMIP6Manager *manager)
(GDestroyNotify) nm_ip6_device_destroy); (GDestroyNotify) nm_ip6_device_destroy);
priv->devices_by_index = g_hash_table_new (NULL, NULL); priv->devices_by_index = g_hash_table_new (NULL, NULL);
priv->netlink = nm_netlink_listener_get (); priv->monitor = nm_netlink_monitor_get ();
g_signal_connect (priv->netlink, "notification", nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_IFADDR, NULL);
G_CALLBACK (netlink_notification), manager); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_IPV6_PREFIX, NULL);
nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_IPV6_IFADDR, NULL); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_ND_USEROPT, NULL);
nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_IPV6_PREFIX, NULL); nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);
nm_netlink_listener_subscribe (priv->netlink, RTNLGRP_ND_USEROPT, NULL);
g_signal_connect (priv->monitor, "notification",
G_CALLBACK (netlink_notification), manager);
priv->nlh = nm_netlink_get_default_handle (); priv->nlh = nm_netlink_get_default_handle ();
priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh); priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh);
@@ -141,7 +146,7 @@ finalize (GObject *object)
g_hash_table_destroy (priv->devices_by_iface); g_hash_table_destroy (priv->devices_by_iface);
g_hash_table_destroy (priv->devices_by_index); g_hash_table_destroy (priv->devices_by_index);
g_object_unref (priv->netlink); g_object_unref (priv->monitor);
nl_cache_free (priv->addr_cache); nl_cache_free (priv->addr_cache);
nl_cache_free (priv->route_cache); nl_cache_free (priv->route_cache);
@@ -348,8 +353,6 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
struct rtnl_addr *rtnladdr; struct rtnl_addr *rtnladdr;
struct nl_addr *nladdr; struct nl_addr *nladdr;
struct in6_addr *addr; struct in6_addr *addr;
struct rtnl_link *link;
guint flags;
CallbackInfo *info; CallbackInfo *info;
guint dhcp_opts = IP6_DHCP_OPT_NONE; guint dhcp_opts = IP6_DHCP_OPT_NONE;
@@ -373,21 +376,16 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
} }
} }
/* Note: we don't want to keep a cache of links, because the if ((device->ra_flags & IF_RA_RCVD) && device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
* kernel doesn't send notifications when the flags change, so the
* cached rtnl_links would have out-of-date flags.
*/
link = nm_netlink_index_to_rtnl_link (device->index);
flags = rtnl_link_get_flags (link);
rtnl_link_put (link);
if ((flags & IF_RA_RCVD) && device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT; device->state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT;
if (flags & IF_RA_MANAGED) if (device->ra_flags & IF_RA_MANAGED) {
dhcp_opts = IP6_DHCP_OPT_MANAGED; dhcp_opts = IP6_DHCP_OPT_MANAGED;
else if (flags & IF_RA_OTHERCONF) nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6");
} else if (device->ra_flags & IF_RA_OTHERCONF) {
dhcp_opts = IP6_DHCP_OPT_OTHERCONF; dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6");
}
if (!device->addrconf_complete) { if (!device->addrconf_complete) {
if (device->state >= device->target_state || if (device->state >= device->target_state ||
@@ -598,8 +596,58 @@ process_nduseropt (NMIP6Manager *manager, struct nl_msg *msg)
return NULL; return NULL;
} }
static struct nla_policy link_policy[IFLA_MAX + 1] = {
[IFLA_PROTINFO] = { .type = NLA_NESTED },
};
static struct nla_policy link_prot_policy[IFLA_INET6_MAX + 1] = {
[IFLA_INET6_FLAGS] = { .type = NLA_U32 },
};
static NMIP6Device *
process_newlink (NMIP6Manager *manager, struct nl_msg *msg)
{
struct nlmsghdr *hdr = nlmsg_hdr (msg);
struct ifinfomsg *ifi;
NMIP6Device *device;
struct nlattr *tb[IFLA_MAX + 1];
struct nlattr *pi[IFLA_INET6_MAX + 1];
int err;
ifi = nlmsg_data (hdr);
if (ifi->ifi_family != AF_INET6)
return NULL;
device = nm_ip6_manager_get_device (manager, ifi->ifi_index);
if (!device || device->addrconf_complete)
return NULL;
/* FIXME: we have to do this manually for now since libnl doesn't yet
* support the IFLA_PROTINFO attribute of NEWLINK messages. When it does,
* we can get rid of this function and just grab IFLA_PROTINFO from
* nm_ip6_device_sync_from_netlink(), then get the IFLA_INET6_FLAGS out of
* the PROTINFO.
*/
err = nlmsg_parse (hdr, sizeof (*ifi), tb, IFLA_MAX, link_policy);
if (err < 0)
return NULL;
if (!tb[IFLA_PROTINFO])
return NULL;
err = nla_parse_nested (pi, IFLA_INET6_MAX, tb[IFLA_PROTINFO], link_prot_policy);
if (err < 0)
return NULL;
if (!pi[IFLA_INET6_FLAGS])
return NULL;
device->ra_flags = nla_get_u32 (pi[IFLA_INET6_FLAGS]);
return device;
}
static void static void
netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer user_data) netlink_notification (NMNetlinkMonitor *monitor, struct nl_msg *msg, gpointer user_data)
{ {
NMIP6Manager *manager = (NMIP6Manager *) user_data; NMIP6Manager *manager = (NMIP6Manager *) user_data;
NMIP6Device *device; NMIP6Device *device;
@@ -613,22 +661,22 @@ netlink_notification (NMNetlinkListener *listener, struct nl_msg *msg, gpointer
device = process_addr (manager, msg); device = process_addr (manager, msg);
config_changed = TRUE; config_changed = TRUE;
break; break;
case RTM_NEWROUTE: case RTM_NEWROUTE:
case RTM_DELROUTE: case RTM_DELROUTE:
device = process_route (manager, msg); device = process_route (manager, msg);
config_changed = TRUE; config_changed = TRUE;
break; break;
case RTM_NEWPREFIX: case RTM_NEWPREFIX:
device = process_prefix (manager, msg); device = process_prefix (manager, msg);
break; break;
case RTM_NEWNDUSEROPT: case RTM_NEWNDUSEROPT:
device = process_nduseropt (manager, msg); device = process_nduseropt (manager, msg);
config_changed = TRUE; config_changed = TRUE;
break; break;
case RTM_NEWLINK:
device = process_newlink (manager, msg);
config_changed = TRUE;
break;
default: default:
return; return;
} }
@@ -758,6 +806,7 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager,
nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", iface); nm_log_info (LOGD_IP6, "Activation (%s) Beginning IP6 addrconf.", iface);
device->addrconf_complete = FALSE; device->addrconf_complete = FALSE;
device->ra_flags = 0;
/* Set up a timeout on the transaction to kill it after the timeout */ /* Set up a timeout on the transaction to kill it after the timeout */
info = callback_info_new (device, 0); info = callback_info_new (device, 0);
@@ -771,6 +820,7 @@ nm_ip6_manager_begin_addrconf (NMIP6Manager *manager,
* device is already fully configured and schedule the * device is already fully configured and schedule the
* ADDRCONF_COMPLETE signal in that case. * ADDRCONF_COMPLETE signal in that case.
*/ */
nm_netlink_monitor_request_ip6_info (priv->monitor, NULL);
nm_ip6_device_sync_from_netlink (device, FALSE); nm_ip6_device_sync_from_netlink (device, FALSE);
} }

View File

@@ -1,406 +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 - 2009 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.
*/
/* FIXME: this should be merged with src/nm-netlink-monitor.c */
#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 <stdio.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "NetworkManager.h"
#include "nm-system.h"
#include "nm-netlink-listener.h"
#include "nm-marshal.h"
#include "nm-netlink.h"
#define NM_NETLINK_LISTENER_EVENT_CONDITIONS \
((GIOCondition) (G_IO_IN | G_IO_PRI))
#define NM_NETLINK_LISTENER_ERROR_CONDITIONS \
((GIOCondition) (G_IO_ERR | G_IO_NVAL))
#define NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS \
((GIOCondition) (G_IO_HUP))
#define NM_NETLINK_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
NM_TYPE_NETLINK_LISTENER, \
NMNetlinkListenerPrivate))
typedef struct {
struct nl_handle *nlh;
struct nl_cb * nlh_cb;
struct nl_cache * nlh_link_cache;
GIOChannel * io_channel;
guint event_id;
guint request_status_id;
} NMNetlinkListenerPrivate;
static gboolean nm_netlink_listener_event_handler (GIOChannel *channel,
GIOCondition io_condition,
gpointer user_data);
static gboolean nm_netlink_listener_error_handler (GIOChannel *channel,
GIOCondition io_condition,
NMNetlinkListener *listener);
static gboolean nm_netlink_listener_disconnect_handler (GIOChannel *channel,
GIOCondition io_condition,
NMNetlinkListener *listener);
static void close_connection (NMNetlinkListener *listener);
enum {
NOTIFICATION = 0,
ERROR,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (NMNetlinkListener, nm_netlink_listener, G_TYPE_OBJECT);
NMNetlinkListener *
nm_netlink_listener_get (void)
{
static NMNetlinkListener *singleton = NULL;
if (!singleton)
singleton = NM_NETLINK_LISTENER (g_object_new (NM_TYPE_NETLINK_LISTENER, NULL));
else
g_object_ref (singleton);
return singleton;
}
static void
nm_netlink_listener_init (NMNetlinkListener *listener)
{
}
static void
finalize (GObject *object)
{
NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (object);
if (priv->request_status_id)
g_source_remove (priv->request_status_id);
if (priv->io_channel)
close_connection (NM_NETLINK_LISTENER (object));
if (priv->nlh) {
nl_handle_destroy (priv->nlh);
priv->nlh = NULL;
}
if (priv->nlh_cb) {
nl_cb_put (priv->nlh_cb);
priv->nlh_cb = NULL;
}
G_OBJECT_CLASS (nm_netlink_listener_parent_class)->finalize (object);
}
static void
nm_netlink_listener_class_init (NMNetlinkListenerClass *listener_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (listener_class);
g_type_class_add_private (listener_class, sizeof (NMNetlinkListenerPrivate));
/* 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 (NMNetlinkListenerClass, notification),
NULL, NULL, g_cclosure_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
signals[ERROR] =
g_signal_new ("error",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NMNetlinkListenerClass, error),
NULL, NULL, _nm_marshal_VOID__POINTER,
G_TYPE_NONE, 1, G_TYPE_POINTER);
}
static int
netlink_event_input (struct nl_msg *msg, void *listener)
{
struct nlmsghdr *hdr = nlmsg_hdr (msg);
if (hdr->nlmsg_pid != 0)
return NL_STOP;
g_signal_emit (listener, signals[NOTIFICATION], 0, msg);
/* Stop processing messages */
return NL_STOP;
}
static gboolean
open_connection (NMNetlinkListener *listener, GError **error)
{
NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
int fd;
GError *channel_error = NULL;
GIOFlags channel_flags;
g_return_val_if_fail (priv->io_channel == NULL, FALSE);
priv->nlh_cb = nl_cb_alloc (NL_CB_DEFAULT);
priv->nlh = nl_handle_alloc_cb (priv->nlh_cb);
if (!priv->nlh) {
g_set_error (error, NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_HANDLE,
_("unable to allocate netlink handle: %s"),
nl_geterror ());
goto error;
}
nl_disable_sequence_check (priv->nlh);
nl_socket_modify_cb (priv->nlh, NL_CB_VALID, NL_CB_CUSTOM, netlink_event_input, listener);
if (nl_connect (priv->nlh, NETLINK_ROUTE) < 0) {
g_set_error (error, NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_NETLINK_CONNECT,
_("unable to connect to netlink: %s"),
nl_geterror ());
goto error;
}
fd = nl_socket_get_fd (priv->nlh);
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;
}
priv->event_id = g_io_add_watch (priv->io_channel,
(NM_NETLINK_LISTENER_EVENT_CONDITIONS |
NM_NETLINK_LISTENER_ERROR_CONDITIONS |
NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS),
nm_netlink_listener_event_handler,
listener);
return TRUE;
error:
if (priv->io_channel)
close_connection (listener);
if (priv->nlh) {
nl_handle_destroy (priv->nlh);
priv->nlh = NULL;
}
if (priv->nlh_cb) {
nl_cb_put (priv->nlh_cb);
priv->nlh_cb = NULL;
}
return FALSE;
}
static void
close_connection (NMNetlinkListener *listener)
{
NMNetlinkListenerPrivate *priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
g_return_if_fail (priv->io_channel != NULL);
if (priv->event_id) {
g_source_remove (priv->event_id);
priv->event_id = 0;
}
g_io_channel_shutdown (priv->io_channel,
TRUE /* flush pending data */,
NULL);
g_io_channel_unref (priv->io_channel);
priv->io_channel = NULL;
}
GQuark
nm_netlink_listener_error_quark (void)
{
static GQuark error_quark = 0;
if (error_quark == 0)
error_quark = g_quark_from_static_string ("nm-netlink-listener-error-quark");
return error_quark;
}
gboolean
nm_netlink_listener_subscribe (NMNetlinkListener *listener,
int group,
GError **error)
{
NMNetlinkListenerPrivate *priv;
g_return_val_if_fail (NM_IS_NETLINK_LISTENER (listener), FALSE);
priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
if (!priv->nlh) {
if (!open_connection (listener, error))
return FALSE;
}
if (nl_socket_add_membership (priv->nlh, group) < 0) {
g_set_error (error, NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_NETLINK_JOIN_GROUP,
_("unable to join netlink group: %s"),
nl_geterror ());
return FALSE;
}
return TRUE;
}
void
nm_netlink_listener_unsubscribe (NMNetlinkListener *listener, int group)
{
NMNetlinkListenerPrivate *priv;
g_return_if_fail (NM_IS_NETLINK_LISTENER (listener));
priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
g_return_if_fail (priv->nlh != NULL);
nl_socket_drop_membership (priv->nlh, group);
}
static gboolean
nm_netlink_listener_event_handler (GIOChannel *channel,
GIOCondition io_condition,
gpointer user_data)
{
NMNetlinkListener *listener = (NMNetlinkListener *) user_data;
NMNetlinkListenerPrivate *priv;
GError *error = NULL;
g_return_val_if_fail (NM_IS_NETLINK_LISTENER (listener), TRUE);
priv = NM_NETLINK_LISTENER_GET_PRIVATE (listener);
g_return_val_if_fail (priv->event_id > 0, TRUE);
if (io_condition & NM_NETLINK_LISTENER_ERROR_CONDITIONS)
return nm_netlink_listener_error_handler (channel, io_condition, listener);
else if (io_condition & NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS)
return nm_netlink_listener_disconnect_handler (channel, io_condition, listener);
g_return_val_if_fail (!(io_condition & ~(NM_NETLINK_LISTENER_EVENT_CONDITIONS)), FALSE);
if (nl_recvmsgs_default (priv->nlh) < 0) {
error = g_error_new (NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_PROCESSING_MESSAGE,
_("error processing netlink message: %s"),
nl_geterror ());
g_signal_emit (G_OBJECT (listener),
signals[ERROR],
0, error);
g_error_free (error);
}
return TRUE;
}
static gboolean
nm_netlink_listener_error_handler (GIOChannel *channel,
GIOCondition io_condition,
NMNetlinkListener *listener)
{
GError *socket_error;
const char *err_msg;
int err_code;
socklen_t err_len;
g_return_val_if_fail (io_condition & NM_NETLINK_LISTENER_ERROR_CONDITIONS, FALSE);
err_code = 0;
err_len = sizeof (err_code);
if (getsockopt (g_io_channel_unix_get_fd (channel),
SOL_SOCKET, SO_ERROR, (void *) &err_code, &err_len))
err_msg = strerror (err_code);
else
err_msg = _("error occurred while waiting for data on socket");
socket_error = g_error_new (NM_NETLINK_LISTENER_ERROR,
NM_NETLINK_LISTENER_ERROR_WAITING_FOR_SOCKET_DATA,
"%s",
err_msg);
g_signal_emit (G_OBJECT (listener),
signals[ERROR],
0, socket_error);
g_error_free (socket_error);
return TRUE;
}
static gboolean
nm_netlink_listener_disconnect_handler (GIOChannel *channel,
GIOCondition io_condition,
NMNetlinkListener *listener)
{
g_return_val_if_fail (!(io_condition & ~(NM_NETLINK_LISTENER_DISCONNECT_CONDITIONS)), FALSE);
return FALSE;
}

View File

@@ -1,78 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Netlink socket listener
*
* 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 - 2009 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
* Copyright (C) 2005 Ray Strode
*/
#ifndef NM_NETLINK_LISTENER_H
#define NM_NETLINK_LISTENER_H
#include <glib.h>
#include <glib-object.h>
#include "nm-netlink.h"
G_BEGIN_DECLS
#define NM_TYPE_NETLINK_LISTENER (nm_netlink_listener_get_type ())
#define NM_NETLINK_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_NETLINK_LISTENER, NMNetlinkListener))
#define NM_NETLINK_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_NETLINK_LISTENER, NMNetlinkListenerClass))
#define NM_IS_NETLINK_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_NETLINK_LISTENER))
#define NM_IS_NETLINK_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_NETLINK_LISTENER))
#define NM_NETLINK_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_NETLINK_LISTENER, NMNetlinkListenerClass))
#define NM_NETLINK_LISTENER_ERROR (nm_netlink_listener_error_quark ())
typedef enum {
NM_NETLINK_LISTENER_ERROR_GENERIC = 0,
NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_HANDLE,
NM_NETLINK_LISTENER_ERROR_NETLINK_CONNECT,
NM_NETLINK_LISTENER_ERROR_NETLINK_JOIN_GROUP,
NM_NETLINK_LISTENER_ERROR_NETLINK_ALLOC_LINK_CACHE,
NM_NETLINK_LISTENER_ERROR_PROCESSING_MESSAGE,
NM_NETLINK_LISTENER_ERROR_BAD_ALLOC,
NM_NETLINK_LISTENER_ERROR_WAITING_FOR_SOCKET_DATA,
NM_NETLINK_LISTENER_ERROR_LINK_CACHE_UPDATE
} NMNetlinkListenerError;
typedef struct {
GObject parent;
} NMNetlinkListener;
typedef struct {
GObjectClass parent_class;
/* Signals */
void (*notification) (NMNetlinkListener *listener, struct nl_msg *msg);
void (*error) (NMNetlinkListener *listener, GError *error);
} NMNetlinkListenerClass;
GType nm_netlink_listener_get_type (void) G_GNUC_CONST;
GQuark nm_netlink_listener_error_quark (void) G_GNUC_CONST;
NMNetlinkListener *nm_netlink_listener_get (void);
gboolean nm_netlink_listener_subscribe (NMNetlinkListener *listener,
int group,
GError **error);
void nm_netlink_listener_unsubscribe (NMNetlinkListener *listener,
int group);
G_END_DECLS
#endif /* NM_NETLINK_LISTENER_H */

View File

@@ -442,6 +442,28 @@ nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *self, int group)
set_subs (self, group, subs); 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, RTM_GETLINK, AF_INET6, NLM_F_DUMP);
return TRUE;
}
static gboolean static gboolean
deferred_emit_carrier_state (gpointer user_data) deferred_emit_carrier_state (gpointer user_data)
{ {

View File

@@ -79,6 +79,8 @@ gboolean nm_netlink_monitor_subscribe (NMNetlinkMonitor *monitor
void nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *monitor, void nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *monitor,
int group); int group);
gboolean nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *monitor,
GError **error);
gboolean nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor, gboolean nm_netlink_monitor_request_status (NMNetlinkMonitor *monitor,
GError **error); GError **error);