nm-platform.h 76.7 KB
Newer Older
Pavel Šimerda's avatar
Pavel Šimerda committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-platform.c - Handle runtime kernel networking configuration
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
18
 * Copyright (C) 2009 - 2018 Red Hat, Inc.
Pavel Šimerda's avatar
Pavel Šimerda committed
19 20
 */

21 22
#ifndef __NETWORKMANAGER_PLATFORM_H__
#define __NETWORKMANAGER_PLATFORM_H__
Pavel Šimerda's avatar
Pavel Šimerda committed
23

24 25
#include "nm-dbus-interface.h"
#include "nm-core-types-internal.h"
26

27 28
#include "nm-core-utils.h"
#include "nm-setting-vlan.h"
29
#include "nm-setting-wired.h"
30
#include "nm-setting-wireless.h"
31
#include "nm-setting-ip-tunnel.h"
32

Pavel Šimerda's avatar
Pavel Šimerda committed
33 34 35 36 37 38 39
#define NM_TYPE_PLATFORM            (nm_platform_get_type ())
#define NM_PLATFORM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform))
#define NM_PLATFORM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_PLATFORM, NMPlatformClass))
#define NM_IS_PLATFORM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_PLATFORM))
#define NM_IS_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_PLATFORM))
#define NM_PLATFORM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_PLATFORM, NMPlatformClass))

40 41
#define NM_PLATFORM_NETNS_SUPPORT_DEFAULT    FALSE

42
/*****************************************************************************/
Pavel Šimerda's avatar
Pavel Šimerda committed
43

44
#define NM_PLATFORM_NETNS_SUPPORT      "netns-support"
45
#define NM_PLATFORM_USE_UDEV           "use-udev"
46
#define NM_PLATFORM_LOG_WITH_PTR       "log-with-ptr"
47

48
/*****************************************************************************/
49

50 51 52 53 54 55
/* IFNAMSIZ is both defined in <linux/if.h> and <net/if.h>. In the past, these
 * headers conflicted, so we cannot simply include either of them in a header-file.*/
#define NMP_IFNAMSIZ 16

/*****************************************************************************/

56 57
struct _NMPWireGuardPeer;

58 59
struct udev_device;

60 61 62
typedef gboolean (*NMPObjectPredicateFunc) (const NMPObject *obj,
                                            gpointer user_data);

63 64 65 66 67 68 69 70
/* workaround for older libnl version, that does not define these flags. */
#ifndef IFA_F_MANAGETEMPADDR
#define IFA_F_MANAGETEMPADDR 0x100
#endif
#ifndef IFA_F_NOPREFIXROUTE
#define IFA_F_NOPREFIXROUTE 0x200
#endif

71 72
#define NM_RT_SCOPE_LINK                       253  /* RT_SCOPE_LINK */

73 74 75 76 77 78
/* Define of the IN6_ADDR_GEN_MODE_* values to workaround old kernel headers
 * that don't define it. */
#define NM_IN6_ADDR_GEN_MODE_UNKNOWN           255  /* no corresponding value.  */
#define NM_IN6_ADDR_GEN_MODE_EUI64             0    /* IN6_ADDR_GEN_MODE_EUI64 */
#define NM_IN6_ADDR_GEN_MODE_NONE              1    /* IN6_ADDR_GEN_MODE_NONE */
#define NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY    2    /* IN6_ADDR_GEN_MODE_STABLE_PRIVACY */
79
#define NM_IN6_ADDR_GEN_MODE_RANDOM            3    /* IN6_ADDR_GEN_MODE_RANDOM */
80

81 82
#define NM_IFF_MULTI_QUEUE                     0x0100 /* IFF_MULTI_QUEUE */

83 84 85
/* Redefine this in host's endianness */
#define NM_GRE_KEY      0x2000

86 87 88 89 90 91 92 93
typedef enum {
	/* use our own platform enum for the nlmsg-flags. Otherwise, we'd have
	 * to include <linux/netlink.h> */
	NMP_NLM_FLAG_F_REPLACE      = 0x100, /* NLM_F_REPLACE, Override existing */
	NMP_NLM_FLAG_F_EXCL         = 0x200, /* NLM_F_EXCL, Do not touch, if it exists */
	NMP_NLM_FLAG_F_CREATE       = 0x400, /* NLM_F_CREATE, Create, if it does not exist */
	NMP_NLM_FLAG_F_APPEND       = 0x800, /* NLM_F_APPEND, Add to end of list */

94 95 96 97 98 99 100 101 102
	NMP_NLM_FLAG_FMASK          = 0xFFFF, /* a mask for all NMP_NLM_FLAG_F_* flags */

	/* instructs NM to suppress logging an error message for any failures
	 * received from kernel.
	 *
	 * It will still log with debug-level, and it will still log
	 * other failures aside the kernel response. */
	NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE = 0x10000,

103 104 105 106 107 108 109 110 111 112 113
	/* the following aliases correspond to iproute2's `ip route CMD` for
	 * RTM_NEWROUTE, with CMD being one of add, change, replace, prepend,
	 * append and test. */
	NMP_NLM_FLAG_ADD            = NMP_NLM_FLAG_F_CREATE                          | NMP_NLM_FLAG_F_EXCL,
	NMP_NLM_FLAG_CHANGE         =                         NMP_NLM_FLAG_F_REPLACE,
	NMP_NLM_FLAG_REPLACE        = NMP_NLM_FLAG_F_CREATE | NMP_NLM_FLAG_F_REPLACE,
	NMP_NLM_FLAG_PREPEND        = NMP_NLM_FLAG_F_CREATE,
	NMP_NLM_FLAG_APPEND         = NMP_NLM_FLAG_F_CREATE                                                | NMP_NLM_FLAG_F_APPEND,
	NMP_NLM_FLAG_TEST           =                                                  NMP_NLM_FLAG_F_EXCL,
} NMPNlmFlags;

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
typedef enum {
	/* compare fields which kernel considers as similar routes.
	 * It is a looser comparisong then NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID
	 * and means that `ip route add` would fail to add two routes
	 * that have the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID.
	 * On the other hand, `ip route append` would allow that, as
	 * long as NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID differs. */
	NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID,

	/* compare two routes as kernel would allow to add them with
	 * `ip route append`. In other words, kernel does not allow you to
	 * add two routes (at the same time) which compare equal according
	 * to NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID.
	 *
	 * For the ID we can only recognize route fields that we actually implement.
	 * However, kernel supports more routing options, some of them also part of
	 * the ID. NetworkManager is oblivious to these options and will wrongly think
	 * that two routes are idential, while they are not. That can lead to an
	 * inconsistent platform cache. Not much what we can do about that, except
	 * implementing all options that kernel supports *sigh*. See rh#1337860.
	 */
	NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID,

	/* compare all fields as they make sense for kernel. For example,
	 * a route destination 192.168.1.5/24 is not accepted by kernel and
	 * we treat it identical to 192.168.1.0/24. Semantically these
	 * routes are identical, but NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL will
141 142 143 144
	 * report them as different.
	 *
	 * The result shall be identical to call first nm_platform_ip_route_normalize()
	 * on both routes and then doing a full comparison. */
145 146 147 148 149 150 151 152 153
	NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY,

	/* compare all fields. This should have the same effect as memcmp(),
	 * except allowing for undefined data in holes between field alignment.
	 */
	NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL,

} NMPlatformIPRouteCmpType;

