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