e2ff1f61af402d06b554c4be6e645a9855539ca9
[NetworkManager.git] / src / platform / nm-linux-platform.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* nm-linux-platform.c - Linux kernel & udev network configuration layer
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, or (at your option)
7  * 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) 2012-2015 Red Hat, Inc.
19  */
20 #include "nm-default.h"
21
22 #include "nm-linux-platform.h"
23
24 #include <errno.h>
25 #include <unistd.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #include <fcntl.h>
29 #include <dlfcn.h>
30 #include <arpa/inet.h>
31 #include <netinet/icmp6.h>
32 #include <netinet/in.h>
33 #include <linux/ip.h>
34 #include <linux/if_arp.h>
35 #include <linux/if_link.h>
36 #include <linux/if_tun.h>
37 #include <linux/if_tunnel.h>
38 #include <netlink/netlink.h>
39 #include <netlink/object.h>
40 #include <netlink/cache.h>
41 #include <netlink/route/link.h>
42 #include <netlink/route/link/vlan.h>
43 #include <netlink/route/addr.h>
44 #include <netlink/route/route.h>
45 #include <gudev/gudev.h>
46
47 #include "nm-utils.h"
48 #include "nm-core-internal.h"
49 #include "nm-setting-vlan.h"
50
51 #include "nm-core-utils.h"
52 #include "nmp-object.h"
53 #include "nmp-netns.h"
54 #include "nm-platform-utils.h"
55 #include "wifi/wifi-utils.h"
56 #include "wifi/wifi-utils-wext.h"
57
58 #define VLAN_FLAG_MVRP 0x8
59
60 /* nm-internal error codes for libnl. Make sure they don't overlap. */
61 #define _NLE_NM_NOBUFS 500
62
63 /*********************************************************************************************/
64
65 #define IFQDISCSIZ                      32
66
67 /*********************************************************************************************/
68
69 #ifndef IFLA_PROMISCUITY
70 #define IFLA_PROMISCUITY                30
71 #endif
72 #define IFLA_NUM_TX_QUEUES              31
73 #define IFLA_NUM_RX_QUEUES              32
74 #define IFLA_CARRIER                    33
75 #define IFLA_PHYS_PORT_ID               34
76 #define IFLA_LINK_NETNSID               37
77 #define __IFLA_MAX                      39
78
79 #define IFLA_INET6_TOKEN                7
80 #define IFLA_INET6_ADDR_GEN_MODE        8
81 #define __IFLA_INET6_MAX                9
82
83 #define IFLA_VLAN_PROTOCOL              5
84 #define __IFLA_VLAN_MAX                 6
85
86 #define IFA_FLAGS                       8
87 #define __IFA_MAX                       9
88
89 #define IFLA_MACVLAN_FLAGS              2
90 #define __IFLA_MACVLAN_MAX              3
91
92 #define IFLA_IPTUN_LINK                 1
93 #define IFLA_IPTUN_LOCAL                2
94 #define IFLA_IPTUN_REMOTE               3
95 #define IFLA_IPTUN_TTL                  4
96 #define IFLA_IPTUN_TOS                  5
97 #define IFLA_IPTUN_ENCAP_LIMIT          6
98 #define IFLA_IPTUN_FLOWINFO             7
99 #define IFLA_IPTUN_FLAGS                8
100 #define IFLA_IPTUN_PROTO                9
101 #define IFLA_IPTUN_PMTUDISC             10
102 #define __IFLA_IPTUN_MAX                19
103 #ifndef IFLA_IPTUN_MAX
104 #define IFLA_IPTUN_MAX                  (__IFLA_IPTUN_MAX - 1)
105 #endif
106
107 #ifndef MACVLAN_FLAG_NOPROMISC
108 #define MACVLAN_FLAG_NOPROMISC          1
109 #endif
110
111 #define IP6_FLOWINFO_TCLASS_MASK        0x0FF00000
112 #define IP6_FLOWINFO_TCLASS_SHIFT       20
113 #define IP6_FLOWINFO_FLOWLABEL_MASK     0x000FFFFF
114
115 /*********************************************************************************************/
116
117 #define _NMLOG_PREFIX_NAME                "platform-linux"
118 #define _NMLOG_DOMAIN                     LOGD_PLATFORM
119 #define _NMLOG2_DOMAIN                    LOGD_PLATFORM
120 #define _NMLOG(level, ...)                _LOG     (       level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)
121 #define _NMLOG_err(errsv, level, ...)     _LOG_err (errsv, level, _NMLOG_DOMAIN,  platform, __VA_ARGS__)
122 #define _NMLOG2(level, ...)               _LOG     (       level, _NMLOG2_DOMAIN, NULL,     __VA_ARGS__)
123 #define _NMLOG2_err(errsv, level, ...)    _LOG_err (errsv, level, _NMLOG2_DOMAIN, NULL,     __VA_ARGS__)
124
125
126 #define _LOG_print(__level, __domain, __errsv, self, ...) \
127     G_STMT_START { \
128         char __prefix[32]; \
129         const char *__p_prefix = _NMLOG_PREFIX_NAME; \
130         const void *const __self = (self); \
131         \
132         if (__self && __self != nm_platform_try_get ()) { \
133             g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
134             __p_prefix = __prefix; \
135         } \
136         _nm_log (__level, __domain, __errsv, \
137                  "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
138                  __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
139     } G_STMT_END
140
141 #define _LOG(level, domain, self, ...) \
142     G_STMT_START { \
143         const NMLogLevel __level = (level); \
144         const NMLogDomain __domain = (domain); \
145         \
146         if (nm_logging_enabled (__level, __domain)) { \
147             _LOG_print (__level, __domain, 0, self, __VA_ARGS__); \
148         } \
149     } G_STMT_END
150
151 #define _LOG_err(errsv, level, domain, self, ...) \
152     G_STMT_START { \
153         const NMLogLevel __level = (level); \
154         const NMLogDomain __domain = (domain); \
155         \
156         if (nm_logging_enabled (__level, __domain)) { \
157             int __errsv = (errsv); \
158             \
159             /* The %m format specifier (GNU extension) would alread allow you to specify the error
160              * message conveniently (and nm_log would get that right too). But we don't want to depend
161              * on that, so instead append the message at the end.
162              * Currently users are expected not to use %m in the format string. */ \
163             _LOG_print (__level, __domain, __errsv, self, \
164                         _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \
165                         _NM_UTILS_MACRO_REST (__VA_ARGS__), \
166                         g_strerror (__errsv), __errsv); \
167         } \
168     } G_STMT_END
169
170
171 #define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s"
172
173 /******************************************************************
174  * Forward declarations and enums
175  ******************************************************************/
176
177 typedef enum {
178         DELAYED_ACTION_TYPE_NONE                        = 0,
179         DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS           = (1LL << 0),
180         DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES   = (1LL << 1),
181         DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES   = (1LL << 2),
182         DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES      = (1LL << 3),
183         DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES      = (1LL << 4),
184         DELAYED_ACTION_TYPE_REFRESH_LINK                = (1LL << 5),
185         DELAYED_ACTION_TYPE_MASTER_CONNECTED            = (1LL << 6),
186         DELAYED_ACTION_TYPE_READ_NETLINK                = (1LL << 7),
187         DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE        = (1LL << 8),
188         __DELAYED_ACTION_TYPE_MAX,
189
190         DELAYED_ACTION_TYPE_REFRESH_ALL                 = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
191                                                           DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
192                                                           DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
193                                                           DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
194                                                           DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
195
196         DELAYED_ACTION_TYPE_MAX                         = __DELAYED_ACTION_TYPE_MAX -1,
197 } DelayedActionType;
198
199 typedef enum {
200         /* Negative values are errors from kernel. Add dummy member to
201          * make enum signed. */
202         _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = -1,
203
204         WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN = 0,
205         WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK,
206         WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN,
207         WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC,
208         WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL,
209         WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT,
210         WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING,
211 } WaitForNlResponseResult;
212
213 typedef void (*WaitForNlResponseCallback) (NMPlatform *platform,
214                                            guint32 seq_number,
215                                            WaitForNlResponseResult seq_result,
216                                            gpointer user_data);
217
218 static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data);
219 static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink);
220 static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name);
221 static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type);
222 static void cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
223 static void cache_prune_candidates_prune (NMPlatform *platform);
224 static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks);
225 static void _assert_netns_current (NMPlatform *platform);
226
227 /*****************************************************************************/
228
229 static const char *
230 wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, char *buf, gsize buf_size)
231 {
232         char *buf0 = buf;
233
234         switch (seq_result) {
235         case WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN:
236                 nm_utils_strbuf_append_str (&buf, &buf_size, "unknown");
237                 break;
238         case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK:
239                 nm_utils_strbuf_append_str (&buf, &buf_size, "success");
240                 break;
241         case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN:
242                 nm_utils_strbuf_append_str (&buf, &buf_size, "failure");
243                 break;
244         default:
245                 if (seq_result < 0)
246                         nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s)", -((int) seq_result), g_strerror (-((int) seq_result)));
247                 else
248                         nm_utils_strbuf_append (&buf, &buf_size, "internal failure %d", (int) seq_result);
249                 break;
250         }
251         return buf0;
252 }
253
254 /******************************************************************
255  * Support IFLA_INET6_ADDR_GEN_MODE
256  ******************************************************************/
257
258 static int _support_user_ipv6ll = 0;
259 #define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0))
260
261 static gboolean
262 _support_user_ipv6ll_get (void)
263 {
264         if (_support_user_ipv6ll_still_undecided ()) {
265                 _support_user_ipv6ll = -1;
266                 _LOG2W ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "failed to detect; assume no support");
267                 return FALSE;
268         }
269         return _support_user_ipv6ll > 0;
270
271 }
272
273 static void
274 _support_user_ipv6ll_detect (struct nlattr **tb)
275 {
276         if (_support_user_ipv6ll_still_undecided ()) {
277                 if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
278                         _support_user_ipv6ll = 1;
279                         _LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "detected");
280                 } else {
281                         _support_user_ipv6ll = -1;
282                         _LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "not detected");
283                 }
284         }
285 }
286
287 /******************************************************************
288  * Various utilities
289  ******************************************************************/
290
291 static guint
292 _nm_ip_config_source_to_rtprot (NMIPConfigSource source)
293 {
294         switch (source) {
295         case NM_IP_CONFIG_SOURCE_UNKNOWN:
296                 return RTPROT_UNSPEC;
297         case NM_IP_CONFIG_SOURCE_KERNEL:
298         case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
299                 return RTPROT_KERNEL;
300         case NM_IP_CONFIG_SOURCE_DHCP:
301                 return RTPROT_DHCP;
302         case NM_IP_CONFIG_SOURCE_RDISC:
303                 return RTPROT_RA;
304
305         default:
306                 return RTPROT_STATIC;
307         }
308 }
309
310 static NMIPConfigSource
311 _nm_ip_config_source_from_rtprot (guint rtprot)
312 {
313         switch (rtprot) {
314         case RTPROT_UNSPEC:
315                 return NM_IP_CONFIG_SOURCE_UNKNOWN;
316         case RTPROT_KERNEL:
317                 return NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
318         case RTPROT_REDIRECT:
319                 return NM_IP_CONFIG_SOURCE_KERNEL;
320         case RTPROT_RA:
321                 return NM_IP_CONFIG_SOURCE_RDISC;
322         case RTPROT_DHCP:
323                 return NM_IP_CONFIG_SOURCE_DHCP;
324
325         default:
326                 return NM_IP_CONFIG_SOURCE_USER;
327         }
328 }
329
330 static void
331 clear_host_address (int family, const void *network, int plen, void *dst)
332 {
333         g_return_if_fail (plen == (guint8)plen);
334         g_return_if_fail (network);
335
336         switch (family) {
337         case AF_INET:
338                 *((in_addr_t *) dst) = nm_utils_ip4_address_clear_host_address (*((in_addr_t *) network), plen);
339                 break;
340         case AF_INET6:
341                 nm_utils_ip6_address_clear_host_address ((struct in6_addr *) dst, (const struct in6_addr *) network, plen);
342                 break;
343         default:
344                 g_assert_not_reached ();
345         }
346 }
347
348 static int
349 _vlan_qos_mapping_cmp_from (gconstpointer a, gconstpointer b, gpointer user_data)
350 {
351         const NMVlanQosMapping *map_a = a;
352         const NMVlanQosMapping *map_b = b;
353
354         if (map_a->from != map_b->from)
355                 return map_a->from < map_b->from ? -1 : 1;
356         return 0;
357 }
358
359 static int
360 _vlan_qos_mapping_cmp_from_ptr (gconstpointer a, gconstpointer b, gpointer user_data)
361 {
362         return _vlan_qos_mapping_cmp_from (*((const NMVlanQosMapping **) a),
363                                            *((const NMVlanQosMapping **) b),
364                                            NULL);
365 }
366
367 /******************************************************************
368  * NMLinkType functions
369  ******************************************************************/
370
371 typedef struct {
372         const NMLinkType nm_type;
373         const char *type_string;
374
375         /* IFLA_INFO_KIND / rtnl_link_get_type() where applicable; the rtnl type
376          * should only be specified if the device type can be created without
377          * additional parameters, and if the device type can be determined from
378          * the rtnl_type.  eg, tun/tap should not be specified since both
379          * tun and tap devices use "tun", and InfiniBand should not be
380          * specified because a PKey is required at creation. Drivers set this
381          * value from their 'struct rtnl_link_ops' structure.
382          */
383         const char *rtnl_type;
384
385         /* uevent DEVTYPE where applicable, from /sys/class/net/<ifname>/uevent;
386          * drivers set this value from their SET_NETDEV_DEV() call and the
387          * 'struct device_type' name member.
388          */
389         const char *devtype;
390 } LinkDesc;
391
392 static const LinkDesc linktypes[] = {
393         { NM_LINK_TYPE_NONE,          "none",        NULL,          NULL },
394         { NM_LINK_TYPE_UNKNOWN,       "unknown",     NULL,          NULL },
395
396         { NM_LINK_TYPE_ETHERNET,      "ethernet",    NULL,          NULL },
397         { NM_LINK_TYPE_INFINIBAND,    "infiniband",  NULL,          NULL },
398         { NM_LINK_TYPE_OLPC_MESH,     "olpc-mesh",   NULL,          NULL },
399         { NM_LINK_TYPE_WIFI,          "wifi",        NULL,          "wlan" },
400         { NM_LINK_TYPE_WWAN_ETHERNET, "wwan",        NULL,          "wwan" },
401         { NM_LINK_TYPE_WIMAX,         "wimax",       "wimax",       "wimax" },
402
403         { NM_LINK_TYPE_DUMMY,         "dummy",       "dummy",       NULL },
404         { NM_LINK_TYPE_GRE,           "gre",         "gre",         NULL },
405         { NM_LINK_TYPE_GRETAP,        "gretap",      "gretap",      NULL },
406         { NM_LINK_TYPE_IFB,           "ifb",         "ifb",         NULL },
407         { NM_LINK_TYPE_IP6TNL,        "ip6tnl",      "ip6tnl",      NULL },
408         { NM_LINK_TYPE_IPIP,          "ipip",        "ipip",        NULL },
409         { NM_LINK_TYPE_LOOPBACK,      "loopback",    NULL,          NULL },
410         { NM_LINK_TYPE_MACVLAN,       "macvlan",     "macvlan",     NULL },
411         { NM_LINK_TYPE_MACVTAP,       "macvtap",     "macvtap",     NULL },
412         { NM_LINK_TYPE_OPENVSWITCH,   "openvswitch", "openvswitch", NULL },
413         { NM_LINK_TYPE_SIT,           "sit",         "sit",         NULL },
414         { NM_LINK_TYPE_TAP,           "tap",         NULL,          NULL },
415         { NM_LINK_TYPE_TUN,           "tun",         NULL,          NULL },
416         { NM_LINK_TYPE_VETH,          "veth",        "veth",        NULL },
417         { NM_LINK_TYPE_VLAN,          "vlan",        "vlan",        "vlan" },
418         { NM_LINK_TYPE_VXLAN,         "vxlan",       "vxlan",       "vxlan" },
419         { NM_LINK_TYPE_BNEP,          "bluetooth",   NULL,          "bluetooth" },
420
421         { NM_LINK_TYPE_BRIDGE,        "bridge",      "bridge",      "bridge" },
422         { NM_LINK_TYPE_BOND,          "bond",        "bond",        "bond" },
423         { NM_LINK_TYPE_TEAM,          "team",        "team",        NULL },
424 };
425
426 static const char *
427 nm_link_type_to_rtnl_type_string (NMLinkType type)
428 {
429         int i;
430
431         for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
432                 if (type == linktypes[i].nm_type)
433                         return linktypes[i].rtnl_type;
434         }
435         g_return_val_if_reached (NULL);
436 }
437
438 const char *
439 nm_link_type_to_string (NMLinkType type)
440 {
441         int i;
442
443         for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
444                 if (type == linktypes[i].nm_type)
445                         return linktypes[i].type_string;
446         }
447         g_return_val_if_reached (NULL);
448 }
449
450 /******************************************************************
451  * Utilities
452  ******************************************************************/
453
454 /* _timestamp_nl_to_ms:
455  * @timestamp_nl: a timestamp from ifa_cacheinfo.
456  * @monotonic_ms: *now* in CLOCK_MONOTONIC. Needed to estimate the current
457  * uptime and how often timestamp_nl wrapped.
458  *
459  * Convert the timestamp from ifa_cacheinfo to CLOCK_MONOTONIC milliseconds.
460  * The ifa_cacheinfo fields tstamp and cstamp contains timestamps that counts
461  * with in 1/100th of a second of clock_gettime(CLOCK_MONOTONIC). However,
462  * the uint32 counter wraps every 497 days of uptime, so we have to compensate
463  * for that. */
464 static gint64
465 _timestamp_nl_to_ms (guint32 timestamp_nl, gint64 monotonic_ms)
466 {
467         const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100);
468         gint64 timestamp_nl_ms;
469
470         /* convert timestamp from 1/100th of a second to msec. */
471         timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100);
472
473         /* timestamp wraps every 497 days. Try to compensate for that.*/
474         if (timestamp_nl_ms > monotonic_ms) {
475                 /* timestamp_nl_ms is in the future. Truncate it to *now* */
476                 timestamp_nl_ms = monotonic_ms;
477         } else if (monotonic_ms >= WRAP_INTERVAL) {
478                 timestamp_nl_ms += (monotonic_ms / WRAP_INTERVAL) * WRAP_INTERVAL;
479                 if (timestamp_nl_ms > monotonic_ms)
480                         timestamp_nl_ms -= WRAP_INTERVAL;
481         }
482
483         return timestamp_nl_ms;
484 }
485
486 static guint32
487 _addrtime_timestamp_to_nm (guint32 timestamp, gint32 *out_now_nm)
488 {
489         struct timespec tp;
490         gint64 now_nl, now_nm, result;
491         int err;
492
493         /* timestamp is unset. Default to 1. */
494         if (!timestamp) {
495                 if (out_now_nm)
496                         *out_now_nm = 0;
497                 return 1;
498         }
499
500         /* do all the calculations in milliseconds scale */
501
502         err = clock_gettime (CLOCK_MONOTONIC, &tp);
503         g_assert (err == 0);
504         now_nm = nm_utils_get_monotonic_timestamp_ms ();
505         now_nl = (((gint64) tp.tv_sec) * ((gint64) 1000)) +
506                  (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000));
507
508         result = now_nm - (now_nl - _timestamp_nl_to_ms (timestamp, now_nl));
509
510         if (out_now_nm)
511                 *out_now_nm = now_nm / 1000;
512
513         /* converting the timestamp into nm_utils_get_monotonic_timestamp_ms() scale is
514          * a good guess but fails in the following situations:
515          *
516          * - If the address existed before start of the process, the timestamp in nm scale would
517          *   be negative or zero. In this case we default to 1.
518          * - during hibernation, the CLOCK_MONOTONIC/timestamp drifts from
519          *   nm_utils_get_monotonic_timestamp_ms() scale.
520          */
521         if (result <= 1000)
522                 return 1;
523
524         if (result > now_nm)
525                 return now_nm / 1000;
526
527         return result / 1000;
528 }
529
530 static guint32
531 _addrtime_extend_lifetime (guint32 lifetime, guint32 seconds)
532 {
533         guint64 v;
534
535         if (   lifetime == NM_PLATFORM_LIFETIME_PERMANENT
536             || seconds == 0)
537                 return lifetime;
538
539         v = (guint64) lifetime + (guint64) seconds;
540         return MIN (v, NM_PLATFORM_LIFETIME_PERMANENT - 1);
541 }
542
543 /* The rtnl_addr object contains relative lifetimes @valid and @preferred
544  * that count in seconds, starting from the moment when the kernel constructed
545  * the netlink message.
546  *
547  * There is also a field rtnl_addr_last_update_time(), which is the absolute
548  * time in 1/100th of a second of clock_gettime (CLOCK_MONOTONIC) when the address
549  * was modified (wrapping every 497 days).
550  * Immediately at the time when the address was last modified, #NOW and @last_update_time
551  * are the same, so (only) in that case @valid and @preferred are anchored at @last_update_time.
552  * However, this is not true in general. As time goes by, whenever kernel sends a new address
553  * via netlink, the lifetimes keep counting down.
554  **/
555 static void
556 _addrtime_get_lifetimes (guint32 timestamp,
557                          guint32 lifetime,
558                          guint32 preferred,
559                          guint32 *out_timestamp,
560                          guint32 *out_lifetime,
561                          guint32 *out_preferred)
562 {
563         gint32 now;
564
565         if (   lifetime != NM_PLATFORM_LIFETIME_PERMANENT
566             || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
567                 if (preferred > lifetime)
568                         preferred = lifetime;
569                 timestamp = _addrtime_timestamp_to_nm (timestamp, &now);
570
571                 if (now == 0) {
572                         /* strange. failed to detect the last-update time and assumed that timestamp is 1. */
573                         nm_assert (timestamp == 1);
574                         now = nm_utils_get_monotonic_timestamp_s ();
575                 }
576                 if (timestamp < now) {
577                         guint32 diff = now - timestamp;
578
579                         lifetime = _addrtime_extend_lifetime (lifetime, diff);
580                         preferred = _addrtime_extend_lifetime (preferred, diff);
581                 } else
582                         nm_assert (timestamp == now);
583         } else
584                 timestamp = 0;
585         *out_timestamp = timestamp;
586         *out_lifetime = lifetime;
587         *out_preferred = preferred;
588 }
589
590 /******************************************************************/
591
592 static const NMPObject *
593 _lookup_cached_link (const NMPCache *cache, int ifindex, gboolean *completed_from_cache, const NMPObject **link_cached)
594 {
595         const NMPObject *obj;
596
597         nm_assert (completed_from_cache && link_cached);
598
599         if (!*completed_from_cache) {
600                 obj = ifindex > 0 && cache ? nmp_cache_lookup_link (cache, ifindex) : NULL;
601
602                 if (obj && obj->_link.netlink.is_in_netlink)
603                         *link_cached = obj;
604                 else
605                         *link_cached = NULL;
606                 *completed_from_cache = TRUE;
607         }
608         return *link_cached;
609 }
610
611 /******************************************************************/
612
613 #define DEVTYPE_PREFIX "DEVTYPE="
614
615 static char *
616 _linktype_read_devtype (const char *sysfs_path)
617 {
618         gs_free char *uevent = g_strdup_printf ("%s/uevent", sysfs_path);
619         char *contents = NULL;
620         char *cont, *end;
621
622         if (!g_file_get_contents (uevent, &contents, NULL, NULL))
623                 return NULL;
624         for (cont = contents; cont; cont = end) {
625                 end = strpbrk (cont, "\r\n");
626                 if (end)
627                         *end++ = '\0';
628                 if (strncmp (cont, DEVTYPE_PREFIX, NM_STRLEN (DEVTYPE_PREFIX)) == 0) {
629                         cont += NM_STRLEN (DEVTYPE_PREFIX);
630                         memmove (contents, cont, strlen (cont) + 1);
631                         return contents;
632                 }
633         }
634         g_free (contents);
635         return NULL;
636 }
637
638 static NMLinkType
639 _linktype_get_type (NMPlatform *platform,
640                     const NMPCache *cache,
641                     const char *kind,
642                     int ifindex,
643                     const char *ifname,
644                     unsigned flags,
645                     unsigned arptype,
646                     gboolean *completed_from_cache,
647                     const NMPObject **link_cached,
648                     const char **out_kind)
649 {
650         guint i;
651
652         _assert_netns_current (platform);
653
654         if (completed_from_cache) {
655                 const NMPObject *obj;
656
657                 obj = _lookup_cached_link (cache, ifindex, completed_from_cache, link_cached);
658
659                 /* If we detected the link type before, we stick to that
660                  * decision unless the "kind" changed.
661                  *
662                  * This way, we save edditional ethtool/sysctl lookups, but moreover,
663                  * we keep the linktype stable and don't change it as long as the link
664                  * exists.
665                  *
666                  * Note that kernel *can* reuse the ifindex (on integer overflow, and
667                  * when moving interfce to other netns). Thus here there is a tiny potential
668                  * of messing stuff up. */
669                 if (   obj
670                     && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE)
671                     && (   !kind
672                         || !g_strcmp0 (kind, obj->link.kind))) {
673                         nm_assert (obj->link.kind == g_intern_string (obj->link.kind));
674                         *out_kind = obj->link.kind;
675                         return obj->link.type;
676                 }
677         }
678
679         *out_kind = g_intern_string (kind);
680
681         if (kind) {
682                 for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
683                         if (g_strcmp0 (kind, linktypes[i].rtnl_type) == 0)
684                                 return linktypes[i].nm_type;
685                 }
686
687                 if (!strcmp (kind, "tun")) {
688                         NMPlatformTunProperties props;
689
690                         if (   platform
691                             && nm_platform_link_tun_get_properties_ifname (platform, ifname, &props)) {
692                                 if (!g_strcmp0 (props.mode, "tap"))
693                                         return NM_LINK_TYPE_TAP;
694                                 if (!g_strcmp0 (props.mode, "tun"))
695                                         return NM_LINK_TYPE_TUN;
696                         }
697
698                         /* try guessing the type using the link flags instead... */
699                         if (flags & IFF_POINTOPOINT)
700                                 return NM_LINK_TYPE_TUN;
701                         return NM_LINK_TYPE_TAP;
702                 }
703         }
704
705         if (arptype == ARPHRD_LOOPBACK)
706                 return NM_LINK_TYPE_LOOPBACK;
707         else if (arptype == ARPHRD_INFINIBAND)
708                 return NM_LINK_TYPE_INFINIBAND;
709         else if (arptype == ARPHRD_SIT)
710                 return NM_LINK_TYPE_SIT;
711         else if (arptype == ARPHRD_TUNNEL6)
712                 return NM_LINK_TYPE_IP6TNL;
713
714         if (ifname) {
715                 gs_free char *driver = NULL;
716                 gs_free char *sysfs_path = NULL;
717                 gs_free char *anycast_mask = NULL;
718                 gs_free char *devtype = NULL;
719
720                 /* Fallback OVS detection for kernel <= 3.16 */
721                 if (nmp_utils_ethtool_get_driver_info (ifname, &driver, NULL, NULL)) {
722                         if (!g_strcmp0 (driver, "openvswitch"))
723                                 return NM_LINK_TYPE_OPENVSWITCH;
724
725                         if (arptype == 256) {
726                                 /* Some s390 CTC-type devices report 256 for the encapsulation type
727                                  * for some reason, but we need to call them Ethernet.
728                                  */
729                                 if (!g_strcmp0 (driver, "ctcm"))
730                                         return NM_LINK_TYPE_ETHERNET;
731                         }
732                 }
733
734                 sysfs_path = g_strdup_printf ("/sys/class/net/%s", ifname);
735                 anycast_mask = g_strdup_printf ("%s/anycast_mask", sysfs_path);
736                 if (g_file_test (anycast_mask, G_FILE_TEST_EXISTS))
737                         return NM_LINK_TYPE_OLPC_MESH;
738
739                 devtype = _linktype_read_devtype (sysfs_path);
740                 for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) {
741                         if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) {
742                                 if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) {
743                                         /* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must
744                                          * use arptype to distinguish between them.
745                                          */
746                                         if (arptype != ARPHRD_ETHER)
747                                                 continue;
748                                 }
749                                 return linktypes[i].nm_type;
750                         }
751                 }
752
753                 /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
754                 if (wifi_utils_is_wifi (ifname, sysfs_path))
755                         return NM_LINK_TYPE_WIFI;
756
757                 if (arptype == ARPHRD_ETHER) {
758                         /* Standard wired ethernet interfaces don't report an rtnl_link_type, so
759                          * only allow fallback to Ethernet if no type is given.  This should
760                          * prevent future virtual network drivers from being treated as Ethernet
761                          * when they should be Generic instead.
762                          */
763                         if (!kind && !devtype)
764                                 return NM_LINK_TYPE_ETHERNET;
765                         /* The USB gadget interfaces behave and look like ordinary ethernet devices
766                          * aside from the DEVTYPE. */
767                         if (!g_strcmp0 (devtype, "gadget"))
768                                 return NM_LINK_TYPE_ETHERNET;
769                 }
770         }
771
772         return NM_LINK_TYPE_UNKNOWN;
773 }
774
775 /******************************************************************
776  * libnl unility functions and wrappers
777  ******************************************************************/
778
779 #define nm_auto_nlmsg __attribute__((cleanup(_nm_auto_nl_msg_cleanup)))
780 static void
781 _nm_auto_nl_msg_cleanup (void *ptr)
782 {
783         nlmsg_free (*((struct nl_msg **) ptr));
784 }
785
786 static const char *
787 _nl_nlmsg_type_to_str (guint16 type, char *buf, gsize len)
788 {
789         const char *str_type = NULL;
790
791         switch (type) {
792         case RTM_NEWLINK:  str_type = "NEWLINK";  break;
793         case RTM_DELLINK:  str_type = "DELLINK";  break;
794         case RTM_NEWADDR:  str_type = "NEWADDR";  break;
795         case RTM_DELADDR:  str_type = "DELADDR";  break;
796         case RTM_NEWROUTE: str_type = "NEWROUTE"; break;
797         case RTM_DELROUTE: str_type = "DELROUTE"; break;
798         }
799         if (str_type)
800                 g_strlcpy (buf, str_type, len);
801         else
802                 g_snprintf (buf, len, "(%d)", type);
803         return buf;
804 }
805
806 /******************************************************************
807  * NMPObject/netlink functions
808  ******************************************************************/
809
810 #define _check_addr_or_errout(tb, attr, addr_len) \
811         ({ \
812             const struct nlattr *__t = (tb)[(attr)]; \
813                 \
814             if (__t) { \
815                         if (nla_len (__t) != (addr_len)) { \
816                                 goto errout; \
817                         } \
818                 } \
819                 !!__t; \
820         })
821
822 /*****************************************************************************/
823
824 /* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */
825 static gboolean
826 _parse_af_inet6 (NMPlatform *platform,
827                  struct nlattr *attr,
828                  NMUtilsIPv6IfaceId *out_iid,
829                  guint8 *out_iid_is_valid,
830                  guint8 *out_addr_gen_mode_inv)
831 {
832         static struct nla_policy policy[IFLA_INET6_MAX+1] = {
833                 [IFLA_INET6_FLAGS]              = { .type = NLA_U32 },
834                 [IFLA_INET6_CACHEINFO]          = { .minlen = sizeof(struct ifla_cacheinfo) },
835                 [IFLA_INET6_CONF]               = { .minlen = 4 },
836                 [IFLA_INET6_STATS]              = { .minlen = 8 },
837                 [IFLA_INET6_ICMP6STATS]         = { .minlen = 8 },
838                 [IFLA_INET6_TOKEN]              = { .minlen = sizeof(struct in6_addr) },
839                 [IFLA_INET6_ADDR_GEN_MODE]      = { .type = NLA_U8 },
840         };
841         struct nlattr *tb[IFLA_INET6_MAX+1];
842         int err;
843         struct in6_addr i6_token;
844         gboolean iid_is_valid = FALSE;
845         guint8 i6_addr_gen_mode_inv = 0;
846         gboolean success = FALSE;
847
848         err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy);
849         if (err < 0)
850                 goto errout;
851
852         if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4)
853                 goto errout;
854         if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8)
855                 goto errout;
856         if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8)
857                 goto errout;
858
859         if (_check_addr_or_errout (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr))) {
860                 nla_memcpy (&i6_token, tb[IFLA_INET6_TOKEN], sizeof (struct in6_addr));
861                 if (!IN6_IS_ADDR_UNSPECIFIED (&i6_token))
862                         iid_is_valid = TRUE;
863         }
864
865         /* Hack to detect support addrgenmode of the kernel. We only parse
866          * netlink messages that we receive from kernel, hence this check
867          * is valid. */
868         _support_user_ipv6ll_detect (tb);
869
870         if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
871                 i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]));
872                 if (i6_addr_gen_mode_inv == 0) {
873                         /* an inverse addrgenmode of zero is unexpected. We need to reserve zero
874                          * to signal "unset". */
875                         goto errout;
876                 }
877         }
878
879         success = TRUE;
880         if (iid_is_valid) {
881                 out_iid->id_u8[7] = i6_token.s6_addr[15];
882                 out_iid->id_u8[6] = i6_token.s6_addr[14];
883                 out_iid->id_u8[5] = i6_token.s6_addr[13];
884                 out_iid->id_u8[4] = i6_token.s6_addr[12];
885                 out_iid->id_u8[3] = i6_token.s6_addr[11];
886                 out_iid->id_u8[2] = i6_token.s6_addr[10];
887                 out_iid->id_u8[1] = i6_token.s6_addr[9];
888                 out_iid->id_u8[0] = i6_token.s6_addr[8];
889                 *out_iid_is_valid = TRUE;
890         }
891         *out_addr_gen_mode_inv = i6_addr_gen_mode_inv;
892 errout:
893         return success;
894 }
895
896 /*****************************************************************************/
897
898 static NMPObject *
899 _parse_lnk_gre (const char *kind, struct nlattr *info_data)
900 {
901         static struct nla_policy policy[IFLA_GRE_MAX + 1] = {
902                 [IFLA_GRE_LINK]     = { .type = NLA_U32 },
903                 [IFLA_GRE_IFLAGS]   = { .type = NLA_U16 },
904                 [IFLA_GRE_OFLAGS]   = { .type = NLA_U16 },
905                 [IFLA_GRE_IKEY]     = { .type = NLA_U32 },
906                 [IFLA_GRE_OKEY]     = { .type = NLA_U32 },
907                 [IFLA_GRE_LOCAL]    = { .type = NLA_U32 },
908                 [IFLA_GRE_REMOTE]   = { .type = NLA_U32 },
909                 [IFLA_GRE_TTL]      = { .type = NLA_U8 },
910                 [IFLA_GRE_TOS]      = { .type = NLA_U8 },
911                 [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
912         };
913         struct nlattr *tb[IFLA_GRE_MAX + 1];
914         int err;
915         NMPObject *obj;
916         NMPlatformLnkGre *props;
917
918         if (!info_data || g_strcmp0 (kind, "gre"))
919                 return NULL;
920
921         err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy);
922         if (err < 0)
923                 return NULL;
924
925         obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_GRE, NULL);
926         props = &obj->lnk_gre;
927
928         props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0;
929         props->input_flags = tb[IFLA_GRE_IFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS])) : 0;
930         props->output_flags = tb[IFLA_GRE_OFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS])) : 0;
931         props->input_key = tb[IFLA_GRE_IKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY])) : 0;
932         props->output_key = tb[IFLA_GRE_OKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])) : 0;
933         props->local = tb[IFLA_GRE_LOCAL] ? nla_get_u32 (tb[IFLA_GRE_LOCAL]) : 0;
934         props->remote = tb[IFLA_GRE_REMOTE] ? nla_get_u32 (tb[IFLA_GRE_REMOTE]) : 0;
935         props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0;
936         props->ttl = tb[IFLA_GRE_TTL] ? nla_get_u8 (tb[IFLA_GRE_TTL]) : 0;
937         props->path_mtu_discovery = !tb[IFLA_GRE_PMTUDISC] || !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]);
938
939         return obj;
940 }
941
942 /*****************************************************************************/
943
944 /* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers
945  * we're building against might not have those properties even though the
946  * running kernel might.
947  */
948 #define IFLA_IPOIB_UNSPEC 0
949 #define IFLA_IPOIB_PKEY   1
950 #define IFLA_IPOIB_MODE   2
951 #define IFLA_IPOIB_UMCAST 3
952 #undef IFLA_IPOIB_MAX
953 #define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST
954
955 #define IPOIB_MODE_DATAGRAM  0 /* using unreliable datagram QPs */
956 #define IPOIB_MODE_CONNECTED 1 /* using connected QPs */
957
958 static NMPObject *
959 _parse_lnk_infiniband (const char *kind, struct nlattr *info_data)
960 {
961         static struct nla_policy policy[IFLA_IPOIB_MAX + 1] = {
962                 [IFLA_IPOIB_PKEY]   = { .type = NLA_U16 },
963                 [IFLA_IPOIB_MODE]   = { .type = NLA_U16 },
964                 [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 },
965         };
966         struct nlattr *tb[IFLA_IPOIB_MAX + 1];
967         NMPlatformLnkInfiniband *info;
968         NMPObject *obj;
969         int err;
970         const char *mode;
971
972         if (!info_data || g_strcmp0 (kind, "ipoib"))
973                 return NULL;
974
975         err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, policy);
976         if (err < 0)
977                 return NULL;
978
979         if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE])
980                 return NULL;
981
982         switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) {
983         case IPOIB_MODE_DATAGRAM:
984                 mode = "datagram";
985                 break;
986         case IPOIB_MODE_CONNECTED:
987                 mode = "connected";
988                 break;
989         default:
990                 return NULL;
991         }
992
993         obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL);
994         info = &obj->lnk_infiniband;
995
996         info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]);
997         info->mode = mode;
998
999         return obj;
1000 }
1001
1002 /*****************************************************************************/
1003
1004 static NMPObject *
1005 _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data)
1006 {
1007         static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
1008                 [IFLA_IPTUN_LINK]        = { .type = NLA_U32 },
1009                 [IFLA_IPTUN_LOCAL]       = { .type = NLA_UNSPEC,
1010                                              .minlen = sizeof (struct in6_addr)},
1011                 [IFLA_IPTUN_REMOTE]      = { .type = NLA_UNSPEC,
1012                                              .minlen = sizeof (struct in6_addr)},
1013                 [IFLA_IPTUN_TTL]         = { .type = NLA_U8 },
1014                 [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 },
1015                 [IFLA_IPTUN_FLOWINFO]    = { .type = NLA_U32 },
1016                 [IFLA_IPTUN_PROTO]       = { .type = NLA_U8 },
1017         };
1018         struct nlattr *tb[IFLA_IPTUN_MAX + 1];
1019         int err;
1020         NMPObject *obj;
1021         NMPlatformLnkIp6Tnl *props;
1022         guint32 flowinfo;
1023
1024         if (!info_data || g_strcmp0 (kind, "ip6tnl"))
1025                 return NULL;
1026
1027         err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
1028         if (err < 0)
1029                 return NULL;
1030
1031         obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL);
1032         props = &obj->lnk_ip6tnl;
1033
1034         if (tb[IFLA_IPTUN_LINK])
1035                 props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]);
1036         if (tb[IFLA_IPTUN_LOCAL])
1037                 memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local));
1038         if (tb[IFLA_IPTUN_REMOTE])
1039                 memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote));
1040         if (tb[IFLA_IPTUN_TTL])
1041                 props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]);
1042         if (tb[IFLA_IPTUN_ENCAP_LIMIT])
1043                 props->encap_limit = nla_get_u8 (tb[IFLA_IPTUN_ENCAP_LIMIT]);
1044         if (tb[IFLA_IPTUN_FLOWINFO]) {
1045                 flowinfo = ntohl (nla_get_u32 (tb[IFLA_IPTUN_FLOWINFO]));
1046                 props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK;
1047                 props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT;
1048         }
1049         if (tb[IFLA_IPTUN_PROTO])
1050                 props->proto = nla_get_u8 (tb[IFLA_IPTUN_PROTO]);
1051
1052         return obj;
1053 }
1054
1055 /*****************************************************************************/
1056
1057 static NMPObject *
1058 _parse_lnk_ipip (const char *kind, struct nlattr *info_data)
1059 {
1060         static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
1061                 [IFLA_IPTUN_LINK]     = { .type = NLA_U32 },
1062                 [IFLA_IPTUN_LOCAL]    = { .type = NLA_U32 },
1063                 [IFLA_IPTUN_REMOTE]   = { .type = NLA_U32 },
1064                 [IFLA_IPTUN_TTL]      = { .type = NLA_U8 },
1065                 [IFLA_IPTUN_TOS]      = { .type = NLA_U8 },
1066                 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
1067         };
1068         struct nlattr *tb[IFLA_IPTUN_MAX + 1];
1069         int err;
1070         NMPObject *obj;
1071         NMPlatformLnkIpIp *props;
1072
1073         if (!info_data || g_strcmp0 (kind, "ipip"))
1074                 return NULL;
1075
1076         err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
1077         if (err < 0)
1078                 return NULL;
1079
1080         obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IPIP, NULL);
1081         props = &obj->lnk_ipip;
1082
1083         props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0;
1084         props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0;
1085         props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0;
1086         props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0;
1087         props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0;
1088         props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]);
1089
1090         return obj;
1091 }
1092
1093 /*****************************************************************************/
1094
1095 static NMPObject *
1096 _parse_lnk_macvlan (const char *kind, struct nlattr *info_data)
1097 {
1098         static struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = {
1099                 [IFLA_MACVLAN_MODE]  = { .type = NLA_U32 },
1100                 [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
1101         };
1102         NMPlatformLnkMacvlan *props;
1103         struct nlattr *tb[IFLA_MACVLAN_MAX + 1];
1104         int err;
1105         NMPObject *obj;
1106         gboolean tap;
1107
1108         if (!info_data)
1109                 return NULL;
1110
1111         if (!g_strcmp0 (kind, "macvlan"))
1112                 tap = FALSE;
1113         else if (!g_strcmp0 (kind, "macvtap"))
1114                 tap = TRUE;
1115         else
1116                 return NULL;
1117
1118         err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, policy);
1119         if (err < 0)
1120                 return NULL;
1121
1122         if (!tb[IFLA_MACVLAN_MODE])
1123                 return NULL;
1124
1125         obj = nmp_object_new (tap ? NMP_OBJECT_TYPE_LNK_MACVTAP : NMP_OBJECT_TYPE_LNK_MACVLAN, NULL);
1126         props = &obj->lnk_macvlan;
1127         props->mode = nla_get_u32 (tb[IFLA_MACVLAN_MODE]);
1128         props->tap = tap;
1129
1130         if (tb[IFLA_MACVLAN_FLAGS])
1131                 props->no_promisc = NM_FLAGS_HAS (nla_get_u16 (tb[IFLA_MACVLAN_FLAGS]), MACVLAN_FLAG_NOPROMISC);
1132
1133         return obj;
1134 }
1135
1136 /*****************************************************************************/
1137
1138 static NMPObject *
1139 _parse_lnk_sit (const char *kind, struct nlattr *info_data)
1140 {
1141         static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = {
1142                 [IFLA_IPTUN_LINK]     = { .type = NLA_U32 },
1143                 [IFLA_IPTUN_LOCAL]    = { .type = NLA_U32 },
1144                 [IFLA_IPTUN_REMOTE]   = { .type = NLA_U32 },
1145                 [IFLA_IPTUN_TTL]      = { .type = NLA_U8 },
1146                 [IFLA_IPTUN_TOS]      = { .type = NLA_U8 },
1147                 [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
1148                 [IFLA_IPTUN_FLAGS]    = { .type = NLA_U16 },
1149                 [IFLA_IPTUN_PROTO]    = { .type = NLA_U8 },
1150         };
1151         struct nlattr *tb[IFLA_IPTUN_MAX + 1];
1152         int err;
1153         NMPObject *obj;
1154         NMPlatformLnkSit *props;
1155
1156         if (!info_data || g_strcmp0 (kind, "sit"))
1157                 return NULL;
1158
1159         err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy);
1160         if (err < 0)
1161                 return NULL;
1162
1163         obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_SIT, NULL);
1164         props = &obj->lnk_sit;
1165
1166         props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0;
1167         props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0;
1168         props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0;
1169         props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0;
1170         props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0;
1171         props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]);
1172         props->flags = tb[IFLA_IPTUN_FLAGS] ? nla_get_u16 (tb[IFLA_IPTUN_FLAGS]) : 0;
1173         props->proto = tb[IFLA_IPTUN_PROTO] ? nla_get_u8 (tb[IFLA_IPTUN_PROTO]) : 0;
1174
1175         return obj;
1176 }
1177
1178 /*****************************************************************************/
1179
1180 static gboolean
1181 _vlan_qos_mapping_from_nla (struct nlattr *nlattr,
1182                             const NMVlanQosMapping **out_map,
1183                             guint *out_n_map)
1184 {
1185         struct nlattr *nla;
1186         int remaining;
1187         gs_unref_ptrarray GPtrArray *array = NULL;
1188
1189         G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (struct ifla_vlan_qos_mapping));
1190         G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->to) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->to));
1191         G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->from) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->from));
1192         G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (((NMVlanQosMapping *) 0)->from) + sizeof (((NMVlanQosMapping *) 0)->to));
1193
1194         nm_assert (out_map && !*out_map);
1195         nm_assert (out_n_map && !*out_n_map);
1196
1197         if (!nlattr)
1198                 return TRUE;
1199
1200         array = g_ptr_array_new ();
1201         nla_for_each_nested (nla, nlattr, remaining) {
1202                 if (nla_len (nla) < sizeof(NMVlanQosMapping))
1203                         return FALSE;
1204                 g_ptr_array_add (array, nla_data (nla));
1205         }
1206
1207         if (array->len > 0) {
1208                 NMVlanQosMapping *list;
1209                 guint i, j;
1210
1211                 /* The sorting is necessary, because for egress mapping, kernel
1212                  * doesn't sent the items strictly sorted by the from field. */
1213                 g_ptr_array_sort_with_data (array, _vlan_qos_mapping_cmp_from_ptr, NULL);
1214
1215                 list = g_new (NMVlanQosMapping,  array->len);
1216
1217                 for (i = 0, j = 0; i < array->len; i++) {
1218                         NMVlanQosMapping *map;
1219
1220                         map = array->pdata[i];
1221
1222                         /* kernel doesn't really send us duplicates. Just be extra cautious
1223                          * because we want strong guarantees about the sort order and uniqueness
1224                          * of our mapping list (for simpler equality comparison). */
1225                         if (   j > 0
1226                             && list[j - 1].from == map->from)
1227                                 list[j - 1] = *map;
1228                         else
1229                                 list[j++] = *map;
1230                 }
1231
1232                 *out_n_map = j;
1233                 *out_map = list;
1234         }
1235
1236         return TRUE;
1237 }
1238
1239 /* Copied and heavily modified from libnl3's vlan_parse() */
1240 static NMPObject *
1241 _parse_lnk_vlan (const char *kind, struct nlattr *info_data)
1242 {
1243         static struct nla_policy policy[IFLA_VLAN_MAX+1] = {
1244                 [IFLA_VLAN_ID]          = { .type = NLA_U16 },
1245                 [IFLA_VLAN_FLAGS]       = { .minlen = sizeof(struct ifla_vlan_flags) },
1246                 [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
1247                 [IFLA_VLAN_EGRESS_QOS]  = { .type = NLA_NESTED },
1248                 [IFLA_VLAN_PROTOCOL]    = { .type = NLA_U16 },
1249         };
1250         struct nlattr *tb[IFLA_VLAN_MAX+1];
1251         int err;
1252         nm_auto_nmpobj NMPObject *obj = NULL;
1253         NMPObject *obj_result;
1254
1255         if (!info_data || g_strcmp0 (kind, "vlan"))
1256                 return NULL;
1257
1258         if ((err = nla_parse_nested (tb, IFLA_VLAN_MAX, info_data, policy)) < 0)
1259                 return NULL;
1260
1261         if (!tb[IFLA_VLAN_ID])
1262                 return NULL;
1263
1264         obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
1265         obj->lnk_vlan.id = nla_get_u16 (tb[IFLA_VLAN_ID]);
1266
1267         if (tb[IFLA_VLAN_FLAGS]) {
1268                 struct ifla_vlan_flags flags;
1269
1270                 nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags));
1271
1272                 obj->lnk_vlan.flags = flags.flags;
1273         }
1274
1275         if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_INGRESS_QOS],
1276                                          &obj->_lnk_vlan.ingress_qos_map,
1277                                          &obj->_lnk_vlan.n_ingress_qos_map))
1278                 return NULL;
1279
1280         if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_EGRESS_QOS],
1281                                          &obj->_lnk_vlan.egress_qos_map,
1282                                          &obj->_lnk_vlan.n_egress_qos_map))
1283                 return NULL;
1284
1285
1286         obj_result = obj;
1287         obj = NULL;
1288         return obj_result;
1289 }
1290
1291 /*****************************************************************************/
1292
1293 /* The installed kernel headers might not have VXLAN stuff at all, or
1294  * they might have the original properties, but not PORT, GROUP6, or LOCAL6.
1295  * So until we depend on kernel >= 3.11, we just ignore the actual enum
1296  * in if_link.h and define the values ourselves.
1297  */
1298 #define IFLA_VXLAN_UNSPEC      0
1299 #define IFLA_VXLAN_ID          1
1300 #define IFLA_VXLAN_GROUP       2
1301 #define IFLA_VXLAN_LINK        3
1302 #define IFLA_VXLAN_LOCAL       4
1303 #define IFLA_VXLAN_TTL         5
1304 #define IFLA_VXLAN_TOS         6
1305 #define IFLA_VXLAN_LEARNING    7
1306 #define IFLA_VXLAN_AGEING      8
1307 #define IFLA_VXLAN_LIMIT       9
1308 #define IFLA_VXLAN_PORT_RANGE 10
1309 #define IFLA_VXLAN_PROXY      11
1310 #define IFLA_VXLAN_RSC        12
1311 #define IFLA_VXLAN_L2MISS     13
1312 #define IFLA_VXLAN_L3MISS     14
1313 #define IFLA_VXLAN_PORT       15
1314 #define IFLA_VXLAN_GROUP6     16
1315 #define IFLA_VXLAN_LOCAL6     17
1316 #undef IFLA_VXLAN_MAX
1317 #define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6
1318
1319 /* older kernel header might not contain 'struct ifla_vxlan_port_range'.
1320  * Redefine it. */
1321 struct nm_ifla_vxlan_port_range {
1322         guint16 low;
1323         guint16 high;
1324 };
1325
1326 static NMPObject *
1327 _parse_lnk_vxlan (const char *kind, struct nlattr *info_data)
1328 {
1329         static struct nla_policy policy[IFLA_VXLAN_MAX + 1] = {
1330                 [IFLA_VXLAN_ID]         = { .type = NLA_U32 },
1331                 [IFLA_VXLAN_GROUP]      = { .type = NLA_U32 },
1332                 [IFLA_VXLAN_GROUP6]     = { .type = NLA_UNSPEC,
1333                                             .minlen = sizeof (struct in6_addr) },
1334                 [IFLA_VXLAN_LINK]       = { .type = NLA_U32 },
1335                 [IFLA_VXLAN_LOCAL]      = { .type = NLA_U32 },
1336                 [IFLA_VXLAN_LOCAL6]     = { .type = NLA_UNSPEC,
1337                                             .minlen = sizeof (struct in6_addr) },
1338                 [IFLA_VXLAN_TOS]        = { .type = NLA_U8 },
1339                 [IFLA_VXLAN_TTL]        = { .type = NLA_U8 },
1340                 [IFLA_VXLAN_LEARNING]   = { .type = NLA_U8 },
1341                 [IFLA_VXLAN_AGEING]     = { .type = NLA_U32 },
1342                 [IFLA_VXLAN_LIMIT]      = { .type = NLA_U32 },
1343                 [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_UNSPEC,
1344                                             .minlen  = sizeof (struct nm_ifla_vxlan_port_range) },
1345                 [IFLA_VXLAN_PROXY]      = { .type = NLA_U8 },
1346                 [IFLA_VXLAN_RSC]        = { .type = NLA_U8 },
1347                 [IFLA_VXLAN_L2MISS]     = { .type = NLA_U8 },
1348                 [IFLA_VXLAN_L3MISS]     = { .type = NLA_U8 },
1349                 [IFLA_VXLAN_PORT]       = { .type = NLA_U16 },
1350         };
1351         NMPlatformLnkVxlan *props;
1352         struct nlattr *tb[IFLA_VXLAN_MAX + 1];
1353         struct nm_ifla_vxlan_port_range *range;
1354         int err;
1355         NMPObject *obj;
1356
1357         if (!info_data || g_strcmp0 (kind, "vxlan"))
1358                 return NULL;
1359
1360         err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, policy);
1361         if (err < 0)
1362                 return NULL;
1363
1364         obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL);
1365
1366         props = &obj->lnk_vxlan;
1367
1368         if (tb[IFLA_VXLAN_LINK])
1369                 props->parent_ifindex = nla_get_u32 (tb[IFLA_VXLAN_LINK]);
1370         if (tb[IFLA_VXLAN_ID])
1371                 props->id = nla_get_u32 (tb[IFLA_VXLAN_ID]);
1372         if (tb[IFLA_VXLAN_GROUP])
1373                 props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]);
1374         if (tb[IFLA_VXLAN_LOCAL])
1375                 props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]);
1376         if (tb[IFLA_VXLAN_GROUP6])
1377                 memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6));
1378         if (tb[IFLA_VXLAN_LOCAL6])
1379                 memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6));
1380
1381         if (tb[IFLA_VXLAN_AGEING])
1382                 props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]);
1383         if (tb[IFLA_VXLAN_LIMIT])
1384                 props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]);
1385         if (tb[IFLA_VXLAN_TOS])
1386                 props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]);
1387         if (tb[IFLA_VXLAN_TTL])
1388                 props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]);
1389
1390         if (tb[IFLA_VXLAN_PORT])
1391                 props->dst_port = ntohs (nla_get_u16 (tb[IFLA_VXLAN_PORT]));
1392
1393         if (tb[IFLA_VXLAN_PORT_RANGE]) {
1394                 range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]);
1395                 props->src_port_min = ntohs (range->low);
1396                 props->src_port_max = ntohs (range->high);
1397         }
1398
1399         if (tb[IFLA_VXLAN_LEARNING])
1400                 props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]);
1401         if (tb[IFLA_VXLAN_PROXY])
1402                 props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]);
1403         if (tb[IFLA_VXLAN_RSC])
1404                 props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]);
1405         if (tb[IFLA_VXLAN_L2MISS])
1406                 props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]);
1407         if (tb[IFLA_VXLAN_L3MISS])
1408                 props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]);
1409
1410         return obj;
1411 }
1412
1413 /*****************************************************************************/
1414
1415 /* Copied and heavily modified from libnl3's link_msg_parser(). */
1416 static NMPObject *
1417 _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only)
1418 {
1419         static struct nla_policy policy[IFLA_MAX+1] = {
1420                 [IFLA_IFNAME]           = { .type = NLA_STRING,
1421                                             .maxlen = IFNAMSIZ },
1422                 [IFLA_MTU]              = { .type = NLA_U32 },
1423                 [IFLA_TXQLEN]           = { .type = NLA_U32 },
1424                 [IFLA_LINK]             = { .type = NLA_U32 },
1425                 [IFLA_WEIGHT]           = { .type = NLA_U32 },
1426                 [IFLA_MASTER]           = { .type = NLA_U32 },
1427                 [IFLA_OPERSTATE]        = { .type = NLA_U8 },
1428                 [IFLA_LINKMODE]         = { .type = NLA_U8 },
1429                 [IFLA_LINKINFO]         = { .type = NLA_NESTED },
1430                 [IFLA_QDISC]            = { .type = NLA_STRING,
1431                                             .maxlen = IFQDISCSIZ },
1432                 [IFLA_STATS]            = { .minlen = sizeof(struct rtnl_link_stats) },
1433                 [IFLA_STATS64]          = { .minlen = sizeof(struct rtnl_link_stats64)},
1434                 [IFLA_MAP]              = { .minlen = sizeof(struct rtnl_link_ifmap) },
1435                 [IFLA_IFALIAS]          = { .type = NLA_STRING, .maxlen = IFALIASZ },
1436                 [IFLA_NUM_VF]           = { .type = NLA_U32 },
1437                 [IFLA_AF_SPEC]          = { .type = NLA_NESTED },
1438                 [IFLA_PROMISCUITY]      = { .type = NLA_U32 },
1439                 [IFLA_NUM_TX_QUEUES]    = { .type = NLA_U32 },
1440                 [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
1441                 [IFLA_GROUP]            = { .type = NLA_U32 },
1442                 [IFLA_CARRIER]          = { .type = NLA_U8 },
1443                 [IFLA_PHYS_PORT_ID]     = { .type = NLA_UNSPEC },
1444                 [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
1445                 [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
1446         };
1447         static struct nla_policy policy_link_info[IFLA_INFO_MAX+1] = {
1448                 [IFLA_INFO_KIND]        = { .type = NLA_STRING },
1449                 [IFLA_INFO_DATA]        = { .type = NLA_NESTED },
1450                 [IFLA_INFO_XSTATS]      = { .type = NLA_NESTED },
1451         };
1452         const struct ifinfomsg *ifi;
1453         struct nlattr *tb[IFLA_MAX+1];
1454         struct nlattr *li[IFLA_INFO_MAX+1];
1455         struct nlattr *nl_info_data = NULL;
1456         const char *nl_info_kind = NULL;
1457         int err;
1458         nm_auto_nmpobj NMPObject *obj = NULL;
1459         NMPObject *obj_result = NULL;
1460         gboolean completed_from_cache_val = FALSE;
1461         gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL;
1462         const NMPObject *link_cached = NULL;
1463         NMPObject *lnk_data = NULL;
1464
1465         if (!nlmsg_valid_hdr (nlh, sizeof (*ifi)))
1466                 return NULL;
1467         ifi = nlmsg_data(nlh);
1468
1469         obj = nmp_object_new_link (ifi->ifi_index);
1470
1471         if (id_only)
1472                 goto id_only_handled;
1473
1474         err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy);
1475         if (err < 0)
1476                 goto errout;
1477
1478         if (!tb[IFLA_IFNAME])
1479                 goto errout;
1480         nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ);
1481         if (!obj->link.name[0])
1482                 goto errout;
1483
1484         if (tb[IFLA_LINKINFO]) {
1485                 err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info);
1486                 if (err < 0)
1487                         goto errout;
1488
1489                 if (li[IFLA_INFO_KIND])
1490                         nl_info_kind = nla_get_string (li[IFLA_INFO_KIND]);
1491
1492                 nl_info_data = li[IFLA_INFO_DATA];
1493         }
1494
1495         obj->link.n_ifi_flags = ifi->ifi_flags;
1496         obj->link.connected = NM_FLAGS_HAS (obj->link.n_ifi_flags, IFF_LOWER_UP);
1497         obj->link.arptype = ifi->ifi_type;
1498
1499         obj->link.type = _linktype_get_type (platform,
1500                                              cache,
1501                                              nl_info_kind,
1502                                              obj->link.ifindex,
1503                                              obj->link.name,
1504                                              obj->link.n_ifi_flags,
1505                                              obj->link.arptype,
1506                                              completed_from_cache,
1507                                              &link_cached,
1508                                              &obj->link.kind);
1509
1510         if (tb[IFLA_MASTER])
1511                 obj->link.master = nla_get_u32 (tb[IFLA_MASTER]);
1512
1513         if (tb[IFLA_LINK]) {
1514                 if (!tb[IFLA_LINK_NETNSID])
1515                         obj->link.parent = nla_get_u32 (tb[IFLA_LINK]);
1516                 else
1517                         obj->link.parent = NM_PLATFORM_LINK_OTHER_NETNS;
1518         }
1519
1520         if (tb[IFLA_ADDRESS]) {
1521                 int l = nla_len (tb[IFLA_ADDRESS]);
1522
1523                 if (l > 0 && l <= NM_UTILS_HWADDR_LEN_MAX) {
1524                         G_STATIC_ASSERT (NM_UTILS_HWADDR_LEN_MAX == sizeof (obj->link.addr.data));
1525                         memcpy (obj->link.addr.data, nla_data (tb[IFLA_ADDRESS]), l);
1526                         obj->link.addr.len = l;
1527                 }
1528         }
1529
1530         if (tb[IFLA_AF_SPEC]) {
1531                 struct nlattr *af_attr;
1532                 int remaining;
1533
1534                 nla_for_each_nested (af_attr, tb[IFLA_AF_SPEC], remaining) {
1535                         switch (nla_type (af_attr)) {
1536                         case AF_INET6:
1537                                 _parse_af_inet6 (platform,
1538                                                  af_attr,
1539                                                  &obj->link.inet6_token.iid,
1540                                                  &obj->link.inet6_token.is_valid,
1541                                                  &obj->link.inet6_addr_gen_mode_inv);
1542                                 break;
1543                         }
1544                 }
1545         }
1546
1547         if (tb[IFLA_MTU])
1548                 obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]);
1549
1550         switch (obj->link.type) {
1551         case NM_LINK_TYPE_GRE:
1552                 lnk_data = _parse_lnk_gre (nl_info_kind, nl_info_data);
1553                 break;
1554         case NM_LINK_TYPE_INFINIBAND:
1555                 lnk_data = _parse_lnk_infiniband (nl_info_kind, nl_info_data);
1556                 break;
1557         case NM_LINK_TYPE_IP6TNL:
1558                 lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data);
1559                 break;
1560         case NM_LINK_TYPE_IPIP:
1561                 lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data);
1562                 break;
1563         case NM_LINK_TYPE_MACVLAN:
1564         case NM_LINK_TYPE_MACVTAP:
1565                 lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data);
1566                 break;
1567         case NM_LINK_TYPE_SIT:
1568                 lnk_data = _parse_lnk_sit (nl_info_kind, nl_info_data);
1569                 break;
1570         case NM_LINK_TYPE_VLAN:
1571                 lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data);
1572                 break;
1573         case NM_LINK_TYPE_VXLAN:
1574                 lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data);
1575                 break;
1576         default:
1577                 goto lnk_data_handled;
1578         }
1579
1580         /* We always try to look into the cache and reuse the object there.
1581          * We do that, because we consider the lnk object as immutable and don't
1582          * modify it after creating. Hence we can share it and reuse.
1583          *
1584          * Also, sometimes the info-data is missing for updates. In this case
1585          * we want to keep the previously received lnk_data. */
1586         if (completed_from_cache) {
1587                 _lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
1588                 if (   link_cached
1589                     && link_cached->link.type == obj->link.type
1590                     && (   !lnk_data
1591                         || nmp_object_equal (lnk_data, link_cached->_link.netlink.lnk))) {
1592                         nmp_object_unref (lnk_data);
1593                         lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk);
1594                 }
1595         }
1596
1597 lnk_data_handled:
1598         obj->_link.netlink.lnk = lnk_data;
1599
1600         obj->_link.netlink.is_in_netlink = TRUE;
1601 id_only_handled:
1602         obj_result = obj;
1603         obj = NULL;
1604 errout:
1605         return obj_result;
1606 }
1607
1608 /* Copied and heavily modified from libnl3's addr_msg_parser(). */
1609 static NMPObject *
1610 _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only)
1611 {
1612         static struct nla_policy policy[IFA_MAX+1] = {
1613                 [IFA_LABEL]     = { .type = NLA_STRING,
1614                                      .maxlen = IFNAMSIZ },
1615                 [IFA_CACHEINFO] = { .minlen = sizeof(struct ifa_cacheinfo) },
1616         };
1617         const struct ifaddrmsg *ifa;
1618         struct nlattr *tb[IFA_MAX+1];
1619         int err;
1620         gboolean is_v4;
1621         nm_auto_nmpobj NMPObject *obj = NULL;
1622         NMPObject *obj_result = NULL;
1623         int addr_len;
1624         guint32 lifetime, preferred, timestamp;
1625
1626         if (!nlmsg_valid_hdr (nlh, sizeof (*ifa)))
1627                 return NULL;
1628         ifa = nlmsg_data(nlh);
1629
1630         if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6))
1631                 goto errout;
1632         is_v4 = ifa->ifa_family == AF_INET;
1633
1634         err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, policy);
1635         if (err < 0)
1636                 goto errout;
1637
1638         addr_len = is_v4
1639                    ? sizeof (in_addr_t)
1640                    : sizeof (struct in6_addr);
1641
1642         /*****************************************************************/
1643
1644         obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ADDRESS : NMP_OBJECT_TYPE_IP6_ADDRESS, NULL);
1645
1646         obj->ip_address.ifindex = ifa->ifa_index;
1647         obj->ip_address.plen = ifa->ifa_prefixlen;
1648
1649         _check_addr_or_errout (tb, IFA_ADDRESS, addr_len);
1650         _check_addr_or_errout (tb, IFA_LOCAL, addr_len);
1651         if (is_v4) {
1652                 /* For IPv4, kernel omits IFA_LOCAL/IFA_ADDRESS if (and only if) they
1653                  * are effectively 0.0.0.0 (all-zero). */
1654                 if (tb[IFA_LOCAL])
1655                         memcpy (&obj->ip4_address.address, nla_data (tb[IFA_LOCAL]), addr_len);
1656                 if (tb[IFA_ADDRESS])
1657                         memcpy (&obj->ip4_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len);
1658         } else {
1659                 /* For IPv6, IFA_ADDRESS is always present.
1660                  *
1661                  * If IFA_LOCAL is missing, IFA_ADDRESS is @address and @peer_address
1662                  * is :: (all-zero).
1663                  *
1664                  * If unexpectely IFA_ADDRESS is missing, make the best of it -- but it _should_
1665                  * actually be there. */
1666                 if (tb[IFA_ADDRESS] || tb[IFA_LOCAL]) {
1667                         if (tb[IFA_LOCAL]) {
1668                                 memcpy (&obj->ip6_address.address, nla_data (tb[IFA_LOCAL]), addr_len);
1669                                 if (tb[IFA_ADDRESS])
1670                                         memcpy (&obj->ip6_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len);
1671                                 else
1672                                         obj->ip6_address.peer_address = obj->ip6_address.address;
1673                         } else
1674                                 memcpy (&obj->ip6_address.address, nla_data (tb[IFA_ADDRESS]), addr_len);
1675                 }
1676         }
1677
1678         obj->ip_address.source = NM_IP_CONFIG_SOURCE_KERNEL;
1679
1680         obj->ip_address.n_ifa_flags = tb[IFA_FLAGS]
1681                                       ? nla_get_u32 (tb[IFA_FLAGS])
1682                                       : ifa->ifa_flags;
1683
1684         if (is_v4) {
1685                 if (tb[IFA_LABEL]) {
1686                         char label[IFNAMSIZ];
1687
1688                         nla_strlcpy (label, tb[IFA_LABEL], IFNAMSIZ);
1689
1690                         /* Check for ':'; we're only interested in labels used as interface aliases */
1691                         if (strchr (label, ':'))
1692                                 g_strlcpy (obj->ip4_address.label, label, sizeof (obj->ip4_address.label));
1693                 }
1694         }
1695
1696         lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
1697         preferred = NM_PLATFORM_LIFETIME_PERMANENT;
1698         timestamp = 0;
1699         /* IPv6 only */
1700         if (tb[IFA_CACHEINFO]) {
1701                 const struct ifa_cacheinfo *ca = nla_data(tb[IFA_CACHEINFO]);
1702
1703                 lifetime = ca->ifa_valid;
1704                 preferred = ca->ifa_prefered;
1705                 timestamp = ca->tstamp;
1706         }
1707         _addrtime_get_lifetimes (timestamp,
1708                                  lifetime,
1709                                  preferred,
1710                                  &obj->ip_address.timestamp,
1711                                  &obj->ip_address.lifetime,
1712                                  &obj->ip_address.preferred);
1713
1714         obj_result = obj;
1715         obj = NULL;
1716 errout:
1717         return obj_result;
1718 }
1719
1720 /* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */
1721 static NMPObject *
1722 _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
1723 {
1724         static struct nla_policy policy[RTA_MAX+1] = {
1725                 [RTA_IIF]       = { .type = NLA_U32 },
1726                 [RTA_OIF]       = { .type = NLA_U32 },
1727                 [RTA_PRIORITY]  = { .type = NLA_U32 },
1728                 [RTA_FLOW]      = { .type = NLA_U32 },
1729                 [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
1730                 [RTA_METRICS]   = { .type = NLA_NESTED },
1731                 [RTA_MULTIPATH] = { .type = NLA_NESTED },
1732         };
1733         const struct rtmsg *rtm;
1734         struct nlattr *tb[RTA_MAX + 1];
1735         int err;
1736         gboolean is_v4;
1737         nm_auto_nmpobj NMPObject *obj = NULL;
1738         NMPObject *obj_result = NULL;
1739         int addr_len;
1740         struct {
1741                 gboolean is_present;
1742                 int ifindex;
1743                 NMIPAddr gateway;
1744         } nh;
1745         guint32 mss;
1746         guint32 table;
1747
1748         if (!nlmsg_valid_hdr (nlh, sizeof (*rtm)))
1749                 return NULL;
1750         rtm = nlmsg_data(nlh);
1751
1752         /*****************************************************************
1753          * only handle ~normal~ routes.
1754          *****************************************************************/
1755
1756         if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6))
1757                 goto errout;
1758
1759         if (   rtm->rtm_type != RTN_UNICAST
1760             || rtm->rtm_tos != 0)
1761                 goto errout;
1762
1763         err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy);
1764         if (err < 0)
1765                 goto errout;
1766
1767         table = tb[RTA_TABLE]
1768                 ? nla_get_u32 (tb[RTA_TABLE])
1769                 : (guint32) rtm->rtm_table;
1770         if (table != RT_TABLE_MAIN)
1771                 goto errout;
1772
1773         /*****************************************************************/
1774
1775         is_v4 = rtm->rtm_family == AF_INET;
1776         addr_len = is_v4
1777                    ? sizeof (in_addr_t)
1778                    : sizeof (struct in6_addr);
1779
1780         /*****************************************************************
1781          * parse nexthops. Only handle routes with one nh.
1782          *****************************************************************/
1783
1784         memset (&nh, 0, sizeof (nh));
1785
1786         if (tb[RTA_MULTIPATH]) {
1787                 struct rtnexthop *rtnh = nla_data (tb[RTA_MULTIPATH]);
1788                 size_t tlen = nla_len(tb[RTA_MULTIPATH]);
1789
1790                 while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
1791
1792                         if (nh.is_present) {
1793                                 /* we don't support multipath routes. */
1794                                 goto errout;
1795                         }
1796                         nh.is_present = TRUE;
1797
1798                         nh.ifindex = rtnh->rtnh_ifindex;
1799
1800                         if (rtnh->rtnh_len > sizeof(*rtnh)) {
1801                                 struct nlattr *ntb[RTA_MAX + 1];
1802
1803                                 err = nla_parse (ntb, RTA_MAX, (struct nlattr *)
1804                                                  RTNH_DATA(rtnh),
1805                                                  rtnh->rtnh_len - sizeof (*rtnh),
1806                                                  policy);
1807                                 if (err < 0)
1808                                         goto errout;
1809
1810                                 if (_check_addr_or_errout (ntb, RTA_GATEWAY, addr_len))
1811                                         memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len);
1812                         }
1813
1814                         tlen -= RTNH_ALIGN(rtnh->rtnh_len);
1815                         rtnh = RTNH_NEXT(rtnh);
1816                 }
1817         }
1818
1819         if (   tb[RTA_OIF]
1820             || tb[RTA_GATEWAY]
1821             || tb[RTA_FLOW]) {
1822                 int ifindex = 0;
1823                 NMIPAddr gateway = NMIPAddrInit;
1824
1825                 if (tb[RTA_OIF])
1826                         ifindex = nla_get_u32 (tb[RTA_OIF]);
1827                 if (_check_addr_or_errout (tb, RTA_GATEWAY, addr_len))
1828                         memcpy (&gateway, nla_data (tb[RTA_GATEWAY]), addr_len);
1829
1830                 if (!nh.is_present) {
1831                         /* If no nexthops have been provided via RTA_MULTIPATH
1832                          * we add it as regular nexthop to maintain backwards
1833                          * compatibility */
1834                         nh.ifindex = ifindex;
1835                         nh.gateway = gateway;
1836                 } else {
1837                         /* Kernel supports new style nexthop configuration,
1838                          * verify that it is a duplicate and ignore old-style nexthop. */
1839                         if (   nh.ifindex != ifindex
1840                             || memcmp (&nh.gateway, &gateway, addr_len) != 0)
1841                                 goto errout;
1842                 }
1843         } else if (!nh.is_present)
1844                 goto errout;
1845
1846         /*****************************************************************/
1847
1848         mss = 0;
1849         if (tb[RTA_METRICS]) {
1850                 struct nlattr *mtb[RTAX_MAX + 1];
1851                 int i;
1852
1853                 err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
1854                 if (err < 0)
1855                         goto errout;
1856
1857                 for (i = 1; i <= RTAX_MAX; i++) {
1858                         if (mtb[i]) {
1859                                 if (i == RTAX_ADVMSS) {
1860                                         if (nla_len (mtb[i]) >= sizeof (uint32_t))
1861                                                 mss = nla_get_u32(mtb[i]);
1862                                         break;
1863                                 }
1864                         }
1865                 }
1866         }
1867
1868         /*****************************************************************/
1869
1870         obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
1871
1872         obj->ip_route.ifindex = nh.ifindex;
1873
1874         if (_check_addr_or_errout (tb, RTA_DST, addr_len))
1875                 memcpy (obj->ip_route.network_ptr, nla_data (tb[RTA_DST]), addr_len);
1876
1877         obj->ip_route.plen = rtm->rtm_dst_len;
1878
1879         if (tb[RTA_PRIORITY])
1880                 obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]);
1881
1882         if (is_v4)
1883                 obj->ip4_route.gateway = nh.gateway.addr4;
1884         else
1885                 obj->ip6_route.gateway = nh.gateway.addr6;
1886
1887         if (is_v4)
1888                 obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope);
1889
1890         if (is_v4) {
1891                 if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len))
1892                         memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len);
1893         }
1894
1895         obj->ip_route.mss = mss;
1896
1897         if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) {
1898                 /* we must not straight way reject cloned routes, because we might have cached
1899                  * a non-cloned route. If we now receive an update of the route with the route
1900                  * being cloned, we must still return the object, so that we can remove the old
1901                  * one from the cache.
1902                  *
1903                  * This happens, because this route is not nmp_object_is_alive().
1904                  * */
1905                 obj->ip_route.source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED;
1906         } else
1907                 obj->ip_route.source = _nm_ip_config_source_from_rtprot (rtm->rtm_protocol);
1908
1909         obj_result = obj;
1910         obj = NULL;
1911 errout:
1912         return obj_result;
1913 }
1914
1915 /**
1916  * nmp_object_new_from_nl:
1917  * @platform: (allow-none): for creating certain objects, the constructor wants to check
1918  *   sysfs. For this the platform instance is needed. If missing, the object might not
1919  *   be correctly detected.
1920  * @cache: (allow-none): for certain objects, the netlink message doesn't contain all the information.
1921  *   If a cache is given, the object is completed with information from the cache.
1922  * @nlh: the netlink message header
1923  * @id_only: whether only to create an empty object with only the ID fields set.
1924  *
1925  * Returns: %NULL or a newly created NMPObject instance.
1926  **/
1927 static NMPObject *
1928 nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_msg *msg, gboolean id_only)
1929 {
1930         struct nlmsghdr *msghdr;
1931
1932         if (nlmsg_get_proto (msg) != NETLINK_ROUTE)
1933                 return NULL;
1934
1935         msghdr = nlmsg_hdr (msg);
1936
1937         switch (msghdr->nlmsg_type) {
1938         case RTM_NEWLINK:
1939         case RTM_DELLINK:
1940         case RTM_GETLINK:
1941         case RTM_SETLINK:
1942                 return _new_from_nl_link (platform, cache, msghdr, id_only);
1943         case RTM_NEWADDR:
1944         case RTM_DELADDR:
1945         case RTM_GETADDR:
1946                 return _new_from_nl_addr (msghdr, id_only);
1947         case RTM_NEWROUTE:
1948         case RTM_DELROUTE:
1949         case RTM_GETROUTE:
1950                 return _new_from_nl_route (msghdr, id_only);
1951         default:
1952                 return NULL;
1953         }
1954 }
1955
1956 /******************************************************************/
1957
1958 static gboolean
1959 _nl_msg_new_link_set_afspec (struct nl_msg *msg,
1960                              int addr_gen_mode)
1961 {
1962         struct nlattr *af_spec;
1963         struct nlattr *af_attr;
1964
1965         nm_assert (msg);
1966
1967         if (!(af_spec = nla_nest_start (msg, IFLA_AF_SPEC)))
1968                 goto nla_put_failure;
1969
1970         if (addr_gen_mode >= 0) {
1971                 if (!(af_attr = nla_nest_start (msg, AF_INET6)))
1972                         goto nla_put_failure;
1973
1974                 NLA_PUT_U8 (msg, IFLA_INET6_ADDR_GEN_MODE, addr_gen_mode);
1975
1976                 nla_nest_end (msg, af_attr);
1977         }
1978
1979         nla_nest_end (msg, af_spec);
1980
1981         return TRUE;
1982 nla_put_failure:
1983         return FALSE;
1984 }
1985
1986 static gboolean
1987 _nl_msg_new_link_set_linkinfo (struct nl_msg *msg,
1988                                NMLinkType link_type)
1989 {
1990         struct nlattr *info;
1991         const char *kind;
1992
1993         nm_assert (msg);
1994
1995         kind = nm_link_type_to_rtnl_type_string (link_type);
1996         if (!kind)
1997                 goto nla_put_failure;
1998
1999         if (!(info = nla_nest_start (msg, IFLA_LINKINFO)))
2000                 goto nla_put_failure;
2001
2002         NLA_PUT_STRING (msg, IFLA_INFO_KIND, kind);
2003
2004         nla_nest_end (msg, info);
2005
2006         return TRUE;
2007 nla_put_failure:
2008         return FALSE;
2009 }
2010
2011 static gboolean
2012 _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg,
2013                                     int vlan_id,
2014                                     guint32 flags_mask,
2015                                     guint32 flags_set,
2016                                     const NMVlanQosMapping *ingress_qos,
2017                                     int ingress_qos_len,
2018                                     const NMVlanQosMapping *egress_qos,
2019                                     int egress_qos_len)
2020 {
2021         struct nlattr *info;
2022         struct nlattr *data;
2023         guint i;
2024         gboolean has_any_vlan_properties = FALSE;
2025
2026 #define VLAN_XGRESS_PRIO_VALID(from) (((from) & ~(guint32) 0x07) == 0)
2027
2028         nm_assert (msg);
2029
2030         /* We must not create an empty IFLA_LINKINFO section. Otherwise, kernel
2031          * rejects the request as invalid. */
2032         if (   flags_mask != 0
2033             || vlan_id >= 0)
2034                 has_any_vlan_properties = TRUE;
2035         if (   !has_any_vlan_properties
2036             && ingress_qos && ingress_qos_len > 0) {
2037                 for (i = 0; i < ingress_qos_len; i++) {
2038                         if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) {
2039                                 has_any_vlan_properties = TRUE;
2040                                 break;
2041                         }
2042                 }
2043         }
2044         if (   !has_any_vlan_properties
2045             && egress_qos && egress_qos_len > 0) {
2046                 for (i = 0; i < egress_qos_len; i++) {
2047                         if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) {
2048                                 has_any_vlan_properties = TRUE;
2049                                 break;
2050                         }
2051                 }
2052         }
2053         if (!has_any_vlan_properties)
2054                 return TRUE;
2055
2056         if (!(info = nla_nest_start (msg, IFLA_LINKINFO)))
2057                 goto nla_put_failure;
2058
2059         NLA_PUT_STRING (msg, IFLA_INFO_KIND, "vlan");
2060
2061         if (!(data = nla_nest_start (msg, IFLA_INFO_DATA)))
2062                 goto nla_put_failure;
2063
2064         if (vlan_id >= 0)
2065                 NLA_PUT_U16 (msg, IFLA_VLAN_ID, vlan_id);
2066
2067         if (flags_mask != 0) {
2068                 struct ifla_vlan_flags flags = {
2069                         .flags = flags_mask & flags_set,
2070                         .mask = flags_mask,
2071                 };
2072
2073                 NLA_PUT (msg, IFLA_VLAN_FLAGS, sizeof (flags), &flags);
2074         }
2075
2076         if (ingress_qos && ingress_qos_len > 0) {
2077                 struct nlattr *qos = NULL;
2078
2079                 for (i = 0; i < ingress_qos_len; i++) {
2080                         /* Silently ignore invalid mappings. Kernel would truncate
2081                          * them and modify the wrong mapping. */
2082                         if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) {
2083                                 if (!qos) {
2084                                         if (!(qos = nla_nest_start (msg, IFLA_VLAN_INGRESS_QOS)))
2085                                                 goto nla_put_failure;
2086                                 }
2087                                 NLA_PUT (msg, i, sizeof (ingress_qos[i]), &ingress_qos[i]);
2088                         }
2089                 }
2090
2091                 if (qos)
2092                         nla_nest_end (msg, qos);
2093         }
2094
2095         if (egress_qos && egress_qos_len > 0) {
2096                 struct nlattr *qos = NULL;
2097
2098                 for (i = 0; i < egress_qos_len; i++) {
2099                         if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) {
2100                                 if (!qos) {
2101                                         if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
2102                                                 goto nla_put_failure;
2103                                 }
2104                                 NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]);
2105                         }
2106                 }
2107
2108                 if (qos)
2109                         nla_nest_end(msg, qos);
2110         }
2111
2112         nla_nest_end (msg, data);
2113         nla_nest_end (msg, info);
2114
2115         return TRUE;
2116 nla_put_failure:
2117         return FALSE;
2118 }
2119
2120 static struct nl_msg *
2121 _nl_msg_new_link (int nlmsg_type,
2122                   int nlmsg_flags,
2123                   int ifindex,
2124                   const char *ifname,
2125                   unsigned flags_mask,
2126                   unsigned flags_set)
2127 {
2128         struct nl_msg *msg;
2129         struct ifinfomsg ifi = {
2130                 .ifi_change = flags_mask,
2131                 .ifi_flags = flags_set,
2132                 .ifi_index = ifindex,
2133         };
2134
2135         nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK));
2136
2137         if (!(msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags)))
2138                 g_return_val_if_reached (NULL);
2139
2140         if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0)
2141                 goto nla_put_failure;
2142
2143         if (ifname)
2144                 NLA_PUT_STRING (msg, IFLA_IFNAME, ifname);
2145
2146         return msg;
2147 nla_put_failure:
2148         nlmsg_free (msg);
2149         g_return_val_if_reached (NULL);
2150 }
2151
2152 /* Copied and modified from libnl3's build_addr_msg(). */
2153 static struct nl_msg *
2154 _nl_msg_new_address (int nlmsg_type,
2155                      int nlmsg_flags,
2156                      int family,
2157                      int ifindex,
2158                      gconstpointer address,
2159                      int plen,
2160                      gconstpointer peer_address,
2161                      guint32 flags,
2162                      int scope,
2163                      guint32 lifetime,
2164                      guint32 preferred,
2165                      const char *label)
2166 {
2167         struct nl_msg *msg;
2168         struct ifaddrmsg am = {
2169                 .ifa_family = family,
2170                 .ifa_index = ifindex,
2171                 .ifa_prefixlen = plen,
2172                 .ifa_flags = flags,
2173         };
2174         gsize addr_len;
2175
2176         nm_assert (NM_IN_SET (family, AF_INET, AF_INET6));
2177         nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWADDR, RTM_DELADDR));
2178
2179         msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
2180         if (!msg)
2181                 g_return_val_if_reached (NULL);
2182
2183         if (scope == -1) {
2184                 /* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */
2185                 if (   family == AF_INET
2186                     && address
2187                     && *((char *) address) == 127)
2188                         scope = RT_SCOPE_HOST;
2189                 else
2190                         scope = RT_SCOPE_UNIVERSE;
2191         }
2192         am.ifa_scope = scope,
2193
2194         addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
2195
2196         if (nlmsg_append (msg, &am, sizeof (am), NLMSG_ALIGNTO) < 0)
2197                 goto nla_put_failure;
2198
2199         if (address)
2200                 NLA_PUT (msg, IFA_LOCAL, addr_len, address);
2201
2202         if (peer_address)
2203                 NLA_PUT (msg, IFA_ADDRESS, addr_len, peer_address);
2204         else if (address)
2205                 NLA_PUT (msg, IFA_ADDRESS, addr_len, address);
2206
2207         if (label && label[0])
2208                 NLA_PUT_STRING (msg, IFA_LABEL, label);
2209
2210         if (   family == AF_INET
2211             && nlmsg_type != RTM_DELADDR
2212             && address
2213             && *((in_addr_t *) address) != 0) {
2214                 in_addr_t broadcast;
2215
2216                 broadcast = *((in_addr_t *) address) | ~nm_utils_ip4_prefix_to_netmask (plen);
2217                 NLA_PUT (msg, IFA_BROADCAST, addr_len, &broadcast);
2218         }
2219
2220         if (   lifetime != NM_PLATFORM_LIFETIME_PERMANENT
2221             || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
2222                 struct ifa_cacheinfo ca = {
2223                         .ifa_valid = lifetime,
2224                         .ifa_prefered = preferred,
2225                 };
2226
2227                 NLA_PUT (msg, IFA_CACHEINFO, sizeof(ca), &ca);
2228         }
2229
2230         if (flags & ~((guint32) 0xFF)) {
2231                 /* only set the IFA_FLAGS attribute, if they actually contain additional
2232                  * flags that are not already set to am.ifa_flags.
2233                  *
2234                  * Older kernels refuse RTM_NEWADDR and RTM_NEWROUTE messages with EINVAL
2235                  * if they contain unknown netlink attributes. See net/core/rtnetlink.c, which
2236                  * was fixed by kernel commit 661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59. */
2237                 NLA_PUT_U32 (msg, IFA_FLAGS, flags);
2238         }
2239
2240         return msg;
2241
2242 nla_put_failure:
2243         nlmsg_free (msg);
2244         g_return_val_if_reached (NULL);
2245 }
2246
2247 /* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */
2248 static struct nl_msg *
2249 _nl_msg_new_route (int nlmsg_type,
2250                    int nlmsg_flags,
2251                    int family,
2252                    int ifindex,
2253                    NMIPConfigSource source,
2254                    unsigned char scope,
2255                    gconstpointer network,
2256                    int plen,
2257                    gconstpointer gateway,
2258                    guint32 metric,
2259                    guint32 mss,
2260                    gconstpointer pref_src)
2261 {
2262         struct nl_msg *msg;
2263         struct rtmsg rtmsg = {
2264                 .rtm_family = family,
2265                 .rtm_tos = 0,
2266                 .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */
2267                 .rtm_protocol = _nm_ip_config_source_to_rtprot (source),
2268                 .rtm_scope = scope,
2269                 .rtm_type = RTN_UNICAST,
2270                 .rtm_flags = 0,
2271                 .rtm_dst_len = plen,
2272                 .rtm_src_len = 0,
2273         };
2274         NMIPAddr network_clean;
2275
2276         gsize addr_len;
2277
2278         nm_assert (NM_IN_SET (family, AF_INET, AF_INET6));
2279         nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE));
2280         nm_assert (network);
2281
2282         msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
2283         if (!msg)
2284                 g_return_val_if_reached (NULL);
2285
2286         if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0)
2287                 goto nla_put_failure;
2288
2289         addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
2290
2291         clear_host_address (family, network, plen, &network_clean);
2292         NLA_PUT (msg, RTA_DST, addr_len, &network_clean);
2293
2294         NLA_PUT_U32 (msg, RTA_PRIORITY, metric);
2295
2296         if (pref_src)
2297                 NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src);
2298
2299         if (mss > 0) {
2300                 struct nlattr *metrics;
2301
2302                 metrics = nla_nest_start (msg, RTA_METRICS);
2303                 if (!metrics)
2304                         goto nla_put_failure;
2305
2306                 NLA_PUT_U32 (msg, RTAX_ADVMSS, mss);
2307
2308                 nla_nest_end(msg, metrics);
2309         }
2310
2311         /* We currently don't have need for multi-hop routes... */
2312         if (   gateway
2313             && memcmp (gateway, &nm_ip_addr_zero, addr_len) != 0)
2314                 NLA_PUT (msg, RTA_GATEWAY, addr_len, gateway);
2315         NLA_PUT_U32 (msg, RTA_OIF, ifindex);
2316
2317         return msg;
2318
2319 nla_put_failure:
2320         nlmsg_free (msg);
2321         g_return_val_if_reached (NULL);
2322 }
2323
2324 /******************************************************************/
2325
2326 static int _support_kernel_extended_ifa_flags = -1;
2327
2328 #define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == -1))
2329
2330 static void
2331 _support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
2332 {
2333         struct nlmsghdr *msg_hdr;
2334
2335         if (!_support_kernel_extended_ifa_flags_still_undecided ())
2336                 return;
2337
2338         msg_hdr = nlmsg_hdr (msg);
2339         if (msg_hdr->nlmsg_type != RTM_NEWADDR)
2340                 return;
2341
2342         /* the extended address flags are only set for AF_INET6 */
2343         if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6)
2344                 return;
2345
2346         /* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
2347          * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
2348          * and IFA_F_NOPREFIXROUTE (they were added together).
2349          **/
2350         _support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */);
2351         _LOG2D ("support: kernel-extended-ifa-flags: %ssupported", _support_kernel_extended_ifa_flags ? "" : "not ");
2352 }
2353
2354 static gboolean
2355 _support_kernel_extended_ifa_flags_get (void)
2356 {
2357         if (_support_kernel_extended_ifa_flags_still_undecided ()) {
2358                 _LOG2W ("support: kernel-extended-ifa-flags: unable to detect kernel support for handling IPv6 temporary addresses. Assume support");
2359                 _support_kernel_extended_ifa_flags = 1;
2360         }
2361         return _support_kernel_extended_ifa_flags;
2362 }
2363
2364 /******************************************************************
2365  * NMPlatform types and functions
2366  ******************************************************************/
2367
2368 typedef struct {
2369         guint32 seq_number;
2370         gint64 timeout_abs_ns;
2371         WaitForNlResponseResult seq_result;
2372         WaitForNlResponseResult *out_seq_result;
2373 } DelayedActionWaitForNlResponseData;
2374
2375 typedef struct _NMLinuxPlatformPrivate NMLinuxPlatformPrivate;
2376
2377 struct _NMLinuxPlatformPrivate {
2378         struct nl_sock *nlh;
2379         guint32 nlh_seq_next;
2380         guint32 nlh_seq_last_handled;
2381         NMPCache *cache;
2382         GIOChannel *event_channel;
2383         guint event_id;
2384
2385         gboolean sysctl_get_warned;
2386         GHashTable *sysctl_get_prev_values;
2387
2388         GUdevClient *udev_client;
2389
2390         struct {
2391                 DelayedActionType flags;
2392                 GPtrArray *list_master_connected;
2393                 GPtrArray *list_refresh_link;
2394                 GArray *list_wait_for_nl_response;
2395                 gint is_handling;
2396         } delayed_action;
2397
2398         GHashTable *prune_candidates;
2399
2400         GHashTable *wifi_data;
2401 };
2402
2403 static inline NMLinuxPlatformPrivate *
2404 NM_LINUX_PLATFORM_GET_PRIVATE (const void *self)
2405 {
2406         nm_assert (NM_IS_LINUX_PLATFORM (self));
2407
2408         return ((NMLinuxPlatform *) self)->priv;
2409 }
2410
2411 G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
2412
2413 void
2414 nm_linux_platform_setup (void)
2415 {
2416         g_object_new (NM_TYPE_LINUX_PLATFORM,
2417                       NM_PLATFORM_NETNS_SUPPORT, FALSE,
2418                       NM_PLATFORM_REGISTER_SINGLETON, TRUE,
2419                       NULL);
2420 }
2421
2422 /******************************************************************/
2423
2424 static void
2425 _assert_netns_current (NMPlatform *platform)
2426 {
2427 #if NM_MORE_ASSERTS
2428         nm_assert (NM_IS_LINUX_PLATFORM (platform));
2429
2430         nm_assert (NM_IN_SET (nm_platform_netns_get (platform), NULL, nmp_netns_get_current ()));
2431 #endif
2432 }
2433
2434 static void
2435 _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *path, const char *value)
2436 {
2437         GError *error = NULL;
2438         char *contents, *contents_escaped;
2439         char *value_escaped = g_strescape (value, NULL);
2440
2441         if (!g_file_get_contents (path, &contents, NULL, &error)) {
2442                 _LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", path, value_escaped, error->message);
2443                 g_clear_error (&error);
2444         } else {
2445                 g_strstrip (contents);
2446                 contents_escaped = g_strescape (contents, NULL);
2447                 if (strcmp (contents, value) == 0)
2448                         _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", path, value_escaped);
2449                 else
2450                         _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", path, value_escaped, contents_escaped);
2451                 g_free (contents);
2452                 g_free (contents_escaped);
2453         }
2454         g_free (value_escaped);
2455 }
2456
2457 #define _log_dbg_sysctl_set(platform, path, value) \
2458         G_STMT_START { \
2459                 if (_LOGD_ENABLED ()) { \
2460                         _log_dbg_sysctl_set_impl (platform, path, value); \
2461                 } \
2462         } G_STMT_END
2463
2464 static gboolean
2465 sysctl_set (NMPlatform *platform, const char *path, const char *value)
2466 {
2467         nm_auto_pop_netns NMPNetns *netns = NULL;
2468         int fd, tries;
2469         gssize nwrote;
2470         gsize len;
2471         char *actual;
2472         gs_free char *actual_free = NULL;
2473
2474         g_return_val_if_fail (path != NULL, FALSE);
2475         g_return_val_if_fail (value != NULL, FALSE);
2476
2477         /* Don't write outside known locations */
2478         g_assert (g_str_has_prefix (path, "/proc/sys/")
2479                   || g_str_has_prefix (path, "/sys/"));
2480         /* Don't write to suspicious locations */
2481         g_assert (!strstr (path, "/../"));
2482
2483         if (!nm_platform_netns_push (platform, &netns))
2484                 return FALSE;
2485
2486         fd = open (path, O_WRONLY | O_TRUNC);
2487         if (fd == -1) {
2488                 if (errno == ENOENT) {
2489                         _LOGD ("sysctl: failed to open '%s': (%d) %s",
2490                                path, errno, strerror (errno));
2491                 } else {
2492                         _LOGE ("sysctl: failed to open '%s': (%d) %s",
2493                                path, errno, strerror (errno));
2494                 }
2495                 return FALSE;
2496         }
2497
2498         _log_dbg_sysctl_set (platform, path, value);
2499
2500         /* Most sysfs and sysctl options don't care about a trailing LF, while some
2501          * (like infiniband) do.  So always add the LF.  Also, neither sysfs nor
2502          * sysctl support partial writes so the LF must be added to the string we're
2503          * about to write.
2504          */
2505         len = strlen (value) + 1;
2506         if (len > 512)
2507                 actual = actual_free = g_malloc (len + 1);
2508         else
2509                 actual = g_alloca (len + 1);
2510         memcpy (actual, value, len - 1);
2511         actual[len - 1] = '\n';
2512         actual[len] = '\0';
2513
2514         /* Try to write the entire value three times if a partial write occurs */
2515         for (tries = 0, nwrote = 0; tries < 3 && nwrote != len; tries++) {
2516                 nwrote = write (fd, actual, len);
2517                 if (nwrote == -1) {
2518                         if (errno == EINTR) {
2519                                 _LOGD ("sysctl: interrupted, will try again");
2520                                 continue;
2521                         }
2522                         break;
2523                 }
2524         }
2525         if (nwrote == -1 && errno != EEXIST) {
2526                 _LOGE ("sysctl: failed to set '%s' to '%s': (%d) %s",
2527                        path, value, errno, strerror (errno));
2528         } else if (nwrote < len) {
2529                 _LOGE ("sysctl: failed to set '%s' to '%s' after three attempts",
2530                        path, value);
2531         }
2532
2533         close (fd);
2534         return (nwrote == len);
2535 }
2536
2537 static GSList *sysctl_clear_cache_list;
2538
2539 static void
2540 _nm_logging_clear_platform_logging_cache_impl (void)
2541 {
2542         while (sysctl_clear_cache_list) {
2543                 NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (sysctl_clear_cache_list->data);
2544
2545                 sysctl_clear_cache_list = g_slist_delete_link (sysctl_clear_cache_list, sysctl_clear_cache_list);
2546
2547                 g_hash_table_destroy (priv->sysctl_get_prev_values);
2548                 priv->sysctl_get_prev_values = NULL;
2549                 priv->sysctl_get_warned = FALSE;
2550         }
2551 }
2552
2553 static void
2554 _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *contents)
2555 {
2556         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2557         const char *prev_value = NULL;
2558
2559         if (!priv->sysctl_get_prev_values) {
2560                 _nm_logging_clear_platform_logging_cache = _nm_logging_clear_platform_logging_cache_impl;
2561                 sysctl_clear_cache_list = g_slist_prepend (sysctl_clear_cache_list, platform);
2562                 priv->sysctl_get_prev_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
2563         } else
2564                 prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, path);
2565
2566         if (prev_value) {
2567                 if (strcmp (prev_value, contents) != 0) {
2568                         char *contents_escaped = g_strescape (contents, NULL);
2569                         char *prev_value_escaped = g_strescape (prev_value, NULL);
2570
2571                         _LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", path, contents_escaped, prev_value_escaped);
2572                         g_free (contents_escaped);
2573                         g_free (prev_value_escaped);
2574                         g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents));
2575                 }
2576         } else {
2577                 char *contents_escaped = g_strescape (contents, NULL);
2578
2579                 _LOGD ("sysctl: reading '%s': '%s'", path, contents_escaped);
2580                 g_free (contents_escaped);
2581                 g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents));
2582         }
2583
2584         if (   !priv->sysctl_get_warned
2585             && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) {
2586                 _LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`.");
2587                 priv->sysctl_get_warned = TRUE;
2588         }
2589 }
2590
2591 #define _log_dbg_sysctl_get(platform, path, contents) \
2592         G_STMT_START { \
2593                 if (_LOGD_ENABLED ()) \
2594                         _log_dbg_sysctl_get_impl (platform, path, contents); \
2595         } G_STMT_END
2596
2597 static char *
2598 sysctl_get (NMPlatform *platform, const char *path)
2599 {
2600         nm_auto_pop_netns NMPNetns *netns = NULL;
2601         GError *error = NULL;
2602         char *contents;
2603
2604         /* Don't write outside known locations */
2605         g_assert (g_str_has_prefix (path, "/proc/sys/")
2606                   || g_str_has_prefix (path, "/sys/"));
2607         /* Don't write to suspicious locations */
2608         g_assert (!strstr (path, "/../"));
2609
2610         if (!nm_platform_netns_push (platform, &netns))
2611                 return NULL;
2612
2613         if (!g_file_get_contents (path, &contents, NULL, &error)) {
2614                 /* We assume FAILED means EOPNOTSUP */
2615                 if (   g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)
2616                     || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_FAILED))
2617                         _LOGD ("error reading %s: %s", path, error->message);
2618                 else
2619                         _LOGE ("error reading %s: %s", path, error->message);
2620                 g_clear_error (&error);
2621                 return NULL;
2622         }
2623
2624         g_strstrip (contents);
2625
2626         _log_dbg_sysctl_get (platform, path, contents);
2627
2628         return contents;
2629 }
2630
2631 /******************************************************************/
2632
2633 static gboolean
2634 check_support_kernel_extended_ifa_flags (NMPlatform *platform)
2635 {
2636         g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
2637
2638         return _support_kernel_extended_ifa_flags_get ();
2639 }
2640
2641 static gboolean
2642 check_support_user_ipv6ll (NMPlatform *platform)
2643 {
2644         g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
2645
2646         return _support_user_ipv6ll_get ();
2647 }
2648
2649 static void
2650 process_events (NMPlatform *platform)
2651 {
2652         delayed_action_handle_all (platform, TRUE);
2653 }
2654
2655 /******************************************************************/
2656
2657 #define cache_lookup_all_objects(type, platform, obj_type, visible_only) \
2658         ((const type *const*) nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE ((platform))->cache, \
2659                                                       nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, (obj_type), (visible_only)), \
2660                                                       NULL))
2661
2662 /******************************************************************/
2663
2664 static void
2665 do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cache_op, gboolean was_visible)
2666 {
2667         gboolean is_visible;
2668         NMPObject obj_clone;
2669         const NMPClass *klass;
2670
2671         nm_assert (NM_IN_SET ((NMPlatformSignalChangeType) cache_op, (NMPlatformSignalChangeType) NMP_CACHE_OPS_UNCHANGED, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_SIGNAL_REMOVED));
2672
2673         nm_assert (obj || cache_op == NMP_CACHE_OPS_UNCHANGED);
2674         nm_assert (!obj || cache_op == NMP_CACHE_OPS_REMOVED || obj == nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
2675         nm_assert (!obj || cache_op != NMP_CACHE_OPS_REMOVED || obj != nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
2676
2677         /* we raise the signals inside the namespace of the NMPlatform instance. */
2678         _assert_netns_current (platform);
2679
2680         switch (cache_op) {
2681         case NMP_CACHE_OPS_ADDED:
2682                 if (!nmp_object_is_visible (obj))
2683                         return;
2684                 break;
2685         case NMP_CACHE_OPS_UPDATED:
2686                 is_visible = nmp_object_is_visible (obj);
2687                 if (!was_visible && is_visible)
2688                         cache_op = NMP_CACHE_OPS_ADDED;
2689                 else if (was_visible && !is_visible) {
2690                         /* This is a bit ugly. The object was visible and changed in a way that it became invisible.
2691                          * We raise a removed signal, but contrary to a real 'remove', @obj is already changed to be
2692                          * different from what it was when the user saw it the last time.
2693                          *
2694                          * The more correct solution would be to have cache_pre_hook() create a clone of the original
2695                          * value before it was changed to become invisible.
2696                          *
2697                          * But, don't bother. Probably nobody depends on the original values and only cares about the
2698                          * id properties (which are still correct).
2699                          */
2700                         cache_op = NMP_CACHE_OPS_REMOVED;
2701                 } else if (!is_visible)
2702                         return;
2703                 break;
2704         case NMP_CACHE_OPS_REMOVED:
2705                 if (!was_visible)
2706                         return;
2707                 break;
2708         default:
2709                 g_assert (cache_op == NMP_CACHE_OPS_UNCHANGED);
2710                 return;
2711         }
2712
2713         klass = NMP_OBJECT_GET_CLASS (obj);
2714
2715         _LOGt ("emit signal %s %s: %s",
2716                klass->signal_type,
2717                nm_platform_signal_change_type_to_string ((NMPlatformSignalChangeType) cache_op),
2718                nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
2719
2720         /* don't expose @obj directly, but clone the public fields. A signal handler might
2721          * call back into NMPlatform which could invalidate (or modify) @obj. */
2722         memcpy (&obj_clone.object, &obj->object, klass->sizeof_public);
2723         g_signal_emit (platform,
2724                        _nm_platform_signal_id_get (klass->signal_type_id),
2725                        0,
2726                        klass->obj_type,
2727                        obj_clone.object.ifindex,
2728                        &obj_clone.object,
2729                        (NMPlatformSignalChangeType) cache_op);
2730 }
2731
2732 /******************************************************************/
2733
2734 static DelayedActionType
2735 delayed_action_refresh_from_object_type (NMPObjectType obj_type)
2736 {
2737         switch (obj_type) {
2738         case NMP_OBJECT_TYPE_LINK:          return DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS;
2739         case NMP_OBJECT_TYPE_IP4_ADDRESS:   return DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES;
2740         case NMP_OBJECT_TYPE_IP6_ADDRESS:   return DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES;
2741         case NMP_OBJECT_TYPE_IP4_ROUTE:     return DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES;
2742         case NMP_OBJECT_TYPE_IP6_ROUTE:     return DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES;
2743         default: g_return_val_if_reached (DELAYED_ACTION_TYPE_NONE);
2744         }
2745 }
2746
2747 static NMPObjectType
2748 delayed_action_refresh_to_object_type (DelayedActionType action_type)
2749 {
2750         switch (action_type) {
2751         case DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS:             return NMP_OBJECT_TYPE_LINK;
2752         case DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES:     return NMP_OBJECT_TYPE_IP4_ADDRESS;
2753         case DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES:     return NMP_OBJECT_TYPE_IP6_ADDRESS;
2754         case DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES:        return NMP_OBJECT_TYPE_IP4_ROUTE;
2755         case DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES:        return NMP_OBJECT_TYPE_IP6_ROUTE;
2756         default: g_return_val_if_reached (NMP_OBJECT_TYPE_UNKNOWN);
2757         }
2758 }
2759
2760 static const char *
2761 delayed_action_to_string (DelayedActionType action_type)
2762 {
2763         switch (action_type) {
2764         case DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS              : return "refresh-all-links";
2765         case DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES      : return "refresh-all-ip4-addresses";
2766         case DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES      : return "refresh-all-ip6-addresses";
2767         case DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES         : return "refresh-all-ip4-routes";
2768         case DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES         : return "refresh-all-ip6-routes";
2769         case DELAYED_ACTION_TYPE_REFRESH_LINK                   : return "refresh-link";
2770         case DELAYED_ACTION_TYPE_MASTER_CONNECTED               : return "master-connected";
2771         case DELAYED_ACTION_TYPE_READ_NETLINK                   : return "read-netlink";
2772         case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE           : return "wait-for-nl-response";
2773         default:
2774                 return "unknown";
2775         }
2776 }
2777
2778 static const char *
2779 delayed_action_to_string_full (DelayedActionType action_type, gpointer user_data, char *buf, gsize buf_size)
2780 {
2781         char *buf0 = buf;
2782         const DelayedActionWaitForNlResponseData *data;
2783
2784         nm_utils_strbuf_append_str (&buf, &buf_size, delayed_action_to_string (action_type));
2785         switch (action_type) {
2786         case DELAYED_ACTION_TYPE_MASTER_CONNECTED:
2787                 nm_utils_strbuf_append (&buf, &buf_size, " (master-ifindex %d)", GPOINTER_TO_INT (user_data));
2788                 break;
2789         case DELAYED_ACTION_TYPE_REFRESH_LINK:
2790                 nm_utils_strbuf_append (&buf, &buf_size, " (ifindex %d)", GPOINTER_TO_INT (user_data));
2791                 break;
2792         case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE:
2793                 data = user_data;
2794
2795                 if (data) {
2796                         gint64 timeout = data->timeout_abs_ns - nm_utils_get_monotonic_timestamp_ns ();
2797                         char b[255];
2798
2799                         nm_utils_strbuf_append (&buf, &buf_size, " (seq %u, timeout in %s%"G_GINT64_FORMAT".%09"G_GINT64_FORMAT"%s%s)",
2800                                                 data->seq_number,
2801                                                 timeout < 0 ? "-" : "",
2802                                                 (timeout < 0 ? -timeout : timeout) / NM_UTILS_NS_PER_SECOND,
2803                                                 (timeout < 0 ? -timeout : timeout) % NM_UTILS_NS_PER_SECOND,
2804                                                 data->seq_result ? ", " : "",
2805                                                 data->seq_result ? wait_for_nl_response_to_string (data->seq_result, b, sizeof (b)) : "");
2806                 } else
2807                         nm_utils_strbuf_append_str (&buf, &buf_size, " (any)");
2808                 break;
2809         default:
2810                 nm_assert (!user_data);
2811                 break;
2812         }
2813         return buf0;
2814 }
2815
2816 #define _LOGt_delayed_action(action_type, user_data, operation) \
2817     G_STMT_START { \
2818         char _buf[255]; \
2819         \
2820         _LOGt ("delayed-action: %s %s", \
2821                ""operation, \
2822                delayed_action_to_string_full (action_type, user_data, _buf, sizeof (_buf))); \
2823     } G_STMT_END
2824
2825 /*****************************************************************************/
2826
2827 static void
2828 delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
2829                                               guint idx,
2830                                               WaitForNlResponseResult seq_result)
2831 {
2832         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2833         DelayedActionWaitForNlResponseData *data;
2834         WaitForNlResponseResult *out_seq_result;
2835
2836         nm_assert (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
2837         nm_assert (idx < priv->delayed_action.list_wait_for_nl_response->len);
2838         nm_assert (seq_result);
2839
2840         data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx);
2841
2842         _LOGt_delayed_action (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, data, "complete");
2843
2844         out_seq_result = data->out_seq_result;
2845
2846         g_array_remove_index_fast (priv->delayed_action.list_wait_for_nl_response, idx);
2847         /* Note: @data is invalidated at this point */
2848
2849         if (priv->delayed_action.list_wait_for_nl_response->len <= 0)
2850                 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE;
2851
2852         if (out_seq_result)
2853                 *out_seq_result = seq_result;
2854 }
2855
2856 static void
2857 delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform,
2858                                                   WaitForNlResponseResult fallback_result)
2859 {
2860         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2861
2862         if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
2863                 while (priv->delayed_action.list_wait_for_nl_response->len > 0) {
2864                         const DelayedActionWaitForNlResponseData *data;
2865                         guint idx = priv->delayed_action.list_wait_for_nl_response->len - 1;
2866                         WaitForNlResponseResult r;
2867
2868                         data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx);
2869
2870                         /* prefer the result that we already have. */
2871                         r = data->seq_result ? : fallback_result;
2872
2873                         delayed_action_wait_for_nl_response_complete (platform, idx, r);
2874                 }
2875         }
2876         nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
2877         nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0);
2878 }
2879
2880 /*****************************************************************************/
2881
2882 static void
2883 delayed_action_handle_MASTER_CONNECTED (NMPlatform *platform, int master_ifindex)
2884 {
2885         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2886         nm_auto_nmpobj NMPObject *obj_cache = NULL;
2887         gboolean was_visible;
2888         NMPCacheOpsType cache_op;
2889
2890         cache_op = nmp_cache_update_link_master_connected (priv->cache, master_ifindex, &obj_cache, &was_visible, cache_pre_hook, platform);
2891         do_emit_signal (platform, obj_cache, cache_op, was_visible);
2892 }
2893
2894 static void
2895 delayed_action_handle_REFRESH_LINK (NMPlatform *platform, int ifindex)
2896 {
2897         do_request_link_no_delayed_actions (platform, ifindex, NULL);
2898 }
2899
2900 static void
2901 delayed_action_handle_REFRESH_ALL (NMPlatform *platform, DelayedActionType flags)
2902 {
2903         do_request_all_no_delayed_actions (platform, flags);
2904 }
2905
2906 static void
2907 delayed_action_handle_READ_NETLINK (NMPlatform *platform)
2908 {
2909         event_handler_read_netlink (platform, FALSE);
2910 }
2911
2912 static void
2913 delayed_action_handle_WAIT_FOR_NL_RESPONSE (NMPlatform *platform)
2914 {
2915         event_handler_read_netlink (platform, TRUE);
2916 }
2917
2918 static gboolean
2919 delayed_action_handle_one (NMPlatform *platform)
2920 {
2921         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
2922         gpointer user_data;
2923
2924         if (priv->delayed_action.flags == DELAYED_ACTION_TYPE_NONE)
2925                 return FALSE;
2926
2927         /* First process DELAYED_ACTION_TYPE_MASTER_CONNECTED actions.
2928          * This type of action is entirely cache-internal and is here to resolve a
2929          * cache inconsistency. It should be fixed right away. */
2930         if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_MASTER_CONNECTED)) {
2931                 nm_assert (priv->delayed_action.list_master_connected->len > 0);
2932
2933                 user_data = priv->delayed_action.list_master_connected->pdata[0];
2934                 g_ptr_array_remove_index_fast (priv->delayed_action.list_master_connected, 0);
2935                 if (priv->delayed_action.list_master_connected->len == 0)
2936                         priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_MASTER_CONNECTED;
2937                 nm_assert (_nm_utils_ptrarray_find_first (priv->delayed_action.list_master_connected->pdata, priv->delayed_action.list_master_connected->len, user_data) < 0);
2938
2939                 _LOGt_delayed_action (DELAYED_ACTION_TYPE_MASTER_CONNECTED, user_data, "handle");
2940                 delayed_action_handle_MASTER_CONNECTED (platform, GPOINTER_TO_INT (user_data));
2941                 return TRUE;
2942         }
2943         nm_assert (priv->delayed_action.list_master_connected->len == 0);
2944
2945         /* Next we prefer read-netlink, because the buffer size is limited and we want to process events
2946          * from netlink early. */
2947         if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_READ_NETLINK)) {
2948                 _LOGt_delayed_action (DELAYED_ACTION_TYPE_READ_NETLINK, NULL, "handle");
2949                 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_READ_NETLINK;
2950                 delayed_action_handle_READ_NETLINK (platform);
2951                 return TRUE;
2952         }
2953
2954         if (NM_FLAGS_ANY (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_ALL)) {
2955                 DelayedActionType flags, iflags;
2956
2957                 flags = priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_ALL;
2958
2959                 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL;
2960
2961                 if (_LOGt_ENABLED ()) {
2962                         for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
2963                                 if (NM_FLAGS_HAS (flags, iflags))
2964                                         _LOGt_delayed_action (iflags, NULL, "handle");
2965                         }
2966                 }
2967
2968                 delayed_action_handle_REFRESH_ALL (platform, flags);
2969                 return TRUE;
2970         }
2971
2972         if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)) {
2973                 nm_assert (priv->delayed_action.list_refresh_link->len > 0);
2974
2975                 user_data = priv->delayed_action.list_refresh_link->pdata[0];
2976                 g_ptr_array_remove_index_fast (priv->delayed_action.list_refresh_link, 0);
2977                 if (priv->delayed_action.list_refresh_link->len == 0)
2978                         priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK;
2979                 nm_assert (_nm_utils_ptrarray_find_first (priv->delayed_action.list_refresh_link->pdata, priv->delayed_action.list_refresh_link->len, user_data) < 0);
2980
2981                 _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, user_data, "handle");
2982
2983                 delayed_action_handle_REFRESH_LINK (platform, GPOINTER_TO_INT (user_data));
2984
2985                 return TRUE;
2986         }
2987
2988         if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
2989                 nm_assert (priv->delayed_action.list_wait_for_nl_response->len > 0);
2990                 _LOGt_delayed_action (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, NULL, "handle");
2991                 delayed_action_handle_WAIT_FOR_NL_RESPONSE (platform);
2992                 return TRUE;
2993         }
2994
2995         return FALSE;
2996 }
2997
2998 static gboolean
2999 delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink)
3000 {
3001         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3002         gboolean any = FALSE;
3003
3004         g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE);
3005
3006         priv->delayed_action.is_handling++;
3007         if (read_netlink)
3008                 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_READ_NETLINK, NULL);
3009         while (delayed_action_handle_one (platform))
3010                 any = TRUE;
3011         priv->delayed_action.is_handling--;
3012
3013         cache_prune_candidates_prune (platform);
3014
3015         return any;
3016 }
3017
3018 static void
3019 delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data)
3020 {
3021         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3022         DelayedActionType iflags;
3023
3024         nm_assert (action_type != DELAYED_ACTION_TYPE_NONE);
3025
3026         switch (action_type) {
3027         case DELAYED_ACTION_TYPE_REFRESH_LINK:
3028                 if (_nm_utils_ptrarray_find_first (priv->delayed_action.list_refresh_link->pdata, priv->delayed_action.list_refresh_link->len, user_data) < 0)
3029                         g_ptr_array_add (priv->delayed_action.list_refresh_link, user_data);
3030                 break;
3031         case DELAYED_ACTION_TYPE_MASTER_CONNECTED:
3032                 if (_nm_utils_ptrarray_find_first (priv->delayed_action.list_master_connected->pdata, priv->delayed_action.list_master_connected->len, user_data) < 0)
3033                         g_ptr_array_add (priv->delayed_action.list_master_connected, user_data);
3034                 break;
3035         case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE:
3036                 g_array_append_vals (priv->delayed_action.list_wait_for_nl_response, user_data, 1);
3037                 break;
3038         default:
3039                 nm_assert (!user_data);
3040                 nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_REFRESH_LINK));
3041                 nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_MASTER_CONNECTED));
3042                 nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
3043                 break;
3044         }
3045
3046         priv->delayed_action.flags |= action_type;
3047
3048         if (_LOGt_ENABLED ()) {
3049                 for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
3050                         if (NM_FLAGS_HAS (action_type, iflags))
3051                                 _LOGt_delayed_action (iflags, user_data, "schedule");
3052                 }
3053         }
3054 }
3055
3056 static void
3057 delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform,
3058                                               guint32 seq_number,
3059                                               WaitForNlResponseResult *out_seq_result)
3060 {
3061         DelayedActionWaitForNlResponseData data = {
3062                 .seq_number = seq_number,
3063                 .timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)),
3064                 .out_seq_result = out_seq_result,
3065         };
3066
3067         delayed_action_schedule (platform,
3068                                  DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE,
3069                                  &data);
3070 }
3071
3072 /******************************************************************/
3073
3074 static void
3075 cache_prune_candidates_record_all (NMPlatform *platform, NMPObjectType obj_type)
3076 {
3077         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3078
3079         priv->prune_candidates = nmp_cache_lookup_all_to_hash (priv->cache,
3080                                                                nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, obj_type, FALSE),
3081                                                                priv->prune_candidates);
3082         _LOGt ("cache-prune: record %s (now %u candidates)", nmp_class_from_type (obj_type)->obj_type_name,
3083                priv->prune_candidates ? g_hash_table_size (priv->prune_candidates) : 0);
3084 }
3085
3086 static void
3087 cache_prune_candidates_record_one (NMPlatform *platform, NMPObject *obj)
3088 {
3089         NMLinuxPlatformPrivate *priv;
3090
3091         if (!obj)
3092                 return;
3093
3094         priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3095
3096         if (!priv->prune_candidates)
3097                 priv->prune_candidates = g_hash_table_new_full (NULL, NULL, (GDestroyNotify) nmp_object_unref, NULL);
3098
3099         if (_LOGt_ENABLED () && !g_hash_table_contains (priv->prune_candidates, obj))
3100                 _LOGt ("cache-prune: record-one: %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
3101         g_hash_table_add (priv->prune_candidates, nmp_object_ref (obj));
3102 }
3103
3104 static void
3105 cache_prune_candidates_drop (NMPlatform *platform, const NMPObject *obj)
3106 {
3107         NMLinuxPlatformPrivate *priv;
3108
3109         if (!obj)
3110                 return;
3111
3112         priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3113         if (priv->prune_candidates) {
3114                 if (_LOGt_ENABLED () && g_hash_table_contains (priv->prune_candidates, obj))
3115                         _LOGt ("cache-prune: drop-one: %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
3116                 g_hash_table_remove (priv->prune_candidates, obj);
3117         }
3118 }
3119
3120 static void
3121 cache_prune_candidates_prune (NMPlatform *platform)
3122 {
3123         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3124         GHashTable *prune_candidates;
3125         GHashTableIter iter;
3126         const NMPObject *obj;
3127         gboolean was_visible;
3128         NMPCacheOpsType cache_op;
3129
3130         if (!priv->prune_candidates)
3131                 return;
3132
3133         prune_candidates = priv->prune_candidates;
3134         priv->prune_candidates = NULL;
3135
3136         g_hash_table_iter_init (&iter, prune_candidates);
3137         while (g_hash_table_iter_next (&iter, (gpointer *)&obj, NULL)) {
3138                 nm_auto_nmpobj NMPObject *obj_cache = NULL;
3139
3140                 _LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
3141                 cache_op = nmp_cache_remove (priv->cache, obj, TRUE, &obj_cache, &was_visible, cache_pre_hook, platform);
3142                 do_emit_signal (platform, obj_cache, cache_op, was_visible);
3143         }
3144
3145         g_hash_table_unref (prune_candidates);
3146 }
3147
3148 static void
3149 cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data)
3150 {
3151         NMPlatform *platform = NM_PLATFORM (user_data);
3152         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3153         const NMPClass *klass;
3154         char str_buf[sizeof (_nm_utils_to_string_buffer)];
3155         char str_buf2[sizeof (_nm_utils_to_string_buffer)];
3156
3157         nm_assert (old || new);
3158         nm_assert (NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_REMOVED, NMP_CACHE_OPS_UPDATED));
3159         nm_assert (ops_type != NMP_CACHE_OPS_ADDED   || (old == NULL && NMP_OBJECT_IS_VALID (new) && nmp_object_is_alive (new)));
3160         nm_assert (ops_type != NMP_CACHE_OPS_REMOVED || (new == NULL && NMP_OBJECT_IS_VALID (old) && nmp_object_is_alive (old)));
3161         nm_assert (ops_type != NMP_CACHE_OPS_UPDATED || (NMP_OBJECT_IS_VALID (old) && nmp_object_is_alive (old) && NMP_OBJECT_IS_VALID (new) && nmp_object_is_alive (new)));
3162         nm_assert (new == NULL || old == NULL || nmp_object_id_equal (new, old));
3163
3164         klass = old ? NMP_OBJECT_GET_CLASS (old) : NMP_OBJECT_GET_CLASS (new);
3165
3166         nm_assert (klass == (new ? NMP_OBJECT_GET_CLASS (new) : NMP_OBJECT_GET_CLASS (old)));
3167
3168         _LOGt ("update-cache-%s: %s: %s%s%s",
3169                klass->obj_type_name,
3170                (ops_type == NMP_CACHE_OPS_UPDATED
3171                    ? "UPDATE"
3172                    : (ops_type == NMP_CACHE_OPS_REMOVED
3173                          ? "REMOVE"
3174                          : (ops_type == NMP_CACHE_OPS_ADDED) ? "ADD" : "???")),
3175                (ops_type != NMP_CACHE_OPS_ADDED
3176                    ? nmp_object_to_string (old, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof (str_buf2))
3177                    : nmp_object_to_string (new, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof (str_buf2))),
3178                (ops_type == NMP_CACHE_OPS_UPDATED) ? " -> " : "",
3179                (ops_type == NMP_CACHE_OPS_UPDATED
3180                    ? nmp_object_to_string (new, NMP_OBJECT_TO_STRING_ALL, str_buf, sizeof (str_buf))
3181                    : ""));
3182
3183         switch (klass->obj_type) {
3184         case NMP_OBJECT_TYPE_LINK:
3185                 {
3186                         /* check whether changing a slave link can cause a master link (bridge or bond) to go up/down */
3187                         if (   old
3188                             && nmp_cache_link_connected_needs_toggle_by_ifindex (priv->cache, old->link.master, new, old))
3189                                 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (old->link.master));
3190                         if (   new
3191                             && (!old || old->link.master != new->link.master)
3192                             && nmp_cache_link_connected_needs_toggle_by_ifindex (priv->cache, new->link.master, new, old))
3193                                 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (new->link.master));
3194                 }
3195                 {
3196                         /* check whether we are about to change a master link that needs toggling connected state. */
3197                         if (   new /* <-- nonsensical, make coverity happy */
3198                             && nmp_cache_link_connected_needs_toggle (cache, new, new, old))
3199                                 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (new->link.ifindex));
3200                 }
3201                 {
3202                         int ifindex = 0;
3203
3204                         /* if we remove a link (from netlink), we must refresh the addresses and routes */
3205                         if (   ops_type == NMP_CACHE_OPS_REMOVED
3206                             && old /* <-- nonsensical, make coverity happy */)
3207                                 ifindex = old->link.ifindex;
3208                         else if (   ops_type == NMP_CACHE_OPS_UPDATED
3209                                  && old && new /* <-- nonsensical, make coverity happy */
3210                                  && !new->_link.netlink.is_in_netlink
3211                                  && new->_link.netlink.is_in_netlink != old->_link.netlink.is_in_netlink)
3212                                 ifindex = new->link.ifindex;
3213
3214                         if (ifindex > 0) {
3215                                 delayed_action_schedule (platform,
3216                                                          DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
3217                                                          DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
3218                                                          DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
3219                                                          DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
3220                                                          NULL);
3221                         }
3222                 }
3223                 {
3224                         int ifindex = -1;
3225
3226                         /* removal of a link could be caused by moving the link to another netns.
3227                          * In this case, we potentially have to update other links that have this link as parent.
3228                          * Currently, kernel misses to sent us a notification in this case
3229                          * (https://bugzilla.redhat.com/show_bug.cgi?id=1262908). */
3230
3231                         if (   ops_type == NMP_CACHE_OPS_REMOVED
3232                             && old /* <-- nonsensical, make coverity happy */
3233                             && old->_link.netlink.is_in_netlink)
3234                                 ifindex = old->link.ifindex;
3235                         else if (   ops_type == NMP_CACHE_OPS_UPDATED
3236                                  && old && new /* <-- nonsensical, make coverity happy */
3237                                  && old->_link.netlink.is_in_netlink
3238                                  && !new->_link.netlink.is_in_netlink)
3239                                 ifindex = new->link.ifindex;
3240
3241                         if (ifindex > 0) {
3242                                 const NMPlatformLink *const *links;
3243
3244                                 links = cache_lookup_all_objects (NMPlatformLink, platform, NMP_OBJECT_TYPE_LINK, FALSE);
3245                                 if (links) {
3246                                         for (; *links; links++) {
3247                                                 const NMPlatformLink *l = (*links);
3248
3249                                                 if (l->parent == ifindex)
3250                                                         delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (l->ifindex));
3251                                         }
3252                                 }
3253                         }
3254                 }
3255                 {
3256                         /* if a link goes down, we must refresh routes */
3257                         if (   ops_type == NMP_CACHE_OPS_UPDATED
3258                             && old && new /* <-- nonsensical, make coverity happy */
3259                             && old->_link.netlink.is_in_netlink
3260                             && NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_LOWER_UP)
3261                             && new->_link.netlink.is_in_netlink
3262                             && !NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_LOWER_UP)) {
3263                                 delayed_action_schedule (platform,
3264                                                          DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
3265                                                          DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
3266                                                          NULL);
3267                         }
3268                 }
3269                 if (   NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED)
3270                     && (new && new->_link.netlink.is_in_netlink)
3271                     && (!old || !old->_link.netlink.is_in_netlink))
3272                 {
3273                         if (!new->_link.netlink.lnk) {
3274                                 /* certain link-types also come with a IFLA_INFO_DATA/lnk_data. It may happen that
3275                                  * kernel didn't send this notification, thus when we first learn about a link
3276                                  * that lacks an lnk_data we re-request it again.
3277                                  *
3278                                  * For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */
3279                                 switch (new->link.type) {
3280                                 case NM_LINK_TYPE_GRE:
3281                                 case NM_LINK_TYPE_IP6TNL:
3282                                 case NM_LINK_TYPE_INFINIBAND:
3283                                 case NM_LINK_TYPE_MACVLAN:
3284                                 case NM_LINK_TYPE_MACVTAP:
3285                                 case NM_LINK_TYPE_SIT:
3286                                 case NM_LINK_TYPE_VLAN:
3287                                 case NM_LINK_TYPE_VXLAN:
3288                                         delayed_action_schedule (platform,
3289                                                                  DELAYED_ACTION_TYPE_REFRESH_LINK,
3290                                                                  GINT_TO_POINTER (new->link.ifindex));
3291                                         break;
3292                                 default:
3293                                         break;
3294                                 }
3295                         }
3296                         if (   new->link.type == NM_LINK_TYPE_VETH
3297                             && new->link.parent == 0) {
3298                                 /* the initial notification when adding a veth pair can lack the parent/IFLA_LINK
3299                                  * (https://bugzilla.redhat.com/show_bug.cgi?id=1285827).
3300                                  * Request it again. */
3301                                 delayed_action_schedule (platform,
3302                                                          DELAYED_ACTION_TYPE_REFRESH_LINK,
3303                                                          GINT_TO_POINTER (new->link.ifindex));
3304                         }
3305                         if (   new->link.type == NM_LINK_TYPE_ETHERNET
3306                             && new->link.addr.len == 0) {
3307                                 /* Due to a kernel bug, we sometimes receive spurious NEWLINK
3308                                  * messages after a wifi interface has disappeared. Since the
3309                                  * link is not present anymore we can't determine its type and
3310                                  * thus it will show up as a Ethernet one, with no address
3311                                  * specified.  Request the link again to check if it really
3312                                  * exists.  https://bugzilla.redhat.com/show_bug.cgi?id=1302037
3313                                  */
3314                                 delayed_action_schedule (platform,
3315                                                          DELAYED_ACTION_TYPE_REFRESH_LINK,
3316                                                          GINT_TO_POINTER (new->link.ifindex));
3317                         }
3318                 }
3319                 {
3320                         /* on enslave/release, we also refresh the master. */
3321                         int ifindex1 = 0, ifindex2 = 0;
3322                         gboolean changed_master, changed_connected;
3323
3324                         changed_master =    (new && new->_link.netlink.is_in_netlink && new->link.master > 0 ? new->link.master : 0)
3325                                          != (old && old->_link.netlink.is_in_netlink && old->link.master > 0 ? old->link.master : 0);
3326                         changed_connected =    (new && new->_link.netlink.is_in_netlink ? NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_LOWER_UP) : 2)
3327                                             != (old && old->_link.netlink.is_in_netlink ? NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_LOWER_UP) : 2);
3328
3329                         if (changed_master || changed_connected) {
3330                                 ifindex1 = (old && old->_link.netlink.is_in_netlink && old->link.master > 0) ? old->link.master : 0;
3331                                 ifindex2 = (new && new->_link.netlink.is_in_netlink && new->link.master > 0) ? new->link.master : 0;
3332
3333                                 if (ifindex1 > 0)
3334                                         delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex1));
3335                                 if (ifindex2 > 0 && ifindex1 != ifindex2)
3336                                         delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex2));
3337                         }
3338                 }
3339                 {
3340                         if (   (       (ops_type == NMP_CACHE_OPS_REMOVED)
3341                                 || (   (ops_type == NMP_CACHE_OPS_UPDATED)
3342                                     && new
3343                                     && !new->_link.netlink.is_in_netlink))
3344                             && old
3345                             && old->_link.netlink.is_in_netlink
3346                             && old->link.master) {
3347                                 /* sometimes we receive a wrong RTM_DELLINK message when unslaving
3348                                  * a device. Refetch the link again to check whether the device
3349                                  * is really gone.
3350                                  *
3351                                  * https://bugzilla.redhat.com/show_bug.cgi?id=1285719#c2 */
3352                                 delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (old->link.ifindex));
3353                         }
3354                 }
3355                 break;
3356         case NMP_OBJECT_TYPE_IP4_ADDRESS:
3357         case NMP_OBJECT_TYPE_IP6_ADDRESS:
3358                 {
3359                         /* Address deletion is sometimes accompanied by route deletion. We need to
3360                          * check all routes belonging to the same interface. */
3361                         if (ops_type == NMP_CACHE_OPS_REMOVED) {
3362                                 delayed_action_schedule (platform,
3363                                                          (klass->obj_type == NMP_OBJECT_TYPE_IP4_ADDRESS)
3364                                                              ? DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES
3365                                                              : DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
3366                                                          NULL);
3367                         }
3368                 }
3369         default:
3370                 break;
3371         }
3372 }
3373
3374 /******************************************************************/
3375
3376 static int
3377 _nl_send_auto_with_seq (NMPlatform *platform,
3378                         struct nl_msg *nlmsg,
3379                         WaitForNlResponseResult *out_seq_result)
3380 {
3381         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3382         guint32 seq;
3383         int nle;
3384
3385         /* complete the message with a sequence number (ensuring it's not zero). */
3386         seq = priv->nlh_seq_next++ ?: priv->nlh_seq_next++;
3387
3388         nlmsg_hdr (nlmsg)->nlmsg_seq = seq;
3389
3390         nle = nl_send_auto (priv->nlh, nlmsg);
3391
3392         if (nle >= 0) {
3393                 nle = 0;
3394                 delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result);
3395         } else
3396                 _LOGD ("netlink: send: failed sending message: %s (%d)", nl_geterror (nle), nle);
3397
3398         return nle;
3399 }
3400
3401 static void
3402 do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name)
3403 {
3404         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3405         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
3406
3407         if (name && !name[0])
3408                 name = NULL;
3409
3410         g_return_if_fail (ifindex > 0 || name);
3411
3412         _LOGD ("do-request-link: %d %s", ifindex, name ? name : "");
3413
3414         if (ifindex > 0) {
3415                 cache_prune_candidates_record_one (platform,
3416                                                    (NMPObject *) nmp_cache_lookup_link (priv->cache, ifindex));
3417         }
3418
3419         event_handler_read_netlink (platform, FALSE);
3420
3421         nlmsg = _nl_msg_new_link (RTM_GETLINK,
3422                                   0,
3423                                   ifindex,
3424                                   name,
3425                                   0,
3426                                   0);
3427         if (nlmsg)
3428                 _nl_send_auto_with_seq (platform, nlmsg, NULL);
3429 }
3430
3431 static void
3432 do_request_link (NMPlatform *platform, int ifindex, const char *name)
3433 {
3434         do_request_link_no_delayed_actions (platform, ifindex, name);
3435         delayed_action_handle_all (platform, FALSE);
3436 }
3437
3438 static void
3439 do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type)
3440 {
3441         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3442         DelayedActionType iflags;
3443
3444         nm_assert (!NM_FLAGS_ANY (action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL));
3445         action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL;
3446
3447         for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
3448                 if (NM_FLAGS_HAS (action_type, iflags))
3449                         cache_prune_candidates_record_all (platform, delayed_action_refresh_to_object_type (iflags));
3450         }
3451
3452         for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
3453                 if (NM_FLAGS_HAS (action_type, iflags)) {
3454                         NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags);
3455                         const NMPClass *klass = nmp_class_from_type (obj_type);
3456                         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
3457                         struct rtgenmsg gmsg = {
3458                                 .rtgen_family = klass->addr_family,
3459                         };
3460                         int nle;
3461
3462                         /* clear any delayed action that request a refresh of this object type. */
3463                         priv->delayed_action.flags &= ~iflags;
3464                         _LOGt_delayed_action (iflags, NULL, "handle (do-request-all)");
3465                         if (obj_type == NMP_OBJECT_TYPE_LINK) {
3466                                 priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK;
3467                                 g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0);
3468                                 _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, NULL, "clear (do-request-all)");
3469                         }
3470
3471                         event_handler_read_netlink (platform, FALSE);
3472
3473                         /* reimplement
3474                          *   nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP);
3475                          * because we need the sequence number.
3476                          */
3477                         nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP);
3478                         if (!nlmsg)
3479                                 goto next;
3480
3481                         nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO);
3482                         if (nle < 0)
3483                                 goto next;
3484
3485                         _nl_send_auto_with_seq (platform, nlmsg, NULL);
3486                 }
3487 next:
3488                 ;
3489         }
3490 }
3491
3492 static void
3493 do_request_one_type (NMPlatform *platform, NMPObjectType obj_type)
3494 {
3495         do_request_all_no_delayed_actions (platform, delayed_action_refresh_from_object_type (obj_type));
3496         delayed_action_handle_all (platform, FALSE);
3497 }
3498
3499 static void
3500 event_seq_check (NMPlatform *platform, struct nl_msg *msg, WaitForNlResponseResult seq_result)
3501 {
3502         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3503         DelayedActionWaitForNlResponseData *data;
3504         guint32 seq_number;
3505         guint i;
3506
3507         seq_number = nlmsg_hdr (msg)->nlmsg_seq;
3508
3509         if (seq_number == 0)
3510                 return;
3511
3512         if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
3513                 nm_assert (priv->delayed_action.list_wait_for_nl_response->len > 0);
3514
3515                 for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) {
3516                         data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
3517
3518                         if (data->seq_number == seq_number) {
3519                                 /* We potentially receive many parts partial responses for the same sequence number.
3520                                  * Thus, we only remember the result, and collect it later. */
3521                                 if (data->seq_result < 0) {
3522                                         /* we already saw an error for this seqence number.
3523                                          * Preserve it. */
3524                                 } else if (   seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN
3525                                            || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN)
3526                                         data->seq_result = seq_result;
3527                                 return;
3528                         }
3529                 }
3530         }
3531
3532         if (seq_number != priv->nlh_seq_last_handled)
3533                 _LOGt ("netlink: recvmsg: unwaited sequence number %u", seq_number);
3534         priv->nlh_seq_last_handled = seq_number;
3535 }
3536
3537 static void
3538 event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_events)
3539 {
3540         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3541         nm_auto_nmpobj NMPObject *obj = NULL;
3542         nm_auto_nmpobj NMPObject *obj_cache = NULL;
3543         NMPCacheOpsType cache_op;
3544         struct nlmsghdr *msghdr;
3545         char buf_nlmsg_type[16];
3546         gboolean id_only = FALSE;
3547         gboolean was_visible;
3548
3549         msghdr = nlmsg_hdr (msg);
3550
3551         if (_support_kernel_extended_ifa_flags_still_undecided () && msghdr->nlmsg_type == RTM_NEWADDR)
3552                 _support_kernel_extended_ifa_flags_detect (msg);
3553
3554         if (!handle_events)
3555                 return;
3556
3557         if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE)) {
3558                 /* The event notifies about a deleted object. We don't need to initialize all
3559                  * fields of the object. */
3560                 id_only = TRUE;
3561         }
3562
3563         obj = nmp_object_new_from_nl (platform, priv->cache, msg, id_only);
3564         if (!obj) {
3565                 _LOGT ("event-notification: %s, seq %u: ignore",
3566                        _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)),
3567                        msghdr->nlmsg_seq);
3568                 return;
3569         }
3570
3571         _LOGT ("event-notification: %s, seq %u: %s",
3572                _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)),
3573                msghdr->nlmsg_seq, nmp_object_to_string (obj,
3574                    id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
3575
3576         switch (msghdr->nlmsg_type) {
3577
3578         case RTM_NEWLINK:
3579         case RTM_NEWADDR:
3580         case RTM_NEWROUTE:
3581                 cache_op = nmp_cache_update_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform);
3582                 do_emit_signal (platform, obj_cache, cache_op, was_visible);
3583                 break;
3584
3585         case RTM_DELLINK:
3586         case RTM_DELADDR:
3587         case RTM_DELROUTE:
3588                 cache_op = nmp_cache_remove_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform);
3589                 do_emit_signal (platform, obj_cache, cache_op, was_visible);
3590                 break;
3591
3592         default:
3593                 break;
3594         }
3595
3596         cache_prune_candidates_drop (platform, obj_cache);
3597 }
3598
3599 /******************************************************************/
3600
3601 static const NMPObject *
3602 cache_lookup_link (NMPlatform *platform, int ifindex)
3603 {
3604         const NMPObject *obj_cache;
3605
3606         obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
3607         if (!nmp_object_is_visible (obj_cache))
3608                 return NULL;
3609
3610         return obj_cache;
3611 }
3612
3613 static GArray *
3614 link_get_all (NMPlatform *platform)
3615 {
3616         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3617
3618         return nmp_cache_lookup_multi_to_array (priv->cache,
3619                                                 NMP_OBJECT_TYPE_LINK,
3620                                                 nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, NMP_OBJECT_TYPE_LINK, TRUE));
3621 }
3622
3623 static const NMPlatformLink *
3624 _nm_platform_link_get (NMPlatform *platform, int ifindex)
3625 {
3626         const NMPObject *obj;
3627
3628         obj = cache_lookup_link (platform, ifindex);
3629         return obj ? &obj->link : NULL;
3630 }
3631
3632 static const NMPlatformLink *
3633 _nm_platform_link_get_by_ifname (NMPlatform *platform,
3634                                  const char *ifname)
3635 {
3636         const NMPObject *obj = NULL;
3637
3638         if (ifname && *ifname) {
3639                 obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
3640                                                   0, ifname, TRUE, NM_LINK_TYPE_NONE, NULL, NULL);
3641         }
3642         return obj ? &obj->link : NULL;
3643 }
3644
3645 struct _nm_platform_link_get_by_address_data {
3646         gconstpointer address;
3647         guint8 length;
3648 };
3649
3650 static gboolean
3651 _nm_platform_link_get_by_address_match_link (const NMPObject *obj, struct _nm_platform_link_get_by_address_data *d)
3652 {
3653         return obj->link.addr.len == d->length && !memcmp (obj->link.addr.data, d->address, d->length);
3654 }
3655
3656 static const NMPlatformLink *
3657 _nm_platform_link_get_by_address (NMPlatform *platform,
3658                                   gconstpointer address,
3659                                   size_t length)
3660 {
3661         const NMPObject *obj;
3662         struct _nm_platform_link_get_by_address_data d = {
3663                 .address = address,
3664                 .length = length,
3665         };
3666
3667         if (length <= 0 || length > NM_UTILS_HWADDR_LEN_MAX)
3668                 return NULL;
3669         if (!address)
3670                 return NULL;
3671
3672         obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
3673                                           0, NULL, TRUE, NM_LINK_TYPE_NONE,
3674                                           (NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link, &d);
3675         return obj ? &obj->link : NULL;
3676 }
3677
3678 /*****************************************************************************/
3679
3680 static const NMPObject *
3681 link_get_lnk (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link)
3682 {
3683         const NMPObject *obj = cache_lookup_link (platform, ifindex);
3684
3685         if (!obj)
3686                 return NULL;
3687
3688         NM_SET_OUT (out_link, &obj->link);
3689
3690         if (!obj->_link.netlink.lnk)
3691                 return NULL;
3692         if (   link_type != NM_LINK_TYPE_NONE
3693             && (   link_type != obj->link.type
3694                 || link_type != NMP_OBJECT_GET_CLASS (obj->_link.netlink.lnk)->lnk_link_type))
3695                 return NULL;
3696
3697         return obj->_link.netlink.lnk;
3698 }
3699
3700 /*****************************************************************************/
3701
3702 static gboolean
3703 do_add_link_with_lookup (NMPlatform *platform,
3704                          NMLinkType link_type,
3705                          const char *name,
3706                          struct nl_msg *nlmsg,
3707                          const NMPlatformLink **out_link)
3708 {
3709         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3710         const NMPObject *obj = NULL;
3711         WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
3712         int nle;
3713         char s_buf[256];
3714
3715         event_handler_read_netlink (platform, FALSE);
3716
3717         if (nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) {
3718                 /* hm, a link with such a name already exists. Try reloading first. */
3719                 do_request_link (platform, 0, name);
3720
3721                 obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL);
3722                 if (obj) {
3723                         _LOGE ("do-add-link[%s/%s]: link already exists: %s",
3724                                name,
3725                                nm_link_type_to_string (link_type),
3726                                nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
3727                         return FALSE;
3728                 }
3729         }
3730
3731         nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
3732         if (nle < 0) {
3733                 _LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)",
3734                        name,
3735                        nm_link_type_to_string (link_type),
3736                        nl_geterror (nle), -nle);
3737                 return FALSE;
3738         }
3739
3740         delayed_action_handle_all (platform, FALSE);
3741
3742         nm_assert (seq_result);
3743
3744         _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
3745                     ? LOGL_DEBUG
3746                     : LOGL_ERR,
3747                 "do-add-link[%s/%s]: %s",
3748                 name,
3749                 nm_link_type_to_string (link_type),
3750                 wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)));
3751
3752         if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
3753                 obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, link_type, NULL, NULL);
3754
3755         if (!obj) {
3756                 /* either kernel signaled failure, or it signaled success and the link object
3757                  * is not (yet) in the cache. Try to reload it... */
3758                 do_request_link (platform, 0, name);
3759                 obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, link_type, NULL, NULL);
3760         }
3761
3762         if (out_link)
3763                 *out_link = obj ? &obj->link : NULL;
3764         return !!obj;
3765 }
3766
3767 static gboolean
3768 do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
3769 {
3770         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3771         WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
3772         int nle;
3773         char s_buf[256];
3774         const NMPObject *obj;
3775
3776         nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id),
3777                               NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS,
3778                               NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
3779
3780         event_handler_read_netlink (platform, FALSE);
3781
3782         nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
3783         if (nle < 0) {
3784                 _LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)",
3785                        NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
3786                        nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
3787                        nl_geterror (nle), -nle);
3788                 return FALSE;
3789         }
3790
3791         delayed_action_handle_all (platform, FALSE);
3792
3793         nm_assert (seq_result);
3794
3795         _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
3796                     ? LOGL_DEBUG
3797                     : LOGL_ERR,
3798                 "do-add-%s[%s]: %s",
3799                 NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
3800                 nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
3801                 wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)));
3802
3803         /* In rare cases, the object is not yet ready as we received the ACK from
3804          * kernel. Need to refetch.
3805          *
3806          * We want to safe the expensive refetch, thus we look first into the cache
3807          * whether the object exists.
3808          *
3809          * FIXME: if the object already existed previously, we might not notice a
3810          * missing update. It's not clear how to fix that reliably without refechting
3811          * all the time. */
3812         obj = nmp_cache_lookup_obj (priv->cache, obj_id);
3813         if (!obj) {
3814                 do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
3815                 obj = nmp_cache_lookup_obj (priv->cache, obj_id);
3816         }
3817
3818         /* Adding is only successful, if kernel reported success *and* we have the
3819          * expected object in cache afterwards. */
3820         return obj && seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
3821 }
3822
3823 static gboolean
3824 do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
3825 {
3826         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3827         WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
3828         int nle;
3829         char s_buf[256];
3830         gboolean success = TRUE;
3831         const char *log_detail = "";
3832
3833         event_handler_read_netlink (platform, FALSE);
3834
3835         nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
3836         if (nle < 0) {
3837                 _LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)",
3838                        NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
3839                        nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
3840                        nl_geterror (nle), -nle);
3841                 goto out;
3842         }
3843
3844         delayed_action_handle_all (platform, FALSE);
3845
3846         nm_assert (seq_result);
3847
3848         if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) {
3849                 /* ok */
3850         } else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT))
3851                 log_detail = ", meaning the object was already removed";
3852         else if (   NM_IN_SET (-((int) seq_result), ENXIO)
3853                  && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), NMP_OBJECT_TYPE_IP6_ADDRESS)) {
3854                 /* On RHEL7 kernel, deleting a non existing address fails with ENXIO */
3855                 log_detail = ", meaning the address was already removed";
3856         } else if (   NM_IN_SET (-((int) seq_result), EADDRNOTAVAIL)
3857                    && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS))
3858                 log_detail = ", meaning the address was already removed";
3859         else
3860                 success = FALSE;
3861
3862         _NMLOG (success ? LOGL_DEBUG : LOGL_ERR,
3863                 "do-delete-%s[%s]: %s%s",
3864                 NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
3865                 nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
3866                 wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)),
3867                 log_detail);
3868
3869 out:
3870         if (!nmp_cache_lookup_obj (priv->cache, obj_id))
3871                 return TRUE;
3872
3873         /* such an object still exists in the cache. To be sure, refetch it (and
3874          * hope it's gone) */
3875         do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
3876         return !!nmp_cache_lookup_obj (priv->cache, obj_id);
3877 }
3878
3879 static NMPlatformError
3880 do_change_link (NMPlatform *platform,
3881                 int ifindex,
3882                 struct nl_msg *nlmsg)
3883 {
3884         nm_auto_pop_netns NMPNetns *netns = NULL;
3885         WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
3886         int nle;
3887         char s_buf[256];
3888         NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS;
3889         NMLogLevel log_level = LOGL_DEBUG;
3890         const char *log_result = "failure", *log_detail = "";
3891
3892         if (!nm_platform_netns_push (platform, &netns))
3893                 return NM_PLATFORM_ERROR_UNSPECIFIED;
3894
3895 retry:
3896         nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
3897         if (nle < 0) {
3898                 _LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)",
3899                        ifindex,
3900                        nl_geterror (nle), -nle);
3901                 return NM_PLATFORM_ERROR_UNSPECIFIED;
3902         }
3903
3904         /* always refetch the link after changing it. There seems to be issues
3905          * and we sometimes lack events. Nuke it from the orbit... */
3906         delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex));
3907
3908         delayed_action_handle_all (platform, FALSE);
3909
3910         nm_assert (seq_result);
3911
3912         if (   NM_IN_SET (-((int) seq_result), EOPNOTSUPP)
3913             && nlmsg_hdr (nlmsg)->nlmsg_type == RTM_NEWLINK) {
3914                 nlmsg_hdr (nlmsg)->nlmsg_type = RTM_SETLINK;
3915                 goto retry;
3916         }
3917
3918         if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) {
3919                 log_result = "success";
3920         } else if (NM_IN_SET (-((int) seq_result), EEXIST, EADDRINUSE)) {
3921                 /* */
3922         } else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT)) {
3923                 log_detail = ", firmware not found";
3924                 result = NM_PLATFORM_ERROR_NO_FIRMWARE;
3925         } else {
3926                 log_level = LOGL_ERR;
3927                 result = NM_PLATFORM_ERROR_UNSPECIFIED;
3928         }
3929         _NMLOG (log_level,
3930                 "do-change-link[%d]: %s changing link: %s%s",
3931                 ifindex,
3932                 log_result,
3933                 wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)),
3934                 log_detail);
3935
3936         return result;
3937 }
3938
3939 static gboolean
3940 link_add (NMPlatform *platform,
3941           const char *name,
3942           NMLinkType type,
3943           const void *address,
3944           size_t address_len,
3945           const NMPlatformLink **out_link)
3946 {
3947         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
3948
3949         if (type == NM_LINK_TYPE_BOND) {
3950                 /* When the kernel loads the bond module, either via explicit modprobe
3951                  * or automatically in response to creating a bond master, it will also
3952                  * create a 'bond0' interface.  Since the bond we're about to create may
3953                  * or may not be named 'bond0' prevent potential confusion about a bond
3954                  * that the user didn't want by telling the bonding module not to create
3955                  * bond0 automatically.
3956                  */
3957                 if (!g_file_test ("/sys/class/net/bonding_masters", G_FILE_TEST_EXISTS))
3958                         (void) nm_utils_modprobe (NULL, TRUE, "bonding", "max_bonds=0", NULL);
3959         }
3960
3961         _LOGD ("link: add link '%s' of type '%s' (%d)",
3962                name, nm_link_type_to_string (type), (int) type);
3963
3964         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
3965                                   NLM_F_CREATE,
3966                                   0,
3967                                   name,
3968                                   0,
3969                                   0);
3970         if (!nlmsg)
3971                 return FALSE;
3972
3973         if (address && address_len)
3974                 NLA_PUT (nlmsg, IFLA_ADDRESS, address_len, address);
3975
3976         if (!_nl_msg_new_link_set_linkinfo (nlmsg, type))
3977                 return FALSE;
3978
3979         return do_add_link_with_lookup (platform, type, name, nlmsg, out_link);
3980 nla_put_failure:
3981         g_return_val_if_reached (FALSE);
3982 }
3983
3984 static gboolean
3985 link_delete (NMPlatform *platform, int ifindex)
3986 {
3987         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
3988         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
3989         NMPObject obj_id;
3990         const NMPObject *obj;
3991
3992         obj = nmp_cache_lookup_link (priv->cache, ifindex);
3993         if (!obj || !obj->_link.netlink.is_in_netlink)
3994                 return FALSE;
3995
3996         nlmsg = _nl_msg_new_link (RTM_DELLINK,
3997                                   0,
3998                                   ifindex,
3999                                   NULL,
4000                                   0,
4001                                   0);
4002
4003         nmp_object_stackinit_id_link (&obj_id, ifindex);
4004         return do_delete_object (platform, &obj_id, nlmsg);
4005 }
4006
4007 static const char *
4008 link_get_type_name (NMPlatform *platform, int ifindex)
4009 {
4010         const NMPObject *obj = cache_lookup_link (platform, ifindex);
4011
4012         if (!obj)
4013                 return NULL;
4014
4015         if (obj->link.type != NM_LINK_TYPE_UNKNOWN) {
4016                 /* We could detect the @link_type. In this case the function returns
4017                  * our internel module names, which differs from rtnl_link_get_type():
4018                  *   - NM_LINK_TYPE_INFINIBAND (gives "infiniband", instead of "ipoib")
4019                  *   - NM_LINK_TYPE_TAP (gives "tap", instead of "tun").
4020                  * Note that this functions is only used by NMDeviceGeneric to
4021                  * set type_description. */
4022                 return nm_link_type_to_string (obj->link.type);
4023         }
4024         /* Link type not detected. Fallback to rtnl_link_get_type()/IFLA_INFO_KIND. */
4025         return obj->link.kind ?: "unknown";
4026 }
4027
4028 static gboolean
4029 link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *unmanaged)
4030 {
4031         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
4032         const NMPObject *link;
4033         GUdevDevice *udev_device = NULL;
4034
4035         link = nmp_cache_lookup_link (priv->cache, ifindex);
4036         if (link)
4037                 udev_device = link->_link.udev.device;
4038
4039         if (udev_device && g_udev_device_get_property (udev_device, "NM_UNMANAGED")) {
4040                 *unmanaged = g_udev_device_get_property_as_boolean (udev_device, "NM_UNMANAGED");
4041                 return TRUE;
4042         }
4043
4044         return FALSE;
4045 }
4046
4047 static gboolean
4048 link_refresh (NMPlatform *platform, int ifindex)
4049 {
4050         do_request_link (platform, ifindex, NULL);
4051         return !!cache_lookup_link (platform, ifindex);
4052 }
4053
4054 static gboolean
4055 link_set_netns (NMPlatform *platform,
4056                 int ifindex,
4057                 int netns_fd)
4058 {
4059         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4060
4061         _LOGD ("link: move link %d to network namespace with fd %d", ifindex, netns_fd);
4062
4063         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4064                                   0,
4065                                   ifindex,
4066                                   NULL,
4067                                   0,
4068                                   0);
4069         if (!nlmsg)
4070                 return FALSE;
4071
4072         NLA_PUT (nlmsg, IFLA_NET_NS_FD, 4, &netns_fd);
4073         return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4074
4075 nla_put_failure:
4076         g_return_val_if_reached (FALSE);
4077 }
4078
4079 static NMPlatformError
4080 link_change_flags (NMPlatform *platform,
4081                    int ifindex,
4082                    unsigned flags_mask,
4083                    unsigned flags_set)
4084 {
4085         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4086         char s_flags[100];
4087
4088         _LOGD ("link: change %d: flags: set 0x%x/0x%x ([%s] / [%s])",
4089                ifindex,
4090                flags_set,
4091                flags_mask,
4092                nm_platform_link_flags2str (flags_set, s_flags, sizeof (s_flags)),
4093                nm_platform_link_flags2str (flags_mask, NULL, 0));
4094
4095         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4096                                   0,
4097                                   ifindex,
4098                                   NULL,
4099                                   flags_mask,
4100                                   flags_set);
4101         if (!nlmsg)
4102                 return NM_PLATFORM_ERROR_UNSPECIFIED;
4103         return do_change_link (platform, ifindex, nlmsg);
4104 }
4105
4106 static gboolean
4107 link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware)
4108 {
4109         NMPlatformError plerr;
4110
4111         plerr = link_change_flags (platform, ifindex, IFF_UP, IFF_UP);
4112         if (out_no_firmware)
4113                 *out_no_firmware = plerr == NM_PLATFORM_ERROR_NO_FIRMWARE;
4114         return plerr == NM_PLATFORM_ERROR_SUCCESS;
4115 }
4116
4117 static gboolean
4118 link_set_down (NMPlatform *platform, int ifindex)
4119 {
4120         return link_change_flags (platform, ifindex, IFF_UP, 0) == NM_PLATFORM_ERROR_SUCCESS;
4121 }
4122
4123 static gboolean
4124 link_set_arp (NMPlatform *platform, int ifindex)
4125 {
4126         return link_change_flags (platform, ifindex, IFF_NOARP, 0) == NM_PLATFORM_ERROR_SUCCESS;
4127 }
4128
4129 static gboolean
4130 link_set_noarp (NMPlatform *platform, int ifindex)
4131 {
4132         return link_change_flags (platform, ifindex, IFF_NOARP, IFF_NOARP) == NM_PLATFORM_ERROR_SUCCESS;
4133 }
4134
4135 static const char *
4136 link_get_udi (NMPlatform *platform, int ifindex)
4137 {
4138         const NMPObject *obj = cache_lookup_link (platform, ifindex);
4139
4140         if (   !obj
4141             || !obj->_link.netlink.is_in_netlink
4142             || !obj->_link.udev.device)
4143                 return NULL;
4144         return g_udev_device_get_sysfs_path (obj->_link.udev.device);
4145 }
4146
4147 static GObject *
4148 link_get_udev_device (NMPlatform *platform, int ifindex)
4149 {
4150         const NMPObject *obj_cache;
4151
4152         /* we don't use cache_lookup_link() because this would return NULL
4153          * if the link is not visible in libnl. For link_get_udev_device()
4154          * we want to return whatever we have, even if the link itself
4155          * appears invisible via other platform functions. */
4156
4157         obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
4158         return obj_cache ? (GObject *) obj_cache->_link.udev.device : NULL;
4159 }
4160
4161 static gboolean
4162 link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled)
4163 {
4164         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4165         guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64;
4166
4167         if (!_support_user_ipv6ll_get ()) {
4168                 _LOGD ("link: change %d: user-ipv6ll: not supported", ifindex);
4169                 return FALSE;
4170         }
4171
4172         _LOGD ("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s",
4173                ifindex,
4174                nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0));
4175
4176         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4177                                   0,
4178                                   ifindex,
4179                                   NULL,
4180                                   0,
4181                                   0);
4182         if (   !nlmsg
4183             || !_nl_msg_new_link_set_afspec (nlmsg,
4184                                              mode))
4185                 g_return_val_if_reached (FALSE);
4186
4187         return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4188 }
4189
4190 static gboolean
4191 link_supports_carrier_detect (NMPlatform *platform, int ifindex)
4192 {
4193         nm_auto_pop_netns NMPNetns *netns = NULL;
4194         const char *name = nm_platform_link_get_name (platform, ifindex);
4195
4196         if (!name)
4197                 return FALSE;
4198
4199         if (!nm_platform_netns_push (platform, &netns))
4200                 return FALSE;
4201
4202         /* We use netlink for the actual carrier detection, but netlink can't tell
4203          * us whether the device actually supports carrier detection in the first
4204          * place. We assume any device that does implements one of these two APIs.
4205          */
4206         return nmp_utils_ethtool_supports_carrier_detect (name) || nmp_utils_mii_supports_carrier_detect (name);
4207 }
4208
4209 static gboolean
4210 link_supports_vlans (NMPlatform *platform, int ifindex)
4211 {
4212         nm_auto_pop_netns NMPNetns *netns = NULL;
4213         const NMPObject *obj;
4214
4215         obj = cache_lookup_link (platform, ifindex);
4216
4217         /* Only ARPHRD_ETHER links can possibly support VLANs. */
4218         if (!obj || obj->link.arptype != ARPHRD_ETHER)
4219                 return FALSE;
4220
4221         if (!nm_platform_netns_push (platform, &netns))
4222                 return FALSE;
4223
4224         return nmp_utils_ethtool_supports_vlans (obj->link.name);
4225 }
4226
4227 static gboolean
4228 link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length)
4229 {
4230         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4231         gs_free char *mac = NULL;
4232
4233         if (!address || !length)
4234                 g_return_val_if_reached (FALSE);
4235
4236         _LOGD ("link: change %d: address: %s (%lu bytes)", ifindex,
4237                (mac = nm_utils_hwaddr_ntoa (address, length)),
4238                (unsigned long) length);
4239
4240         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4241                                   0,
4242                                   ifindex,
4243                                   NULL,
4244                                   0,
4245                                   0);
4246         if (!nlmsg)
4247                 return FALSE;
4248
4249         NLA_PUT (nlmsg, IFLA_ADDRESS, length, address);
4250
4251         return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4252 nla_put_failure:
4253         g_return_val_if_reached (FALSE);
4254 }
4255
4256 static gboolean
4257 link_get_permanent_address (NMPlatform *platform,
4258                             int ifindex,
4259                             guint8 *buf,
4260                             size_t *length)
4261 {
4262         nm_auto_pop_netns NMPNetns *netns = NULL;
4263
4264         if (!nm_platform_netns_push (platform, &netns))
4265                 return FALSE;
4266
4267         return nmp_utils_ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length);
4268 }
4269
4270 static gboolean
4271 link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
4272 {
4273         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4274
4275         _LOGD ("link: change %d: mtu: %u", ifindex, (unsigned) mtu);
4276
4277         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4278                                   0,
4279                                   ifindex,
4280                                   NULL,
4281                                   0,
4282                                   0);
4283         if (!nlmsg)
4284                 return FALSE;
4285
4286         NLA_PUT_U32 (nlmsg, IFLA_MTU, mtu);
4287
4288         return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4289 nla_put_failure:
4290         g_return_val_if_reached (FALSE);
4291 }
4292
4293 static char *
4294 link_get_physical_port_id (NMPlatform *platform, int ifindex)
4295 {
4296         const char *ifname;
4297         char *path, *id;
4298
4299         ifname = nm_platform_link_get_name (platform, ifindex);
4300         if (!ifname)
4301                 return NULL;
4302
4303         ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname);
4304
4305         path = g_strdup_printf ("/sys/class/net/%s/phys_port_id", ifname);
4306         id = sysctl_get (platform, path);
4307         g_free (path);
4308
4309         return id;
4310 }
4311
4312 static guint
4313 link_get_dev_id (NMPlatform *platform, int ifindex)
4314 {
4315         const char *ifname;
4316         gs_free char *path = NULL, *id = NULL;
4317         gint64 int_val;
4318
4319         ifname = nm_platform_link_get_name (platform, ifindex);
4320         if (!ifname)
4321                 return 0;
4322
4323         ifname = NM_ASSERT_VALID_PATH_COMPONENT (ifname);
4324
4325         path = g_strdup_printf ("/sys/class/net/%s/dev_id", ifname);
4326         id = sysctl_get (platform, path);
4327         if (!id || !*id)
4328                 return 0;
4329
4330         /* Value is reported as hex */
4331         int_val = _nm_utils_ascii_str_to_int64 (id, 16, 0, G_MAXUINT16, 0);
4332
4333         return errno ? 0 : (int) int_val;
4334 }
4335
4336 static int
4337 vlan_add (NMPlatform *platform,
4338           const char *name,
4339           int parent,
4340           int vlan_id,
4341           guint32 vlan_flags,
4342           const NMPlatformLink **out_link)
4343 {
4344         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4345
4346         G_STATIC_ASSERT (NM_VLAN_FLAG_REORDER_HEADERS == (guint32) VLAN_FLAG_REORDER_HDR);
4347         G_STATIC_ASSERT (NM_VLAN_FLAG_GVRP == (guint32) VLAN_FLAG_GVRP);
4348         G_STATIC_ASSERT (NM_VLAN_FLAG_LOOSE_BINDING == (guint32) VLAN_FLAG_LOOSE_BINDING);
4349         G_STATIC_ASSERT (NM_VLAN_FLAG_MVRP == (guint32) VLAN_FLAG_MVRP);
4350
4351         vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL;
4352
4353         _LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X",
4354                name, parent, vlan_id, (unsigned int) vlan_flags);
4355
4356         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4357                                   NLM_F_CREATE,
4358                                   0,
4359                                   name,
4360                                   0,
4361                                   0);
4362         if (!nlmsg)
4363                 return FALSE;
4364
4365         NLA_PUT_U32 (nlmsg, IFLA_LINK, parent);
4366
4367         if (!_nl_msg_new_link_set_linkinfo_vlan (nlmsg,
4368                                                  vlan_id,
4369                                                  NM_VLAN_FLAGS_ALL,
4370                                                  vlan_flags,
4371                                                  NULL,
4372                                                  0,
4373                                                  NULL,
4374                                                  0))
4375                 return FALSE;
4376
4377         return do_add_link_with_lookup (platform, NM_LINK_TYPE_VLAN, name, nlmsg, out_link);
4378 nla_put_failure:
4379         g_return_val_if_reached (FALSE);
4380 }
4381
4382 static int
4383 link_gre_add (NMPlatform *platform,
4384               const char *name,
4385               const NMPlatformLnkGre *props,
4386               const NMPlatformLink **out_link)
4387 {
4388         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4389         struct nlattr *info;
4390         struct nlattr *data;
4391         char buffer[INET_ADDRSTRLEN];
4392
4393         _LOGD (LOG_FMT_IP_TUNNEL,
4394                "gre",
4395                name,
4396                props->parent_ifindex,
4397                nm_utils_inet4_ntop (props->local, NULL),
4398                nm_utils_inet4_ntop (props->remote, buffer));
4399
4400         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4401                                   NLM_F_CREATE,
4402                                   0,
4403                                   name,
4404                                   0,
4405                                   0);
4406         if (!nlmsg)
4407                 return FALSE;
4408
4409         if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4410                 goto nla_put_failure;
4411
4412         NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "gre");
4413
4414         if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4415                 goto nla_put_failure;
4416
4417         if (props->parent_ifindex)
4418                 NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex);
4419         NLA_PUT_U32 (nlmsg, IFLA_GRE_LOCAL, props->local);
4420         NLA_PUT_U32 (nlmsg, IFLA_GRE_REMOTE, props->remote);
4421         NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl);
4422         NLA_PUT_U8 (nlmsg, IFLA_GRE_TOS, props->tos);
4423         NLA_PUT_U8 (nlmsg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery);
4424         NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key));
4425         NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key));
4426         NLA_PUT_U32 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags));
4427         NLA_PUT_U32 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags));
4428
4429         nla_nest_end (nlmsg, data);
4430         nla_nest_end (nlmsg, info);
4431
4432         return do_add_link_with_lookup (platform, NM_LINK_TYPE_GRE, name, nlmsg, out_link);
4433 nla_put_failure:
4434         g_return_val_if_reached (FALSE);
4435 }
4436
4437 static int
4438 link_ip6tnl_add (NMPlatform *platform,
4439                  const char *name,
4440                  const NMPlatformLnkIp6Tnl *props,
4441                  const NMPlatformLink **out_link)
4442 {
4443         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4444         struct nlattr *info;
4445         struct nlattr *data;
4446         char buffer[INET_ADDRSTRLEN];
4447         guint32 flowinfo;
4448
4449         _LOGD (LOG_FMT_IP_TUNNEL,
4450                "ip6tnl",
4451                name,
4452                props->parent_ifindex,
4453                nm_utils_inet6_ntop (&props->local, NULL),
4454                nm_utils_inet6_ntop (&props->remote, buffer));
4455
4456         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4457                                   NLM_F_CREATE,
4458                                   0,
4459                                   name,
4460                                   0,
4461                                   0);
4462         if (!nlmsg)
4463                 return FALSE;
4464
4465         if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4466                 goto nla_put_failure;
4467
4468         NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ip6tnl");
4469
4470         if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4471                 goto nla_put_failure;
4472
4473         if (props->parent_ifindex)
4474                 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
4475
4476         if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any)))
4477                 NLA_PUT (nlmsg, IFLA_IPTUN_LOCAL, sizeof (props->local), &props->local);
4478         if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any)))
4479                 NLA_PUT (nlmsg, IFLA_IPTUN_REMOTE, sizeof (props->remote), &props->remote);
4480
4481         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
4482         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit);
4483
4484         flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK;
4485         flowinfo |=   (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT)
4486                     & IP6_FLOWINFO_TCLASS_MASK;
4487         NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo));
4488         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto);
4489
4490         nla_nest_end (nlmsg, data);
4491         nla_nest_end (nlmsg, info);
4492
4493         return do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link);
4494 nla_put_failure:
4495         g_return_val_if_reached (FALSE);
4496 }
4497
4498 static int
4499 link_ipip_add (NMPlatform *platform,
4500                const char *name,
4501                const NMPlatformLnkIpIp *props,
4502                const NMPlatformLink **out_link)
4503 {
4504         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4505         struct nlattr *info;
4506         struct nlattr *data;
4507         char buffer[INET_ADDRSTRLEN];
4508
4509         _LOGD (LOG_FMT_IP_TUNNEL,
4510                "ipip",
4511                name,
4512                props->parent_ifindex,
4513                nm_utils_inet4_ntop (props->local, NULL),
4514                nm_utils_inet4_ntop (props->remote, buffer));
4515
4516         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4517                                   NLM_F_CREATE,
4518                                   0,
4519                                   name,
4520                                   0,
4521                                   0);
4522         if (!nlmsg)
4523                 return FALSE;
4524
4525         if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4526                 goto nla_put_failure;
4527
4528         NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ipip");
4529
4530         if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4531                 goto nla_put_failure;
4532
4533         if (props->parent_ifindex)
4534                 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
4535         NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local);
4536         NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote);
4537         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
4538         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos);
4539         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery);
4540
4541         nla_nest_end (nlmsg, data);
4542         nla_nest_end (nlmsg, info);
4543
4544         return do_add_link_with_lookup (platform, NM_LINK_TYPE_IPIP, name, nlmsg, out_link);
4545 nla_put_failure:
4546         g_return_val_if_reached (FALSE);
4547 }
4548
4549 static int
4550 link_macvlan_add (NMPlatform *platform,
4551                   const char *name,
4552                   int parent,
4553                   const NMPlatformLnkMacvlan *props,
4554                   const NMPlatformLink **out_link)
4555 {
4556         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4557         struct nlattr *info;
4558         struct nlattr *data;
4559
4560         _LOGD ("adding %s '%s' parent %u mode %u",
4561                props->tap ? "macvtap" : "macvlan",
4562                name,
4563                parent,
4564                props->mode);
4565
4566         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4567                                   NLM_F_CREATE,
4568                                   0,
4569                                   name,
4570                                   0,
4571                                   0);
4572         if (!nlmsg)
4573                 return FALSE;
4574
4575         NLA_PUT_U32 (nlmsg, IFLA_LINK, parent);
4576
4577         if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4578                 goto nla_put_failure;
4579
4580         NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->tap ? "macvtap" : "macvlan");
4581
4582         if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4583                 goto nla_put_failure;
4584
4585         NLA_PUT_U32 (nlmsg, IFLA_MACVLAN_MODE, props->mode);
4586         NLA_PUT_U16 (nlmsg, IFLA_MACVLAN_FLAGS, props->no_promisc ? MACVLAN_FLAG_NOPROMISC : 0);
4587
4588         nla_nest_end (nlmsg, data);
4589         nla_nest_end (nlmsg, info);
4590
4591         return do_add_link_with_lookup (platform,
4592                                         props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN,
4593                                         name, nlmsg, out_link);
4594 nla_put_failure:
4595         g_return_val_if_reached (FALSE);
4596 }
4597
4598 static int
4599 link_sit_add (NMPlatform *platform,
4600               const char *name,
4601               const NMPlatformLnkSit *props,
4602               const NMPlatformLink **out_link)
4603 {
4604         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4605         struct nlattr *info;
4606         struct nlattr *data;
4607         char buffer[INET_ADDRSTRLEN];
4608
4609         _LOGD (LOG_FMT_IP_TUNNEL,
4610                "sit",
4611                name,
4612                props->parent_ifindex,
4613                nm_utils_inet4_ntop (props->local, NULL),
4614                nm_utils_inet4_ntop (props->remote, buffer));
4615
4616         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4617                                   NLM_F_CREATE,
4618                                   0,
4619                                   name,
4620                                   0,
4621                                   0);
4622         if (!nlmsg)
4623                 return FALSE;
4624
4625         if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4626                 goto nla_put_failure;
4627
4628         NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "sit");
4629
4630         if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4631                 goto nla_put_failure;
4632
4633         if (props->parent_ifindex)
4634                 NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex);
4635         NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local);
4636         NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote);
4637         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl);
4638         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos);
4639         NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery);
4640
4641         nla_nest_end (nlmsg, data);
4642         nla_nest_end (nlmsg, info);
4643
4644         return do_add_link_with_lookup (platform, NM_LINK_TYPE_SIT, name, nlmsg, out_link);
4645 nla_put_failure:
4646         g_return_val_if_reached (FALSE);
4647 }
4648
4649 static gboolean
4650 link_vxlan_add (NMPlatform *platform,
4651                 const char *name,
4652                 const NMPlatformLnkVxlan *props,
4653                 const NMPlatformLink **out_link)
4654 {
4655         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4656         struct nlattr *info;
4657         struct nlattr *data;
4658         struct nm_ifla_vxlan_port_range port_range;
4659
4660         g_return_val_if_fail (props, FALSE);
4661
4662         _LOGD ("link: add vxlan '%s', parent %d, vxlan id %d",
4663                name, props->parent_ifindex, props->id);
4664
4665         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4666                                   NLM_F_CREATE,
4667                                   0,
4668                                   name,
4669                                   0,
4670                                   0);
4671         if (!nlmsg)
4672                 return FALSE;
4673
4674         if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO)))
4675                 goto nla_put_failure;
4676
4677         NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "vxlan");
4678
4679         if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA)))
4680                 goto nla_put_failure;
4681
4682         NLA_PUT_U32 (nlmsg, IFLA_VXLAN_ID, props->id);
4683
4684         if (props->group)
4685                 NLA_PUT (nlmsg, IFLA_VXLAN_GROUP, sizeof (props->group), &props->group);
4686         else if (memcmp (&props->group6, &in6addr_any, sizeof (in6addr_any)))
4687                 NLA_PUT (nlmsg, IFLA_VXLAN_GROUP6, sizeof (props->group6), &props->group6);
4688
4689         if (props->local)
4690                 NLA_PUT (nlmsg, IFLA_VXLAN_LOCAL, sizeof (props->local), &props->local);
4691         else if (memcmp (&props->local6, &in6addr_any, sizeof (in6addr_any)))
4692                 NLA_PUT (nlmsg, IFLA_VXLAN_LOCAL6, sizeof (props->local6), &props->local6);
4693
4694         if (props->parent_ifindex >= 0)
4695                 NLA_PUT_U32 (nlmsg, IFLA_VXLAN_LINK, props->parent_ifindex);
4696
4697         if (props->src_port_min || props->src_port_max) {
4698                 port_range.low = htons (props->src_port_min);
4699                 port_range.high = htons (props->src_port_max);
4700                 NLA_PUT (nlmsg, IFLA_VXLAN_PORT_RANGE, sizeof (port_range), &port_range);
4701         }
4702
4703         NLA_PUT_U16 (nlmsg, IFLA_VXLAN_PORT, htons (props->dst_port));
4704         NLA_PUT_U8 (nlmsg, IFLA_VXLAN_TOS, props->tos);
4705         NLA_PUT_U8 (nlmsg, IFLA_VXLAN_TTL, props->ttl);
4706         NLA_PUT_U32 (nlmsg, IFLA_VXLAN_AGEING, props->ageing);
4707         NLA_PUT_U32 (nlmsg, IFLA_VXLAN_LIMIT, props->limit);
4708         NLA_PUT_U8 (nlmsg, IFLA_VXLAN_LEARNING, !!props->learning);
4709         NLA_PUT_U8 (nlmsg, IFLA_VXLAN_PROXY, !!props->proxy);
4710         NLA_PUT_U8 (nlmsg, IFLA_VXLAN_RSC, !!props->rsc);
4711         NLA_PUT_U8 (nlmsg, IFLA_VXLAN_L2MISS, !!props->l2miss);
4712         NLA_PUT_U8 (nlmsg, IFLA_VXLAN_L3MISS, !!props->l3miss);
4713
4714         nla_nest_end (nlmsg, data);
4715         nla_nest_end (nlmsg, info);
4716
4717         return do_add_link_with_lookup (platform, NM_LINK_TYPE_VXLAN, name, nlmsg, out_link);
4718 nla_put_failure:
4719         g_return_val_if_reached (FALSE);
4720 }
4721
4722 static void
4723 _vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map,
4724                                       gboolean reset_all,
4725                                       const NMVlanQosMapping *current_map,
4726                                       guint current_n_map,
4727                                       const NMVlanQosMapping *set_map,
4728                                       guint set_n_map,
4729                                       NMVlanQosMapping **out_map,
4730                                       guint *out_n_map)
4731 {
4732         NMVlanQosMapping *map;
4733         guint i, j, len;
4734         const guint INGRESS_RANGE_LEN = 8;
4735
4736         nm_assert (out_map && !*out_map);
4737         nm_assert (out_n_map && !*out_n_map);
4738
4739         if (!reset_all)
4740                 current_n_map = 0;
4741         else if (is_ingress_map)
4742                 current_n_map = INGRESS_RANGE_LEN;
4743
4744         len = current_n_map + set_n_map;
4745
4746         if (len == 0)
4747                 return;
4748
4749         map = g_new (NMVlanQosMapping, len);
4750
4751         if (current_n_map) {
4752                 if (is_ingress_map) {
4753                         /* For the ingress-map, there are only 8 entries (0 to 7).
4754                          * When the user requests to reset all entires, we don't actually
4755                          * need the cached entries, we can just explicitly clear all possible
4756                          * ones.
4757                          *
4758                          * That makes only a real difference in case our cache is out-of-date.
4759                          *
4760                          * For the egress map we cannot do that, because there are far too
4761                          * many. There we can only clear the entries that we know about. */
4762                         for (i = 0; i < INGRESS_RANGE_LEN; i++) {
4763                                 map[i].from = i;
4764                                 map[i].to = 0;
4765                         }
4766                 } else {
4767                         for (i = 0; i < current_n_map; i++) {
4768                                 map[i].from = current_map[i].from;
4769                                 map[i].to = 0;
4770                         }
4771                 }
4772         }
4773         if (set_n_map)
4774                 memcpy (&map[current_n_map], set_map, sizeof (*set_map) * set_n_map);
4775
4776         g_qsort_with_data (map,
4777                            len,
4778                            sizeof (*map),
4779                            _vlan_qos_mapping_cmp_from,
4780                            NULL);
4781
4782         for (i = 0, j = 0; i < len; i++) {
4783                 if (   ( is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].from))
4784                     || (!is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].to)))
4785                         continue;
4786                 if (   j > 0
4787                     && map[j - 1].from == map[i].from)
4788                         map[j - 1] = map[i];
4789                 else
4790                         map[j++] = map[i];
4791         }
4792
4793         *out_map = map;
4794         *out_n_map = j;
4795 }
4796
4797 static gboolean
4798 link_vlan_change (NMPlatform *platform,
4799                   int ifindex,
4800                   NMVlanFlags flags_mask,
4801                   NMVlanFlags flags_set,
4802                   gboolean ingress_reset_all,
4803                   const NMVlanQosMapping *ingress_map,
4804                   gsize n_ingress_map,
4805                   gboolean egress_reset_all,
4806                   const NMVlanQosMapping *egress_map,
4807                   gsize n_egress_map)
4808 {
4809         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
4810         const NMPObject *obj_cache;
4811         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4812         const NMPObjectLnkVlan *lnk;
4813         guint new_n_ingress_map = 0;
4814         guint new_n_egress_map = 0;
4815         gs_free NMVlanQosMapping *new_ingress_map = NULL;
4816         gs_free NMVlanQosMapping *new_egress_map = NULL;
4817         char s_flags[64];
4818         char s_ingress[256];
4819         char s_egress[256];
4820
4821         obj_cache = nmp_cache_lookup_link (priv->cache, ifindex);
4822         if (   !obj_cache
4823             || !obj_cache->_link.netlink.is_in_netlink) {
4824                 _LOGD ("link: change %d: %s: link does not exist", ifindex, "vlan");
4825                 return FALSE;
4826         }
4827
4828         lnk = obj_cache->_link.netlink.lnk ? &obj_cache->_link.netlink.lnk->_lnk_vlan : NULL;
4829
4830         flags_set &= flags_mask;
4831
4832         _vlan_change_vlan_qos_mapping_create (TRUE,
4833                                               ingress_reset_all,
4834                                               lnk ? lnk->ingress_qos_map : NULL,
4835                                               lnk ? lnk->n_ingress_qos_map : 0,
4836                                               ingress_map,
4837                                               n_ingress_map,
4838                                               &new_ingress_map,
4839                                               &new_n_ingress_map);
4840
4841         _vlan_change_vlan_qos_mapping_create (FALSE,
4842                                               egress_reset_all,
4843                                               lnk ? lnk->egress_qos_map : NULL,
4844                                               lnk ? lnk->n_egress_qos_map : 0,
4845                                               egress_map,
4846                                               n_egress_map,
4847                                               &new_egress_map,
4848                                               &new_n_egress_map);
4849
4850         _LOGD ("link: change %d: vlan:%s%s%s",
4851                ifindex,
4852                flags_mask
4853                    ? nm_sprintf_buf (s_flags, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask)
4854                    : "",
4855                new_n_ingress_map
4856                    ? nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map",
4857                                                              new_ingress_map,
4858                                                              new_n_ingress_map,
4859                                                              s_ingress,
4860                                                              sizeof (s_ingress))
4861                    : "",
4862                new_n_egress_map
4863                    ? nm_platform_vlan_qos_mapping_to_string (" egress-qos-map",
4864                                                              new_egress_map,
4865                                                              new_n_egress_map,
4866                                                              s_egress,
4867                                                              sizeof (s_egress))
4868                    : "");
4869
4870         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4871                                   0,
4872                                   ifindex,
4873                                   NULL,
4874                                   0,
4875                                   0);
4876         if (   !nlmsg
4877             || !_nl_msg_new_link_set_linkinfo_vlan (nlmsg,
4878                                                     -1,
4879                                                     flags_mask,
4880                                                     flags_set,
4881                                                     new_ingress_map,
4882                                                     new_n_ingress_map,
4883                                                     new_egress_map,
4884                                                     new_n_egress_map))
4885                 g_return_val_if_reached (FALSE);
4886
4887         return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4888 }
4889
4890 static int
4891 tun_add (NMPlatform *platform, const char *name, gboolean tap,
4892          gint64 owner, gint64 group, gboolean pi, gboolean vnet_hdr,
4893          gboolean multi_queue, const NMPlatformLink **out_link)
4894 {
4895         const NMPObject *obj;
4896         struct ifreq ifr = { };
4897         int fd;
4898
4899         _LOGD ("link: add %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT,
4900                tap ? "tap" : "tun", name, owner, group);
4901
4902         fd = open ("/dev/net/tun", O_RDWR);
4903         if (fd < 0)
4904                 return FALSE;
4905
4906         nm_utils_ifname_cpy (ifr.ifr_name, name);
4907         ifr.ifr_flags = tap ? IFF_TAP : IFF_TUN;
4908
4909         if (!pi)
4910                 ifr.ifr_flags |= IFF_NO_PI;
4911         if (vnet_hdr)
4912                 ifr.ifr_flags |= IFF_VNET_HDR;
4913         if (multi_queue)
4914                 ifr.ifr_flags |= NM_IFF_MULTI_QUEUE;
4915
4916         if (ioctl (fd, TUNSETIFF, &ifr)) {
4917                 close (fd);
4918                 return FALSE;
4919         }
4920
4921         if (owner >= 0 && owner < G_MAXINT32) {
4922                 if (ioctl (fd, TUNSETOWNER, (uid_t) owner)) {
4923                         close (fd);
4924                         return FALSE;
4925                 }
4926         }
4927
4928         if (group >= 0 && group < G_MAXINT32) {
4929                 if (ioctl (fd, TUNSETGROUP, (gid_t) group)) {
4930                         close (fd);
4931                         return FALSE;
4932                 }
4933         }
4934
4935         if (ioctl (fd, TUNSETPERSIST, 1)) {
4936                 close (fd);
4937                 return FALSE;
4938         }
4939         do_request_link (platform, 0, name);
4940         obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
4941                                           0, name, FALSE,
4942                                           tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN,
4943                                           NULL, NULL);
4944         if (out_link)
4945                 *out_link = obj ? &obj->link : NULL;
4946
4947         close (fd);
4948         return !!obj;
4949 }
4950
4951 static gboolean
4952 link_enslave (NMPlatform *platform, int master, int slave)
4953 {
4954         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
4955         int ifindex = slave;
4956
4957         _LOGD ("link: change %d: enslave: master %d", slave, master);
4958
4959         nlmsg = _nl_msg_new_link (RTM_NEWLINK,
4960                                   0,
4961                                   ifindex,
4962                                   NULL,
4963                                   0,
4964                                   0);
4965         if (!nlmsg)
4966                 return FALSE;
4967
4968         NLA_PUT_U32 (nlmsg, IFLA_MASTER, master);
4969
4970         return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
4971 nla_put_failure:
4972         g_return_val_if_reached (FALSE);
4973 }
4974
4975 static gboolean
4976 link_release (NMPlatform *platform, int master, int slave)
4977 {
4978         return link_enslave (platform, 0, slave);
4979 }
4980
4981 /******************************************************************/
4982
4983 static gboolean
4984 infiniband_partition_add (NMPlatform *platform, int parent, int p_key, const NMPlatformLink **out_link)
4985 {
4986         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
4987         const NMPObject *obj_parent;
4988         const NMPObject *obj;
4989         gs_free char *path = NULL;
4990         gs_free char *id = NULL;
4991         gs_free char *ifname = NULL;
4992
4993         obj_parent = nmp_cache_lookup_link (priv->cache, parent);
4994         if (!obj_parent || !obj_parent->link.name[0])
4995                 g_return_val_if_reached (FALSE);
4996
4997         ifname = g_strdup_printf ("%s.%04x", obj_parent->link.name, p_key);
4998
4999         path = g_strdup_printf ("/sys/class/net/%s/create_child", NM_ASSERT_VALID_PATH_COMPONENT (obj_parent->link.name));
5000         id = g_strdup_printf ("0x%04x", p_key);
5001         if (!nm_platform_sysctl_set (platform, path, id))
5002                 return FALSE;
5003
5004         do_request_link (platform, 0, ifname);
5005
5006         obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
5007                                           0, ifname, FALSE, NM_LINK_TYPE_INFINIBAND, NULL, NULL);
5008         if (out_link)
5009                 *out_link = obj ? &obj->link : NULL;
5010         return !!obj;
5011 }
5012
5013 /******************************************************************/
5014
5015 static WifiData *
5016 wifi_get_wifi_data (NMPlatform *platform, int ifindex)
5017 {
5018         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5019         WifiData *wifi_data;
5020
5021         wifi_data = g_hash_table_lookup (priv->wifi_data, GINT_TO_POINTER (ifindex));
5022         if (!wifi_data) {
5023                 const NMPlatformLink *pllink;
5024
5025                 pllink = nm_platform_link_get (platform, ifindex);
5026                 if (pllink) {
5027                         if (pllink->type == NM_LINK_TYPE_WIFI)
5028                                 wifi_data = wifi_utils_init (pllink->name, ifindex, TRUE);
5029                         else if (pllink->type == NM_LINK_TYPE_OLPC_MESH) {
5030                                 /* The kernel driver now uses nl80211, but we force use of WEXT because
5031                                  * the cfg80211 interactions are not quite ready to support access to
5032                                  * mesh control through nl80211 just yet.
5033                                  */
5034 #if HAVE_WEXT
5035                                 wifi_data = wifi_wext_init (pllink->name, ifindex, FALSE);
5036 #endif
5037                         }
5038
5039                         if (wifi_data)
5040                                 g_hash_table_insert (priv->wifi_data, GINT_TO_POINTER (ifindex), wifi_data);
5041                 }
5042         }
5043
5044         return wifi_data;
5045 }
5046 #define WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, retval) \
5047         nm_auto_pop_netns NMPNetns *netns = NULL; \
5048         WifiData *wifi_data; \
5049         if (!nm_platform_netns_push (platform, &netns)) \
5050                 return retval; \
5051         wifi_data = wifi_get_wifi_data (platform, ifindex); \
5052         if (!wifi_data) \
5053                 return retval;
5054
5055 static gboolean
5056 wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps)
5057 {
5058         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5059         if (caps)
5060                 *caps = wifi_utils_get_caps (wifi_data);
5061         return TRUE;
5062 }
5063
5064 static gboolean
5065 wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid)
5066 {
5067         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5068         return wifi_utils_get_bssid (wifi_data, bssid);
5069 }
5070
5071 static guint32
5072 wifi_get_frequency (NMPlatform *platform, int ifindex)
5073 {
5074         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
5075         return wifi_utils_get_freq (wifi_data);
5076 }
5077
5078 static gboolean
5079 wifi_get_quality (NMPlatform *platform, int ifindex)
5080 {
5081         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5082         return wifi_utils_get_qual (wifi_data);
5083 }
5084
5085 static guint32
5086 wifi_get_rate (NMPlatform *platform, int ifindex)
5087 {
5088         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5089         return wifi_utils_get_rate (wifi_data);
5090 }
5091
5092 static NM80211Mode
5093 wifi_get_mode (NMPlatform *platform, int ifindex)
5094 {
5095         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, NM_802_11_MODE_UNKNOWN);
5096         return wifi_utils_get_mode (wifi_data);
5097 }
5098
5099 static void
5100 wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode)
5101 {
5102         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
5103         wifi_utils_set_mode (wifi_data, mode);
5104 }
5105
5106 static void
5107 wifi_set_powersave (NMPlatform *platform, int ifindex, guint32 powersave)
5108 {
5109         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
5110         wifi_utils_set_powersave (wifi_data, powersave);
5111 }
5112
5113 static guint32
5114 wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs)
5115 {
5116         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
5117         return wifi_utils_find_freq (wifi_data, freqs);
5118 }
5119
5120 static void
5121 wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running)
5122 {
5123         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, );
5124         wifi_utils_indicate_addressing_running (wifi_data, running);
5125 }
5126
5127 /******************************************************************/
5128
5129 static guint32
5130 mesh_get_channel (NMPlatform *platform, int ifindex)
5131 {
5132         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0);
5133         return wifi_utils_get_mesh_channel (wifi_data);
5134 }
5135
5136 static gboolean
5137 mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel)
5138 {
5139         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5140         return wifi_utils_set_mesh_channel (wifi_data, channel);
5141 }
5142
5143 static gboolean
5144 mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
5145 {
5146         WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE);
5147         return wifi_utils_set_mesh_ssid (wifi_data, ssid, len);
5148 }
5149
5150 /******************************************************************/
5151
5152 static gboolean
5153 link_get_wake_on_lan (NMPlatform *platform, int ifindex)
5154 {
5155         nm_auto_pop_netns NMPNetns *netns = NULL;
5156         NMLinkType type = nm_platform_link_get_type (platform, ifindex);
5157
5158         if (!nm_platform_netns_push (platform, &netns))
5159                 return FALSE;
5160
5161         if (type == NM_LINK_TYPE_ETHERNET)
5162                 return nmp_utils_ethtool_get_wake_on_lan (nm_platform_link_get_name (platform, ifindex));
5163         else if (type == NM_LINK_TYPE_WIFI) {
5164                 WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
5165
5166                 if (!wifi_data)
5167                         return FALSE;
5168
5169                 return wifi_utils_get_wowlan (wifi_data);
5170         } else
5171                 return FALSE;
5172 }
5173
5174 static gboolean
5175 link_get_driver_info (NMPlatform *platform,
5176                       int ifindex,
5177                       char **out_driver_name,
5178                       char **out_driver_version,
5179                       char **out_fw_version)
5180 {
5181         nm_auto_pop_netns NMPNetns *netns = NULL;
5182
5183         if (!nm_platform_netns_push (platform, &netns))
5184                 return FALSE;
5185
5186         return nmp_utils_ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex),
5187                                                   out_driver_name,
5188                                                   out_driver_version,
5189                                                   out_fw_version);
5190 }
5191
5192 /******************************************************************/
5193
5194 static GArray *
5195 ipx_address_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type)
5196 {
5197         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5198
5199         nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS));
5200
5201         return nmp_cache_lookup_multi_to_array (priv->cache,
5202                                                 obj_type,
5203                                                 nmp_cache_id_init_addrroute_visible_by_ifindex (NMP_CACHE_ID_STATIC,
5204                                                                                                 obj_type,
5205                                                                                                 ifindex));
5206 }
5207
5208 static GArray *
5209 ip4_address_get_all (NMPlatform *platform, int ifindex)
5210 {
5211         return ipx_address_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ADDRESS);
5212 }
5213
5214 static GArray *
5215 ip6_address_get_all (NMPlatform *platform, int ifindex)
5216 {
5217         return ipx_address_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS);
5218 }
5219
5220 static gboolean
5221 ip4_address_add (NMPlatform *platform,
5222                  int ifindex,
5223                  in_addr_t addr,
5224                  int plen,
5225                  in_addr_t peer_addr,
5226                  guint32 lifetime,
5227                  guint32 preferred,
5228                  guint32 flags,
5229                  const char *label)
5230 {
5231         NMPObject obj_id;
5232         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5233
5234         nlmsg = _nl_msg_new_address (RTM_NEWADDR,
5235                                      NLM_F_CREATE | NLM_F_REPLACE,
5236                                      AF_INET,
5237                                      ifindex,
5238                                      &addr,
5239                                      plen,
5240                                      &peer_addr,
5241                                      flags,
5242                                      nm_utils_ip4_address_is_link_local (addr) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE,
5243                                      lifetime,
5244                                      preferred,
5245                                      label);
5246
5247         nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_addr);
5248         return do_add_addrroute (platform, &obj_id, nlmsg);
5249 }
5250
5251 static gboolean
5252 ip6_address_add (NMPlatform *platform,
5253                  int ifindex,
5254                  struct in6_addr addr,
5255                  int plen,
5256                  struct in6_addr peer_addr,
5257                  guint32 lifetime,
5258                  guint32 preferred,
5259                  guint32 flags)
5260 {
5261         NMPObject obj_id;
5262         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5263
5264         nlmsg = _nl_msg_new_address (RTM_NEWADDR,
5265                                      NLM_F_CREATE | NLM_F_REPLACE,
5266                                      AF_INET6,
5267                                      ifindex,
5268                                      &addr,
5269                                      plen,
5270                                      &peer_addr,
5271                                      flags,
5272                                      RT_SCOPE_UNIVERSE,
5273                                      lifetime,
5274                                      preferred,
5275                                      NULL);
5276
5277         nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
5278         return do_add_addrroute (platform, &obj_id, nlmsg);
5279 }
5280
5281 static gboolean
5282 ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address)
5283 {
5284         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5285         NMPObject obj_id;
5286
5287         nlmsg = _nl_msg_new_address (RTM_DELADDR,
5288                                      0,
5289                                      AF_INET,
5290                                      ifindex,
5291                                      &addr,
5292                                      plen,
5293                                      &peer_address,
5294                                      0,
5295                                      RT_SCOPE_NOWHERE,
5296                                      NM_PLATFORM_LIFETIME_PERMANENT,
5297                                      NM_PLATFORM_LIFETIME_PERMANENT,
5298                                      NULL);
5299         if (!nlmsg)
5300                 g_return_val_if_reached (FALSE);
5301
5302         nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address);
5303         return do_delete_object (platform, &obj_id, nlmsg);
5304 }
5305
5306 static gboolean
5307 ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
5308 {
5309         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5310         NMPObject obj_id;
5311
5312         nlmsg = _nl_msg_new_address (RTM_DELADDR,
5313                                      0,
5314                                      AF_INET6,
5315                                      ifindex,
5316                                      &addr,
5317                                      plen,
5318                                      NULL,
5319                                      0,
5320                                      RT_SCOPE_NOWHERE,
5321                                      NM_PLATFORM_LIFETIME_PERMANENT,
5322                                      NM_PLATFORM_LIFETIME_PERMANENT,
5323                                      NULL);
5324         if (!nlmsg)
5325                 g_return_val_if_reached (FALSE);
5326
5327         nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
5328         return do_delete_object (platform, &obj_id, nlmsg);
5329 }
5330
5331 static const NMPlatformIP4Address *
5332 ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address)
5333 {
5334         NMPObject obj_id;
5335         const NMPObject *obj;
5336
5337         nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address);
5338         obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
5339         if (nmp_object_is_visible (obj))
5340                 return &obj->ip4_address;
5341         return NULL;
5342 }
5343
5344 static const NMPlatformIP6Address *
5345 ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
5346 {
5347         NMPObject obj_id;
5348         const NMPObject *obj;
5349
5350         nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
5351         obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
5352         if (nmp_object_is_visible (obj))
5353                 return &obj->ip6_address;
5354         return NULL;
5355 }
5356
5357 /******************************************************************/
5358
5359 static GArray *
5360 ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags)
5361 {
5362         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5363         NMPCacheId cache_id;
5364         const NMPlatformIPRoute *const* routes;
5365         GArray *array;
5366         const NMPClass *klass;
5367         gboolean with_rtprot_kernel;
5368         guint i, len;
5369
5370         nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
5371
5372         if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
5373                 flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT;
5374
5375         klass = nmp_class_from_type (obj_type);
5376
5377         nmp_cache_id_init_routes_visible (&cache_id,
5378                                           obj_type,
5379                                           NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT),
5380                                           NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT),
5381                                           ifindex);
5382
5383         routes = (const NMPlatformIPRoute *const*) nmp_cache_lookup_multi (priv->cache, &cache_id, &len);
5384
5385         array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len);
5386
5387         with_rtprot_kernel = NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL);
5388         for (i = 0; i < len; i++) {
5389                 nm_assert (NMP_OBJECT_GET_CLASS (NMP_OBJECT_UP_CAST (routes[i])) == klass);
5390
5391                 if (   with_rtprot_kernel
5392                     || routes[i]->source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
5393                         g_array_append_vals (array, routes[i], 1);
5394         }
5395         return array;
5396 }
5397
5398 static GArray *
5399 ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
5400 {
5401         return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags);
5402 }
5403
5404 static GArray *
5405 ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
5406 {
5407         return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags);
5408 }
5409
5410 static gboolean
5411 ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
5412                in_addr_t network, int plen, in_addr_t gateway,
5413                in_addr_t pref_src, guint32 metric, guint32 mss)
5414 {
5415         NMPObject obj_id;
5416         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5417
5418         nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
5419                                    NLM_F_CREATE | NLM_F_REPLACE,
5420                                    AF_INET,
5421                                    ifindex,
5422                                    source,
5423                                    gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
5424                                    &network,
5425                                    plen,
5426                                    &gateway,
5427                                    metric,
5428                                    mss,
5429                                    pref_src ? &pref_src : NULL);
5430
5431         nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
5432         return do_add_addrroute (platform, &obj_id, nlmsg);
5433 }
5434
5435 static gboolean
5436 ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
5437                struct in6_addr network, int plen, struct in6_addr gateway,
5438                guint32 metric, guint32 mss)
5439 {
5440         NMPObject obj_id;
5441         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5442
5443         nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
5444                                    NLM_F_CREATE | NLM_F_REPLACE,
5445                                    AF_INET6,
5446                                    ifindex,
5447                                    source,
5448                                    !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
5449                                    &network,
5450                                    plen,
5451                                    &gateway,
5452                                    metric,
5453                                    mss,
5454                                    NULL);
5455
5456         nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
5457         return do_add_addrroute (platform, &obj_id, nlmsg);
5458 }
5459
5460 static gboolean
5461 ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
5462 {
5463         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5464         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5465         NMPObject obj_id;
5466
5467         nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
5468
5469         if (metric == 0) {
5470                 /* Deleting an IPv4 route with metric 0 does not only delete an exectly matching route.
5471                  * If no route with metric 0 exists, it might delete another route to the same destination.
5472                  * For nm_platform_ip4_route_delete() we don't want this semantic.
5473                  *
5474                  * Instead, make sure that we have the most recent state and process all
5475                  * delayed actions (including re-reading data from netlink). */
5476                 delayed_action_handle_all (platform, TRUE);
5477
5478                 if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) {
5479                         /* hmm... we are about to delete an IP4 route with metric 0. We must only
5480                          * send the delete request if such a route really exists. Above we refreshed
5481                          * the platform cache, still no such route exists.
5482                          *
5483                          * Be extra careful and reload the routes. We must be sure that such a
5484                          * route doesn't exists, because when we add an IPv4 address, we immediately
5485                          * afterwards try to delete the kernel-added device route with metric 0.
5486                          * It might be, that we didn't yet get the notification about that route.
5487                          *
5488                          * FIXME: once our ip4_address_add() is sure that upon return we have
5489                          * the latest state from in the platform cache, we might save this
5490                          * additional expensive cache-resync. */
5491                         do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE);
5492
5493                         if (!nmp_cache_lookup_obj (priv->cache, &obj_id))
5494                                 return TRUE;
5495                 }
5496         }
5497
5498         nlmsg = _nl_msg_new_route (RTM_DELROUTE,
5499                                    0,
5500                                    AF_INET,
5501                                    ifindex,
5502                                    NM_IP_CONFIG_SOURCE_UNKNOWN,
5503                                    RT_SCOPE_NOWHERE,
5504                                    &network,
5505                                    plen,
5506                                    NULL,
5507                                    metric,
5508                                    0,
5509                                    NULL);
5510         if (!nlmsg)
5511                 return FALSE;
5512
5513         return do_delete_object (platform, &obj_id, nlmsg);
5514 }
5515
5516 static gboolean
5517 ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
5518 {
5519         nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
5520         NMPObject obj_id;
5521
5522         metric = nm_utils_ip6_route_metric_normalize (metric);
5523
5524         nlmsg = _nl_msg_new_route (RTM_DELROUTE,
5525                                    0,
5526                                    AF_INET6,
5527                                    ifindex,
5528                                    NM_IP_CONFIG_SOURCE_UNKNOWN,
5529                                    RT_SCOPE_NOWHERE,
5530                                    &network,
5531                                    plen,
5532                                    NULL,
5533                                    metric,
5534                                    0,
5535                                    NULL);
5536         if (!nlmsg)
5537                 return FALSE;
5538
5539         nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
5540
5541         return do_delete_object (platform, &obj_id, nlmsg);
5542 }
5543
5544 static const NMPlatformIP4Route *
5545 ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
5546 {
5547         NMPObject obj_id;
5548         const NMPObject *obj;
5549
5550         nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
5551         obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
5552         if (nmp_object_is_visible (obj))
5553                 return &obj->ip4_route;
5554         return NULL;
5555 }
5556
5557 static const NMPlatformIP6Route *
5558 ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
5559 {
5560         NMPObject obj_id;
5561         const NMPObject *obj;
5562
5563         metric = nm_utils_ip6_route_metric_normalize (metric);
5564
5565         nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
5566         obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
5567         if (nmp_object_is_visible (obj))
5568                 return &obj->ip6_route;
5569         return NULL;
5570 }
5571
5572 /******************************************************************/
5573
5574 #define EVENT_CONDITIONS      ((GIOCondition) (G_IO_IN | G_IO_PRI))
5575 #define ERROR_CONDITIONS      ((GIOCondition) (G_IO_ERR | G_IO_NVAL))
5576 #define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP))
5577
5578 static gboolean
5579 event_handler (GIOChannel *channel,
5580                GIOCondition io_condition,
5581                gpointer user_data)
5582 {
5583         delayed_action_handle_all (NM_PLATFORM (user_data), TRUE);
5584         return TRUE;
5585 }
5586
5587 /*****************************************************************************/
5588
5589 /* copied from libnl3's recvmsgs() */
5590 static int
5591 event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events)
5592 {
5593         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5594         struct nl_sock *sk = priv->nlh;
5595         int n, err = 0, multipart = 0, interrupted = 0;
5596         struct nlmsghdr *hdr;
5597         WaitForNlResponseResult seq_result;
5598
5599         /*
5600         nla is passed on to not only to nl_recv() but may also be passed
5601         to a function pointer provided by the caller which may or may not
5602         initialize the variable. Thomas Graf.
5603         */
5604         struct sockaddr_nl nla = {0};
5605         nm_auto_free struct ucred *creds = NULL;
5606         nm_auto_free unsigned char *buf = NULL;
5607
5608 continue_reading:
5609         g_clear_pointer (&buf, free);
5610         g_clear_pointer (&creds, free);
5611         errno = 0;
5612         n = nl_recv (sk, &nla, &buf, &creds);
5613
5614         switch (n) {
5615         case 0:
5616                 /* Work around a libnl bug fixed in 3.2.22 (375a6294) */
5617                 if (errno == EAGAIN) {
5618                         /* EAGAIN is equal to EWOULDBLOCK. If it would not be, we'd have to
5619                          * workaround libnl3 mapping EWOULDBLOCK to -NLE_FAILURE. */
5620                         G_STATIC_ASSERT (EAGAIN == EWOULDBLOCK);
5621                         n = -NLE_AGAIN;
5622                 }
5623                 break;
5624         case -NLE_NOMEM:
5625                 if (errno == ENOBUFS) {
5626                         /* we are very much interested in a overrun of the receive buffer.
5627                          * nl_recv() maps all kinds of errors to NLE_NOMEM, so check also
5628                          * for errno explicitly. And if so, hack our own return code to signal
5629                          * the overrun. */
5630                         n = -_NLE_NM_NOBUFS;
5631                 }
5632                 break;
5633         }
5634
5635         if (n <= 0)
5636                 return n;
5637
5638         hdr = (struct nlmsghdr *) buf;
5639         while (nlmsg_ok (hdr, n)) {
5640                 nm_auto_nlmsg struct nl_msg *msg = NULL;
5641                 gboolean abort_parsing = FALSE;
5642
5643                 msg = nlmsg_convert (hdr);
5644                 if (!msg) {
5645                         err = -NLE_NOMEM;
5646                         goto out;
5647                 }
5648
5649                 nlmsg_set_proto (msg, NETLINK_ROUTE);
5650                 nlmsg_set_src (msg, &nla);
5651
5652                 if (!creds || creds->pid) {
5653                         if (creds)
5654                                 _LOGT ("netlink: recvmsg: received non-kernel message (pid %d)", creds->pid);
5655                         else
5656                                 _LOGT ("netlink: recvmsg: received message without credentials");
5657                         err = 0;
5658                         goto stop;
5659                 }
5660
5661                 _LOGt ("netlink: recvmsg: new message type %d, seq %u",
5662                        hdr->nlmsg_type, hdr->nlmsg_seq);
5663
5664                 if (creds)
5665                         nlmsg_set_creds (msg, creds);
5666
5667                 if (hdr->nlmsg_flags & NLM_F_MULTI)
5668                         multipart = 1;
5669
5670                 if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) {
5671                         /*
5672                          * We have to continue reading to clear
5673                          * all messages until a NLMSG_DONE is
5674                          * received and report the inconsistency.
5675                          */
5676                         interrupted = 1;
5677                 }
5678
5679                 /* Other side wishes to see an ack for this message */
5680                 if (hdr->nlmsg_flags & NLM_F_ACK) {
5681                         /* FIXME: implement */
5682                 }
5683
5684                 seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN;
5685
5686                 if (hdr->nlmsg_type == NLMSG_DONE) {
5687                         /* messages terminates a multipart message, this is
5688                          * usually the end of a message and therefore we slip
5689                          * out of the loop by default. the user may overrule
5690                          * this action by skipping this packet. */
5691                         multipart = 0;
5692                         seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
5693                 } else if (hdr->nlmsg_type == NLMSG_NOOP) {
5694                         /* Message to be ignored, the default action is to
5695                          * skip this message if no callback is specified. The
5696                          * user may overrule this action by returning
5697                          * NL_PROCEED. */
5698                 } else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
5699                         /* Data got lost, report back to user. The default action is to
5700                          * quit parsing. The user may overrule this action by retuning
5701                          * NL_SKIP or NL_PROCEED (dangerous) */
5702                         err = -NLE_MSG_OVERFLOW;
5703                         abort_parsing = TRUE;
5704                 } else if (hdr->nlmsg_type == NLMSG_ERROR) {
5705                         /* Message carries a nlmsgerr */
5706                         struct nlmsgerr *e = nlmsg_data (hdr);
5707
5708                         if (hdr->nlmsg_len < nlmsg_size (sizeof (*e))) {
5709                                 /* Truncated error message, the default action
5710                                  * is to stop parsing. The user may overrule
5711                                  * this action by returning NL_SKIP or
5712                                  * NL_PROCEED (dangerous) */
5713                                 err = -NLE_MSG_TRUNC;
5714                                 abort_parsing = TRUE;
5715                         } else if (e->error) {
5716                                 int errsv = e->error > 0 ? e->error : -e->error;
5717
5718                                 /* Error message reported back from kernel. */
5719                                 _LOGD ("netlink: recvmsg: error message from kernel: %s (%d) for request %d",
5720                                        strerror (errsv),
5721                                        errsv,
5722                                        nlmsg_hdr (msg)->nlmsg_seq);
5723                                 seq_result = -errsv;
5724                         } else
5725                                 seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
5726                 } else {
5727                         /* Valid message (not checking for MULTIPART bit to
5728                          * get along with broken kernels. NL_SKIP has no
5729                          * effect on this.  */
5730
5731                         event_valid_msg (platform, msg, handle_events);
5732
5733                         seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
5734                 }
5735
5736                 event_seq_check (platform, msg, seq_result);
5737
5738                 if (abort_parsing)
5739                         goto stop;
5740
5741                 err = 0;
5742                 hdr = nlmsg_next (hdr, &n);
5743         }
5744
5745         if (multipart) {
5746                 /* Multipart message not yet complete, continue reading */
5747                 goto continue_reading;
5748         }
5749 stop:
5750         if (!handle_events) {
5751                 /* when we don't handle events, we want to drain all messages from the socket
5752                  * without handling the messages (but still check for sequence numbers).
5753                  * Repeat reading. */
5754                 goto continue_reading;
5755         }
5756 out:
5757         if (interrupted)
5758                 err = -NLE_DUMP_INTR;
5759         return err;
5760 }
5761
5762 /*****************************************************************************/
5763
5764 static gboolean
5765 event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
5766 {
5767         nm_auto_pop_netns NMPNetns *netns = NULL;
5768         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5769         int r, nle;
5770         struct pollfd pfd;
5771         gboolean any = FALSE;
5772         gint64 now_ns;
5773         int timeout_ms;
5774         guint i;
5775         struct {
5776                 guint32 seq_number;
5777                 gint64 timeout_abs_ns;
5778         } data_next;
5779
5780         if (!nm_platform_netns_push (platform, &netns))
5781                 return FALSE;
5782
5783         while (TRUE) {
5784
5785                 while (TRUE) {
5786
5787                         nle = event_handler_recvmsgs (platform, TRUE);
5788
5789                         if (nle < 0)
5790                                 switch (nle) {
5791                                 case -NLE_AGAIN:
5792                                         goto after_read;
5793                                 case -NLE_DUMP_INTR:
5794                                         _LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
5795                                         break;
5796                                 case -_NLE_NM_NOBUFS:
5797                                         _LOGI ("netlink: read: too many netlink events. Need to resynchronize platform cache");
5798                                         event_handler_recvmsgs (platform, FALSE);
5799                                         delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
5800                                         delayed_action_schedule (platform,
5801                                                                  DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
5802                                                                  DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
5803                                                                  DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
5804                                                                  DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
5805                                                                  DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
5806                                                                  NULL);
5807                                         break;
5808                                 default:
5809                                         _LOGE ("netlink: read: failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
5810                                         break;
5811                         }
5812                         any = TRUE;
5813                 }
5814
5815 after_read:
5816
5817                 if (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE))
5818                         return any;
5819
5820                 now_ns = 0;
5821                 data_next.seq_number = 0;
5822                 data_next.timeout_abs_ns = 0;
5823
5824                 for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) {
5825                         DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
5826
5827                         if (data->seq_result)
5828                                 delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result);
5829                         else if ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) > data->timeout_abs_ns)
5830                                 delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT);
5831                         else {
5832                                 i++;
5833
5834                                 if (   data_next.seq_number == 0
5835                                     || data_next.timeout_abs_ns > data->timeout_abs_ns) {
5836                                         data_next.seq_number = data->seq_number;
5837                                         data_next.timeout_abs_ns = data->timeout_abs_ns;
5838                                 }
5839                         }
5840                 }
5841
5842                 if (   !wait_for_acks
5843                     || !NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE))
5844                         return any;
5845
5846                 nm_assert (data_next.seq_number);
5847                 nm_assert (data_next.timeout_abs_ns > 0);
5848                 nm_assert (now_ns > 0);
5849
5850                 _LOGT ("netlink: read: wait for ACK for sequence number %u...", data_next.seq_number);
5851
5852                 timeout_ms = (data_next.timeout_abs_ns - now_ns) / (NM_UTILS_NS_PER_SECOND / 1000);
5853
5854                 memset (&pfd, 0, sizeof (pfd));
5855                 pfd.fd = nl_socket_get_fd (priv->nlh);
5856                 pfd.events = POLLIN;
5857                 r = poll (&pfd, 1, MAX (1, timeout_ms));
5858
5859                 if (r == 0) {
5860                         /* timeout and there is nothing to read. */
5861                         goto after_read;
5862                 }
5863                 if (r < 0) {
5864                         int errsv = errno;
5865
5866                         if (errsv != EINTR) {
5867                                 _LOGE ("netlink: read: poll failed with %s", strerror (errsv));
5868                                 delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL);
5869                                 return any;
5870                         }
5871                         /* Continue to read again, even if there might be nothing to read after EINTR. */
5872                 }
5873         }
5874 }
5875
5876 /******************************************************************/
5877
5878 static void
5879 cache_update_link_udev (NMPlatform *platform, int ifindex, GUdevDevice *udev_device)
5880 {
5881         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
5882         nm_auto_nmpobj NMPObject *obj_cache = NULL;
5883         gboolean was_visible;
5884         NMPCacheOpsType cache_op;
5885
5886         cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udev_device, &obj_cache, &was_visible, cache_pre_hook, platform);
5887
5888         if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
5889                 nm_auto_pop_netns NMPNetns *netns = NULL;
5890
5891                 if (!nm_platform_netns_push (platform, &netns))
5892                         return;
5893                 do_emit_signal (platform, obj_cache, cache_op, was_visible);
5894         }
5895 }
5896
5897 static void
5898 udev_device_added (NMPlatform *platform,
5899                    GUdevDevice *udev_device)
5900 {
5901         const char *ifname;
5902         int ifindex;
5903
5904         ifname = g_udev_device_get_name (udev_device);
5905         if (!ifname) {
5906                 _LOGD ("udev-add: failed to get device's interface");
5907                 return;
5908         }
5909
5910         if (!g_udev_device_get_property (udev_device, "IFINDEX")) {
5911                 _LOGW ("udev-add[%s]failed to get device's ifindex", ifname);
5912                 return;
5913         }
5914         ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
5915         if (ifindex <= 0) {
5916                 _LOGW ("udev-add[%s]: retrieved invalid IFINDEX=%d", ifname, ifindex);
5917                 return;
5918         }
5919
5920         if (!g_udev_device_get_sysfs_path (udev_device)) {
5921                 _LOGD ("udev-add[%s,%d]: couldn't determine device path; ignoring...", ifname, ifindex);
5922                 return;
5923         }
5924
5925         _LOGT ("udev-add[%s,%d]: device added", ifname, ifindex);
5926         cache_update_link_udev (platform, ifindex, udev_device);
5927 }
5928
5929 static gboolean
5930 _udev_device_removed_match_link (const NMPObject *obj, gpointer udev_device)
5931 {
5932         return obj->_link.udev.device == udev_device;
5933 }
5934
5935 static void
5936 udev_device_removed (NMPlatform *platform,
5937                      GUdevDevice *udev_device)
5938 {
5939         int ifindex = 0;
5940
5941         if (g_udev_device_get_property (udev_device, "IFINDEX"))
5942                 ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
5943         else {
5944                 const NMPObject *obj;
5945
5946                 obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
5947                                                   0, NULL, FALSE, NM_LINK_TYPE_NONE, _udev_device_removed_match_link, udev_device);
5948                 if (obj)
5949                         ifindex = obj->link.ifindex;
5950         }
5951
5952         _LOGD ("udev-remove: IFINDEX=%d", ifindex);
5953         if (ifindex <= 0)
5954                 return;
5955
5956         cache_update_link_udev (platform, ifindex, NULL);
5957 }
5958
5959 static void
5960 handle_udev_event (GUdevClient *client,
5961                    const char *action,
5962                    GUdevDevice *udev_device,
5963                    gpointer user_data)
5964 {
5965         nm_auto_pop_netns NMPNetns *netns = NULL;
5966         NMPlatform *platform = NM_PLATFORM (user_data);
5967         const char *subsys;
5968         const char *ifindex;
5969         guint64 seqnum;
5970
5971         g_return_if_fail (action != NULL);
5972
5973         if (!nm_platform_netns_push (platform, &netns))
5974                 return;
5975
5976         /* A bit paranoid */
5977         subsys = g_udev_device_get_subsystem (udev_device);
5978         g_return_if_fail (!g_strcmp0 (subsys, "net"));
5979
5980         ifindex = g_udev_device_get_property (udev_device, "IFINDEX");
5981         seqnum = g_udev_device_get_seqnum (udev_device);
5982         _LOGD ("UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT,
5983                 action, subsys, g_udev_device_get_name (udev_device),
5984                 ifindex ? ifindex : "unknown", seqnum);
5985
5986         if (!strcmp (action, "add") || !strcmp (action, "move"))
5987                 udev_device_added (platform, udev_device);
5988         if (!strcmp (action, "remove"))
5989                 udev_device_removed (platform, udev_device);
5990 }
5991
5992 /******************************************************************/
5993
5994 static void
5995 nm_linux_platform_init (NMLinuxPlatform *self)
5996 {
5997         NMLinuxPlatformPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformPrivate);
5998         gboolean use_udev;
5999
6000         use_udev =    nmp_netns_is_initial ()
6001                    && access ("/sys", W_OK) == 0;
6002
6003         self->priv = priv;
6004
6005         priv->nlh_seq_next = 1;
6006         priv->cache = nmp_cache_new (use_udev);
6007         priv->delayed_action.list_master_connected = g_ptr_array_new ();
6008         priv->delayed_action.list_refresh_link = g_ptr_array_new ();
6009         priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData));
6010         priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
6011
6012         if (use_udev)
6013                 priv->udev_client = g_udev_client_new ((const char *[]) { "net", NULL });
6014 }
6015
6016 static void
6017 constructed (GObject *_object)
6018 {
6019         NMPlatform *platform = NM_PLATFORM (_object);
6020         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
6021         int channel_flags;
6022         gboolean status;
6023         int nle;
6024
6025         nm_assert (!platform->_netns || platform->_netns == nmp_netns_get_current ());
6026
6027         _LOGD ("create (%s netns, %s, %s udev)",
6028                !platform->_netns ? "ignore" : "use",
6029                !platform->_netns && nmp_netns_is_initial ()
6030                    ? "initial netns"
6031                    : (!nmp_netns_get_current ()
6032                         ? "no netns support"
6033                         : nm_sprintf_bufa (100, "in netns[%p]%s",
6034                                            nmp_netns_get_current (),
6035                                            nmp_netns_get_current () == nmp_netns_get_initial () ? "/main" : "")),
6036                nmp_cache_use_udev_get (priv->cache) ? "use" : "no");
6037
6038         priv->nlh = nl_socket_alloc ();
6039         g_assert (priv->nlh);
6040
6041         nle = nl_connect (priv->nlh, NETLINK_ROUTE);
6042         g_assert (!nle);
6043         nle = nl_socket_set_passcred (priv->nlh, 1);
6044         g_assert (!nle);
6045
6046         /* No blocking for event socket, so that we can drain it safely. */
6047         nle = nl_socket_set_nonblocking (priv->nlh);
6048         g_assert (!nle);
6049
6050         /* use 8 MB for receive socket kernel queue. */
6051         nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0);
6052         g_assert (!nle);
6053
6054         nle = nl_socket_add_memberships (priv->nlh,
6055                                          RTNLGRP_LINK,
6056                                          RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR,
6057                                          RTNLGRP_IPV4_ROUTE,  RTNLGRP_IPV6_ROUTE,
6058                                          0);
6059         g_assert (!nle);
6060         _LOGD ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), nl_socket_get_fd (priv->nlh));
6061
6062         priv->event_channel = g_io_channel_unix_new (nl_socket_get_fd (priv->nlh));
6063         g_io_channel_set_encoding (priv->event_channel, NULL, NULL);
6064         g_io_channel_set_close_on_unref (priv->event_channel, TRUE);
6065
6066         channel_flags = g_io_channel_get_flags (priv->event_channel);
6067         status = g_io_channel_set_flags (priv->event_channel,
6068                                          channel_flags | G_IO_FLAG_NONBLOCK, NULL);
6069         g_assert (status);
6070         priv->event_id = g_io_add_watch (priv->event_channel,
6071                                         (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS),
6072                                          event_handler, platform);
6073
6074         /* complete construction of the GObject instance before populating the cache. */
6075         G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object);
6076
6077         _LOGD ("populate platform cache");
6078         delayed_action_schedule (platform,
6079                                  DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
6080                                  DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |
6081                                  DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES |
6082                                  DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES |
6083                                  DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES,
6084                                  NULL);
6085
6086         delayed_action_handle_all (platform, FALSE);
6087
6088         /* Set up udev monitoring */
6089         if (priv->udev_client) {
6090                 GUdevEnumerator *enumerator;
6091                 GList *devices, *iter;
6092
6093                 g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
6094
6095                 /* And read initial device list */
6096                 enumerator = g_udev_enumerator_new (priv->udev_client);
6097                 g_udev_enumerator_add_match_subsystem (enumerator, "net");
6098
6099                 g_udev_enumerator_add_match_is_initialized (enumerator);
6100
6101                 devices = g_udev_enumerator_execute (enumerator);
6102                 for (iter = devices; iter; iter = g_list_next (iter)) {
6103                         udev_device_added (platform, G_UDEV_DEVICE (iter->data));
6104                         g_object_unref (G_UDEV_DEVICE (iter->data));
6105                 }
6106                 g_list_free (devices);
6107                 g_object_unref (enumerator);
6108         }
6109 }
6110
6111 static void
6112 dispose (GObject *object)
6113 {
6114         NMPlatform *platform = NM_PLATFORM (object);
6115         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
6116
6117         _LOGD ("dispose");
6118
6119         delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING);
6120
6121         priv->delayed_action.flags = DELAYED_ACTION_TYPE_NONE;
6122         g_ptr_array_set_size (priv->delayed_action.list_master_connected, 0);
6123         g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0);
6124
6125         g_clear_pointer (&priv->prune_candidates, g_hash_table_unref);
6126
6127         if (priv->udev_client) {
6128                 g_signal_handlers_disconnect_by_func (priv->udev_client, G_CALLBACK (handle_udev_event), platform);
6129                 g_clear_object (&priv->udev_client);
6130         }
6131
6132         G_OBJECT_CLASS (nm_linux_platform_parent_class)->dispose (object);
6133 }
6134
6135 static void
6136 nm_linux_platform_finalize (GObject *object)
6137 {
6138         NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (object);
6139
6140         nmp_cache_free (priv->cache);
6141
6142         g_ptr_array_unref (priv->delayed_action.list_master_connected);
6143         g_ptr_array_unref (priv->delayed_action.list_refresh_link);
6144         g_array_unref (priv->delayed_action.list_wait_for_nl_response);
6145
6146         /* Free netlink resources */
6147         g_source_remove (priv->event_id);
6148         g_io_channel_unref (priv->event_channel);
6149         nl_socket_free (priv->nlh);
6150
6151         g_hash_table_unref (priv->wifi_data);
6152
6153         if (priv->sysctl_get_prev_values) {
6154                 sysctl_clear_cache_list = g_slist_remove (sysctl_clear_cache_list, object);
6155                 g_hash_table_destroy (priv->sysctl_get_prev_values);
6156         }
6157
6158         G_OBJECT_CLASS (nm_linux_platform_parent_class)->finalize (object);
6159 }
6160
6161 #define OVERRIDE(function) platform_class->function = function
6162
6163 static void
6164 nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
6165 {
6166         GObjectClass *object_class = G_OBJECT_CLASS (klass);
6167         NMPlatformClass *platform_class = NM_PLATFORM_CLASS (klass);
6168
6169         g_type_class_add_private (klass, sizeof (NMLinuxPlatformPrivate));
6170
6171         /* virtual methods */
6172         object_class->constructed = constructed;
6173         object_class->dispose = dispose;
6174         object_class->finalize = nm_linux_platform_finalize;
6175
6176         platform_class->sysctl_set = sysctl_set;
6177         platform_class->sysctl_get = sysctl_get;
6178
6179         platform_class->link_get = _nm_platform_link_get;
6180         platform_class->link_get_by_ifname = _nm_platform_link_get_by_ifname;
6181         platform_class->link_get_by_address = _nm_platform_link_get_by_address;
6182         platform_class->link_get_all = link_get_all;
6183         platform_class->link_add = link_add;
6184         platform_class->link_delete = link_delete;
6185         platform_class->link_get_type_name = link_get_type_name;
6186         platform_class->link_get_unmanaged = link_get_unmanaged;
6187
6188         platform_class->link_get_lnk = link_get_lnk;
6189
6190         platform_class->link_refresh = link_refresh;
6191
6192         platform_class->link_set_netns = link_set_netns;
6193
6194         platform_class->link_set_up = link_set_up;
6195         platform_class->link_set_down = link_set_down;
6196         platform_class->link_set_arp = link_set_arp;
6197         platform_class->link_set_noarp = link_set_noarp;
6198
6199         platform_class->link_get_udi = link_get_udi;
6200         platform_class->link_get_udev_device = link_get_udev_device;
6201
6202         platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled;
6203
6204         platform_class->link_set_address = link_set_address;
6205         platform_class->link_get_permanent_address = link_get_permanent_address;
6206         platform_class->link_set_mtu = link_set_mtu;
6207
6208         platform_class->link_get_physical_port_id = link_get_physical_port_id;
6209         platform_class->link_get_dev_id = link_get_dev_id;
6210         platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
6211         platform_class->link_get_driver_info = link_get_driver_info;
6212
6213         platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
6214         platform_class->link_supports_vlans = link_supports_vlans;
6215
6216         platform_class->link_enslave = link_enslave;
6217         platform_class->link_release = link_release;
6218
6219         platform_class->vlan_add = vlan_add;
6220         platform_class->link_vlan_change = link_vlan_change;
6221         platform_class->link_vxlan_add = link_vxlan_add;
6222
6223         platform_class->tun_add = tun_add;
6224
6225         platform_class->infiniband_partition_add = infiniband_partition_add;
6226
6227         platform_class->wifi_get_capabilities = wifi_get_capabilities;
6228         platform_class->wifi_get_bssid = wifi_get_bssid;
6229         platform_class->wifi_get_frequency = wifi_get_frequency;
6230         platform_class->wifi_get_quality = wifi_get_quality;
6231         platform_class->wifi_get_rate = wifi_get_rate;
6232         platform_class->wifi_get_mode = wifi_get_mode;
6233         platform_class->wifi_set_mode = wifi_set_mode;
6234         platform_class->wifi_set_powersave = wifi_set_powersave;
6235         platform_class->wifi_find_frequency = wifi_find_frequency;
6236         platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running;
6237
6238         platform_class->mesh_get_channel = mesh_get_channel;
6239         platform_class->mesh_set_channel = mesh_set_channel;
6240         platform_class->mesh_set_ssid = mesh_set_ssid;
6241
6242         platform_class->link_gre_add = link_gre_add;
6243         platform_class->link_ip6tnl_add = link_ip6tnl_add;
6244         platform_class->link_macvlan_add = link_macvlan_add;
6245         platform_class->link_ipip_add = link_ipip_add;
6246         platform_class->link_sit_add = link_sit_add;
6247
6248         platform_class->ip4_address_get = ip4_address_get;
6249         platform_class->ip6_address_get = ip6_address_get;
6250         platform_class->ip4_address_get_all = ip4_address_get_all;
6251         platform_class->ip6_address_get_all = ip6_address_get_all;
6252         platform_class->ip4_address_add = ip4_address_add;
6253         platform_class->ip6_address_add = ip6_address_add;
6254         platform_class->ip4_address_delete = ip4_address_delete;
6255         platform_class->ip6_address_delete = ip6_address_delete;
6256
6257         platform_class->ip4_route_get = ip4_route_get;
6258         platform_class->ip6_route_get = ip6_route_get;
6259         platform_class->ip4_route_get_all = ip4_route_get_all;
6260         platform_class->ip6_route_get_all = ip6_route_get_all;
6261         platform_class->ip4_route_add = ip4_route_add;
6262         platform_class->ip6_route_add = ip6_route_add;
6263         platform_class->ip4_route_delete = ip4_route_delete;
6264         platform_class->ip6_route_delete = ip6_route_delete;
6265
6266         platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags;
6267         platform_class->check_support_user_ipv6ll = check_support_user_ipv6ll;
6268
6269         platform_class->process_events = process_events;
6270 }
6271