154 155 156 157 158 159 160 161
typedef enum {
	NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID,

	NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY,

	NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL,
} NMPlatformRoutingRuleCmpType;

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
typedef enum {

	/* match-flags are strictly inclusive. That means,
	 * by default nothing is matched, but if you enable a particular
	 * flag, a candidate that matches passes the check.
	 *
	 * In other words: adding more flags can only extend the result
	 * set of matching objects.
	 *
	 * Also, the flags form partitions. Like, an address can be either of
	 * ADDRTYPE_NORMAL or ADDRTYPE_LINKLOCAL, but never both. Same for
	 * the ADDRSTATE match types.
	 */
	NM_PLATFORM_MATCH_WITH_NONE                                 = 0,

	NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL                      = (1LL <<  0),
	NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL                   = (1LL <<  1),
	NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY                        =   NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL
	                                                              | NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL,

	NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL                     = (1LL <<  2),
	NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE                  = (1LL <<  3),
	NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED                  = (1LL <<  4),
	NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY                       =   NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL
	                                                              | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE
	                                                              | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED,
} NMPlatformMatchFlags;

190 191
#define NM_PLATFORM_LINK_OTHER_NETNS    (-1)

192 193 194 195 196 197 198
struct _NMPlatformObject {
	/* the object type has no fields of its own, it is only used to having
	 * a special pointer type that can be used to indicate "any" type. */
	char _dummy_don_t_use_me;
};

#define __NMPlatformObjWithIfindex_COMMON \
199 200 201
	int ifindex; \
	;

202 203 204 205
struct _NMPlatformObjWithIfindex {
	__NMPlatformObjWithIfindex_COMMON;
};

206
struct _NMPlatformLink {
207
	__NMPlatformObjWithIfindex_COMMON;
208
	char name[NMP_IFNAMSIZ];
Pavel Šimerda's avatar
Pavel Šimerda committed
209
	NMLinkType type;
210

211 212
	/* rtnl_link_get_type(), IFLA_INFO_KIND. */
	/* NMPlatform initializes this field with a static string. */
213 214
	const char *kind;

215
	/* NMPlatform initializes this field with a static string. */
216
	const char *driver;
217

218
	int master;
219 220 221 222

	/* rtnl_link_get_link(), IFLA_LINK.
	 * If IFLA_LINK_NETNSID indicates that the parent is in another namespace,
	 * this field be set to (negative) NM_PLATFORM_LINK_OTHER_NETNS. */
223
	int parent;
224

225 226 227 228 229
	/* IFF_* flags. Note that the flags in 'struct ifinfomsg' are declared as 'unsigned'. */
	guint n_ifi_flags;

	guint mtu;

230 231 232
	/* rtnl_link_get_arptype(), ifinfomsg.ifi_type. */
	guint32 arptype;

233
	/* rtnl_link_get_addr(), IFLA_ADDRESS */
234 235 236 237 238
	struct {
		guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */
		guint8 len;
	} addr;

239 240
	/* rtnl_link_inet6_get_token(), IFLA_INET6_TOKEN */
	NMUtilsIPv6IfaceId inet6_token;
241

242 243 244 245 246
	/* The bitwise inverse of rtnl_link_inet6_get_addr_gen_mode(). It is inverse
	 * to have a default of 0 -- meaning: unspecified. That way, a struct
	 * initialized with memset(0) has and unset value.*/
	guint8 inet6_addr_gen_mode_inv;

247 248 249 250 251 252
	/* Statistics */
	guint64 rx_packets;
	guint64 rx_bytes;
	guint64 tx_packets;
	guint64 tx_bytes;

253
	/* @connected is mostly identical to (@n_ifi_flags & IFF_UP). Except for bridge/bond masters,
254
	 * where we coerce the link as disconnect if it has no slaves. */
255
	bool connected:1;
256

257
	bool initialized:1;
258
};
Pavel Šimerda's avatar
Pavel Šimerda committed
259

