core: misc style fixes to libnl compat code
[NetworkManager.git] / src / nm-netlink-monitor.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Copyright (C) 2005 - 2010 Red Hat, Inc.
19  * Copyright (C) 2005 - 2008 Novell, Inc.
20  * Copyright (C) 2005 Ray Strode
21  *
22  * Some code borrowed from HAL:  
23  *
24  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
25  * Copyright (C) 2004 Novell, Inc.
26  */
27
28 /* for struct ucred and LIBNL_NEEDS_ADDR_CACHING_WORKAROUND */
29 #include <config.h>
30
31 #include <errno.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <linux/types.h>
36 #include <linux/netlink.h>
37 #include <linux/rtnetlink.h>
38 #include <linux/if.h>
39 #include <linux/unistd.h>
40 #include <unistd.h>
41 #include <netlink/object-api.h>
42 #include <netlink/route/addr.h>
43 #include <netlink/route/rtnl.h>
44
45 #include <glib.h>
46 #include <glib/gi18n.h>
47
48 #include "nm-netlink-compat.h"
49 #include "nm-netlink-monitor.h"
50 #include "nm-logging.h"
51
52 #define EVENT_CONDITIONS      ((GIOCondition) (G_IO_IN | G_IO_PRI))
53 #define ERROR_CONDITIONS      ((GIOCondition) (G_IO_ERR | G_IO_NVAL))
54 #define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP))
55
56 #define NM_NETLINK_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
57                                            NM_TYPE_NETLINK_MONITOR, \
58                                            NMNetlinkMonitorPrivate))
59
60 typedef struct {
61         /* Async event listener connection */
62         struct nl_sock *nlh_event;
63         GIOChannel *      io_channel;
64         guint             event_id;
65
66         /* Sync/blocking request/response connection */
67         struct nl_sock *nlh_sync;
68         struct nl_cache * link_cache;
69
70         guint request_status_id;
71
72         GHashTable *subscriptions;
73 } NMNetlinkMonitorPrivate;
74
75 enum {
76         NOTIFICATION = 0,
77         CARRIER_ON,
78         CARRIER_OFF,
79         ERROR,
80         LAST_SIGNAL
81 };
82 static guint signals[LAST_SIGNAL] = { 0 };
83
84
85 G_DEFINE_TYPE (NMNetlinkMonitor, nm_netlink_monitor, G_TYPE_OBJECT);
86
87 static void
88 link_msg_handler (struct nl_object *obj, void *arg)
89 {
90         NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg);
91         GError *error;
92         struct rtnl_link *filter;
93         struct rtnl_link *link_obj;
94         guint flags;
95         guint ifidx;
96
97         filter = rtnl_link_alloc ();
98         if (!filter) {
99                 error = g_error_new (NM_NETLINK_MONITOR_ERROR,
100                                      NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
101                                      _("error processing netlink message: %s"),
102                                      nl_geterror (ENOMEM));
103                 g_signal_emit (self, signals[ERROR], 0, error);
104                 g_error_free (error);
105                 return;
106         }
107
108         /* Ensure it's a link object */
109         if (nl_object_match_filter (obj, OBJ_CAST (filter)) == 0) {
110                 rtnl_link_put (filter);
111                 return;
112         }
113
114         link_obj = (struct rtnl_link *) obj;
115         flags = rtnl_link_get_flags (link_obj);
116         ifidx = rtnl_link_get_ifindex (link_obj);
117
118         nm_log_dbg (LOGD_HW, "netlink link message: iface idx %d flags 0x%X", ifidx, flags);
119
120         /* IFF_LOWER_UP is the indicator of carrier status since kernel commit
121          * b00055aacdb172c05067612278ba27265fcd05ce in 2.6.17.
122          */
123         if (flags & IFF_LOWER_UP)
124                 g_signal_emit (self, signals[CARRIER_ON], 0, ifidx);
125         else
126                 g_signal_emit (self, signals[CARRIER_OFF], 0, ifidx);
127
128         rtnl_link_put (filter);
129 }
130
131 static int
132 event_msg_recv (struct nl_msg *msg, void *arg)
133 {
134         struct nl_sock *nlh = arg;
135         struct nlmsghdr *hdr = nlmsg_hdr (msg);
136         struct ucred *creds = nlmsg_get_creds (msg);
137         const struct sockaddr_nl *snl;
138         guint32 local_port;
139         gboolean accept_msg = FALSE;
140
141         /* Only messages sent from the kernel */
142         if (!creds || creds->uid != 0) {
143                 nm_log_dbg (LOGD_HW, "ignoring netlink message from UID %d",
144                             creds ? creds->uid : -1);
145                 return NL_SKIP;
146         }
147
148         snl = nlmsg_get_src (msg);
149         g_assert (snl);
150
151         /* Accept any messages from the kernel */
152         if (hdr->nlmsg_pid == 0 || snl->nl_pid == 0)
153                 accept_msg = TRUE;
154
155         /* And any multicast message directed to our netlink PID, since multicast
156          * currently requires CAP_ADMIN to use.
157          */
158         local_port = nl_socket_get_local_port (nlh);
159         if ((hdr->nlmsg_pid == local_port) && snl->nl_groups)
160                 accept_msg = TRUE;
161
162         if (accept_msg == FALSE) {
163                 nm_log_dbg (LOGD_HW, "ignoring netlink message from PID %d (local PID %d, multicast %d)",
164                             hdr->nlmsg_pid,
165                             local_port,
166                             (hdr->nlmsg_flags & NLM_F_MULTI));
167                 return NL_SKIP;
168         }
169
170         return NL_OK;
171 }
172
173 static int
174 event_msg_ready (struct nl_msg *msg, void *arg)
175 {
176         NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg);
177
178         /* By the time the message gets here we've already checked the sender
179          * and we're sure it's safe to parse this message.
180          */
181
182         /* Let clients handle generic messages */
183         g_signal_emit (self, signals[NOTIFICATION], 0, msg);
184
185         /* Parse carrier messages */
186         nl_msg_parse (msg, &link_msg_handler, self);
187
188         return NL_OK;
189 }
190
191 static gboolean
192 event_handler (GIOChannel *channel,
193                GIOCondition io_condition,
194                gpointer user_data)
195 {
196         NMNetlinkMonitor *self = (NMNetlinkMonitor *) user_data;
197         NMNetlinkMonitorPrivate *priv;
198         GError *error = NULL;
199         int err;
200
201         g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), TRUE);
202
203         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
204         g_return_val_if_fail (priv->event_id > 0, TRUE);
205
206         if (io_condition & ERROR_CONDITIONS) {
207                 const char *err_msg;
208                 int err_code = 0;
209                 socklen_t err_len = sizeof (err_code);
210
211                 /* Grab error information */     
212                 if (getsockopt (g_io_channel_unix_get_fd (channel), 
213                                                 SOL_SOCKET, SO_ERROR, (void *) &err_code, &err_len))
214                         err_msg = strerror (err_code);
215                 else
216                         err_msg = _("error occurred while waiting for data on socket");
217
218                 error = g_error_new (NM_NETLINK_MONITOR_ERROR,
219                                      NM_NETLINK_MONITOR_ERROR_WAITING_FOR_SOCKET_DATA,
220                                      "%s", err_msg);
221                 g_signal_emit (self, signals[ERROR], 0, error);
222                 g_error_free (error);
223                 return TRUE;
224         } else if (io_condition & DISCONNECT_CONDITIONS)
225                 return FALSE;
226
227         g_return_val_if_fail (!(io_condition & ~EVENT_CONDITIONS), FALSE);
228
229         /* Process the netlink messages */
230         err = nl_recvmsgs_default (priv->nlh_event);
231         if (err < 0) {
232                 error = g_error_new (NM_NETLINK_MONITOR_ERROR,
233                                      NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE,
234                                      _("error processing netlink message: %s"),
235                                      nl_geterror (err));
236                 g_signal_emit (self, signals[ERROR], 0, error);
237                 g_error_free (error);
238         }
239
240         return TRUE;
241 }
242
243 static gboolean
244 nlh_setup (struct nl_sock *nlh,
245            nl_recvmsg_msg_cb_t valid_func,
246            gpointer cb_data,
247            GError **error)
248 {
249         int err;
250
251         nl_socket_modify_cb (nlh, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, cb_data);
252
253         if (valid_func)
254                 nl_socket_modify_cb (nlh, NL_CB_VALID, NL_CB_CUSTOM, valid_func, cb_data);
255
256         err = nl_connect (nlh, NETLINK_ROUTE);
257         if (err < 0) {
258                 g_set_error (error, NM_NETLINK_MONITOR_ERROR,
259                              NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
260                              _("unable to connect to netlink for monitoring link status: %s"),
261                              nl_geterror (err));
262                 return FALSE;
263         }
264
265         /* Enable unix socket peer credentials which we use for verifying that the
266          * sender of the message is actually the kernel.
267          */
268         if (nl_socket_set_passcred (nlh, 1) < 0) {
269                 g_set_error (error, NM_NETLINK_MONITOR_ERROR,
270                              NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
271                              _("unable to enable netlink handle credential passing: %s"),
272                              nl_geterror (err));
273                 return FALSE;
274         }
275
276         return TRUE;
277 }
278
279 static gboolean
280 event_connection_setup (NMNetlinkMonitor *self, GError **error)
281 {
282         NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
283         GError *channel_error = NULL;
284         GIOFlags channel_flags;
285         struct nl_cb *cb;
286         int fd;
287
288         g_return_val_if_fail (priv->io_channel == NULL, FALSE);
289
290         /* Set up the event listener connection */
291         cb = nl_cb_alloc (NL_CB_DEFAULT);
292         priv->nlh_event = nl_socket_alloc_cb (cb);
293         nl_cb_put (cb);
294         if (!priv->nlh_event) {
295                 g_set_error (error, NM_NETLINK_MONITOR_ERROR,
296                              NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
297                              _("unable to allocate netlink handle for monitoring link status: %s"),
298                              nl_geterror (ENOMEM));
299                 goto error;
300         }
301
302         if (!nlh_setup (priv->nlh_event, event_msg_ready, self, error))
303                 goto error;
304
305         nl_socket_disable_seq_check (priv->nlh_event);
306
307         /* Subscribe to the LINK group for internal carrier signals */
308         if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error))
309                 goto error;
310
311         fd = nl_socket_get_fd (priv->nlh_event);
312         priv->io_channel = g_io_channel_unix_new (fd);
313
314         g_io_channel_set_encoding (priv->io_channel, NULL, &channel_error);
315         /* Encoding is NULL, so no conversion error can possibly occur */
316         g_assert (channel_error == NULL);
317
318         g_io_channel_set_close_on_unref (priv->io_channel, TRUE);
319         channel_flags = g_io_channel_get_flags (priv->io_channel);
320         channel_error = NULL;
321         g_io_channel_set_flags (priv->io_channel,
322                                 channel_flags | G_IO_FLAG_NONBLOCK,
323                                 &channel_error);
324         if (channel_error != NULL) {
325                 g_propagate_error (error, channel_error);
326                 goto error;
327         }
328
329         return TRUE;
330
331 error:
332         if (priv->io_channel)
333                 nm_netlink_monitor_close_connection (self);
334
335         if (priv->nlh_event) {
336                 nl_socket_free (priv->nlh_event);
337                 priv->nlh_event = NULL;
338         }
339
340         return FALSE;
341 }
342
343 static gboolean
344 sync_connection_setup (NMNetlinkMonitor *self, GError **error)
345 {
346         NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
347         struct nl_cb *cb;
348 #ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
349         struct nl_cache *addr_cache;
350 #endif
351         int err;
352
353         /* Set up the event listener connection */
354         cb = nl_cb_alloc (NL_CB_DEFAULT);
355         priv->nlh_sync = nl_socket_alloc_cb (cb);
356         nl_cb_put (cb);
357         if (!priv->nlh_sync) {
358                 g_set_error (error, NM_NETLINK_MONITOR_ERROR,
359                              NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
360                              _("unable to allocate netlink handle for monitoring link status: %s"),
361                              nl_geterror (ENOMEM));
362                 goto error;
363         }
364
365         if (!nlh_setup (priv->nlh_sync, NULL, self, error))
366                 goto error;
367
368 #ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
369         /* Work around apparent libnl bug; rtnl_addr requires that all
370          * addresses have the "peer" attribute set in order to be compared
371          * for equality, but this attribute is not normally set. As a
372          * result, most addresses will not compare as equal even to
373          * themselves, busting caching.
374          */
375         rtnl_addr_alloc_cache (priv->nlh_sync, &addr_cache);
376         g_warn_if_fail (addr_cache != NULL);
377         nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80;
378         nl_cache_free (addr_cache);
379 #endif
380
381         err = rtnl_link_alloc_cache (priv->nlh_sync, &priv->link_cache);
382         if (err < 0) {
383                 g_set_error (error, NM_NETLINK_MONITOR_ERROR,
384                              NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE,
385                              _("unable to allocate netlink link cache for monitoring link status: %s"),
386                              nl_geterror (err));
387                 goto error;
388         }
389         nl_cache_mngt_provide (priv->link_cache);
390
391         return TRUE;
392
393 error:
394         if (priv->link_cache) {
395                 nl_cache_free (priv->link_cache);
396                 priv->link_cache = NULL;
397         }
398
399         if (priv->nlh_sync) {
400                 nl_socket_free (priv->nlh_sync);
401                 priv->nlh_sync = NULL;
402         }
403
404         return FALSE;
405 }
406
407 gboolean
408 nm_netlink_monitor_open_connection (NMNetlinkMonitor *self, GError **error)
409 {
410         g_return_val_if_fail (self != NULL, FALSE);
411         g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
412
413         if (!event_connection_setup (self, error))
414                 return FALSE;
415
416         if (!sync_connection_setup (self, error))
417                 return FALSE;
418
419         return TRUE;
420 }
421
422 void
423 nm_netlink_monitor_close_connection (NMNetlinkMonitor  *self)
424 {
425         NMNetlinkMonitorPrivate *priv;
426
427         g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
428
429         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
430         g_return_if_fail (priv->io_channel != NULL);
431
432         if (priv->event_id)
433                 nm_netlink_monitor_detach (self);
434
435         g_io_channel_shutdown (priv->io_channel,
436                                TRUE /* flush pending data */,
437                                NULL);
438         g_io_channel_unref (priv->io_channel);
439         priv->io_channel = NULL;
440 }
441
442 void
443 nm_netlink_monitor_attach (NMNetlinkMonitor *self)
444 {
445         NMNetlinkMonitorPrivate *priv;
446
447         g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
448
449         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
450         g_return_if_fail (priv->nlh_event != NULL);
451         g_return_if_fail (priv->event_id == 0);
452
453         priv->event_id = g_io_add_watch (priv->io_channel,
454                                          (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS),
455                                          event_handler, self);
456 }
457
458 void
459 nm_netlink_monitor_detach (NMNetlinkMonitor *self)
460 {
461         NMNetlinkMonitorPrivate *priv;
462
463         g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
464
465         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
466         g_return_if_fail (priv->event_id > 0);
467
468         g_source_remove (priv->event_id);
469         priv->event_id = 0;
470 }
471
472 static int
473 get_subs (NMNetlinkMonitor *self, int group)
474 {
475         NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
476
477         return GPOINTER_TO_INT (g_hash_table_lookup (priv->subscriptions,
478                                                      GINT_TO_POINTER (group)));
479 }
480
481 static void
482 set_subs (NMNetlinkMonitor *self, int group, int new_subs)
483 {
484         NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
485
486         g_hash_table_insert (priv->subscriptions,
487                              GINT_TO_POINTER (group),
488                              GINT_TO_POINTER (new_subs));
489 }
490
491 gboolean
492 nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error)
493 {
494         NMNetlinkMonitorPrivate *priv;
495         int subs, err;
496
497         g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
498
499         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
500
501         if (!priv->nlh_event) {
502                 if (!nm_netlink_monitor_open_connection (self, error))
503                         return FALSE;
504         }
505
506         subs = get_subs (self, group) + 1;
507         if (subs == 1) {
508                 err = nl_socket_add_membership (priv->nlh_event, group);
509                 if (err < 0) {
510                         g_set_error (error, NM_NETLINK_MONITOR_ERROR,
511                                      NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP,
512                                      _("unable to join netlink group: %s"),
513                                      nl_geterror (err));
514                         return FALSE;
515                 }
516         }
517
518         /* Update # of subscriptions for this group */
519         set_subs (self, group, subs);
520
521         return TRUE;
522 }
523
524 void
525 nm_netlink_monitor_unsubscribe (NMNetlinkMonitor *self, int group)
526 {
527         NMNetlinkMonitorPrivate *priv;
528         int subs;
529
530         g_return_if_fail (self != NULL);
531         g_return_if_fail (NM_IS_NETLINK_MONITOR (self));
532
533         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
534         g_return_if_fail (priv->nlh_event != NULL);
535
536         subs = get_subs (self, group) - 1;
537         if (subs == 0)
538                 nl_socket_drop_membership (priv->nlh_event, group);
539
540         /* Update # of subscriptions for this group */
541         set_subs (self, group, subs);
542 }
543
544 /***************************************************************/
545
546 gboolean
547 nm_netlink_monitor_request_ip6_info (NMNetlinkMonitor *self, GError **error)
548 {
549         NMNetlinkMonitorPrivate *priv;
550
551         g_return_val_if_fail (self != NULL, FALSE);
552         g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
553
554         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
555
556         /* FIXME: nl_rtgen_request() gets the return value screwed up with
557          * libnl-1.1; revisit this and return a proper error when we port to
558          * a later libnl.
559          */
560         nl_rtgen_request (priv->nlh_event, RTM_GETLINK, AF_INET6, NLM_F_DUMP);
561
562         return TRUE;
563 }
564
565
566 static gboolean
567 deferred_emit_carrier_state (gpointer user_data)
568 {
569         NMNetlinkMonitor *self = NM_NETLINK_MONITOR (user_data);
570         NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
571         int err;
572
573         priv->request_status_id = 0;
574
575         /* Update the link cache with latest state, and if there are no errors
576          * emit the link states for all the interfaces in the cache.
577          */
578         err = nl_cache_refill (priv->nlh_sync, priv->link_cache);
579         if (err < 0)
580                 nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror (err));
581         else
582                 nl_cache_foreach_filter (priv->link_cache, NULL, link_msg_handler, self);
583
584         return FALSE;
585 }
586
587 gboolean
588 nm_netlink_monitor_request_status (NMNetlinkMonitor *self, GError **error)
589 {
590         NMNetlinkMonitorPrivate *priv;
591
592         g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
593
594         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
595
596         /* Schedule the carrier state emission */
597         if (!priv->request_status_id)
598                 priv->request_status_id = g_idle_add (deferred_emit_carrier_state, self);
599
600         return TRUE;
601 }
602
603 typedef struct {
604         NMNetlinkMonitor *self;
605         struct rtnl_link *filter;
606         GError *error;
607         guint32 flags;
608 } GetFlagsInfo;
609
610 static void
611 get_flags_sync_cb (struct nl_object *obj, void *arg)
612 {
613         GetFlagsInfo *info = arg;
614
615         /* Ensure this cache item matches our filter */
616         if (nl_object_match_filter (obj, OBJ_CAST (info->filter)) != 0)
617                 info->flags = rtnl_link_get_flags ((struct rtnl_link *) obj);
618 }
619
620 gboolean
621 nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
622                                    guint32 ifindex,
623                                    guint32 *ifflags,
624                                    GError **error)
625 {
626         NMNetlinkMonitorPrivate *priv;
627         GetFlagsInfo info;
628         struct rtnl_link *filter;
629         int err;
630
631         g_return_val_if_fail (self != NULL, FALSE);
632         g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
633         g_return_val_if_fail (ifflags != NULL, FALSE);
634
635         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
636
637         /* Update the link cache with the latest information */
638         err = nl_cache_refill (priv->nlh_sync, priv->link_cache);
639         if (err < 0) {
640                 g_set_error (error,
641                              NM_NETLINK_MONITOR_ERROR,
642                              NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE,
643                              _("error updating link cache: %s"),
644                              nl_geterror (err));
645                 return FALSE;
646         }
647
648         /* HACK: Apparently to get it working we have to refill the cache twice;
649          * otherwise some kernels (or maybe libnl?) only send a few of the
650          * interfaces in the refill request.
651          */
652         if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) {
653                 g_set_error (error,
654                              NM_NETLINK_MONITOR_ERROR,
655                              NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE,
656                              _("error updating link cache: %s"),
657                              nl_geterror (err));
658                 return FALSE;
659         }
660
661         /* Set up the filter */
662         filter = rtnl_link_alloc ();
663         if (!filter) {
664                 g_set_error (error,
665                              NM_NETLINK_MONITOR_ERROR,
666                              NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
667                              _("error processing netlink message: %s"),
668                              nl_geterror (err));
669                 return FALSE;
670         }
671         rtnl_link_set_ifindex (filter, ifindex);
672
673         memset (&info, 0, sizeof (info));
674         info.self = self;
675         info.filter = filter;
676         info.error = NULL;
677         nl_cache_foreach_filter (priv->link_cache, NULL, get_flags_sync_cb, &info);
678
679         rtnl_link_put (filter);
680
681         if (info.error) {
682                 if (error)
683                         *error = info.error;
684                 else
685                         g_error_free (info.error);
686                 return FALSE;
687         } else
688                 *ifflags = info.flags;
689
690         return TRUE; /* success */
691 }
692
693 /***************************************************************/
694
695 struct nl_sock *
696 nm_netlink_get_default_handle (void)
697 {
698         NMNetlinkMonitor *self;
699         struct nl_sock *nlh;
700
701         self = nm_netlink_monitor_get ();
702         nlh = NM_NETLINK_MONITOR_GET_PRIVATE (self)->nlh_sync;
703         g_object_unref (self);
704
705         return nlh;
706 }
707
708 int
709 nm_netlink_iface_to_index (const char *iface)
710 {
711         NMNetlinkMonitor *self;
712         NMNetlinkMonitorPrivate *priv;
713         int idx;
714
715         g_return_val_if_fail (iface != NULL, -1);
716
717         self = nm_netlink_monitor_get ();
718         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
719
720         nl_cache_refill (priv->nlh_sync, priv->link_cache);
721         idx = rtnl_link_name2i (priv->link_cache, iface);
722         g_object_unref (self);
723
724         return idx;
725 }
726
727 #define MAX_IFACE_LEN 33
728 char *
729 nm_netlink_index_to_iface (int idx)
730 {
731         NMNetlinkMonitor *self;
732         NMNetlinkMonitorPrivate *priv;
733         char *buf = NULL;
734
735         g_return_val_if_fail (idx >= 0, NULL);
736
737         self = nm_netlink_monitor_get ();
738         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
739
740         buf = g_malloc0 (MAX_IFACE_LEN);
741         g_assert (buf);
742
743         nl_cache_refill (priv->nlh_sync, priv->link_cache);
744         if (!rtnl_link_i2name (priv->link_cache, idx, buf, MAX_IFACE_LEN - 1)) {
745                 g_free (buf);
746                 buf = NULL;
747         }
748
749         g_object_unref (self);
750         return buf;
751 }
752
753 struct rtnl_link *
754 nm_netlink_index_to_rtnl_link (int idx)
755 {
756         NMNetlinkMonitor *self;
757         NMNetlinkMonitorPrivate *priv;
758         struct rtnl_link *ret = NULL;
759
760         if (idx <= 0)
761                 return NULL;
762
763         self = nm_netlink_monitor_get ();
764         priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
765
766         nl_cache_refill (priv->nlh_sync, priv->link_cache);
767         ret = rtnl_link_get (priv->link_cache, idx);
768         g_object_unref (self);
769
770         return ret;
771 }
772
773 /***************************************************************/
774
775 NMNetlinkMonitor *
776 nm_netlink_monitor_get (void)
777 {
778         static NMNetlinkMonitor *singleton = NULL;
779
780         if (!singleton)
781                 singleton = NM_NETLINK_MONITOR (g_object_new (NM_TYPE_NETLINK_MONITOR, NULL));
782         else
783                 g_object_ref (singleton);
784
785         return singleton;
786 }
787
788 static void
789 nm_netlink_monitor_init (NMNetlinkMonitor *self)
790 {
791         NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
792
793         priv->subscriptions = g_hash_table_new (g_direct_hash, g_direct_equal);
794 }
795
796 static void
797 finalize (GObject *object)
798 {
799         NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (object);
800
801         if (priv->request_status_id)
802                 g_source_remove (priv->request_status_id);
803
804         if (priv->io_channel)
805                 nm_netlink_monitor_close_connection (NM_NETLINK_MONITOR (object));
806
807         if (priv->link_cache) {
808                 nl_cache_free (priv->link_cache);
809                 priv->link_cache = NULL;
810         }
811
812         if (priv->nlh_event) {
813                 nl_socket_free (priv->nlh_event);
814                 priv->nlh_event = NULL;
815         }
816
817         if (priv->nlh_sync) {
818                 nl_socket_free (priv->nlh_sync);
819                 priv->nlh_sync = NULL;
820         }
821
822         g_hash_table_destroy (priv->subscriptions);
823
824         G_OBJECT_CLASS (nm_netlink_monitor_parent_class)->finalize (object);
825 }
826
827 static void
828 nm_netlink_monitor_class_init (NMNetlinkMonitorClass *monitor_class)
829 {
830         GObjectClass *object_class = G_OBJECT_CLASS (monitor_class);
831
832         g_type_class_add_private (monitor_class, sizeof (NMNetlinkMonitorPrivate));
833
834         /* Virtual methods */
835         object_class->finalize = finalize;
836
837         /* Signals */
838         signals[NOTIFICATION] =
839                 g_signal_new ("notification",
840                               G_OBJECT_CLASS_TYPE (object_class),
841                               G_SIGNAL_RUN_LAST,
842                               G_STRUCT_OFFSET (NMNetlinkMonitorClass, notification),
843                               NULL, NULL, g_cclosure_marshal_VOID__POINTER,
844                               G_TYPE_NONE, 1, G_TYPE_POINTER);
845
846         signals[CARRIER_ON] =
847                 g_signal_new ("carrier-on",
848                               G_OBJECT_CLASS_TYPE (object_class),
849                               G_SIGNAL_RUN_LAST,
850                               G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_on),
851                               NULL, NULL, g_cclosure_marshal_VOID__INT,
852                               G_TYPE_NONE, 1, G_TYPE_INT);
853
854         signals[CARRIER_OFF] =
855                 g_signal_new ("carrier-off",
856                               G_OBJECT_CLASS_TYPE (object_class),
857                               G_SIGNAL_RUN_LAST,
858                               G_STRUCT_OFFSET (NMNetlinkMonitorClass, carrier_off),
859                               NULL, NULL, g_cclosure_marshal_VOID__INT,
860                               G_TYPE_NONE, 1, G_TYPE_INT);
861
862         signals[ERROR] =
863                 g_signal_new ("error",
864                               G_OBJECT_CLASS_TYPE (object_class),
865                               G_SIGNAL_RUN_LAST,
866                               G_STRUCT_OFFSET (NMNetlinkMonitorClass, error),
867                               NULL, NULL, g_cclosure_marshal_VOID__POINTER,
868                               G_TYPE_NONE, 1, G_TYPE_POINTER);
869 }
870
871 GQuark
872 nm_netlink_monitor_error_quark (void)
873 {
874         static GQuark error_quark = 0;
875
876         if (G_UNLIKELY (error_quark == 0))
877                 error_quark = g_quark_from_static_string ("nm-netlink-monitor-error-quark");
878         return error_quark;
879 }
880