netlink: merge nm-netlink.c into nm-netlink-monitor.c
[NetworkManager.git] / src / nm-system.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) 2004 - 2010 Red Hat, Inc.
19  * Copyright (C) 2005 - 2008 Novell, Inc.
20  * Copyright (C) 1996 - 1997 Yoichi Hariguchi <yoichi@fore.com>
21  * Copyright (C) January, 1998 Sergei Viznyuk <sv@phystech.com>
22  */
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
27 #include <sys/stat.h>
28 #include <netinet/in.h>
29 #include <net/route.h>
30 #include <arpa/nameser.h>
31 #include <arpa/inet.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <syslog.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <resolv.h>
40 #include <netdb.h>
41 #include <glib.h>
42 #include <ctype.h>
43 #include <net/if.h>
44
45 #include "nm-system.h"
46 #include "nm-device.h"
47 #include "nm-named-manager.h"
48 #include "NetworkManagerUtils.h"
49 #include "nm-utils.h"
50 #include "nm-logging.h"
51 #include "nm-netlink-monitor.h"
52
53 /* Because of a bug in libnl, rtnl.h should be included before route.h */
54 #include <netlink/route/rtnl.h>
55
56 #include <netlink/route/addr.h>
57 #include <netlink/route/route.h>
58 #include <netlink/netlink.h>
59 #include <netlink/utils.h>
60 #include <netlink/route/link.h>
61
62 static void nm_system_device_set_priority (const char *iface,
63                                                                    NMIP4Config *config,
64                                                                    int priority);
65
66 static gboolean
67 ip4_dest_in_same_subnet (NMIP4Config *config, guint32 dest, guint32 dest_prefix)
68 {
69         int num;
70         int i;
71
72         num = nm_ip4_config_get_num_addresses (config);
73         for (i = 0; i < num; i++) {
74                 NMIP4Address *addr = nm_ip4_config_get_address (config, i);
75                 guint32 prefix = nm_ip4_address_get_prefix (addr);
76                 guint32 address = nm_ip4_address_get_address (addr);
77
78                 if (prefix <= dest_prefix) {
79                         guint32 masked_addr = ntohl(address) >> (32 - prefix);
80                         guint32 masked_dest = ntohl(dest) >> (32 - prefix);
81
82                         if (masked_addr == masked_dest)
83                                 return TRUE;
84                 }
85         }
86
87         return FALSE;
88 }
89
90 static struct rtnl_route *
91 create_route (int iface_idx, int mss)
92 {
93         struct rtnl_route *route;
94
95         route = rtnl_route_alloc ();
96         if (route) {
97                 rtnl_route_set_oif (route, iface_idx);
98
99                 if (mss && rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0) {
100                         nm_log_warn (LOGD_DEVICE, "could not set mss");
101                 }
102         } else
103                 nm_log_err (LOGD_DEVICE, "could not allocate route");
104
105         return route;
106 }
107
108 static struct rtnl_route *
109 nm_system_device_set_ip4_route (const char *iface, 
110                                 guint32 ip4_dest,
111                                 guint32 ip4_prefix,
112                                 guint32 ip4_gateway,
113                                 guint32 metric,
114                                 int mss)
115 {
116         struct nl_handle *nlh;
117         struct rtnl_route *route;
118         struct nl_addr *dest_addr;
119         struct nl_addr *gw_addr = NULL;
120         int err, iface_idx;
121
122         nlh = nm_netlink_get_default_handle ();
123         g_return_val_if_fail (nlh != NULL, NULL);
124
125         iface_idx = nm_netlink_iface_to_index (iface);
126         g_return_val_if_fail (iface_idx >= 0, NULL);
127
128         route = create_route (iface_idx, mss);
129         g_return_val_if_fail (route != NULL, NULL);
130
131         /* Destination */
132         dest_addr = nl_addr_build (AF_INET, &ip4_dest, sizeof (ip4_dest));
133         g_return_val_if_fail (dest_addr != NULL, NULL);
134         nl_addr_set_prefixlen (dest_addr, (int) ip4_prefix);
135
136         rtnl_route_set_dst (route, dest_addr);
137         nl_addr_put (dest_addr);
138
139         /* Gateway */
140         if (ip4_gateway) {
141                 gw_addr = nl_addr_build (AF_INET, &ip4_gateway, sizeof (ip4_gateway));
142                 if (gw_addr) {
143                         rtnl_route_set_gateway (route, gw_addr);
144                         rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
145                 } else {
146                         nm_log_err (LOGD_DEVICE | LOGD_IP4, "Invalid gateway 0x%X", ip4_gateway);
147                         rtnl_route_put (route);
148                         return NULL;
149                 }
150         }
151
152         /* Metric */
153         if (metric)
154                 rtnl_route_set_prio (route, metric);
155
156         /* Add the route */
157         err = rtnl_route_add (nlh, route, 0);
158         if (err == -ESRCH && ip4_gateway) {
159                 /* Gateway might be over a bridge; try adding a route to gateway first */
160                 struct rtnl_route *route2;
161
162                 route2 = create_route (iface_idx, mss);
163                 if (route2) {
164                         /* Add route to gateway over bridge */
165                         rtnl_route_set_dst (route2, gw_addr);
166                         err = rtnl_route_add (nlh, route2, 0);
167                         if (!err) {
168                                 /* Try adding the route again */
169                                 err = rtnl_route_add (nlh, route, 0);
170                                 if (err)
171                                         rtnl_route_del (nlh, route2, 0);
172                         }
173                         rtnl_route_put (route2);
174                 }
175         }
176
177         if (gw_addr)
178                 nl_addr_put (gw_addr);
179
180         if (err) {
181                 nm_log_err (LOGD_DEVICE | LOGD_IP4,
182                             "(%s): failed to set IPv4 route: %s",
183                             iface, nl_geterror ());
184                 rtnl_route_put (route);
185                 route = NULL;
186         }
187
188         return route;
189 }
190
191 static gboolean
192 sync_addresses (const char *iface, int ifindex, int family,
193                                 struct rtnl_addr **addrs, int num_addrs)
194 {
195         struct nl_handle *nlh;
196         struct nl_cache *addr_cache;
197         struct rtnl_addr *filter_addr, *match_addr;
198         struct nl_object *match;
199         int i, err;
200         guint32 log_domain = (family == AF_INET) ? LOGD_IP4 : LOGD_IP6;
201
202         log_domain |= LOGD_DEVICE;
203
204         nlh = nm_netlink_get_default_handle ();
205         if (!nlh)
206                 return FALSE;
207
208         addr_cache = rtnl_addr_alloc_cache (nlh);
209         if (!addr_cache)
210                 return FALSE;
211
212         filter_addr = rtnl_addr_alloc ();
213         if (!filter_addr) {
214                 nl_cache_free (addr_cache);
215                 return FALSE;
216         }
217         rtnl_addr_set_ifindex (filter_addr, ifindex);
218         if (family)
219                 rtnl_addr_set_family (filter_addr, family);
220
221         /* Walk through the cache, comparing the addresses already on
222          * the interface to the addresses in addrs.
223          */
224         for (match = nl_cache_get_first (addr_cache); match; match = nl_cache_get_next (match)) {
225                 match_addr = (struct rtnl_addr *)match;
226
227                 /* Skip addresses not on our interface */
228                 if (!nl_object_match_filter (match, (struct nl_object *)filter_addr))
229                         continue;
230
231                 if (addrs) {
232                         for (i = 0; i < num_addrs; i++) {
233                                 if (addrs[i] &&
234                                         nl_object_identical (match, (struct nl_object *)addrs[i]))
235                                         break;
236                         }
237
238                         if (addrs[i]) {
239                                 /* match == addrs[i], so remove it from addrs so we don't
240                                  * try to add it to the interface again below.
241                                  */
242                                 rtnl_addr_put (addrs[i]);
243                                 addrs[i] = NULL;
244                                 continue;
245                         }
246                 }
247
248                 /* Don't delete IPv6 link-local addresses; they don't belong to NM */
249                 if (rtnl_addr_get_family (match_addr) == AF_INET6 &&
250                         rtnl_addr_get_scope (match_addr) == RT_SCOPE_LINK) {
251                         continue;
252                 }
253
254                 /* Otherwise, match_addr should be removed from the interface. */
255                 err = rtnl_addr_delete (nlh, match_addr, 0);
256                 if (err < 0) {
257                         nm_log_err (log_domain, "(%s): error %d returned from rtnl_addr_delete(): %s",
258                                                 iface, err, nl_geterror ());
259                 }
260         }
261
262         rtnl_addr_put (filter_addr);
263         nl_cache_free (addr_cache);
264
265         /* Now add the remaining new addresses */
266         for (i = 0; i < num_addrs; i++) {
267                 if (!addrs[i])
268                         continue;
269
270                 err = rtnl_addr_add (nlh, addrs[i], 0);
271                 if (err < 0) {
272                         nm_log_err (log_domain,
273                                     "(%s): error %d returned from rtnl_addr_add():\n%s",
274                                                 iface, err, nl_geterror ());
275                 }
276
277                 rtnl_addr_put (addrs[i]);
278         }
279         g_free (addrs);
280
281         return TRUE;
282 }
283
284 static gboolean
285 add_ip4_addresses (NMIP4Config *config, const char *iface)
286 {
287         int num_addrs, i, iface_idx;
288         guint32 flags = 0;
289         gboolean did_gw = FALSE;
290         struct rtnl_addr **addrs;
291
292         iface_idx = nm_netlink_iface_to_index (iface);
293
294         num_addrs = nm_ip4_config_get_num_addresses (config);
295         addrs = g_new0 (struct rtnl_addr *, num_addrs + 1);
296
297         for (i = 0; i < num_addrs; i++) {
298                 NMIP4Address *addr;
299
300                 addr = nm_ip4_config_get_address (config, i);
301                 g_assert (addr);
302
303                 flags = NM_RTNL_ADDR_DEFAULT;
304                 if (nm_ip4_address_get_gateway (addr) && !did_gw) {
305                         if (nm_ip4_config_get_ptp_address (config))
306                                 flags |= NM_RTNL_ADDR_PTP_ADDR;
307                         did_gw = TRUE;
308                 }
309
310                 addrs[i] = nm_ip4_config_to_rtnl_addr (config, i, flags);
311                 if (!addrs[i]) {
312                         nm_log_warn (LOGD_DEVICE | LOGD_IP4,
313                                      "(%s): couldn't create rtnl address!",
314                                      iface);
315                         continue;
316                 }
317                 rtnl_addr_set_ifindex (addrs[i], iface_idx);
318         }
319
320         return sync_addresses (iface, iface_idx, AF_INET, addrs, num_addrs);
321 }
322
323 struct rtnl_route *
324 nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_config)
325 {
326         NMIP4Config *parent_config;
327         guint32 parent_gw = 0, parent_prefix = 0, vpn_gw = 0, i;
328         NMIP4Address *tmp;
329         struct rtnl_route *route = NULL;
330
331         g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL);
332
333         /* Set up a route to the VPN gateway's public IP address through the default
334          * network device if the VPN gateway is on a different subnet.
335          */
336
337         parent_config = nm_device_get_ip4_config (parent_device);
338         g_return_val_if_fail (parent_config != NULL, NULL);
339
340         for (i = 0; i < nm_ip4_config_get_num_addresses (parent_config); i++) {
341                 tmp = nm_ip4_config_get_address (parent_config, i);
342                 if (nm_ip4_address_get_gateway (tmp)) {
343                         parent_gw = nm_ip4_address_get_gateway (tmp);
344                         parent_prefix = nm_ip4_address_get_prefix (tmp);
345                         break;
346                 }
347         }
348
349         for (i = 0; i < nm_ip4_config_get_num_addresses (vpn_config); i++) {
350                 tmp = nm_ip4_config_get_address (vpn_config, i);
351                 if (nm_ip4_address_get_gateway (tmp)) {
352                         vpn_gw = nm_ip4_address_get_gateway (tmp);
353                         break;
354                 }
355         }
356
357         if (!parent_gw || !vpn_gw)
358                 return NULL;
359
360         /* If the VPN gateway is in the same subnet as one of the parent device's
361          * IP addresses, don't add the host route to it, but a route through the
362          * parent device.
363          */
364         if (ip4_dest_in_same_subnet (parent_config, vpn_gw, parent_prefix)) {
365                 route = nm_system_device_set_ip4_route (nm_device_get_ip_iface (parent_device),
366                                                         vpn_gw, 32, 0, 0, nm_ip4_config_get_mss (parent_config));
367         } else {
368                 route = nm_system_device_set_ip4_route (nm_device_get_ip_iface (parent_device),
369                                                         vpn_gw, 32, parent_gw, 0, nm_ip4_config_get_mss (parent_config));
370         }
371
372         return route;
373 }
374
375 /*
376  * nm_system_apply_ip4_config
377  *
378  * Set IPv4 configuration of the device from an NMIP4Config object.
379  *
380  */
381 gboolean
382 nm_system_apply_ip4_config (const char *iface,
383                             NMIP4Config *config,
384                             int priority,
385                             NMIP4ConfigCompareFlags flags)
386 {
387         int i;
388
389         g_return_val_if_fail (iface != NULL, FALSE);
390         g_return_val_if_fail (config != NULL, FALSE);
391
392         if (flags & NM_IP4_COMPARE_FLAG_ADDRESSES) {
393                 if (!add_ip4_addresses (config, iface))
394                         return FALSE;
395                 sleep (1);
396         }
397
398         if (flags & NM_IP4_COMPARE_FLAG_ROUTES) {
399                 for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) {
400                         NMIP4Route *route = nm_ip4_config_get_route (config, i);
401                         struct rtnl_route *tmp;
402
403                         /* Don't add the route if it's more specific than one of the subnets
404                          * the device already has an IP address on.
405                          */
406                         if (ip4_dest_in_same_subnet (config,
407                                                      nm_ip4_route_get_dest (route),
408                                                      nm_ip4_route_get_prefix (route)))
409                                 continue;
410
411                         /* Don't add the route if it doesn't have a gateway and the connection
412                          * is never supposed to be the default connection.
413                          */
414                         if (   nm_ip4_config_get_never_default (config)
415                             && nm_ip4_route_get_dest (route) == 0)
416                                 continue;
417
418                         tmp = nm_system_device_set_ip4_route (iface,
419                                                               nm_ip4_route_get_dest (route),
420                                                               nm_ip4_route_get_prefix (route),
421                                                               nm_ip4_route_get_next_hop (route),
422                                                               nm_ip4_route_get_metric (route),
423                                                               nm_ip4_config_get_mss (config));
424                         rtnl_route_put (tmp);
425                 }
426         }
427
428         if (flags & NM_IP4_COMPARE_FLAG_MTU) {
429                 if (nm_ip4_config_get_mtu (config))
430                         nm_system_device_set_mtu (iface, nm_ip4_config_get_mtu (config));
431         }
432
433         if (priority > 0)
434                 nm_system_device_set_priority (iface, config, priority);
435
436         return TRUE;
437 }
438
439 static struct rtnl_route *
440 nm_system_device_set_ip6_route (const char *iface,
441                                 const struct in6_addr *ip6_dest,
442                                 guint32 ip6_prefix,
443                                 const struct in6_addr *ip6_gateway,
444                                 guint32 metric,
445                                 int mss)
446 {
447         struct nl_handle *nlh;
448         struct rtnl_route *route;
449         struct nl_addr *dest_addr;
450         struct nl_addr *gw_addr = NULL;
451         int err, iface_idx;
452
453         nlh = nm_netlink_get_default_handle ();
454         g_return_val_if_fail (nlh != NULL, NULL);
455
456         iface_idx = nm_netlink_iface_to_index (iface);
457         g_return_val_if_fail (iface_idx >= 0, NULL);
458
459         route = create_route (iface_idx, mss);
460         g_return_val_if_fail (route != NULL, NULL);
461
462         /* Destination */
463         dest_addr = nl_addr_build (AF_INET6, (struct in6_addr *)ip6_dest, sizeof (*ip6_dest));
464         g_return_val_if_fail (dest_addr != NULL, NULL);
465         nl_addr_set_prefixlen (dest_addr, (int) ip6_prefix);
466
467         rtnl_route_set_dst (route, dest_addr);
468         nl_addr_put (dest_addr);
469
470         /* Gateway */
471         if (ip6_gateway && !IN6_IS_ADDR_UNSPECIFIED (ip6_gateway)) {
472                 gw_addr = nl_addr_build (AF_INET6, (struct in6_addr *)ip6_gateway, sizeof (*ip6_gateway));
473                 if (gw_addr) {
474                         rtnl_route_set_gateway (route, gw_addr);
475                         rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
476                 } else {
477                         nm_log_warn (LOGD_DEVICE | LOGD_IP6, "Invalid gateway");
478                         rtnl_route_put (route);
479                         return NULL;
480                 }
481         }
482
483         /* Metric */
484         if (metric)
485                 rtnl_route_set_prio (route, metric);
486
487         /* Add the route */
488         err = rtnl_route_add (nlh, route, 0);
489         if (err == -ESRCH && ip6_gateway) {
490                 /* Gateway might be over a bridge; try adding a route to gateway first */
491                 struct rtnl_route *route2;
492
493                 route2 = create_route (iface_idx, mss);
494                 if (route2) {
495                         /* Add route to gateway over bridge */
496                         rtnl_route_set_dst (route2, gw_addr);
497                         err = rtnl_route_add (nlh, route2, 0);
498                         if (!err) {
499                                 /* Try adding the route again */
500                                 err = rtnl_route_add (nlh, route, 0);
501                                 if (err)
502                                         rtnl_route_del (nlh, route2, 0);
503                         }
504                         rtnl_route_put (route2);
505                 }
506         }
507
508         if (gw_addr)
509                 nl_addr_put (gw_addr);
510
511         if (err) {
512                 nm_log_err (LOGD_DEVICE | LOGD_IP6,
513                             "(%s): failed to set IPv6 route: %s",
514                             iface, nl_geterror ());
515                 rtnl_route_put (route);
516                 route = NULL;
517         }
518
519         return route;
520 }
521
522 static gboolean
523 add_ip6_addresses (NMIP6Config *config, const char *iface)
524 {
525         int num_addrs, i, iface_idx;
526         struct rtnl_addr **addrs;
527
528         iface_idx = nm_netlink_iface_to_index (iface);
529
530         num_addrs = nm_ip6_config_get_num_addresses (config);
531         addrs = g_new0 (struct rtnl_addr *, num_addrs + 1);
532
533         for (i = 0; i < num_addrs; i++) {
534                 NMIP6Address *addr;
535
536                 addr = nm_ip6_config_get_address (config, i);
537                 g_assert (addr);
538
539                 addrs[i] = nm_ip6_config_to_rtnl_addr (config, i, NM_RTNL_ADDR_DEFAULT);
540                 if (!addrs[i]) {
541                         nm_log_warn (LOGD_DEVICE | LOGD_IP6,
542                                      "(%s): couldn't create rtnl address!",
543                                      iface);
544                         continue;
545                 }
546                 rtnl_addr_set_ifindex (addrs[i], iface_idx);
547         }
548
549         return sync_addresses (iface, iface_idx, AF_INET6, addrs, num_addrs);
550 }
551
552 /*
553  * nm_system_apply_ip6_config
554  *
555  * Set IPv6 configuration of the device from an NMIP6Config object.
556  *
557  */
558 gboolean
559 nm_system_apply_ip6_config (const char *iface,
560                             NMIP6Config *config,
561                             int priority,
562                             NMIP6ConfigCompareFlags flags)
563 {
564         int i;
565
566         g_return_val_if_fail (iface != NULL, FALSE);
567         g_return_val_if_fail (config != NULL, FALSE);
568
569         if (flags & NM_IP6_COMPARE_FLAG_ADDRESSES) {
570                 if (!add_ip6_addresses (config, iface))
571                         return FALSE;
572                 sleep (1); // FIXME?
573         }
574
575         if (flags & NM_IP6_COMPARE_FLAG_ROUTES) {
576                 for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) {
577                         NMIP6Route *route = nm_ip6_config_get_route (config, i);
578                         struct rtnl_route *tmp;
579
580                         /* Don't add the route if it doesn't have a gateway and the connection
581                          * is never supposed to be the default connection.
582                          */
583                         if (   nm_ip6_config_get_never_default (config)
584                             && IN6_IS_ADDR_UNSPECIFIED(nm_ip6_route_get_dest (route)))
585                                 continue;
586
587                         tmp = nm_system_device_set_ip6_route (iface,
588                                                               nm_ip6_route_get_dest (route),
589                                                               nm_ip6_route_get_prefix (route),
590                                                               nm_ip6_route_get_next_hop (route),
591                                                               nm_ip6_route_get_metric (route),
592                                                               nm_ip6_config_get_mss (config));
593                         rtnl_route_put (tmp);
594                 }
595         }
596
597 // FIXME
598 //      if (priority > 0)
599 //              nm_system_device_set_priority (iface, config, priority);
600
601         return TRUE;
602 }
603
604 /*
605  * nm_system_device_set_up_down
606  *
607  * Mark the device as up or down.
608  *
609  */
610 gboolean
611 nm_system_device_set_up_down (NMDevice *dev,
612                               gboolean up,
613                               gboolean *no_firmware)
614 {
615         g_return_val_if_fail (dev != NULL, FALSE);
616
617         return nm_system_device_set_up_down_with_iface (nm_device_get_ip_iface (dev), up, no_firmware);
618 }
619
620 gboolean
621 nm_system_device_set_up_down_with_iface (const char *iface,
622                                          gboolean up,
623                                          gboolean *no_firmware)
624 {
625         struct rtnl_link *request = NULL, *old = NULL;
626         struct nl_handle *nlh;
627         gboolean success = FALSE;
628         guint32 idx;
629
630         g_return_val_if_fail (iface != NULL, FALSE);
631         if (no_firmware)
632                 g_return_val_if_fail (*no_firmware == FALSE, FALSE);
633
634         if (!(request = rtnl_link_alloc ()))
635                 goto out;
636
637         if (up)
638                 rtnl_link_set_flags (request, IFF_UP);
639         else
640                 rtnl_link_unset_flags (request, IFF_UP);
641
642         idx = nm_netlink_iface_to_index (iface);
643         old = nm_netlink_index_to_rtnl_link (idx);
644         if (old) {
645                 nlh = nm_netlink_get_default_handle ();
646                 if (nlh) {
647                         if (rtnl_link_change (nlh, old, request, 0) == 0)
648                                 success = TRUE;
649                         else if ((nl_get_errno () == ENOENT) && no_firmware && up)
650                                 *no_firmware = TRUE;
651                 }
652         }
653
654         rtnl_link_put (old);
655         rtnl_link_put (request);
656
657 out:
658         return success;
659 }
660
661 gboolean
662 nm_system_device_is_up (NMDevice *device)
663 {
664         g_return_val_if_fail (device != NULL, FALSE);
665
666         return nm_system_device_is_up_with_iface (nm_device_get_ip_iface (device));
667 }
668
669 gboolean
670 nm_system_device_is_up_with_iface (const char *iface)
671 {
672         struct ifreq ifr;
673         int fd;
674         gboolean up = FALSE;
675
676         fd = socket (PF_INET, SOCK_DGRAM, 0);
677         if (fd < 0) {
678                 nm_log_err (LOGD_HW, "couldn't open control socket.");
679                 return FALSE;
680         }
681
682         /* Get device's flags */
683         memset (&ifr, 0, sizeof (ifr));
684         strncpy (ifr.ifr_name, iface, IFNAMSIZ);
685         if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0) {
686                 if (errno != ENODEV) {
687                         nm_log_err (LOGD_HW, "(%s): could not get flags: errno %d",
688                                     iface, errno);
689                 }
690         } else {
691                 up = !!(ifr.ifr_flags & IFF_UP);
692         }
693         close (fd);
694
695         return up;
696 }
697
698 gboolean
699 nm_system_device_set_mtu (const char *iface, guint32 mtu)
700 {
701         struct rtnl_link *old;
702         struct rtnl_link *new;
703         gboolean success = FALSE;
704         struct nl_handle *nlh;
705         int iface_idx;
706
707         g_return_val_if_fail (iface != NULL, FALSE);
708         g_return_val_if_fail (mtu > 0, FALSE);
709
710         new = rtnl_link_alloc ();
711         if (!new)
712                 return FALSE;
713
714         iface_idx = nm_netlink_iface_to_index (iface);
715         old = nm_netlink_index_to_rtnl_link (iface_idx);
716         if (old) {
717                 rtnl_link_set_mtu (new, mtu);
718                 nlh = nm_netlink_get_default_handle ();
719                 if (nlh) {
720                         rtnl_link_change (nlh, old, new, 0);
721                         success = TRUE;
722                 }
723                 rtnl_link_put (old);
724         }
725
726         rtnl_link_put (new);
727         return success;
728 }
729
730 static struct rtnl_route *
731 add_ip4_route_to_gateway (const char *iface, guint32 gw, guint32 mss)
732 {
733         struct nl_handle *nlh;
734         struct rtnl_route *route = NULL;
735         struct nl_addr *gw_addr = NULL;
736         int iface_idx, err;
737
738         nlh = nm_netlink_get_default_handle ();
739         g_return_val_if_fail (nlh != NULL, NULL);
740
741         iface_idx = nm_netlink_iface_to_index (iface);
742         if (iface_idx < 0)
743                 return NULL;
744
745         /* Gateway might be over a bridge; try adding a route to gateway first */
746         route = rtnl_route_alloc ();
747         if (route == NULL)
748                 return NULL;
749
750         rtnl_route_set_family (route, AF_INET);
751         rtnl_route_set_table (route, RT_TABLE_MAIN);
752         rtnl_route_set_oif (route, iface_idx);
753         rtnl_route_set_scope (route, RT_SCOPE_LINK);
754
755         gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw));
756         if (!gw_addr)
757                 goto error;
758         nl_addr_set_prefixlen (gw_addr, 32);
759         rtnl_route_set_dst (route, gw_addr);
760         nl_addr_put (gw_addr);
761
762         if (mss) {
763                 if (rtnl_route_set_metric (route, RTAX_ADVMSS, mss) < 0)
764                         goto error;
765         }
766
767         /* Add direct route to the gateway */
768         err = rtnl_route_add (nlh, route, 0);
769         if (err) {
770                 nm_log_err (LOGD_DEVICE | LOGD_IP4,
771                             "(%s): failed to add IPv4 route to gateway (%d)",
772                             iface, err);
773                 goto error;
774         }
775
776         return route;
777
778 error:
779         rtnl_route_put (route);
780         return NULL;
781 }
782
783 static int
784 replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
785 {
786         struct rtnl_route *route = NULL;
787         struct nl_handle *nlh;
788         struct nl_addr *dst_addr = NULL;
789         guint32 dst = 0;
790         struct nl_addr *gw_addr = NULL;
791         int iface_idx, err = -1;
792
793         g_return_val_if_fail (iface != NULL, -ENODEV);
794
795         nlh = nm_netlink_get_default_handle ();
796         g_return_val_if_fail (nlh != NULL, -ENOMEM);
797
798         iface_idx = nm_netlink_iface_to_index (iface);
799         if (iface_idx < 0)
800                 return -ENODEV;
801
802         route = rtnl_route_alloc();
803         g_return_val_if_fail (route != NULL, -ENOMEM);
804
805         rtnl_route_set_family (route, AF_INET);
806         rtnl_route_set_table (route, RT_TABLE_MAIN);
807         rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
808         rtnl_route_set_oif (route, iface_idx);
809
810         /* Build up the destination address */
811         dst_addr = nl_addr_build (AF_INET, &dst, sizeof (dst));
812         if (!dst_addr) {
813                 err = -ENOMEM;
814                 goto out;
815         }
816         nl_addr_set_prefixlen (dst_addr, 0);
817         rtnl_route_set_dst (route, dst_addr);
818
819         /* Build up the gateway address */
820         gw_addr = nl_addr_build (AF_INET, &gw, sizeof (gw));
821         if (!gw_addr) {
822                 err = -ENOMEM;
823                 goto out;
824         }
825         nl_addr_set_prefixlen (gw_addr, 0);
826         rtnl_route_set_gateway (route, gw_addr);
827
828         if (mss > 0) {
829                 err = rtnl_route_set_metric (route, RTAX_ADVMSS, mss);
830                 if (err < 0)
831                         goto out;
832         }
833
834         /* Add the new default route */
835         err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
836
837 out:
838         if (dst_addr)
839                 nl_addr_put (dst_addr);
840         if (gw_addr)
841                 nl_addr_put (gw_addr);
842         rtnl_route_put (route);
843         return err;
844 }
845
846 /*
847  * nm_system_replace_default_ip4_route_vpn
848  *
849  * Replace default IPv4 route with one via the current device
850  *
851  */
852 gboolean
853 nm_system_replace_default_ip4_route_vpn (const char *iface,
854                                          guint32 ext_gw,
855                                          guint32 int_gw,
856                                          guint32 mss,
857                                          const char *parent_iface,
858                                          guint32 parent_mss)
859 {
860         struct rtnl_route *gw_route = NULL;
861         struct nl_handle *nlh;
862         gboolean success = FALSE;
863         int err;
864
865         nlh = nm_netlink_get_default_handle ();
866         g_return_val_if_fail (nlh != NULL, FALSE);
867
868         err = replace_default_ip4_route (iface, int_gw, mss);
869         if (err == 0) {
870                 return TRUE;
871         } else if (err != -ESRCH) {
872                 nm_log_err (LOGD_DEVICE | LOGD_IP4,
873                             "(%s): failed to set IPv4 default route: %d",
874                             iface, err);
875                 return FALSE;
876         }
877
878         /* Try adding a direct route to the gateway first */
879         gw_route = add_ip4_route_to_gateway (parent_iface, ext_gw, parent_mss);
880         if (!gw_route)
881                 return FALSE;
882
883         /* Try adding the original route again */
884         err = replace_default_ip4_route (iface, int_gw, mss);
885         if (err != 0) {
886                 rtnl_route_del (nlh, gw_route, 0);
887                 nm_log_err (LOGD_DEVICE | LOGD_IP4,
888                             "(%s): failed to set IPv4 default route (pass #2): %d",
889                             iface, err);
890         } else
891                 success = TRUE;
892
893         rtnl_route_put (gw_route);
894         return success;
895 }
896
897 /*
898  * nm_system_replace_default_ip4_route
899  *
900  * Replace default IPv4 route with one via the current device
901  *
902  */
903 gboolean
904 nm_system_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
905 {
906         struct rtnl_route *gw_route = NULL;
907         struct nl_handle *nlh;
908         gboolean success = FALSE;
909         int err;
910
911         nlh = nm_netlink_get_default_handle ();
912         g_return_val_if_fail (nlh != NULL, FALSE);
913
914         err = replace_default_ip4_route (iface, gw, mss);
915         if (err == 0) {
916                 return TRUE;
917         } else if (err != -ESRCH) {
918                 nm_log_err (LOGD_DEVICE | LOGD_IP4,
919                             "(%s): failed to set IPv4 default route: %d",
920                             iface, err);
921                 return FALSE;
922         }
923
924         /* Try adding a direct route to the gateway first */
925         gw_route = add_ip4_route_to_gateway (iface, gw, mss);
926         if (!gw_route)
927                 return FALSE;
928
929         /* Try adding the original route again */
930         err = replace_default_ip4_route (iface, gw, mss);
931         if (err != 0) {
932                 rtnl_route_del (nlh, gw_route, 0);
933                 nm_log_err (LOGD_DEVICE | LOGD_IP4,
934                             "(%s): failed to set IPv4 default route (pass #2): %d",
935                             iface, err);
936         } else
937                 success = TRUE;
938
939         rtnl_route_put (gw_route);
940         return success;
941 }
942
943 static void flush_addresses (const char *iface, gboolean ipv4_only)
944 {
945         int iface_idx;
946
947         g_return_if_fail (iface != NULL);
948         iface_idx = nm_netlink_iface_to_index (iface);
949         if (iface_idx >= 0)
950                 sync_addresses (iface, iface_idx, ipv4_only ? AF_INET : 0, NULL, 0);
951 }
952
953 /*
954  * nm_system_device_flush_addresses
955  *
956  * Flush all network addresses associated with a network device
957  *
958  */
959 void nm_system_device_flush_addresses (NMDevice *dev)
960 {
961         g_return_if_fail (dev != NULL);
962
963         flush_addresses (nm_device_get_ip_iface (dev),
964                                          nm_device_get_ip6_config (dev) == NULL);
965 }
966
967
968 /*
969  * nm_system_device_flush_addresses_with_iface
970  *
971  * Flush all network addresses associated with a network device
972  *
973  */
974 void nm_system_device_flush_addresses_with_iface (const char *iface)
975 {
976         flush_addresses (iface, FALSE);
977 }
978
979
980 static void
981 foreach_route (void (*callback)(struct nl_object *, gpointer),
982                         gpointer user_data)
983 {
984         struct nl_handle *nlh;
985         struct nl_cache *route_cache;
986
987         nlh = nm_netlink_get_default_handle ();
988         route_cache = rtnl_route_alloc_cache (nlh);
989         nl_cache_mngt_provide (route_cache);
990         nl_cache_foreach (route_cache, callback, user_data);
991         nl_cache_free (route_cache);
992 }
993
994
995 typedef struct {
996         const char *iface;
997         int iface_idx;
998         int family;
999 } RouteCheckData;
1000
1001 static void
1002 check_one_route (struct nl_object *object, void *user_data)
1003 {
1004         RouteCheckData *data = (RouteCheckData *) user_data;
1005         struct rtnl_route *route = (struct rtnl_route *) object;
1006         int err;
1007
1008         /* Delete all routes from this interface */
1009         if (rtnl_route_get_oif (route) != data->iface_idx)
1010                 return;
1011         if (data->family && rtnl_route_get_family (route) != data->family)
1012                 return;
1013
1014         err = rtnl_route_del (nm_netlink_get_default_handle (), route, 0);
1015         if (err < 0) {
1016                 nm_log_err (LOGD_DEVICE,
1017                             "(%s): error %d returned from rtnl_route_del(): %s",
1018                             data->iface, err, nl_geterror());
1019         }
1020 }
1021
1022 static void flush_routes (const char *iface, gboolean ipv4_only)
1023 {
1024         int iface_idx;
1025         RouteCheckData check_data;
1026
1027         g_return_if_fail (iface != NULL);
1028         iface_idx = nm_netlink_iface_to_index (iface);
1029         if (iface_idx >= 0) {
1030                 memset (&check_data, 0, sizeof (check_data));
1031                 check_data.iface = iface;
1032                 check_data.iface_idx = iface_idx;
1033                 check_data.family = ipv4_only ? AF_INET : 0;
1034
1035                 foreach_route (check_one_route, &check_data);
1036         }
1037 }
1038
1039 /*
1040  * nm_system_device_flush_routes
1041  *
1042  * Flush all network addresses associated with a network device
1043  *
1044  */
1045 void nm_system_device_flush_routes (NMDevice *dev)
1046 {
1047         g_return_if_fail (dev != NULL);
1048
1049         flush_routes (nm_device_get_ip_iface (dev),
1050                                   nm_device_get_ip6_config (dev) == NULL);
1051 }
1052
1053 /*
1054  * nm_system_device_flush_routes_with_iface
1055  *
1056  * Flush all routes associated with a network device
1057  *
1058  */
1059 void nm_system_device_flush_routes_with_iface (const char *iface)
1060 {
1061         flush_routes (iface, FALSE);
1062 }
1063
1064 typedef struct {
1065         struct rtnl_route *route;
1066         NMIP4Config *config;
1067         int iface;
1068 } SetPriorityInfo;
1069
1070 static void
1071 find_route (struct nl_object *object, gpointer user_data)
1072 {
1073         struct rtnl_route *route = (struct rtnl_route *) object;
1074         SetPriorityInfo *info = (SetPriorityInfo *) user_data;
1075         struct nl_addr *dst;
1076         struct in_addr *dst_addr;
1077         int num;
1078         int i;
1079
1080         if (info->route ||
1081             rtnl_route_get_oif (route) != info->iface ||
1082             rtnl_route_get_scope (route) != RT_SCOPE_LINK)
1083                 return;
1084
1085         dst = rtnl_route_get_dst (route);
1086         if (nl_addr_get_family (dst) != AF_INET)
1087                 return;
1088
1089         dst_addr = nl_addr_get_binary_addr (dst);
1090         num = nm_ip4_config_get_num_addresses (info->config);
1091         for (i = 0; i < num; i++) {
1092                 NMIP4Address *addr = nm_ip4_config_get_address (info->config, i);
1093                 guint32 prefix = nm_ip4_address_get_prefix (addr);
1094                 guint32 address = nm_ip4_address_get_address (addr);
1095
1096                 if (prefix == nl_addr_get_prefixlen (dst) &&
1097                     (address & nm_utils_ip4_prefix_to_netmask (prefix)) == dst_addr->s_addr) {
1098
1099                         /* Ref the route so it sticks around after the cache is cleared */
1100                         rtnl_route_get (route);
1101                         info->route = route;
1102                         break;
1103                 }
1104         }
1105 }
1106
1107 static void
1108 nm_system_device_set_priority (const char *iface,
1109                                                  NMIP4Config *config,
1110                                                  int priority)
1111 {
1112         SetPriorityInfo info;
1113
1114         info.route = NULL;
1115         info.config = config;
1116         info.iface = nm_netlink_iface_to_index (iface);
1117         g_return_if_fail (info.iface >= 0);
1118
1119         foreach_route (find_route, &info);
1120         if (info.route) {
1121                 struct nl_handle *nlh;
1122
1123                 nlh = nm_netlink_get_default_handle ();
1124                 rtnl_route_del (nlh, info.route, 0);
1125
1126                 rtnl_route_set_prio (info.route, priority);
1127                 rtnl_route_add (nlh, info.route, 0);
1128                 rtnl_route_put (info.route);
1129         }
1130 }