260 261 262 263 264 265 266
typedef enum { /*< skip >*/
	NM_PLATFORM_SIGNAL_ID_NONE,
	NM_PLATFORM_SIGNAL_ID_LINK,
	NM_PLATFORM_SIGNAL_ID_IP4_ADDRESS,
	NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS,
	NM_PLATFORM_SIGNAL_ID_IP4_ROUTE,
	NM_PLATFORM_SIGNAL_ID_IP6_ROUTE,
267
	NM_PLATFORM_SIGNAL_ID_ROUTING_RULE,
268
	NM_PLATFORM_SIGNAL_ID_QDISC,
269
	NM_PLATFORM_SIGNAL_ID_TFILTER,
270 271 272 273 274
	_NM_PLATFORM_SIGNAL_ID_LAST,
} NMPlatformSignalIdType;

guint _nm_platform_signal_id_get (NMPlatformSignalIdType signal_type);

275
typedef enum {
276
	NM_PLATFORM_SIGNAL_NONE,
277 278 279 280 281
	NM_PLATFORM_SIGNAL_ADDED,
	NM_PLATFORM_SIGNAL_CHANGED,
	NM_PLATFORM_SIGNAL_REMOVED,
} NMPlatformSignalChangeType;

282 283
#define NM_PLATFORM_IP_ADDRESS_CAST(address) \
	NM_CONSTCAST (NMPlatformIPAddress, (address), NMPlatformIPXAddress, NMPlatformIP4Address, NMPlatformIP6Address)
284 285

#define __NMPlatformIPAddress_COMMON \
286
	__NMPlatformObjWithIfindex_COMMON; \
287
	NMIPConfigSource addr_source; \
288 289
	\
	/* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*().
290 291 292 293 294 295
	 *
	 * The rules are:
	 * 1 @lifetime==0: @timestamp and @preferred is irrelevant (but mostly set to 0 too). Such addresses
	 *   are permanent. This rule is so that unset addresses (calloc) are permanent by default.
	 * 2 @lifetime==@preferred==NM_PLATFORM_LIFETIME_PERMANENT: @timestamp is irrelevant (but mostly
	 *   set to 0). Such addresses are permanent.
luz.paz's avatar
luz.paz committed
296
	 * 3 Non permanent addresses should (almost) always have @timestamp > 0. 0 is not a valid timestamp
297 298
	 *   and never returned by nm_utils_get_monotonic_timestamp_s(). In this case @valid/@preferred
	 *   is anchored at @timestamp.
luz.paz's avatar
luz.paz committed
299
	 * 4 Non permanent addresses with @timestamp == 0 are implicitly anchored at *now*, thus the time
300 301 302 303 304 305
	 *   moves as time goes by. This is usually not useful, except e.g. nm_platform_ip[46]_address_add().
	 *
	 * Non permanent addresses from DHCP/RA might have the @timestamp set to the moment of when the
	 * lease was received. Addresses from kernel might have the @timestamp based on the last modification
	 * time of the addresses. But don't rely on this behaviour, the @timestamp is only defined for anchoring
	 * @lifetime and @preferred.
306 307 308 309
	 */ \
	guint32 timestamp; \
	guint32 lifetime;   /* seconds since timestamp */ \
	guint32 preferred;  /* seconds since timestamp */ \
310 311 312 313 314
	\
	/* ifa_flags in 'struct ifaddrmsg' from <linux/if_addr.h>, extended to 32 bit by
	 * IFA_FLAGS attribute. */ \
	guint32 n_ifa_flags; \
	\
315
	guint8 plen; \
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
	;

/**
 * NMPlatformIPAddress:
 *
 * Common parts of NMPlatformIP4Address and NMPlatformIP6Address.
 **/
typedef struct {
	__NMPlatformIPAddress_COMMON;
	union {
		guint8 address_ptr[1];
		guint32 __dummy_for_32bit_alignment;
	};
} NMPlatformIPAddress;

331 332 333 334
/**
 * NMPlatformIP4Address:
 * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_s()
 **/
335
struct _NMPlatformIP4Address {
336
	__NMPlatformIPAddress_COMMON;
337 338

	/* The local address IFA_LOCAL. */
Pavel Šimerda's avatar
Pavel Šimerda committed
339
	in_addr_t address;
340 341 342 343 344 345 346 347 348 349

	/* The IFA_ADDRESS PTP peer address. This field is rather important, because
	 * it constitutes the identifier for the IPv4 address (e.g. you can add two
	 * addresses that only differ by their peer's network-part.
	 *
	 * Beware that for most cases, NetworkManager doesn't want to set an explicit
	 * peer-address. Hoever, that corresponds to setting the peer address to @address
	 * itself. Leaving peer-address unset/zero, means explicitly setting the peer
	 * address to 0.0.0.0, which you probably don't want.
	 * */
350
	in_addr_t peer_address;  /* PTP peer address */
351

352
	char label[NMP_IFNAMSIZ];
353
};
Pavel Šimerda's avatar
Pavel Šimerda committed
354

355 356 357 358
/**
 * NMPlatformIP6Address:
 * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_s()
 **/
359
struct _NMPlatformIP6Address {
360
	__NMPlatformIPAddress_COMMON;
Pavel Šimerda's avatar
Pavel Šimerda committed
361
	struct in6_addr address;
362
	struct in6_addr peer_address;
363
};
364

365 366 367 368 369 370
typedef union {
	NMPlatformIPAddress  ax;
	NMPlatformIP4Address a4;
	NMPlatformIP6Address a6;
} NMPlatformIPXAddress;

371 372
#undef __NMPlatformIPAddress_COMMON

373 374 375 376 377 378 379 380 381
/* Default value for adding an IPv4 route. This is also what iproute2 does.
 * Note that contrary to IPv6, you can add routes with metric 0 and it is even
 * the default.
 */
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 0

/* Default value for adding an IPv6 route. This is also what iproute2 does.
 * Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024). */
#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 1024
382

383 384 385 386
/* For IPv4, kernel adds a device route (subnet routes) with metric 0 when user
 * configures addresses. */
#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE 0

387
#define __NMPlatformIPRoute_COMMON \
388
	__NMPlatformObjWithIfindex_COMMON; \
389 390 391 392
	\
	/* The NMIPConfigSource. For routes that we receive from cache this corresponds
	 * to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values).
	 * When adding a route, the source will be coerced to the protocol using
393 394 395 396 397 398 399 400 401
	 * nmp_utils_ip_config_source_coerce_to_rtprot().
	 *
	 * rtm_protocol is part of the primary key of an IPv4 route (meaning, you can add
	 * two IPv4 routes that only differ in their rtm_protocol. For IPv6, that is not
	 * the case.
	 *
	 * When deleting an IPv4/IPv6 route, the rtm_protocol field must match (even
	 * if it is not part of the primary key for IPv6) -- unless rtm_protocol is set
	 * to zero, in which case the first matching route (with proto ignored) is deleted. */ \
402
	NMIPConfigSource rt_source; \
403
	\
404
	guint8 plen; \
405
	\
406 407 408
	/* RTA_METRICS:
	 *
	 * For IPv4 routes, these properties are part of their
409
	 * ID (meaning: you can add otherwise idential IPv4 routes that
410 411 412
	 * only differ by the metric property).
	 * On the other hand, for IPv6 you cannot add two IPv6 routes that only differ
	 * by an RTA_METRICS property.
413
	 *
luz.paz's avatar
luz.paz committed
414
	 * When deleting a route, kernel seems to ignore the RTA_METRICS properties.
415 416 417
	 * That is a problem/bug for IPv4 because you cannot explicitly select which
	 * route to delete. Kernel just picks the first. See rh#1475642. */ \
	\
418 419 420 421 422 423 424
	/* RTA_METRICS.RTAX_LOCK (iproute2: "lock" arguments) */ \
	bool lock_window:1; \
	bool lock_cwnd:1; \
	bool lock_initcwnd:1; \
	bool lock_initrwnd:1; \
	bool lock_mtu:1; \
	\
425 426 427 428 429 430
	/* rtnh_flags
	 *
	 * Routes with rtm_flags RTM_F_CLONED are hidden by platform and
	 * do not exist from the point-of-view of platform users.
	 * Such a route is not alive, according to nmp_object_is_alive().
	 *
431
	 * NOTE: currently we ignore all flags except RTM_F_CLONED
432
	 * and RTNH_F_ONLINK.
433 434 435 436
	 * We also may not properly consider the flags as part of the ID
	 * in route-cmp. */ \
	unsigned r_rtm_flags; \
	\
437
	/* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \
438
	guint32 mss; \
439
	\
440
	/* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \
441
	guint32 window; \
442
	\
443
	/* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \
444
	guint32 cwnd; \
445 446
	\
	/* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \
447
	guint32 initcwnd; \
448 449
	\
	/* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \
450
	guint32 initrwnd; \
451 452
	\
	/* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \
453
	guint32 mtu; \
454 455
	\
	\
456
	/* RTA_PRIORITY (iproute2: metric) */ \
457 458
	guint32 metric; \
	\
459 460 461 462
	/* rtm_table, RTA_TABLE.
	 *
	 * This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and
	 * zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main
463
	 * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \
464 465
	guint32 table_coerced; \
	\
466 467
	/*end*/

468 469 470 471 472 473 474 475
typedef struct {
	__NMPlatformIPRoute_COMMON;
	union {
		guint8 network_ptr[1];
		guint32 __dummy_for_32bit_alignment;
	};
} NMPlatformIPRoute;

476 477 478
#define NM_PLATFORM_IP_ROUTE_CAST(route) \
	NM_CONSTCAST (NMPlatformIPRoute, (route), NMPlatformIPXRoute, NMPlatformIP4Route, NMPlatformIP6Route)

479
#define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \
480
	(NM_PLATFORM_IP_ROUTE_CAST (route)->plen <= 0)
481

482
struct _NMPlatformIP4Route {
483
	__NMPlatformIPRoute_COMMON;
Pavel Šimerda's avatar
Pavel Šimerda committed
484
	in_addr_t network;
485 486

	/* RTA_GATEWAY. The gateway is part of the primary key for a route */
Pavel Šimerda's avatar
Pavel Šimerda committed
487
	in_addr_t gateway;
488

489 490 491 492
	/* RTA_PREFSRC (called "src" by iproute2).
	 *
	 * pref_src is part of the ID of an IPv4 route. When deleting a route,
	 * pref_src must match, unless set to 0.0.0.0 to match any. */
493
	in_addr_t pref_src;
494

495 496 497 498 499 500 501
	/* rtm_tos (iproute2: tos)
	 *
	 * For IPv4, tos is part of the weak-id (like metric).
	 *
	 * For IPv6, tos is ignored by kernel.  */
	guint8 tos;

502 503 504 505 506 507 508 509 510 511 512 513
	/* The bitwise inverse of the route scope rtm_scope. It is inverted so that the
	 * default value (RT_SCOPE_NOWHERE) is zero. Use nm_platform_route_scope_inv()
	 * to convert back and forth between the inverese representation and the
	 * real value.
	 *
	 * rtm_scope is part of the primary key for IPv4 routes. When deleting a route,
	 * the scope must match, unless it is left at RT_SCOPE_NOWHERE, in which case the first
	 * matching route is deleted.
	 *
	 * For IPv6 routes, the scope is ignored and kernel always assumes global scope.
	 * Hence, this field is only in NMPlatformIP4Route. */
	guint8 scope_inv;
514
};
Pavel Šimerda's avatar
Pavel Šimerda committed
515

516
struct _NMPlatformIP6Route {
517
	__NMPlatformIPRoute_COMMON;
Pavel Šimerda's avatar
Pavel Šimerda committed
518
	struct in6_addr network;
519 520

	/* RTA_GATEWAY. The gateway is part of the primary key for a route */
Pavel Šimerda's avatar
Pavel Šimerda committed
521
	struct in6_addr gateway;
522

523 524 525 526 527 528
	/* RTA_PREFSRC (called "src" by iproute2).
	 *
	 * pref_src is not part of the ID for an IPv6 route. You cannot add two
	 * routes that only differ by pref_src.
	 *
	 * When deleting a route, pref_src is ignored by kernel. */
529
	struct in6_addr pref_src;
530

531 532 533 534 535 536 537 538
	/* RTA_SRC and rtm_src_len (called "from" by iproute2).
	 *
	 * Kernel clears the host part of src/src_plen.
	 *
	 * src/src_plen is part of the ID of a route just like network/plen. That is,
	 * Not only `ip route append`, but also `ip route add` allows to add routes that only
	 * differ in their src/src_plen.
	 */
539 540
	struct in6_addr src;
	guint8 src_plen;
541 542 543 544 545 546

	/* RTA_PREF router preference.
	 *
	 * The type is guint8 to keep the struct size small. But the values are compatible with
	 * the NMIcmpv6RouterPref enum. */
	guint8 rt_pref;
547
};
548

549 550 551 552 553 554
typedef union {
	NMPlatformIPRoute  rx;
	NMPlatformIP4Route r4;
	NMPlatformIP6Route r6;
} NMPlatformIPXRoute;

555 556
#undef __NMPlatformIPRoute_COMMON

557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
typedef struct {
	/* struct fib_rule_uid_range */
	guint32 start;
	guint32 end;
} NMFibRuleUidRange;

typedef struct {
	/* struct fib_rule_port_range */
	guint16 start;
	guint16 end;
} NMFibRulePortRange;

typedef struct {
	NMIPAddr src;                        /* FRA_SRC */
	NMIPAddr dst;                        /* FRA_DST */
	guint64  tun_id;                     /* betoh64(FRA_TUN_ID) */
	guint32  table;                      /* (struct fib_rule_hdr).table, FRA_TABLE */
	guint32  flags;                      /* (struct fib_rule_hdr).flags */
	guint32  priority;                   /* RA_PRIORITY */
	guint32  fwmark;                     /* FRA_FWMARK */
	guint32  fwmask;                     /* FRA_FWMASK */
	guint32  goto_target;                /* FRA_GOTO */
	guint32  flow;                       /* FRA_FLOW */
	guint32  suppress_prefixlen_inverse; /* ~(FRA_SUPPRESS_PREFIXLEN) */
	guint32  suppress_ifgroup_inverse;   /* ~(FRA_SUPPRESS_IFGROUP) */
	NMFibRuleUidRange uid_range;         /* FRA_UID_RANGE */
	NMFibRulePortRange sport_range;      /* FRA_SPORT_RANGE */
	NMFibRulePortRange dport_range;      /* FRA_DPORT_RANGE */
	char     iifname[NMP_IFNAMSIZ];      /* FRA_IIFNAME */
	char     oifname[NMP_IFNAMSIZ];      /* FRA_OIFNAME */
	guint8   addr_family;                /* (struct fib_rule_hdr).family */
	guint8   action;                     /* (struct fib_rule_hdr).action */
	guint8   tos;                        /* (struct fib_rule_hdr).tos */
	guint8   src_len;                    /* (struct fib_rule_hdr).src_len */
	guint8   dst_len;                    /* (struct fib_rule_hdr).dst_len */
	guint8   l3mdev;                     /* FRA_L3MDEV */
	guint8   protocol;                   /* FRA_PROTOCOL */
	guint8   ip_proto;                   /* FRA_IP_PROTO */

	bool     uid_range_has:1;            /* has(FRA_UID_RANGE) */
} NMPlatformRoutingRule;

599 600
#define NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET   (~((guint32) 0))

601 602 603 604
#define NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED ((guint32) 0x83126E97u)

G_STATIC_ASSERT (((((guint64) NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED) * 1000u) >> 10) == (guint64) INT_MAX);

605 606 607 608 609 610
typedef struct {
	guint32 limit;
	guint32 flows;
	guint32 target;
	guint32 interval;
	guint32 quantum;
611 612 613 614 615 616 617
	guint32 ce_threshold; /* TCA_FQ_CODEL_CE_THRESHOLD: kernel internally stores this value as
	                       *   ((val64 * NSEC_PER_USEC) >> CODEL_SHIFT). The default value (in
	                       *   the domain with this coersion) is CODEL_DISABLED_THRESHOLD (INT_MAX).
	                       *   That means, "disabled" is expressed on RTM_NEWQDISC netlink API by absence of the
	                       *   netlink attribute but also as the special value 0x83126E97u
	                       *   (NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED).
	                       *   Beware: zero is not the default you must always explicitly set this value. */
618
	guint32 memory_limit; /* TCA_FQ_CODEL_MEMORY_LIMIT: note that only values <= 2^31 are accepted by kernel
619 620 621 622 623
	                       *   and kernel defaults to 32MB.
	                       *   Note that we use the special value NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET
	                       *   to indicate that no explicit limit is set (when we send a RTM_NEWQDISC request).
	                       *   This will cause kernel to choose the default (32MB).
	                       *   Beware: zero is not the default you must always explicitly set this value. */
624 625 626
	bool ecn:1;
} NMPlatformQdiscFqCodel;

627
typedef struct {
628
	__NMPlatformObjWithIfindex_COMMON;
629 630 631

	/* beware, kind is embedded in an NMPObject, hence you must
	 * take care of the lifetime of the string. */
632
	const char *kind;
633

634 635 636 637
	int addr_family;
	guint32 handle;
	guint32 parent;
	guint32 info;
638 639 640
	union {
		NMPlatformQdiscFqCodel fq_codel;
	};
641
} NMPlatformQdisc;
642

643 644 645 646
typedef struct {
	char sdata[32];
} NMPlatformActionSimple;

Lubomir Rintel's avatar
Lubomir Rintel committed
647 648
typedef struct {
	int ifindex;
649 650 651 652
	bool egress:1;
	bool ingress:1;
	bool mirror:1;
	bool redirect:1;
Lubomir Rintel's avatar
Lubomir Rintel committed
653 654
} NMPlatformActionMirred;

655
typedef struct {
656 657 658

	/* beware, kind is embedded in an NMPObject, hence you must
	 * take care of the lifetime of the string. */
659
	const char *kind;
660

661 662
	union {
		NMPlatformActionSimple simple;
Lubomir Rintel's avatar
Lubomir Rintel committed
663
		NMPlatformActionMirred mirred;
664 665 666
	};
} NMPlatformAction;

667
#define NM_PLATFORM_ACTION_KIND_SIMPLE "simple"
Lubomir Rintel's avatar
Lubomir Rintel committed
668
#define NM_PLATFORM_ACTION_KIND_MIRRED "mirred"
669

670
typedef struct {
671
	__NMPlatformObjWithIfindex_COMMON;
672 673 674

	/* beware, kind is embedded in an NMPObject, hence you must
	 * take care of the lifetime of the string. */
675
	const char *kind;
676

677 678 679 680 681 682 683
	int addr_family;
	guint32 handle;
	guint32 parent;
	guint32 info;
	NMPlatformAction action;
} NMPlatformTfilter;

684
#undef __NMPlatformObjWithIfindex_COMMON
685

686 687
typedef struct {
	gboolean is_ip4;
688
	NMPObjectType obj_type;
689 690
	int addr_family;
	gsize sizeof_route;
691
	int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type);
692
	const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len);
693 694 695
	guint32 (*metric_normalize) (guint32 metric);
} NMPlatformVTableRoute;

696 697 698 699 700 701 702 703 704
typedef union {
	struct {
		NMPlatformVTableRoute v6;
		NMPlatformVTableRoute v4;
	};
	NMPlatformVTableRoute vx[2];
} _NMPlatformVTableRouteUnion;

extern const _NMPlatformVTableRouteUnion nm_platform_vtable_route;
705

706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725
typedef struct {
	guint16 id;
	guint32 qos;
	bool proto_ad:1;
} NMPlatformVFVlan;

typedef struct {
	guint32 index;
	guint32 min_tx_rate;
	guint32 max_tx_rate;
	guint num_vlans;
	NMPlatformVFVlan *vlans;
	struct {
		guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */
		guint8 len;
	} mac;
	gint8 spoofchk;
	gint8 trust;
} NMPlatformVF;

726
typedef struct {
727 728
	guint16 vid_start;
	guint16 vid_end;
729 730 731 732
	bool untagged:1;
	bool pvid:1;
} NMPlatformBridgeVlan;

733
typedef struct {
734 735
	in_addr_t local;
	in_addr_t remote;
736 737 738 739 740 741 742
	int parent_ifindex;
	guint16 input_flags;
	guint16 output_flags;
	guint32 input_key;
	guint32 output_key;
	guint8 ttl;
	guint8 tos;
743
	bool path_mtu_discovery:1;
744
	bool is_tap:1;
745
} NMPlatformLnkGre;
746

747
typedef struct {
748
	int p_key;
749
	const char *mode;
750
} NMPlatformLnkInfiniband;
751

752 753 754
typedef struct {
	struct in6_addr local;
	struct in6_addr remote;
755
	int parent_ifindex;
756 757 758 759
	guint8 ttl;
	guint8 tclass;
	guint8 encap_limit;
	guint8 proto;
760
	guint flow_label;
761
	guint32 flags;
762 763 764 765 766 767 768 769

	/* IP6GRE only */
	guint32 input_key;
	guint32 output_key;
	guint16 input_flags;
	guint16 output_flags;
	bool is_tap:1;
	bool is_gre:1;
770 771
} NMPlatformLnkIp6Tnl;

772 773 774
typedef struct {
	in_addr_t local;
	in_addr_t remote;
775
	int parent_ifindex;
776 777
	guint8 ttl;
	guint8 tos;
778
	bool path_mtu_discovery:1;
779 780
} NMPlatformLnkIpIp;

781 782
typedef struct {
	int parent_ifindex;
783
	guint64 sci;                    /* host byte order */
784 785 786 787 788 789 790 791 792 793 794 795 796
	guint64 cipher_suite;
	guint32 window;
	guint8 icv_length;
	guint8 encoding_sa;
	guint8 validation;
	bool encrypt:1;
	bool protect:1;
	bool include_sci:1;
	bool es:1;
	bool scb:1;
	bool replay_protect:1;
} NMPlatformLnkMacsec;

797
typedef struct {
798
	guint mode;
799 800
	bool no_promisc:1;
	bool tap:1;
801
} NMPlatformLnkMacvlan;
802

803 804
typedef NMPlatformLnkMacvlan NMPlatformLnkMacvtap;

805 806 807
typedef struct {
	in_addr_t local;
	in_addr_t remote;
808
	int parent_ifindex;
809
	guint16 flags;
810 811 812
	guint8 ttl;
	guint8 tos;
	guint8 proto;
813
	bool path_mtu_discovery:1;
814 815
} NMPlatformLnkSit;

816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
typedef struct {
	guint32 owner;
	guint32 group;

	guint8 type;

	bool owner_valid:1;
	bool group_valid:1;

	bool pi:1;
	bool vnet_hdr:1;
	bool multi_queue:1;
	bool persist:1;
} NMPlatformLnkTun;

831 832 833
typedef struct {
	/* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */
	guint16 id;
834
	NMVlanFlags flags;
835 836
} NMPlatformLnkVlan;

837 838 839
typedef struct {
	struct in6_addr group6;
	struct in6_addr local6;
840 841 842 843
	in_addr_t group;
	in_addr_t local;
	int parent_ifindex;
	guint32 id;
844 845 846 847 848
	guint32 ageing;
	guint32 limit;
	guint16 dst_port;
	guint16 src_port_min;
	guint16 src_port_max;
849 850 851 852 853 854 855
	guint8 tos;
	guint8 ttl;
	bool learning:1;
	bool proxy:1;
	bool rsc:1;
	bool l2miss:1;
	bool l3miss:1;
856
} NMPlatformLnkVxlan;
857

858 859 860
#define NMP_WIREGUARD_PUBLIC_KEY_LEN 32
#define NMP_WIREGUARD_SYMMETRIC_KEY_LEN 32

861 862
typedef struct {
	guint32 fwmark;
863 864 865
	guint16 listen_port;
	guint8 private_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
	guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
866
} NMPlatformLnkWireGuard;
867

868
typedef enum {
869
	NM_PLATFORM_LINK_DUPLEX_UNKNOWN,
870 871 872 873
	NM_PLATFORM_LINK_DUPLEX_HALF,
	NM_PLATFORM_LINK_DUPLEX_FULL,
} NMPlatformLinkDuplexType;

874
typedef enum {
875 876 877 878 879
	NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE                        = 0,
	NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS               = (1LL << 0),
	NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY             = (1LL << 1),
	NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT             = (1LL << 2),
	NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK                  = (1LL << 3),
880 881
} NMPlatformWireGuardChangeFlags;

882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
typedef enum {
	NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE                   = 0,
	NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME              = (1LL << 0),
	NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY      = (1LL << 1),
	NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL = (1LL << 2),
	NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT           = (1LL << 3),
	NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS         = (1LL << 4),
	NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS     = (1LL << 5),

	NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT =   NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY
	                                                 | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL
	                                                 | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT
	                                                 | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS,

} NMPlatformWireGuardChangePeerFlags;

898
/*****************************************************************************/
Pavel Šimerda's avatar
Pavel Šimerda committed
899

900 901 902 903
typedef enum {
	NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS,
	NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL,
	NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF,
904
	NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV,
905
	NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE,
906
	NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL,
907 908 909 910 911

	/* this also includes FRA_SPORT_RANGE and FRA_DPORT_RANGE which
	 * were added at the same time. */
	NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO,

912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944
	_NM_PLATFORM_KERNEL_SUPPORT_NUM,
} NMPlatformKernelSupportType;

extern volatile int _nm_platform_kernel_support_state[_NM_PLATFORM_KERNEL_SUPPORT_NUM];

int _nm_platform_kernel_support_init (NMPlatformKernelSupportType type,
                                      int value);

#define _nm_platform_kernel_support_detected(type) \
	G_LIKELY (({ \
		const NMPlatformKernelSupportType _type = (type); \
		\
		nm_assert (_NM_INT_NOT_NEGATIVE (_type) && _type < G_N_ELEMENTS (_nm_platform_kernel_support_state)); \
		\
		(_nm_platform_kernel_support_state[_type] != 0); \
	}))

#define nm_platform_kernel_support_get(type) \
	({ \
		const NMPlatformKernelSupportType _type = (type); \
		int _v; \
		\
		nm_assert (_NM_INT_NOT_NEGATIVE (_type) && _type < G_N_ELEMENTS (_nm_platform_kernel_support_state)); \
		\
		_v = _nm_platform_kernel_support_state[_type]; \
		if (G_UNLIKELY (_v == 0)) \
			_v = _nm_platform_kernel_support_init (_type, 0); \
		\
		(_v >= 0); \
	})

/*****************************************************************************/

945 946
struct _NMPlatformPrivate;

947
struct _NMPlatform {
Pavel Šimerda's avatar
Pavel Šimerda committed
948
	GObject parent;
949
	NMPNetns *_netns;
950
	struct _NMPlatformPrivate *_priv;
951
};
Pavel Šimerda's avatar
Pavel Šimerda committed
952 953 954 955

typedef struct {
	GObjectClass parent;

956 957
	gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value);
	char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path);
958

959 960 961 962 963 964 965 966
	int (*link_add) (NMPlatform *,
	                 const char *name,
	                 NMLinkType type,
	                 const char *veth_peer,
	                 const void *address,
	                 size_t address_len,
	                 const NMPlatformLink **out_link);

Pavel Šimerda's avatar
Pavel Šimerda committed
967
	gboolean (*link_delete) (NMPlatform *, int ifindex);
968

969
	gboolean (*link_refresh) (NMPlatform *, int ifindex);
970 971 972

	gboolean (*link_set_netns) (NMPlatform *, int ifindex, int netns_fd);

973
	void (*process_events) (NMPlatform *self);
974

975
	gboolean (*link_set_up) (NMPlatform *, int ifindex, gboolean *out_no_firmware);
976 977 978
	gboolean (*link_set_down) (NMPlatform *, int ifindex);
	gboolean (*link_set_arp) (NMPlatform *, int ifindex);
	gboolean (*link_set_noarp) (NMPlatform *, int ifindex);
Pavel Šimerda's avatar
Pavel Šimerda committed
979

980
	const char *(*link_get_udi) (NMPlatform *self, int ifindex);
981
	struct udev_device *(*link_get_udev_device) (NMPlatform *self, int ifindex);
982

983
	int (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled);
984
	gboolean (*link_set_token) (NMPlatform *, int ifindex, NMUtilsIPv6IfaceId iid);
985

986 987 988 989
	gboolean (*link_get_permanent_address) (NMPlatform *,
	                                        int ifindex,
	                                        guint8 *buf,
	                                        size_t *length);
990 991
	int (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
	int (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
992
	gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name);
993
	gboolean (*link_set_sriov_params) (NMPlatform *, int ifindex, guint num_vfs, int autoprobe);
994
	gboolean (*link_set_sriov_vfs) (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
995
	gboolean (*link_set_bridge_vlans) (NMPlatform *self, int ifindex, gboolean on_master, const NMPlatformBridgeVlan *const *vlans);
996

997 998
	char *   (*link_get_physical_port_id) (NMPlatform *, int ifindex);
	guint    (*link_get_dev_id) (NMPlatform *, int ifindex);
999
	gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex);
1000 1001 1002 1003 1004
	gboolean (*link_get_driver_info) (NMPlatform *,
	                                  int ifindex,
	                                  char **out_driver_name,
	                                  char **out_driver_version,
	                                  char **out_fw_version);
1005

1006 1007
	gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
	gboolean (*link_supports_vlans) (NMPlatform *, int ifindex);
1008
	gboolean (*link_supports_sriov) (NMPlatform *, int ifindex);
1009

1010 1011 1012
	gboolean (*link_enslave) (NMPlatform *, int master, int slave);
	gboolean (*link_release) (NMPlatform *, int master, int slave);

1013 1014
	gboolean (*link_can_assume) (NMPlatform *, int ifindex);

1015 1016 1017 1018
	int (*link_wireguard_change) (NMPlatform *self,
	                              int ifindex,
	                              const NMPlatformLnkWireGuard *lnk_wireguard,
	                              const struct _NMPWireGuardPeer *peers,
1019
	                              const NMPlatformWireGuardChangePeerFlags *peer_flags,
1020
	                              guint peers_len,
1021
	                              NMPlatformWireGuardChangeFlags change_flags);
1022

1023
	gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link);
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
	gboolean (*link_vlan_change) (NMPlatform *self,
	                              int ifindex,
	                              NMVlanFlags flags_mask,
	                              NMVlanFlags flags_set,
	                              gboolean ingress_reset_all,
	                              const NMVlanQosMapping *ingress_map,
	                              gsize n_ingress_map,
	                              gboolean egress_reset_all,
	                              const NMVlanQosMapping *egress_map,
	                              gsize n_egress_map);
1034 1035 1036
	gboolean (*link_vxlan_add) (NMPlatform *,
	                            const char *name,
	                            const NMPlatformLnkVxlan *props,
1037
	                            const NMPlatformLink **out_link);
1038 1039 1040
	gboolean (*link_gre_add) (NMPlatform *,
	                          const char *name,
	                          const NMPlatformLnkGre *props,
1041
	                          const NMPlatformLink **out_link);
1042 1043 1044
	gboolean (*link_ip6tnl_add) (NMPlatform *,
	                             const char *name,
	                             const NMPlatformLnkIp6Tnl *props,
1045
	                             const NMPlatformLink **out_link);
1046 1047 1048 1049
	gboolean (*link_ip6gre_add) (NMPlatform *,
	                             const char *name,
	                             const NMPlatformLnkIp6Tnl *props,
	                             const NMPlatformLink **out_link);
1050 1051 1052
	gboolean (*link_ipip_add) (NMPlatform *,
	                           const char *name,
	                           const NMPlatformLnkIpIp *props,
1053
	                           const NMPlatformLink **out_link);
1054 1055 1056 1057 1058
	gboolean (*link_macsec_add) (NMPlatform *,
	                             const char *name,
	                             int parent,
	                             const NMPlatformLnkMacsec *props,
	                             const NMPlatformLink **out_link);
1059 1060 1061 1062
	gboolean (*link_macvlan_add) (NMPlatform *,
	                              const char *name,
	                              int parent,
	                              const NMPlatformLnkMacvlan *props,
1063
	                              const NMPlatformLink **out_link);
1064 1065 1066
	gboolean (*link_sit_add) (NMPlatform *,
	                          const char *name,
	                          const NMPlatformLnkSit *props,
1067
	                          const NMPlatformLink **out_link);
1068

1069 1070 1071
	gboolean (*link_tun_add) (NMPlatform *platform,
	                          const char *name,
	                          const NMPlatformLnkTun *props,
1072 1073
	                          const NMPlatformLink **out_link,
	                          int *out_fd);
1074

1075 1076 1077 1078 1079
	gboolean (*link_6lowpan_add) (NMPlatform *platform,
	                              const char *name,
	                              int parent,
	                              const NMPlatformLink **out_link);

1080
	gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link);
1081
	gboolean (*infiniband_partition_delete) (NMPlatform *, int parent, int p_key);
1082

1083
	gboolean    (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps);
1084
	gboolean    (*wifi_get_bssid)        (NMPlatform *, int ifindex, guint8 *bssid);
1085 1086 1087 1088 1089
	guint32     (*wifi_get_frequency)    (NMPlatform *, int ifindex);
	int         (*wifi_get_quality)      (NMPlatform *, int ifindex);
	guint32     (*wifi_get_rate)         (NMPlatform *, int ifindex);
	NM80211Mode (*wifi_get_mode)         (NMPlatform *, int ifindex);
	void        (*wifi_set_mode)         (NMPlatform *, int ifindex, NM80211Mode mode);
1090
	void        (*wifi_set_powersave)    (NMPlatform *, int ifindex, guint32 powersave);
1091 1092
	guint32     (*wifi_find_frequency)   (NMPlatform *, int ifindex, const guint32 *freqs);
	void        (*wifi_indicate_addressing_running) (NMPlatform *, int ifindex, gboolean running);