From dd428301eb6f02542015121d7b08d9997f137e50 Mon Sep 17 00:00:00 2001 From: Sebastien Bacher Date: Tue, 12 Mar 2019 15:13:33 +0100 Subject: New upstream version 1.15.91 --- src/platform/nm-fake-platform.c | 1 - src/platform/nm-linux-platform.c | 918 +++++++++++++++++------------- src/platform/nm-netlink.c | 183 +++--- src/platform/nm-netlink.h | 243 ++++++-- src/platform/nm-platform-utils.c | 31 +- src/platform/nm-platform.c | 57 +- src/platform/nm-platform.h | 37 +- src/platform/nmp-netns.c | 239 ++++---- src/platform/nmp-object.c | 19 +- src/platform/nmp-object.h | 18 +- src/platform/tests/meson.build | 20 +- src/platform/tests/test-common.c | 12 +- src/platform/tests/test-common.h | 1 - src/platform/tests/test-link.c | 79 ++- src/platform/tests/test-route.c | 2 +- src/platform/wifi/nm-wifi-utils-nl80211.c | 201 +++---- src/platform/wifi/nm-wifi-utils-wext.c | 38 +- src/platform/wifi/nm-wifi-utils.c | 1 - src/platform/wpan/nm-wpan-utils.c | 19 +- 19 files changed, 1307 insertions(+), 812 deletions(-) (limited to 'src/platform') diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 814d9cea..30466159 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -22,7 +22,6 @@ #include "nm-fake-platform.h" -#include #include #include #include diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 85214ec8..2f5c75b0 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -21,31 +21,30 @@ #include "nm-linux-platform.h" -#include +#include +#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include +#include #include #include #include #include #include #include -#include +#include +#include +#include +#include +#include +#include #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-setting-vlan.h" -#include "nm-utils/nm-errno.h" #include "nm-utils/nm-secret-utils.h" +#include "nm-utils/nm-c-list.h" #include "nm-netlink.h" #include "nm-core-utils.h" #include "nmp-object.h" @@ -322,13 +321,27 @@ typedef enum { } DelayedActionType; #define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ - for ((iflags) = (DelayedActionType) 0x1LL; (iflags) <= DELAYED_ACTION_TYPE_MAX; (iflags) <<= 1) \ - if (NM_FLAGS_ANY (flags_all, iflags)) + for ((iflags) = (DelayedActionType) 0x1LL; \ + ({ \ + gboolean _good = FALSE; \ + \ + nm_assert (nm_utils_is_power_of_two (iflags)); \ + \ + while ((iflags) <= DELAYED_ACTION_TYPE_MAX) { \ + if (NM_FLAGS_ANY ((flags_all), (iflags))) { \ + _good = TRUE; \ + break; \ + } \ + (iflags) <<= 1; \ + } \ + _good; \ + }); \ + (iflags) <<= 1) typedef enum { /* Negative values are errors from kernel. Add dummy member to * make enum signed. */ - _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = -1, + _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = G_MININT, WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN = 0, WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK, @@ -376,8 +389,8 @@ typedef struct { bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; - bool sysctl_get_warned; GHashTable *sysctl_get_prev_values; + CList sysctl_list; NMUdevClient *udev_client; @@ -461,7 +474,7 @@ G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) _LOG_print (__level, __domain, __errsv, self, \ _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \ _NM_UTILS_MACRO_REST (__VA_ARGS__), \ - g_strerror (__errsv), __errsv); \ + nm_strerror_native (__errsv), __errsv); \ } \ } G_STMT_END @@ -512,7 +525,7 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, if (seq_result < 0) { nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s%s%s)", -((int) seq_result), - g_strerror (-((int) seq_result)), + nm_strerror_native (-((int) seq_result)), errmsg ? " - " : "", errmsg ?: ""); } @@ -577,7 +590,7 @@ _support_kernel_extended_ifa_flags_detect (struct nl_msg *msg) /* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6, * but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */ - if (NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6)) + if (!NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6)) return; /* see if the nl_msg contains the IFA_FLAGS attribute. If it does, @@ -1100,7 +1113,7 @@ _linktype_get_type (NMPlatform *platform, ******************************************************************/ #define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) /* copied from iproute2's addattr_l(). */ static gboolean @@ -1154,31 +1167,29 @@ _parse_af_inet6 (NMPlatform *platform, guint8 *out_addr_gen_mode_inv, gboolean *out_addr_gen_mode_valid) { - static const struct nla_policy policy[IFLA_INET6_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_INET6_FLAGS] = { .type = NLA_U32 }, [IFLA_INET6_CACHEINFO] = { .minlen = nm_offsetofend (struct ifla_cacheinfo, retrans_time) }, [IFLA_INET6_CONF] = { .minlen = 4 }, [IFLA_INET6_STATS] = { .minlen = 8 }, [IFLA_INET6_ICMP6STATS] = { .minlen = 8 }, - [IFLA_INET6_TOKEN] = { .minlen = sizeof(struct in6_addr) }, + [IFLA_INET6_TOKEN] = { .minlen = sizeof (struct in6_addr) }, [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_INET6_MAX+1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct in6_addr i6_token; gboolean token_valid = FALSE; gboolean addr_gen_mode_valid = FALSE; guint8 i6_addr_gen_mode_inv = 0; - err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, attr, policy) < 0) return FALSE; - if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4) + if (tb[IFLA_INET6_CONF] && nla_len (tb[IFLA_INET6_CONF]) % 4) return FALSE; - if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8) + if (tb[IFLA_INET6_STATS] && nla_len (tb[IFLA_INET6_STATS]) % 8) return FALSE; - if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8) + if (tb[IFLA_INET6_ICMP6STATS] && nla_len (tb[IFLA_INET6_ICMP6STATS]) % 8) return FALSE; if (_check_addr_or_return_val (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr), FALSE)) { @@ -1218,7 +1229,7 @@ _parse_af_inet6 (NMPlatform *platform, static NMPObject * _parse_lnk_gre (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_GRE_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, @@ -1230,13 +1241,13 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) [IFLA_GRE_TOS] = { .type = NLA_U8 }, [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_GRE_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkGre *props; gboolean is_tap; - if (!info_data || !kind) + if ( !info_data + || !kind) return NULL; if (nm_streq (kind, "gretap")) @@ -1246,8 +1257,7 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) else return NULL; - err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_GRETAP : NMP_OBJECT_TYPE_LNK_GRE, NULL); @@ -1287,25 +1297,25 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_infiniband (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPOIB_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, [IFLA_IPOIB_MODE] = { .type = NLA_U16 }, [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 }, }; - struct nlattr *tb[IFLA_IPOIB_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPlatformLnkInfiniband *info; NMPObject *obj; - int err; const char *mode; - if (!info_data || g_strcmp0 (kind, "ipoib")) + if ( !info_data + || !nm_streq0 (kind, "ipoib")) return NULL; - err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; - if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE]) + if ( !tb[IFLA_IPOIB_PKEY] + || !tb[IFLA_IPOIB_MODE]) return NULL; switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) { @@ -1333,29 +1343,26 @@ _parse_lnk_infiniband (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, - [IFLA_IPTUN_LOCAL] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, - [IFLA_IPTUN_REMOTE] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_LOCAL] = { .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_REMOTE] = { .minlen = sizeof (struct in6_addr)}, [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIp6Tnl *props; guint32 flowinfo; - if (!info_data || g_strcmp0 (kind, "ip6tnl")) + if ( !info_data + || !nm_streq0 (kind, "ip6tnl")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL); @@ -1364,9 +1371,9 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) if (tb[IFLA_IPTUN_LINK]) props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]); if (tb[IFLA_IPTUN_LOCAL]) - memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local)); + props->local = *nla_data_as (struct in6_addr, tb[IFLA_IPTUN_LOCAL]); if (tb[IFLA_IPTUN_REMOTE]) - memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote)); + props->remote = *nla_data_as (struct in6_addr, tb[IFLA_IPTUN_REMOTE]); if (tb[IFLA_IPTUN_TTL]) props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]); if (tb[IFLA_IPTUN_ENCAP_LIMIT]) @@ -1387,23 +1394,22 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_GRE_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_IKEY] = { .type = NLA_U32 }, [IFLA_GRE_OKEY] = { .type = NLA_U32 }, [IFLA_GRE_LOCAL] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + .minlen = sizeof (struct in6_addr)}, [IFLA_GRE_REMOTE] = { .type = NLA_UNSPEC, - .minlen = sizeof (struct in6_addr)}, + .minlen = sizeof (struct in6_addr)}, [IFLA_GRE_TTL] = { .type = NLA_U8 }, [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 }, [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 }, [IFLA_GRE_FLAGS] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_GRE_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIp6Tnl *props; guint32 flowinfo; @@ -1419,8 +1425,7 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) else return NULL; - err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_IP6GRETAP : NMP_OBJECT_TYPE_LNK_IP6GRE, NULL); @@ -1439,9 +1444,9 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) if (tb[IFLA_GRE_OKEY]) props->output_key = ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])); if (tb[IFLA_GRE_LOCAL]) - memcpy (&props->local, nla_data (tb[IFLA_GRE_LOCAL]), sizeof (props->local)); + props->local = *nla_data_as (struct in6_addr, tb[IFLA_GRE_LOCAL]); if (tb[IFLA_GRE_REMOTE]) - memcpy (&props->remote, nla_data (tb[IFLA_GRE_REMOTE]), sizeof (props->remote)); + props->remote = *nla_data_as (struct in6_addr, tb[IFLA_GRE_REMOTE]); if (tb[IFLA_GRE_TTL]) props->ttl = nla_get_u8 (tb[IFLA_GRE_TTL]); if (tb[IFLA_GRE_ENCAP_LIMIT]) @@ -1462,7 +1467,7 @@ _parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_ipip (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, @@ -1470,16 +1475,15 @@ _parse_lnk_ipip (const char *kind, struct nlattr *info_data) [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkIpIp *props; - if (!info_data || g_strcmp0 (kind, "ipip")) + if ( !info_data + || !nm_streq0 (kind, "ipip")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IPIP, NULL); @@ -1500,28 +1504,27 @@ _parse_lnk_ipip (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, }; NMPlatformLnkMacvlan *props; - struct nlattr *tb[IFLA_MACVLAN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; gboolean tap; - if (!info_data) + if ( !info_data + || !kind) return NULL; - if (!g_strcmp0 (kind, "macvlan")) + if (nm_streq (kind, "macvlan")) tap = FALSE; - else if (!g_strcmp0 (kind, "macvtap")) + else if (nm_streq (kind, "macvtap")) tap = TRUE; else return NULL; - err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; if (!tb[IFLA_MACVLAN_MODE]) @@ -1543,7 +1546,7 @@ _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_macsec (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[__IFLA_MACSEC_MAX] = { + static const struct nla_policy policy[] = { [IFLA_MACSEC_SCI] = { .type = NLA_U64 }, [IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 }, [IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 }, @@ -1557,33 +1560,32 @@ _parse_lnk_macsec (const char *kind, struct nlattr *info_data) [IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 }, [IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 }, }; - struct nlattr *tb[__IFLA_MACSEC_MAX]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkMacsec *props; - if (!info_data || !nm_streq0 (kind, "macsec")) + if ( !info_data + || !nm_streq0 (kind, "macsec")) return NULL; - err = nla_parse_nested (tb, __IFLA_MACSEC_MAX - 1, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_MACSEC, NULL); props = &obj->lnk_macsec; - props->sci = tb[IFLA_MACSEC_SCI] ? be64toh (nla_get_u64 (tb[IFLA_MACSEC_SCI])) : 0; - props->icv_length = tb[IFLA_MACSEC_ICV_LEN] ? nla_get_u8 (tb[IFLA_MACSEC_ICV_LEN]) : 0; - props->cipher_suite = tb [IFLA_MACSEC_CIPHER_SUITE] ? nla_get_u64 (tb[IFLA_MACSEC_CIPHER_SUITE]) : 0; - props->window = tb [IFLA_MACSEC_WINDOW] ? nla_get_u32 (tb[IFLA_MACSEC_WINDOW]) : 0; - props->encoding_sa = tb[IFLA_MACSEC_ENCODING_SA] ? !!nla_get_u8 (tb[IFLA_MACSEC_ENCODING_SA]) : 0; - props->encrypt = tb[IFLA_MACSEC_ENCRYPT] ? !!nla_get_u8 (tb[IFLA_MACSEC_ENCRYPT]) : 0; - props->protect = tb[IFLA_MACSEC_PROTECT] ? !!nla_get_u8 (tb[IFLA_MACSEC_PROTECT]) : 0; - props->include_sci = tb[IFLA_MACSEC_INC_SCI] ? !!nla_get_u8 (tb[IFLA_MACSEC_INC_SCI]) : 0; - props->es = tb[IFLA_MACSEC_ES] ? !!nla_get_u8 (tb[IFLA_MACSEC_ES]) : 0; - props->scb = tb[IFLA_MACSEC_SCB] ? !!nla_get_u8 (tb[IFLA_MACSEC_SCB]) : 0; - props->replay_protect = tb[IFLA_MACSEC_REPLAY_PROTECT] ? !!nla_get_u8 (tb[IFLA_MACSEC_REPLAY_PROTECT]) : 0; - props->validation = tb[IFLA_MACSEC_VALIDATION] ? nla_get_u8 (tb[IFLA_MACSEC_VALIDATION]) : 0; + if (tb[IFLA_MACSEC_SCI]) { props->sci = nla_get_be64 (tb[IFLA_MACSEC_SCI]); } + if (tb[IFLA_MACSEC_ICV_LEN]) { props->icv_length = nla_get_u8 (tb[IFLA_MACSEC_ICV_LEN]); } + if (tb[IFLA_MACSEC_CIPHER_SUITE]) { props->cipher_suite = nla_get_u64 (tb[IFLA_MACSEC_CIPHER_SUITE]); } + if (tb[IFLA_MACSEC_WINDOW]) { props->window = nla_get_u32 (tb[IFLA_MACSEC_WINDOW]); } + if (tb[IFLA_MACSEC_ENCODING_SA]) { props->encoding_sa = !!nla_get_u8 (tb[IFLA_MACSEC_ENCODING_SA]); } + if (tb[IFLA_MACSEC_ENCRYPT]) { props->encrypt = !!nla_get_u8 (tb[IFLA_MACSEC_ENCRYPT]); } + if (tb[IFLA_MACSEC_PROTECT]) { props->protect = !!nla_get_u8 (tb[IFLA_MACSEC_PROTECT]); } + if (tb[IFLA_MACSEC_INC_SCI]) { props->include_sci = !!nla_get_u8 (tb[IFLA_MACSEC_INC_SCI]); } + if (tb[IFLA_MACSEC_ES]) { props->es = !!nla_get_u8 (tb[IFLA_MACSEC_ES]); } + if (tb[IFLA_MACSEC_SCB]) { props->scb = !!nla_get_u8 (tb[IFLA_MACSEC_SCB]); } + if (tb[IFLA_MACSEC_REPLAY_PROTECT]) { props->replay_protect = !!nla_get_u8 (tb[IFLA_MACSEC_REPLAY_PROTECT]); } + if (tb[IFLA_MACSEC_VALIDATION]) { props->validation = nla_get_u8 (tb[IFLA_MACSEC_VALIDATION]); } return obj; } @@ -1593,7 +1595,7 @@ _parse_lnk_macsec (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_sit (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, @@ -1603,16 +1605,15 @@ _parse_lnk_sit (const char *kind, struct nlattr *info_data) [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, }; - struct nlattr *tb[IFLA_IPTUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkSit *props; - if (!info_data || g_strcmp0 (kind, "sit")) + if ( !info_data + || !nm_streq0 (kind, "sit")) return NULL; - err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_SIT, NULL); @@ -1635,7 +1636,7 @@ _parse_lnk_sit (const char *kind, struct nlattr *info_data) static NMPObject * _parse_lnk_tun (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_TUN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_TUN_OWNER] = { .type = NLA_U32 }, [IFLA_TUN_GROUP] = { .type = NLA_U32 }, [IFLA_TUN_TYPE] = { .type = NLA_U8 }, @@ -1646,22 +1647,19 @@ _parse_lnk_tun (const char *kind, struct nlattr *info_data) [IFLA_TUN_NUM_QUEUES] = { .type = NLA_U32 }, [IFLA_TUN_NUM_DISABLED_QUEUES] = { .type = NLA_U32 }, }; - struct nlattr *tb[IFLA_TUN_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; NMPlatformLnkTun *props; - if (!info_data || !nm_streq0 (kind, "tun")) + if ( !info_data + || !nm_streq0 (kind, "tun")) return NULL; - err = nla_parse_nested (tb, IFLA_TUN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; - if (!tb[IFLA_TUN_TYPE]) { - /* we require at least a type. */ + if (!tb[IFLA_TUN_TYPE]) return NULL; - } obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_TUN, NULL); props = &obj->lnk_tun; @@ -1708,7 +1706,7 @@ _vlan_qos_mapping_from_nla (struct nlattr *nlattr, array = g_ptr_array_new (); nla_for_each_nested (nla, nlattr, remaining) { - if (nla_len (nla) < sizeof(NMVlanQosMapping)) + if (nla_len (nla) < sizeof (NMVlanQosMapping)) return FALSE; g_ptr_array_add (array, nla_data (nla)); } @@ -1749,22 +1747,22 @@ _vlan_qos_mapping_from_nla (struct nlattr *nlattr, static NMPObject * _parse_lnk_vlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_VLAN_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_VLAN_ID] = { .type = NLA_U16 }, [IFLA_VLAN_FLAGS] = { .minlen = nm_offsetofend (struct ifla_vlan_flags, flags) }, [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED }, [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED }, [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 }, }; - struct nlattr *tb[IFLA_VLAN_MAX+1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; nm_auto_nmpobj NMPObject *obj = NULL; NMPObject *obj_result; - if (!info_data || g_strcmp0 (kind, "vlan")) + if ( !info_data + || !nm_streq0 (kind, "vlan")) return NULL; - if ((err = nla_parse_nested (tb, IFLA_VLAN_MAX, info_data, policy)) < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; if (!tb[IFLA_VLAN_ID]) @@ -1776,7 +1774,7 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data) if (tb[IFLA_VLAN_FLAGS]) { struct ifla_vlan_flags flags; - nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags)); + nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof (flags)); obj->lnk_vlan.flags = flags.flags; } @@ -1834,7 +1832,7 @@ struct nm_ifla_vxlan_port_range { static NMPObject * _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) { - static const struct nla_policy policy[IFLA_VXLAN_MAX + 1] = { + static const struct nla_policy policy[] = { [IFLA_VXLAN_ID] = { .type = NLA_U32 }, [IFLA_VXLAN_GROUP] = { .type = NLA_U32 }, [IFLA_VXLAN_GROUP6] = { .type = NLA_UNSPEC, @@ -1857,16 +1855,14 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, }; NMPlatformLnkVxlan *props; - struct nlattr *tb[IFLA_VXLAN_MAX + 1]; - struct nm_ifla_vxlan_port_range *range; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; NMPObject *obj; - if (!info_data || g_strcmp0 (kind, "vxlan")) + if ( !info_data + || !nm_streq0 (kind, "vxlan")) return NULL; - err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, policy); - if (err < 0) + if (nla_parse_nested_arr (tb, info_data, policy) < 0) return NULL; obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL); @@ -1881,10 +1877,10 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]); if (tb[IFLA_VXLAN_LOCAL]) props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]); - if (tb[IFLA_VXLAN_GROUP6]) - memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6)); if (tb[IFLA_VXLAN_LOCAL6]) - memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6)); + props->local6 = *nla_data_as (struct in6_addr, tb[IFLA_VXLAN_LOCAL6]); + if (tb[IFLA_VXLAN_GROUP6]) + props->group6 = *nla_data_as (struct in6_addr, tb[IFLA_VXLAN_GROUP6]); if (tb[IFLA_VXLAN_AGEING]) props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]); @@ -1899,7 +1895,9 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) props->dst_port = ntohs (nla_get_u16 (tb[IFLA_VXLAN_PORT])); if (tb[IFLA_VXLAN_PORT_RANGE]) { - range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]); + struct nm_ifla_vxlan_port_range *range; + + range = nla_data_as (struct nm_ifla_vxlan_port_range, tb[IFLA_VXLAN_PORT_RANGE]); props->src_port_min = ntohs (range->low); props->src_port_max = ntohs (range->high); } @@ -1924,16 +1922,16 @@ static gboolean _wireguard_update_from_allowed_ips_nla (NMPWireGuardAllowedIP *allowed_ip, struct nlattr *nlattr) { - static const struct nla_policy policy[WGALLOWEDIP_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 }, [WGALLOWEDIP_A_IPADDR] = { .minlen = sizeof (struct in_addr) }, [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 }, }; - struct nlattr *tb[WGALLOWEDIP_A_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; int family; int addr_len; - if (nla_parse_nested (tb, WGALLOWEDIP_A_MAX, nlattr, policy) < 0) + if (nla_parse_nested_arr (tb, nlattr, policy) < 0) return FALSE; if (!tb[WGALLOWEDIP_A_FAMILY]) @@ -1973,7 +1971,7 @@ _wireguard_update_from_peers_nla (CList *peers, GArray **p_allowed_ips, struct nlattr *peer_attr) { - static const struct nla_policy policy[WGPEER_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGPEER_A_PUBLIC_KEY] = { .minlen = NMP_WIREGUARD_PUBLIC_KEY_LEN }, [WGPEER_A_PRESHARED_KEY] = { }, [WGPEER_A_FLAGS] = { .type = NLA_U32 }, @@ -1984,10 +1982,10 @@ _wireguard_update_from_peers_nla (CList *peers, [WGPEER_A_TX_BYTES] = { .type = NLA_U64 }, [WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; WireGuardPeerConstruct *peer_c; - struct nlattr *tb[WGPEER_A_MAX + 1]; - if (nla_parse_nested (tb, WGPEER_A_MAX, peer_attr, policy) < 0) + if (nla_parse_nested_arr (tb, peer_attr, policy) < 0) return FALSE; if (!tb[WGPEER_A_PUBLIC_KEY]) @@ -2017,12 +2015,14 @@ _wireguard_update_from_peers_nla (CList *peers, nm_sock_addr_union_cpy_untrusted (&peer_c->data.endpoint, tb[WGPEER_A_ENDPOINT] ? nla_data (tb[WGPEER_A_ENDPOINT]) : NULL, - tb[WGPEER_A_ENDPOINT] ? nla_len (tb[WGPEER_A_ENDPOINT]) : 0); + tb[WGPEER_A_ENDPOINT] ? nla_len (tb[WGPEER_A_ENDPOINT]) : 0); if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) - peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); - if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) - nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time)); + peer_c->data.persistent_keepalive_interval = nla_get_u16 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); + if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) { + if (nla_len (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) >= sizeof (peer_c->data.last_handshake_time)) + nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time)); + } if (tb[WGPEER_A_RX_BYTES]) peer_c->data.rx_bytes = nla_get_u64 (tb[WGPEER_A_RX_BYTES]); if (tb[WGPEER_A_TX_BYTES]) @@ -2070,7 +2070,7 @@ typedef struct { static int _wireguard_get_device_cb (struct nl_msg *msg, void *arg) { - static const struct nla_policy policy[WGDEVICE_A_MAX + 1] = { + static const struct nla_policy policy[] = { [WGDEVICE_A_IFINDEX] = { .type = NLA_U32 }, [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .maxlen = IFNAMSIZ }, [WGDEVICE_A_PRIVATE_KEY] = { }, @@ -2080,12 +2080,10 @@ _wireguard_get_device_cb (struct nl_msg *msg, void *arg) [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, [WGDEVICE_A_PEERS] = { .type = NLA_NESTED }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; WireGuardParseData *parse_data = arg; - struct nlattr *tb[WGDEVICE_A_MAX + 1]; - int nlerr; - nlerr = genlmsg_parse (nlmsg_hdr (msg), 0, tb, WGDEVICE_A_MAX, policy); - if (nlerr < 0) + if (genlmsg_parse_arr (nlmsg_hdr (msg), 0, tb, policy) < 0) return NL_SKIP; if (tb[WGDEVICE_A_IFINDEX]) { @@ -2164,7 +2162,7 @@ _wireguard_read_info (NMPlatform *platform /* used only as logging context */, nm_assert (wireguard_family_id >= 0); nm_assert (ifindex > 0); - _LOGT ("wireguard: fetching infomation for ifindex %d (genl-id %d)...", ifindex, wireguard_family_id); + _LOGT ("wireguard: fetching information for ifindex %d (genl-id %d)...", ifindex, wireguard_family_id); msg = nlmsg_alloc (); @@ -2373,8 +2371,9 @@ _wireguard_create_change_nlmsgs (NMPlatform *platform, int wireguard_family_id, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers, + NMPlatformWireGuardChangeFlags change_flags, GPtrArray **out_msgs) { gs_unref_ptrarray GPtrArray *msgs = NULL; @@ -2386,6 +2385,7 @@ _wireguard_create_change_nlmsgs (NMPlatform *platform, struct nlattr *nest_curr_peer; struct nlattr *nest_allowed_ips; struct nlattr *nest_curr_allowed_ip; + NMPlatformWireGuardChangePeerFlags p_flags = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT; #define _nla_nest_end(msg, nest_start) \ G_STMT_START { \ @@ -2420,12 +2420,19 @@ again: NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex); if (idx_peer_curr == IDX_NIL) { - NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key); - NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port); - NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark); + guint32 flags; + + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY)) + NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT)) + NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port); + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK)) + NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark); - NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, - replace_peers ? WGDEVICE_F_REPLACE_PEERS : ((guint32) 0u)); + flags = 0; + if (NM_FLAGS_HAS (change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS)) + flags |= WGDEVICE_F_REPLACE_PEERS; + NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, flags); } if (peers_len == 0) @@ -2444,6 +2451,21 @@ again: for (; idx_peer_curr < peers_len; idx_peer_curr++) { const NMPWireGuardPeer *p = &peers[idx_peer_curr]; + if (peer_flags) { + p_flags = peer_flags[idx_peer_curr]; + if (!NM_FLAGS_ANY (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME + | 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 + | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS)) { + /* no flags set. We take that as indication to skip configuring the peer + * entirely. */ + nm_assert (p_flags == NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE); + continue; + } + } + nest_curr_peer = nla_nest_start (msg, 0); if (!nest_curr_peer) goto toobig_peers; @@ -2451,63 +2473,77 @@ again: if (nla_put (msg, WGPEER_A_PUBLIC_KEY, NMP_WIREGUARD_PUBLIC_KEY_LEN, p->public_key) < 0) goto toobig_peers; - if (idx_allowed_ips_curr == IDX_NIL) { - - if (nla_put (msg, WGPEER_A_PRESHARED_KEY, sizeof (p->preshared_key), p->preshared_key) < 0) - goto toobig_peers; - - if (nla_put_uint16 (msg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, p->persistent_keepalive_interval) < 0) + if (NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME)) { + /* all other p_flags are silently ignored. */ + if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REMOVE_ME) < 0) goto toobig_peers; + } else { - if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) - goto toobig_peers; + if (idx_allowed_ips_curr == IDX_NIL) { + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY) + && nla_put (msg, WGPEER_A_PRESHARED_KEY, sizeof (p->preshared_key), p->preshared_key) < 0) + goto toobig_peers; - if (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6)) { - if (nla_put (msg, - WGPEER_A_ENDPOINT, - p->endpoint.sa.sa_family == AF_INET - ? sizeof (p->endpoint.in) - : sizeof (p->endpoint.in6), - &p->endpoint) < 0) + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL) + && nla_put_uint16 (msg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, p->persistent_keepalive_interval) < 0) goto toobig_peers; - } else - nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC); - } - if (p->allowed_ips_len > 0) { - if (idx_allowed_ips_curr == IDX_NIL) - idx_allowed_ips_curr = 0; + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS) + && nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) + goto toobig_peers; - nest_allowed_ips = nla_nest_start (msg, WGPEER_A_ALLOWEDIPS); - if (!nest_allowed_ips) - goto toobig_allowedips; + if (NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT)) { + if (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6)) { + if (nla_put (msg, + WGPEER_A_ENDPOINT, + p->endpoint.sa.sa_family == AF_INET + ? sizeof (p->endpoint.in) + : sizeof (p->endpoint.in6), + &p->endpoint) < 0) + goto toobig_peers; + } else { + /* I think there is no way to clear an endpoint, though there shold be. */ + nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC); + } + } + } - for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) { - const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr]; + if ( NM_FLAGS_HAS (p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS) + && p->allowed_ips_len > 0) { + if (idx_allowed_ips_curr == IDX_NIL) + idx_allowed_ips_curr = 0; - nest_curr_allowed_ip = nla_nest_start (msg, 0); - if (!nest_curr_allowed_ip) + nest_allowed_ips = nla_nest_start (msg, WGPEER_A_ALLOWEDIPS); + if (!nest_allowed_ips) goto toobig_allowedips; - g_return_val_if_fail (NM_IN_SET (aip->family, AF_INET, AF_INET6), -NME_BUG); + for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) { + const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr]; - if (nla_put_uint16 (msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0) - goto toobig_allowedips; - if (nla_put (msg, - WGALLOWEDIP_A_IPADDR, - nm_utils_addr_family_to_size (aip->family), - &aip->addr) < 0) - goto toobig_allowedips; - if (nla_put_uint8 (msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) - goto toobig_allowedips; + nest_curr_allowed_ip = nla_nest_start (msg, 0); + if (!nest_curr_allowed_ip) + goto toobig_allowedips; - _nla_nest_end (msg, nest_curr_allowed_ip); - nest_curr_allowed_ip = NULL; - } - idx_allowed_ips_curr = IDX_NIL; + g_return_val_if_fail (NM_IN_SET (aip->family, AF_INET, AF_INET6), -NME_BUG); - _nla_nest_end (msg, nest_allowed_ips); - nest_allowed_ips = NULL; + if (nla_put_uint16 (msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0) + goto toobig_allowedips; + if (nla_put (msg, + WGALLOWEDIP_A_IPADDR, + nm_utils_addr_family_to_size (aip->family), + &aip->addr) < 0) + goto toobig_allowedips; + if (nla_put_uint8 (msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) + goto toobig_allowedips; + + _nla_nest_end (msg, nest_curr_allowed_ip); + nest_curr_allowed_ip = NULL; + } + idx_allowed_ips_curr = IDX_NIL; + + _nla_nest_end (msg, nest_allowed_ips); + nest_allowed_ips = NULL; + } } _nla_nest_end (msg, nest_curr_peer); @@ -2555,8 +2591,9 @@ link_wireguard_change (NMPlatform *platform, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers) + NMPlatformWireGuardChangeFlags change_flags) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); gs_unref_ptrarray GPtrArray *msgs = NULL; @@ -2573,8 +2610,9 @@ link_wireguard_change (NMPlatform *platform, wireguard_family_id, lnk_wireguard, peers, + peer_flags, peers_len, - replace_peers, + change_flags, &msgs); if (r < 0) { _LOGW ("wireguard: set-device, cannot construct netlink message: %s", nm_strerror (r)); @@ -2610,7 +2648,7 @@ link_wireguard_change (NMPlatform *platform, static NMPObject * _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[IFLA_MAX+1] = { + static const struct nla_policy policy[] = { [IFLA_IFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ }, [IFLA_MTU] = { .type = NLA_U32 }, @@ -2637,18 +2675,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr [IFLA_PHYS_PORT_ID] = { .type = NLA_UNSPEC }, [IFLA_NET_NS_PID] = { .type = NLA_U32 }, [IFLA_NET_NS_FD] = { .type = NLA_U32 }, - }; - static const struct nla_policy policy_link_info[IFLA_INFO_MAX+1] = { - [IFLA_INFO_KIND] = { .type = NLA_STRING }, - [IFLA_INFO_DATA] = { .type = NLA_NESTED }, - [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, + [IFLA_LINK_NETNSID] = { }, }; const struct ifinfomsg *ifi; - struct nlattr *tb[IFLA_MAX+1]; - struct nlattr *li[IFLA_INFO_MAX+1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct nlattr *nl_info_data = NULL; const char *nl_info_kind = NULL; - int err; nm_auto_nmpobj NMPObject *obj = NULL; gboolean completed_from_cache_val = FALSE; gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL; @@ -2662,6 +2694,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr if (!nlmsg_valid_hdr (nlh, sizeof (*ifi))) return NULL; + ifi = nlmsg_data (nlh); if (ifi->ifi_family != AF_UNSPEC) @@ -2674,13 +2707,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr if (id_only) return g_steal_pointer (&obj); - err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, sizeof (*ifi), tb, policy) < 0) return NULL; if (!tb[IFLA_IFNAME]) return NULL; - nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); + nla_strlcpy (obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); if (!obj->link.name[0]) return NULL; @@ -2702,8 +2734,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]); if (tb[IFLA_LINKINFO]) { - err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info); - if (err < 0) + static const struct nla_policy policy_link_info[] = { + [IFLA_INFO_KIND] = { .type = NLA_STRING }, + [IFLA_INFO_DATA] = { .type = NLA_NESTED }, + [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, + }; + struct nlattr *li[G_N_ELEMENTS (policy_link_info)]; + + if (nla_parse_nested_arr (li, tb[IFLA_LINKINFO], policy_link_info) < 0) return NULL; if (li[IFLA_INFO_KIND]) @@ -2713,18 +2751,12 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr } if (tb[IFLA_STATS64]) { - /* tb[IFLA_STATS64] is only guaranteed to be 32bit-aligned, - * so in general we can't access the rtnl_link_stats64 struct - * members directly on 64bit architectures. */ - char *stats = nla_data (tb[IFLA_STATS64]); + const char *stats = nla_data (tb[IFLA_STATS64]); -#define READ_STAT64(member) \ - unaligned_read_ne64 (stats + offsetof (struct rtnl_link_stats64, member)) - - obj->link.rx_packets = READ_STAT64 (rx_packets); - obj->link.rx_bytes = READ_STAT64 (rx_bytes); - obj->link.tx_packets = READ_STAT64 (tx_packets); - obj->link.tx_bytes = READ_STAT64 (tx_bytes); + obj->link.rx_packets = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, rx_packets)]); + obj->link.rx_bytes = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, rx_bytes)]); + obj->link.tx_packets = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, tx_packets)]); + obj->link.tx_bytes = unaligned_read_ne64 (&stats[G_STRUCT_OFFSET (struct rtnl_link_stats64, tx_bytes)]); } obj->link.n_ifi_flags = ifi->ifi_flags; @@ -2952,14 +2984,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr static NMPObject * _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[IFA_MAX+1] = { + static const struct nla_policy policy[] = { [IFA_LABEL] = { .type = NLA_STRING, - .maxlen = IFNAMSIZ }, + .maxlen = IFNAMSIZ }, [IFA_CACHEINFO] = { .minlen = nm_offsetofend (struct ifa_cacheinfo, tstamp) }, + [IFA_FLAGS] = { }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; const struct ifaddrmsg *ifa; - struct nlattr *tb[IFA_MAX+1]; - int err; gboolean is_v4; nm_auto_nmpobj NMPObject *obj = NULL; int addr_len; @@ -2967,14 +2999,15 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) if (!nlmsg_valid_hdr (nlh, sizeof (*ifa))) return NULL; - ifa = nlmsg_data(nlh); + + ifa = nlmsg_data (nlh); if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6)) return NULL; + is_v4 = ifa->ifa_family == AF_INET; - err = nlmsg_parse (nlh, sizeof(*ifa), tb, IFA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, sizeof (*ifa), tb, policy) < 0) return NULL; addr_len = is_v4 @@ -3043,8 +3076,9 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) timestamp = 0; /* IPv6 only */ if (tb[IFA_CACHEINFO]) { - const struct ifa_cacheinfo *ca = nla_data(tb[IFA_CACHEINFO]); + const struct ifa_cacheinfo *ca; + ca = nla_data_as (struct ifa_cacheinfo, tb[IFA_CACHEINFO]); lifetime = ca->ifa_valid; preferred = ca->ifa_prefered; timestamp = ca->tstamp; @@ -3063,7 +3097,7 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) static NMPObject * _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) { - static const struct nla_policy policy[RTA_MAX+1] = { + static const struct nla_policy policy[] = { [RTA_TABLE] = { .type = NLA_U32 }, [RTA_IIF] = { .type = NLA_U32 }, [RTA_OIF] = { .type = NLA_U32 }, @@ -3075,8 +3109,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) [RTA_MULTIPATH] = { .type = NLA_NESTED }, }; const struct rtmsg *rtm; - struct nlattr *tb[RTA_MAX + 1]; - int err; + struct nlattr *tb[G_N_ELEMENTS (policy)]; gboolean is_v4; nm_auto_nmpobj NMPObject *obj = NULL; int addr_len; @@ -3084,13 +3117,21 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) gboolean is_present; int ifindex; NMIPAddr gateway; - } nh; + } nh = { + .is_present = FALSE, + }; guint32 mss; - guint32 window = 0, cwnd = 0, initcwnd = 0, initrwnd = 0, mtu = 0, lock = 0; + guint32 window = 0; + guint32 cwnd = 0; + guint32 initcwnd = 0; + guint32 initrwnd = 0; + guint32 mtu = 0; + guint32 lock = 0; if (!nlmsg_valid_hdr (nlh, sizeof (*rtm))) return NULL; - rtm = nlmsg_data(nlh); + + rtm = nlmsg_data (nlh); /***************************************************************** * only handle ~normal~ routes. @@ -3102,8 +3143,10 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (rtm->rtm_type != RTN_UNICAST) return NULL; - err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, + sizeof (struct rtmsg), + tb, + policy) < 0) return NULL; /*****************************************************************/ @@ -3120,39 +3163,49 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) * parse nexthops. Only handle routes with one nh. *****************************************************************/ - memset (&nh, 0, sizeof (nh)); - if (tb[RTA_MULTIPATH]) { - struct rtnexthop *rtnh = nla_data (tb[RTA_MULTIPATH]); - size_t tlen = nla_len(tb[RTA_MULTIPATH]); + size_t tlen = nla_len (tb[RTA_MULTIPATH]); + struct rtnexthop *rtnh; - while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { + if (tlen < sizeof (*rtnh)) + goto rta_multipath_done; + + rtnh = nla_data_as (struct rtnexthop, tb[RTA_MULTIPATH]); + + if (tlen < rtnh->rtnh_len) + goto rta_multipath_done; + + while (TRUE) { if (nh.is_present) { /* we don't support multipath routes. */ return NULL; } - nh.is_present = TRUE; + nh.is_present = TRUE; nh.ifindex = rtnh->rtnh_ifindex; - if (rtnh->rtnh_len > sizeof(*rtnh)) { - struct nlattr *ntb[RTA_MAX + 1]; + if (rtnh->rtnh_len > sizeof (*rtnh)) { + struct nlattr *ntb[G_N_ELEMENTS (policy)]; - err = nla_parse (ntb, RTA_MAX, (struct nlattr *) - RTNH_DATA(rtnh), - rtnh->rtnh_len - sizeof (*rtnh), - policy); - if (err < 0) + if (nla_parse_arr (ntb, + (struct nlattr *) RTNH_DATA (rtnh), + rtnh->rtnh_len - sizeof (*rtnh), + policy) < 0) return NULL; if (_check_addr_or_return_null (ntb, RTA_GATEWAY, addr_len)) memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len); } - tlen -= RTNH_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); + if (tlen < RTNH_ALIGN (rtnh->rtnh_len) + sizeof (*rtnh)) + goto rta_multipath_done; + + tlen -= RTNH_ALIGN (rtnh->rtnh_len); + rtnh = RTNH_NEXT (rtnh); } +rta_multipath_done: + ; } if ( tb[RTA_OIF] @@ -3186,8 +3239,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) mss = 0; if (tb[RTA_METRICS]) { - struct nlattr *mtb[RTAX_MAX + 1]; - static const struct nla_policy rtax_policy[RTAX_MAX + 1] = { + static const struct nla_policy rtax_policy[] = { [RTAX_LOCK] = { .type = NLA_U32 }, [RTAX_ADVMSS] = { .type = NLA_U32 }, [RTAX_WINDOW] = { .type = NLA_U32 }, @@ -3196,9 +3248,9 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) [RTAX_INITRWND] = { .type = NLA_U32 }, [RTAX_MTU] = { .type = NLA_U32 }, }; + struct nlattr *mtb[G_N_ELEMENTS (rtax_policy)]; - err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy); - if (err < 0) + if (nla_parse_nested_arr (mtb, tb[RTA_METRICS], rtax_policy) < 0) return NULL; if (mtb[RTAX_LOCK]) @@ -3233,7 +3285,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip_route.plen = rtm->rtm_dst_len; if (tb[RTA_PRIORITY]) - obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]); + obj->ip_route.metric = nla_get_u32 (tb[RTA_PRIORITY]); if (is_v4) obj->ip4_route.gateway = nh.gateway.addr4; @@ -3290,25 +3342,24 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) static NMPObject * _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) { - NMPObject *obj = NULL; - const struct tcmsg *tcm; - struct nlattr *tb[TCA_MAX + 1]; - int err; - static const struct nla_policy policy[TCA_MAX + 1] = { + static const struct nla_policy policy[] = { [TCA_KIND] = { .type = NLA_STRING }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + const struct tcmsg *tcm; + NMPObject *obj; - if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) - return NULL; - tcm = nlmsg_data (nlh); - - err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, + sizeof (*tcm), + tb, + policy) < 0) return NULL; if (!tb[TCA_KIND]) return NULL; + tcm = nlmsg_data (nlh); + obj = nmp_object_new (NMP_OBJECT_TYPE_QDISC, NULL); obj->qdisc.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); @@ -3324,25 +3375,21 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) static NMPObject * _new_from_nl_tfilter (struct nlmsghdr *nlh, gboolean id_only) { - NMPObject *obj = NULL; - const struct tcmsg *tcm; - struct nlattr *tb[TCA_MAX + 1]; - int err; - static const struct nla_policy policy[TCA_MAX + 1] = { + static const struct nla_policy policy[] = { [TCA_KIND] = { .type = NLA_STRING }, }; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + NMPObject *obj = NULL; + const struct tcmsg *tcm; - if (!nlmsg_valid_hdr (nlh, sizeof (*tcm))) - return NULL; - tcm = nlmsg_data (nlh); - - err = nlmsg_parse (nlh, sizeof (*tcm), tb, TCA_MAX, policy); - if (err < 0) + if (nlmsg_parse_arr (nlh, sizeof (*tcm), tb, policy) < 0) return NULL; if (!tb[TCA_KIND]) return NULL; + tcm = nlmsg_data (nlh); + obj = nmp_object_new (NMP_OBJECT_TYPE_TFILTER, NULL); obj->tfilter.kind = g_intern_string (nla_get_string (tb[TCA_KIND])); @@ -3464,14 +3511,14 @@ _nl_msg_new_link_set_linkinfo (struct nl_msg *msg, NLA_PUT_STRING (msg, IFLA_INFO_KIND, kind); if (veth_peer) { - struct ifinfomsg ifi = { }; + const struct ifinfomsg ifi = { }; struct nlattr *data, *info_peer; if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) goto nla_put_failure; if (!(info_peer = nla_nest_start (msg, 1 /*VETH_INFO_PEER*/))) goto nla_put_failure; - if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &ifi) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, IFLA_IFNAME, veth_peer); nla_nest_end (msg, info_peer); @@ -3575,7 +3622,7 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, for (i = 0; i < egress_qos_len; i++) { if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) { if (!qos) { - if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS))) + if (!(qos = nla_nest_start (msg, IFLA_VLAN_EGRESS_QOS))) goto nla_put_failure; } NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]); @@ -3583,7 +3630,7 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, } if (qos) - nla_nest_end(msg, qos); + nla_nest_end (msg, qos); } nla_nest_end (msg, data); @@ -3602,8 +3649,8 @@ _nl_msg_new_link (int nlmsg_type, unsigned flags_mask, unsigned flags_set) { - struct nl_msg *msg; - struct ifinfomsg ifi = { + nm_auto_nlmsg struct nl_msg *msg = NULL; + const struct ifinfomsg ifi = { .ifi_change = flags_mask, .ifi_flags = flags_set, .ifi_index = ifindex, @@ -3613,15 +3660,15 @@ _nl_msg_new_link (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &ifi) < 0) goto nla_put_failure; if (ifname) NLA_PUT_STRING (msg, IFLA_IFNAME, ifname); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3640,7 +3687,7 @@ _nl_msg_new_address (int nlmsg_type, guint32 preferred, const char *label) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; struct ifaddrmsg am = { .ifa_family = family, .ifa_index = ifindex, @@ -3667,7 +3714,7 @@ _nl_msg_new_address (int nlmsg_type, addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); - if (nlmsg_append (msg, &am, sizeof (am), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &am) < 0) goto nla_put_failure; if (address) @@ -3698,7 +3745,7 @@ _nl_msg_new_address (int nlmsg_type, .ifa_prefered = preferred, }; - NLA_PUT (msg, IFA_CACHEINFO, sizeof(ca), &ca); + NLA_PUT (msg, IFA_CACHEINFO, sizeof (ca), &ca); } if (flags & ~((guint32) 0xFF)) { @@ -3711,10 +3758,9 @@ _nl_msg_new_address (int nlmsg_type, NLA_PUT_U32 (msg, IFA_FLAGS, flags); } - return msg; + return g_steal_pointer (&msg); nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3734,12 +3780,12 @@ _nl_msg_new_route (int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); gboolean is_v4 = klass->addr_family == AF_INET; const guint32 lock = ip_route_get_lock_flag (NMP_OBJECT_CAST_IP_ROUTE (obj)); const guint32 table = nm_platform_route_table_uncoerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced, TRUE); - struct rtmsg rtmsg = { + const struct rtmsg rtmsg = { .rtm_family = klass->addr_family, .rtm_tos = is_v4 ? obj->ip4_route.tos @@ -3766,7 +3812,7 @@ _nl_msg_new_route (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, (int) nlmsgflags); - if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &rtmsg) < 0) goto nla_put_failure; addr_len = is_v4 @@ -3824,7 +3870,7 @@ _nl_msg_new_route (int nlmsg_type, if (lock) NLA_PUT_U32 (msg, RTAX_LOCK, lock); - nla_nest_end(msg, metrics); + nla_nest_end (msg, metrics); } /* We currently don't have need for multi-hop routes... */ @@ -3840,10 +3886,9 @@ _nl_msg_new_route (int nlmsg_type, && obj->ip6_route.rt_pref != NM_ICMPV6_ROUTER_PREF_MEDIUM) NLA_PUT_U8 (msg, RTA_PREF, obj->ip6_route.rt_pref); - return msg; + return g_steal_pointer (&msg); nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3852,8 +3897,8 @@ _nl_msg_new_qdisc (int nlmsg_type, int nlmsg_flags, const NMPlatformQdisc *qdisc) { - struct nl_msg *msg; - struct tcmsg tcm = { + nm_auto_nlmsg struct nl_msg *msg = NULL; + const struct tcmsg tcm = { .tcm_family = qdisc->addr_family, .tcm_ifindex = qdisc->ifindex, .tcm_handle = qdisc->handle, @@ -3863,14 +3908,14 @@ _nl_msg_new_qdisc (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &tcm) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -3924,10 +3969,10 @@ _nl_msg_new_tfilter (int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tfilter) { - struct nl_msg *msg; + nm_auto_nlmsg struct nl_msg *msg = NULL; struct nlattr *tc_options; struct nlattr *act_tab; - struct tcmsg tcm = { + const struct tcmsg tcm = { .tcm_family = tfilter->addr_family, .tcm_ifindex = tfilter->ifindex, .tcm_handle = tfilter->handle, @@ -3937,7 +3982,7 @@ _nl_msg_new_tfilter (int nlmsg_type, msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); - if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) + if (nlmsg_append_struct (msg, &tcm) < 0) goto nla_put_failure; NLA_PUT_STRING (msg, TCA_KIND, tfilter->kind); @@ -3955,9 +4000,9 @@ _nl_msg_new_tfilter (int nlmsg_type, nla_nest_end (msg, act_tab); - return msg; + return g_steal_pointer (&msg); + nla_put_failure: - nlmsg_free (msg); g_return_val_if_reached (NULL); } @@ -4052,10 +4097,10 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat errsv = errno; if (errsv == ENOENT) { _LOGD ("sysctl: failed to open '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } else { _LOGE ("sysctl: failed to open '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } errno = errsv; return FALSE; @@ -4066,10 +4111,10 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat errsv = errno; if (errsv == ENOENT) { _LOGD ("sysctl: failed to openat '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } else { _LOGE ("sysctl: failed to openat '%s': (%d) %s", - pathid, errsv, strerror (errsv)); + pathid, errsv, nm_strerror_native (errsv)); } errno = errsv; return FALSE; @@ -4119,7 +4164,7 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat } _NMLOG (level, "sysctl: failed to set '%s' to '%s': (%d) %s", - path, value, errsv, strerror (errsv)); + path, value, errsv, nm_strerror_native (errsv)); } else if (nwrote < len - 1) { _LOGE ("sysctl: failed to set '%s' to '%s' after three attempts", path, value); @@ -4146,8 +4191,8 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat static GSList *sysctl_clear_cache_list; -static void -_nm_logging_clear_platform_logging_cache_impl (void) +void +_nm_logging_clear_platform_logging_cache (void) { while (sysctl_clear_cache_list) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (sysctl_clear_cache_list->data); @@ -4156,42 +4201,71 @@ _nm_logging_clear_platform_logging_cache_impl (void) g_hash_table_destroy (priv->sysctl_get_prev_values); priv->sysctl_get_prev_values = NULL; - priv->sysctl_get_warned = FALSE; } } +typedef struct { + const char *path; + CList lst; + char *value; + char path_data[]; +} SysctlCacheEntry; + +static void +sysctl_cache_entry_free (SysctlCacheEntry *entry) +{ + c_list_unlink_stale (&entry->lst); + g_free (entry->value); + g_free (entry); +} + static void _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *pathid, const char *contents) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - const char *prev_value = NULL; + SysctlCacheEntry *entry = NULL; if (!priv->sysctl_get_prev_values) { - _nm_logging_clear_platform_logging_cache = _nm_logging_clear_platform_logging_cache_impl; sysctl_clear_cache_list = g_slist_prepend (sysctl_clear_cache_list, platform); - priv->sysctl_get_prev_values = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); + c_list_init (&priv->sysctl_list); + priv->sysctl_get_prev_values = g_hash_table_new_full (nm_pstr_hash, + nm_pstr_equal, + (GDestroyNotify) sysctl_cache_entry_free, + NULL); } else - prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, pathid); + entry = g_hash_table_lookup (priv->sysctl_get_prev_values, &pathid); - if (prev_value) { - if (strcmp (prev_value, contents) != 0) { + if (entry) { + if (!nm_streq (entry->value, contents)) { gs_free char *contents_escaped = g_strescape (contents, NULL); - gs_free char *prev_value_escaped = g_strescape (prev_value, NULL); + gs_free char *prev_value_escaped = g_strescape (entry->value, NULL); _LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", pathid, contents_escaped, prev_value_escaped); - g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); + g_free (entry->value); + entry->value = g_strdup (contents); } + nm_c_list_move_front (&priv->sysctl_list, &entry->lst); } else { gs_free char *contents_escaped = g_strescape (contents, NULL); + SysctlCacheEntry *old; + size_t len; + + len = strlen (pathid); + entry = g_malloc (sizeof (SysctlCacheEntry) + len + 1); + entry->value = g_strdup (contents); + entry->path = entry->path_data; + memcpy (entry->path_data, pathid, len + 1); + + /* Remove oldest entry when the cache becomes too big */ + if (g_hash_table_size (priv->sysctl_get_prev_values) > 1000) { + old = c_list_last_entry (&priv->sysctl_list, SysctlCacheEntry, lst); + g_hash_table_remove (priv->sysctl_get_prev_values, old); + } _LOGD ("sysctl: reading '%s': '%s'", pathid, contents_escaped); - g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); - if ( !priv->sysctl_get_warned - && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) { - _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`."); - priv->sysctl_get_warned = TRUE; - } + g_hash_table_add (priv->sysctl_get_prev_values, entry); + c_list_link_front (&priv->sysctl_list, &entry->lst); } } @@ -4575,9 +4649,8 @@ delayed_action_handle_one (NMPlatform *platform) priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL; if (_LOGt_ENABLED ()) { - FOR_EACH_DELAYED_ACTION (iflags, flags) { + FOR_EACH_DELAYED_ACTION (iflags, flags) _LOGt_delayed_action (iflags, NULL, "handle"); - } } delayed_action_handle_REFRESH_ALL (platform, flags); @@ -4661,9 +4734,8 @@ delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gp priv->delayed_action.flags |= action_type; if (_LOGt_ENABLED ()) { - FOR_EACH_DELAYED_ACTION (iflags, action_type) { + FOR_EACH_DELAYED_ACTION (iflags, action_type) _LOGt_delayed_action (iflags, user_data, "schedule"); - } } } @@ -4993,7 +5065,7 @@ _nl_send_nlmsghdr (NMPlatform *platform, { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); guint32 seq; - int nle; + int errsv; nm_assert (nlhdr); @@ -5010,7 +5082,7 @@ _nl_send_nlmsghdr (NMPlatform *platform, }; struct msghdr msg = { .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), + .msg_namelen = sizeof (nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; @@ -5022,13 +5094,13 @@ _nl_send_nlmsghdr (NMPlatform *platform, try_count = 0; again: - nle = sendmsg (nl_socket_get_fd (priv->nlh), &msg, 0); - if (nle < 0) { - nle = errno; - if (nle == EINTR && try_count++ < 100) + errsv = sendmsg (nl_socket_get_fd (priv->nlh), &msg, 0); + if (errsv < 0) { + errsv = errno; + if (errsv == EINTR && try_count++ < 100) goto again; - _LOGD ("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", g_strerror (nle), nle); - return -nle; + _LOGD ("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", nm_strerror_native (errsv), errsv); + return -nm_errno_from_native (errsv); } } @@ -5125,6 +5197,59 @@ do_request_link (NMPlatform *platform, int ifindex, const char *name) delayed_action_handle_all (platform, FALSE); } +static struct nl_msg * +_nl_msg_new_dump (NMPObjectType obj_type, + int preferred_addr_family) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + const NMPClass *klass; + + klass = nmp_class_from_type (obj_type); + + nm_assert (klass); + nm_assert (klass->rtm_gettype > 0); + + nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + + if (klass->addr_family != AF_UNSPEC) { + /* if the class specifies a particular address family, then it is preferred. */ + nm_assert (NM_IN_SET (preferred_addr_family, AF_UNSPEC, klass->addr_family)); + preferred_addr_family = klass->addr_family; + } + + switch (klass->obj_type) { + case NMP_OBJECT_TYPE_QDISC: + case NMP_OBJECT_TYPE_TFILTER: + { + const struct tcmsg tcmsg = { + .tcm_family = preferred_addr_family, + }; + + if (nlmsg_append_struct (nlmsg, &tcmsg) < 0) + g_return_val_if_reached (NULL); + } + break; + case NMP_OBJECT_TYPE_LINK: + case NMP_OBJECT_TYPE_IP4_ADDRESS: + case NMP_OBJECT_TYPE_IP6_ADDRESS: + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + { + const struct rtgenmsg gmsg = { + .rtgen_family = preferred_addr_family, + }; + + if (nlmsg_append_struct (nlmsg, &gmsg) < 0) + g_return_val_if_reached (NULL); + } + break; + default: + g_return_val_if_reached (NULL); + } + + return g_steal_pointer (&nlmsg); +} + static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type) { @@ -5135,16 +5260,18 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL; FOR_EACH_DELAYED_ACTION (iflags, action_type) { + NMPLookup lookup; + priv->pruning[delayed_action_refresh_all_to_idx (iflags)] = TRUE; + nmp_lookup_init_obj_type (&lookup, + delayed_action_refresh_to_object_type (iflags)); nmp_cache_dirty_set_all (nm_platform_get_cache (platform), - delayed_action_refresh_to_object_type (iflags)); + &lookup); } FOR_EACH_DELAYED_ACTION (iflags, action_type) { NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags); - const NMPClass *klass = nmp_class_from_type (obj_type); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - int nle; int *out_refresh_all_in_progress; out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (iflags)]; @@ -5162,31 +5289,23 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio event_handler_read_netlink (platform, FALSE); - /* reimplement - * nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP); - * because we need the sequence number. - */ - nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + nlmsg = _nl_msg_new_dump (obj_type, AF_UNSPEC); + if (!nlmsg) + goto next_after_fail; - if ( klass->obj_type == NMP_OBJECT_TYPE_QDISC - || klass->obj_type == NMP_OBJECT_TYPE_TFILTER) { - struct tcmsg tcmsg = { - .tcm_family = AF_UNSPEC, - }; - nle = nlmsg_append (nlmsg, &tcmsg, sizeof (tcmsg), NLMSG_ALIGNTO); - } else { - struct rtgenmsg gmsg = { - .rtgen_family = klass->addr_family, - }; - nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); - } - if (nle < 0) - continue; + if (_nl_send_nlmsg (platform, + nlmsg, + NULL, + NULL, + DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, + out_refresh_all_in_progress) < 0) + goto next_after_fail; - if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progress) < 0) { - nm_assert (*out_refresh_all_in_progress > 0); - *out_refresh_all_in_progress -= 1; - } + continue; + +next_after_fail: + nm_assert (*out_refresh_all_in_progress > 0); + *out_refresh_all_in_progress -= 1; } } @@ -5273,9 +5392,9 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event NMPCacheOpsType cache_op; struct nlmsghdr *msghdr; char buf_nlmsghdr[400]; - gboolean id_only = FALSE; + gboolean is_del = FALSE; + gboolean is_dump = FALSE; NMPCache *cache = nm_platform_get_cache (platform); - gboolean is_dump; msghdr = nlmsg_hdr (msg); @@ -5286,37 +5405,38 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event if (!handle_events) return; - if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE)) { + if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, + RTM_DELADDR, + RTM_DELROUTE, + RTM_DELQDISC, + RTM_DELTFILTER)) { /* The event notifies about a deleted object. We don't need to initialize all * fields of the object. */ - id_only = TRUE; + is_del = TRUE; } - obj = nmp_object_new_from_nl (platform, cache, msg, id_only); + obj = nmp_object_new_from_nl (platform, cache, msg, is_del); if (!obj) { _LOGT ("event-notification: %s: ignore", nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); return; } - switch (msghdr->nlmsg_type) { - case RTM_NEWADDR: - case RTM_NEWLINK: - case RTM_NEWROUTE: - case RTM_NEWQDISC: - case RTM_NEWTFILTER: + if ( !is_del + && NM_IN_SET (msghdr->nlmsg_type, RTM_NEWADDR, + RTM_NEWLINK, + RTM_NEWROUTE, + RTM_NEWQDISC, + RTM_NEWTFILTER)) { is_dump = delayed_action_refresh_all_in_progress (platform, delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj))); - break; - default: - is_dump = FALSE; } _LOGT ("event-notification: %s%s: %s", nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)), is_dump ? ", in-dump" : "", nmp_object_to_string (obj, - id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, + is_del ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); { @@ -6067,6 +6187,7 @@ link_set_sriov_params (NMPlatform *platform, gint64 current_num; char ifname[IFNAMSIZ]; char buf[64]; + int errsv; if (!nm_platform_netns_push (platform, &netns)) return FALSE; @@ -6114,7 +6235,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_numvfs"), "0")) { - _LOGW ("link: couldn't reset SR-IOV num_vfs: %s", strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't reset SR-IOV num_vfs: %s", nm_strerror_native (errsv)); return FALSE; } } @@ -6129,7 +6251,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_drivers_autoprobe"), nm_sprintf_buf (buf, "%d", (int) autoprobe))) { - _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", (int) autoprobe, strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", (int) autoprobe, nm_strerror_native (errsv)); return FALSE; } @@ -6138,7 +6261,8 @@ link_set_sriov_params (NMPlatform *platform, ifname, "device/sriov_numvfs"), nm_sprintf_buf (buf, "%u", num_vfs))) { - _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno)); + errsv = errno; + _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, nm_strerror_native (errsv)); return FALSE; } @@ -7373,7 +7497,7 @@ ip6_address_add (NMPlatform *platform, ifindex, &addr, plen, - &peer_addr, + IN6_IS_ADDR_UNSPECIFIED (&peer_addr) ? NULL : &peer_addr, flags, RT_SCOPE_UNIVERSE, lifetime, @@ -7548,7 +7672,7 @@ ip_route_get (NMPlatform *platform, nle = _nl_send_nlmsghdr (platform, &req.n, &seq_result, NULL, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, &route); if (nle < 0) { _LOGE ("get-route: failure sending netlink request \"%s\" (%d)", - g_strerror (-nle), -nle); + nm_strerror_native (-nle), -nle); return -NME_UNSPEC; } @@ -7792,20 +7916,22 @@ continue_reading: err = -NME_NL_MSG_TRUNC; abort_parsing = TRUE; } else if (e->error) { - int errsv = e->error > 0 ? e->error : -e->error; + int errsv = nm_errno_native (e->error); if ( NM_FLAGS_HAS (hdr->nlmsg_flags, NLM_F_ACK_TLVS) && hdr->nlmsg_len >= sizeof (*e) + e->msg.nlmsg_len) { - static const struct nla_policy policy[NLMSGERR_ATTR_MAX + 1] = { + static const struct nla_policy policy[] = { [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING }, [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 }, }; - struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; + struct nlattr *tb[G_N_ELEMENTS (policy)]; struct nlattr *tlvs; tlvs = (struct nlattr *) ((char *) e + sizeof (*e) + e->msg.nlmsg_len - NLMSG_HDRLEN); - if (!nla_parse (tb, NLMSGERR_ATTR_MAX, tlvs, - hdr->nlmsg_len - sizeof (*e) - e->msg.nlmsg_len, policy)) { + if (nla_parse_arr (tb, + tlvs, + hdr->nlmsg_len - sizeof (*e) - e->msg.nlmsg_len, + policy) >= 0) { if (tb[NLMSGERR_ATTR_MSG]) extack_msg = nla_get_string (tb[NLMSGERR_ATTR_MSG]); } @@ -7813,11 +7939,11 @@ continue_reading: /* Error message reported back from kernel. */ _LOGD ("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", - strerror (errsv), + nm_strerror_native (errsv), errsv, NM_PRINT_FMT_QUOTED (extack_msg, " \"", extack_msg, "\"", ""), nlmsg_hdr (msg)->nlmsg_seq); - seq_result = -errsv; + seq_result = -NM_ERRNO_NATIVE (errsv); } else seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } else @@ -7976,7 +8102,7 @@ after_read: int errsv = errno; if (errsv != EINTR) { - _LOGE ("netlink: read: poll failed with %s", strerror (errsv)); + _LOGE ("netlink: read: poll failed with %s", nm_strerror_native (errsv)); delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL); return any; } diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index 6abc1c3a..71506a2c 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -25,8 +25,6 @@ #include #include -#include "nm-utils/nm-errno.h" - /*****************************************************************************/ #ifndef SOL_NETLINK @@ -104,21 +102,30 @@ nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) b = buf; switch (hdr->nlmsg_type) { - case RTM_NEWLINK: s = "RTM_NEWLINK"; break; - case RTM_DELLINK: s = "RTM_DELLINK"; break; - case RTM_NEWADDR: s = "RTM_NEWADDR"; break; - case RTM_DELADDR: s = "RTM_DELADDR"; break; - case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; - case RTM_DELROUTE: s = "RTM_DELROUTE"; break; - case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; - case RTM_DELQDISC: s = "RTM_DELQDISC"; break; - case RTM_NEWTFILTER: s = "RTM_NEWTFILTER"; break; - case RTM_DELTFILTER: s = "RTM_DELTFILTER"; break; - case NLMSG_NOOP: s = "NLMSG_NOOP"; break; - case NLMSG_ERROR: s = "NLMSG_ERROR"; break; - case NLMSG_DONE: s = "NLMSG_DONE"; break; - case NLMSG_OVERRUN: s = "NLMSG_OVERRUN"; break; - default: s = NULL; break; + case RTM_GETLINK: s = "RTM_GETLINK"; break; + case RTM_NEWLINK: s = "RTM_NEWLINK"; break; + case RTM_DELLINK: s = "RTM_DELLINK"; break; + case RTM_SETLINK: s = "RTM_SETLINK"; break; + case RTM_GETADDR: s = "RTM_GETADDR"; break; + case RTM_NEWADDR: s = "RTM_NEWADDR"; break; + case RTM_DELADDR: s = "RTM_DELADDR"; break; + case RTM_GETROUTE: s = "RTM_GETROUTE"; break; + case RTM_NEWROUTE: s = "RTM_NEWROUTE"; break; + case RTM_DELROUTE: s = "RTM_DELROUTE"; break; + case RTM_GETRULE: s = "RTM_GETRULE"; break; + case RTM_NEWRULE: s = "RTM_NEWRULE"; break; + case RTM_DELRULE: s = "RTM_DELRULE"; break; + case RTM_GETQDISC: s = "RTM_GETQDISC"; break; + case RTM_NEWQDISC: s = "RTM_NEWQDISC"; break; + case RTM_DELQDISC: s = "RTM_DELQDISC"; break; + case RTM_GETTFILTER: s = "RTM_GETTFILTER"; break; + case RTM_NEWTFILTER: s = "RTM_NEWTFILTER"; break; + case RTM_DELTFILTER: s = "RTM_DELTFILTER"; break; + case NLMSG_NOOP: s = "NLMSG_NOOP"; break; + case NLMSG_ERROR: s = "NLMSG_ERROR"; break; + case NLMSG_DONE: s = "NLMSG_DONE"; break; + case NLMSG_OVERRUN: s = "NLMSG_OVERRUN"; break; + default: s = NULL; break; } if (s) @@ -207,6 +214,8 @@ nlmsg_reserve (struct nl_msg *n, size_t len, int pad) size_t nlmsg_len = n->nm_nlh->nlmsg_len; size_t tlen; + nm_assert (pad >= 0); + if (len > n->nm_size) return NULL; @@ -261,11 +270,12 @@ nlmsg_alloc_size (size_t len) if (len < sizeof (struct nlmsghdr)) len = sizeof (struct nlmsghdr); - nm = g_slice_new0 (struct nl_msg); - - nm->nm_protocol = -1; - nm->nm_size = len; - nm->nm_nlh = g_malloc0 (len); + nm = g_slice_new (struct nl_msg); + *nm = (struct nl_msg) { + .nm_protocol = -1, + .nm_size = len, + .nm_nlh = g_malloc0 (len), + }; nm->nm_nlh->nlmsg_len = nlmsg_total_size (0); return nm; } @@ -320,10 +330,18 @@ void nlmsg_free (struct nl_msg *msg) /*****************************************************************************/ int -nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad) +nlmsg_append (struct nl_msg *n, + const void *data, + size_t len, + int pad) { void *tmp; + nm_assert (n); + nm_assert (data); + nm_assert (len > 0); + nm_assert (pad >= 0); + tmp = nlmsg_reserve (n, len, pad); if (tmp == NULL) return -ENOMEM; @@ -367,48 +385,77 @@ nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, return nlh; } -uint64_t -nla_get_u64 (const struct nlattr *nla) -{ - uint64_t tmp = 0; - - if (nla && nla_len (nla) >= sizeof (tmp)) - memcpy (&tmp, nla_data (nla), sizeof (tmp)); - - return tmp; -} - size_t -nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize) -{ - size_t srclen = nla_len (nla); - const char *src = nla_data (nla); - - if (srclen > 0 && src[srclen - 1] == '\0') - srclen--; +nla_strlcpy (char *dst, + const struct nlattr *nla, + size_t dstsize) +{ + const char *src; + size_t srclen; + size_t len; + + /* - Always writes @dstsize bytes to @dst + * - Copies the first non-NUL characters to @dst. + * Any characters after the first NUL bytes in @nla are ignored. + * - If the string @nla is longer than @dstsize, the string + * gets truncated. @dst will always be NUL terminated. */ + + if (G_UNLIKELY (dstsize <= 1)) { + if (dstsize == 1) + dst[0] = '\0'; + if ( nla + && (srclen = nla_len (nla)) > 0) + return strnlen (nla_data (nla), srclen); + return 0; + } - if (dstsize > 0) { - size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; + nm_assert (dst); - memset (dst, 0, dstsize); - memcpy (dst, src, len); + if (nla) { + srclen = nla_len (nla); + if (srclen > 0) { + src = nla_data (nla); + srclen = strnlen (src, srclen); + if (srclen > 0) { + len = NM_MIN (dstsize - 1, srclen); + memcpy (dst, src, len); + memset (&dst[len], 0, dstsize - len); + return srclen; + } + } } - return srclen; + memset (dst, 0, dstsize); + return 0; } -int -nla_memcpy (void *dest, const struct nlattr *src, int count) +size_t +nla_memcpy (void *dst, const struct nlattr *nla, size_t dstsize) { - int minlen; + size_t len; + int srclen; - if (!src) + if (!nla) return 0; - minlen = NM_MIN (count, (int) nla_len (src)); - memcpy (dest, nla_data (src), minlen); + srclen = nla_len (nla); - return minlen; + if (srclen <= 0) { + nm_assert (srclen == 0); + return 0; + } + + len = NM_MIN ((size_t) srclen, dstsize); + if (len > 0) { + /* there is a crucial difference between nla_strlcpy() and nla_memcpy(). + * The former always write @dstsize bytes (akin to strncpy()), here, we only + * write the bytes that we actually have (leaving the remainder undefined). */ + memcpy (dst, + nla_data (nla), + len); + } + + return srclen; } int @@ -548,7 +595,11 @@ validate_nla (const struct nlattr *nla, int maxtype, return -NME_UNSPEC; if (pt->type == NLA_STRING) { - const char *data = nla_data (nla); + const char *data; + + nm_assert (minlen > 0); + + data = nla_data (nla); if (data[nla_len (nla) - 1] != '\0') return -NME_UNSPEC; } @@ -574,15 +625,13 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, if (policy) { nmerr = validate_nla (nla, maxtype, policy); if (nmerr < 0) - goto errout; + return nmerr; } tb[type] = nla; } - nmerr = 0; -errout: - return nmerr; + return 0; } /*****************************************************************************/ @@ -721,21 +770,21 @@ genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], static int _genl_parse_getfamily (struct nl_msg *msg, void *arg) { - static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { + static const struct nla_policy ctrl_policy[] = { [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, - .maxlen = GENL_NAMSIZ }, + .maxlen = GENL_NAMSIZ }, [CTRL_ATTR_VERSION] = { .type = NLA_U32 }, [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 }, [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 }, [CTRL_ATTR_OPS] = { .type = NLA_NESTED }, [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED }, }; - struct nlattr *tb[CTRL_ATTR_MAX+1]; + struct nlattr *tb[G_N_ELEMENTS (ctrl_policy)]; struct nlmsghdr *nlh = nlmsg_hdr (msg); gint32 *response_data = arg; - if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy)) + if (genlmsg_parse_arr (nlh, 0, tb, ctrl_policy) < 0) return NL_SKIP; if (tb[CTRL_ATTR_FAMILY_ID]) @@ -1061,7 +1110,7 @@ do { \ nmerr = _cb->type##_cb ((msg), _cb->type##_arg); \ switch (nmerr) { \ case NL_OK: \ - nmerr = 0; \ + nm_assert (nmerr == 0); \ break; \ case NL_SKIP: \ goto skip; \ @@ -1206,6 +1255,7 @@ skip: /* Multipart message not yet complete, continue reading */ nm_clear_g_free (&buf); + nmerr = 0; goto continue_reading; } @@ -1333,6 +1383,7 @@ nl_recv (struct nl_sock *sk, struct ucred tmpcreds; gboolean tmpcreds_has = FALSE; int retval; + int errsv; nm_assert (nla); nm_assert (buf && !*buf); @@ -1361,10 +1412,10 @@ retry: } if (n < 0) { - if (errno == EINTR) + errsv = errno; + if (errsv == EINTR) goto retry; - - retval = -nm_errno_from_native (errno); + retval = -nm_errno_from_native (errsv); goto abort; } diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index 84bbe27b..094a3c6f 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -25,6 +25,8 @@ #include #include +#include "nm-utils/unaligned.h" + /*****************************************************************************/ #define NLMSGERR_ATTR_UNUSED 0 @@ -87,8 +89,26 @@ struct nla_policy { /*****************************************************************************/ +/* static asserts that @tb and @policy are suitable arguments to nla_parse(). */ +#define _nl_static_assert_tb(tb, policy) \ + G_STMT_START { \ + \ + G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (tb) > 0); \ + \ + /* we allow @policy to be either NULL or a C array. */ \ + G_STATIC_ASSERT_EXPR ( sizeof (policy) == sizeof (NULL) \ + || G_N_ELEMENTS (tb) == (sizeof (policy) / sizeof (struct nla_policy))); \ + \ + /* For above check to work, we don't support policy being an array with same size as + * sizeof(NULL), otherwise, the compile time check breaks down. */ \ + G_STATIC_ASSERT_EXPR (sizeof (NULL) != G_N_ELEMENTS (tb) * sizeof (struct nla_policy)); \ + \ + } G_STMT_END + +/*****************************************************************************/ + static inline int -nla_attr_size(int payload) +nla_attr_size (int payload) { nm_assert (payload >= 0); @@ -104,7 +124,7 @@ nla_total_size (int payload) static inline int nla_padlen (int payload) { - return nla_total_size(payload) - nla_attr_size(payload); + return nla_total_size (payload) - nla_attr_size (payload); } struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen); @@ -112,32 +132,56 @@ struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen); static inline int nla_len (const struct nlattr *nla) { - return nla->nla_len - NLA_HDRLEN; + nm_assert (nla); + nm_assert (nla->nla_len >= NLA_HDRLEN); + + return ((int) nla->nla_len) - NLA_HDRLEN; } static inline int nla_type (const struct nlattr *nla) { + nm_assert (nla_len (nla) >= 0); + return nla->nla_type & NLA_TYPE_MASK; } static inline void * nla_data (const struct nlattr *nla) { - nm_assert (nla); - return (char *) nla + NLA_HDRLEN; + nm_assert (nla_len (nla) >= 0); + + return &(((char *) nla)[NLA_HDRLEN]); } +#define nla_data_as(type, nla) \ + ({ \ + const struct nlattr *_nla = (nla); \ + \ + nm_assert (nla_len (_nla) >= sizeof (type)); \ + \ + /* note that casting the pointer is undefined behavior in C, if + * the data has wrong alignment. Netlink data is aligned to 4 bytes, + * that means, if the alignment is larger than 4, this is invalid. */ \ + G_STATIC_ASSERT_EXPR (_nm_alignof (type) <= NLA_ALIGNTO); \ + \ + (type *) nla_data (_nla); \ + }) + static inline uint8_t nla_get_u8 (const struct nlattr *nla) { - return *(const uint8_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint8_t)); + + return *((const uint8_t *) nla_data (nla)); } -static inline uint8_t +static inline int8_t nla_get_s8 (const struct nlattr *nla) { - return *(const int8_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (int8_t)); + + return *((const int8_t *) nla_data (nla)); } static inline uint8_t @@ -152,39 +196,80 @@ nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_va static inline uint16_t nla_get_u16 (const struct nlattr *nla) { - return *(const uint16_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint16_t)); + + return *((const uint16_t *) nla_data (nla)); } static inline uint32_t -nla_get_u32(const struct nlattr *nla) +nla_get_u32 (const struct nlattr *nla) { - return *(const uint32_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (uint32_t)); + + return *((const uint32_t *) nla_data (nla)); } static inline int32_t -nla_get_s32(const struct nlattr *nla) +nla_get_s32 (const struct nlattr *nla) { - return *(const int32_t *) nla_data (nla); + nm_assert (nla_len (nla) >= sizeof (int32_t)); + + return *((const int32_t *) nla_data (nla)); +} + +static inline uint64_t +nla_get_u64 (const struct nlattr *nla) +{ + nm_assert (nla_len (nla) >= sizeof (uint64_t)); + + return unaligned_read_ne64 (nla_data (nla)); } -uint64_t nla_get_u64 (const struct nlattr *nla); +static inline uint64_t +nla_get_be64 (const struct nlattr *nla) +{ + nm_assert (nla_len (nla) >= sizeof (uint64_t)); + + return unaligned_read_be64 (nla_data (nla)); +} static inline char * nla_get_string (const struct nlattr *nla) { + nm_assert (nla_len (nla) >= 0); + return (char *) nla_data (nla); } size_t nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize); -int nla_memcpy (void *dest, const struct nlattr *src, int count); +size_t nla_memcpy (void *dst, const struct nlattr *nla, size_t dstsize); + +#define nla_memcpy_checked_size(dst, nla, dstsize) \ + G_STMT_START { \ + void *const _dst = (dst); \ + const struct nlattr *const _nla = (nla); \ + const size_t _dstsize = (dstsize); \ + size_t _srcsize; \ + \ + /* assert that, if @nla is given, that it has the exact expected + * size. This implies that the caller previously verified the length + * of the attribute (via minlen/maxlen at nla_parse()). */ \ + \ + if (_nla) { \ + _srcsize = nla_memcpy (_dst, _nla, _dstsize); \ + nm_assert (_srcsize == _dstsize); \ + } \ + } G_STMT_END int nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data); static inline int nla_put_string (struct nl_msg *msg, int attrtype, const char *str) { - return nla_put(msg, attrtype, strlen(str) + 1, str); + nm_assert (str); + + return nla_put (msg, attrtype, strlen (str) + 1, str); } static inline int @@ -206,55 +291,55 @@ nla_put_uint32 (struct nl_msg *msg, int attrtype, uint32_t val) } #define NLA_PUT(msg, attrtype, attrlen, data) \ - do { \ - if (nla_put(msg, attrtype, attrlen, data) < 0) \ + G_STMT_START { \ + if (nla_put (msg, attrtype, attrlen, data) < 0) \ goto nla_put_failure; \ - } while(0) + } G_STMT_END #define NLA_PUT_TYPE(msg, type, attrtype, value) \ - do { \ + G_STMT_START { \ type __nla_tmp = value; \ - NLA_PUT(msg, attrtype, sizeof(type), &__nla_tmp); \ - } while(0) + NLA_PUT (msg, attrtype, sizeof (type), &__nla_tmp); \ + } G_STMT_END #define NLA_PUT_U8(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint8_t, attrtype, value) + NLA_PUT_TYPE (msg, uint8_t, attrtype, value) #define NLA_PUT_S8(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, int8_t, attrtype, value) + NLA_PUT_TYPE (msg, int8_t, attrtype, value) #define NLA_PUT_U16(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint16_t, attrtype, value) + NLA_PUT_TYPE (msg, uint16_t, attrtype, value) #define NLA_PUT_U32(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint32_t, attrtype, value) + NLA_PUT_TYPE (msg, uint32_t, attrtype, value) #define NLA_PUT_S32(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, int32_t, attrtype, value) + NLA_PUT_TYPE (msg, int32_t, attrtype, value) #define NLA_PUT_U64(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint64_t, attrtype, value) + NLA_PUT_TYPE (msg, uint64_t, attrtype, value) #define NLA_PUT_STRING(msg, attrtype, value) \ - NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value) + NLA_PUT (msg, attrtype, (int) strlen (value) + 1, value) #define NLA_PUT_FLAG(msg, attrtype) \ - NLA_PUT(msg, attrtype, 0, NULL) + NLA_PUT (msg, attrtype, 0, NULL) struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype); static inline int nla_ok (const struct nlattr *nla, int remaining) { - return remaining >= (int) sizeof(*nla) && - nla->nla_len >= sizeof(*nla) && + return remaining >= (int) sizeof (*nla) && + nla->nla_len >= sizeof (*nla) && nla->nla_len <= remaining; } static inline struct nlattr * -nla_next(const struct nlattr *nla, int *remaining) +nla_next (const struct nlattr *nla, int *remaining) { - int totlen = NLA_ALIGN(nla->nla_len); + int totlen = NLA_ALIGN (nla->nla_len); *remaining -= totlen; return (struct nlattr *) ((char *) nla + totlen); @@ -262,28 +347,47 @@ nla_next(const struct nlattr *nla, int *remaining) #define nla_for_each_attr(pos, head, len, rem) \ for (pos = head, rem = len; \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) + nla_ok (pos, rem); \ + pos = nla_next (pos, &(rem))) #define nla_for_each_nested(pos, nla, rem) \ - for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) + for (pos = (struct nlattr *) nla_data (nla), rem = nla_len (nla); \ + nla_ok (pos, rem); \ + pos = nla_next (pos, &(rem))) void nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr); struct nlattr *nla_nest_start (struct nl_msg *msg, int attrtype); int nla_nest_end (struct nl_msg *msg, struct nlattr *start); -int nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, +int nla_parse (struct nlattr *tb[], + int maxtype, + struct nlattr *head, + int len, const struct nla_policy *policy); +#define nla_parse_arr(tb, head, len, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + \ + nla_parse ((tb), G_N_ELEMENTS (tb) - 1, (head), (len), (policy)); \ + }) + static inline int -nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, +nla_parse_nested (struct nlattr *tb[], + int maxtype, + struct nlattr *nla, const struct nla_policy *policy) { - return nla_parse (tb, maxtype, nla_data(nla), nla_len(nla), policy); + return nla_parse (tb, maxtype, nla_data (nla), nla_len (nla), policy); } +#define nla_parse_nested_arr(tb, nla, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + \ + nla_parse_nested ((tb), G_N_ELEMENTS (tb) - 1, (nla), (policy)); \ + }) + /*****************************************************************************/ struct nl_msg *nlmsg_alloc (void); @@ -296,7 +400,13 @@ struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags); void *nlmsg_reserve (struct nl_msg *n, size_t len, int pad); -int nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad); +int nlmsg_append (struct nl_msg *n, + const void *data, + size_t len, + int pad); + +#define nlmsg_append_struct(n, data) \ + nlmsg_append (n, (data), sizeof (*(data)), NLMSG_ALIGNTO) void nlmsg_free (struct nl_msg *msg); @@ -316,15 +426,15 @@ nlmsg_total_size (int payload) static inline int nlmsg_ok (const struct nlmsghdr *nlh, int remaining) { - return (remaining >= (int)sizeof(struct nlmsghdr) && - nlh->nlmsg_len >= sizeof(struct nlmsghdr) && + return (remaining >= (int) sizeof (struct nlmsghdr) && + nlh->nlmsg_len >= sizeof (struct nlmsghdr) && nlh->nlmsg_len <= remaining); } static inline struct nlmsghdr * nlmsg_next (struct nlmsghdr *nlh, int *remaining) { - int totlen = NLMSG_ALIGN(nlh->nlmsg_len); + int totlen = NLMSG_ALIGN (nlh->nlmsg_len); *remaining -= totlen; @@ -344,7 +454,7 @@ _nm_auto_nl_msg_cleanup (struct nl_msg **ptr) { nlmsg_free (*ptr); } -#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) +#define nm_auto_nlmsg nm_auto (_nm_auto_nl_msg_cleanup) static inline void * nlmsg_data (const struct nlmsghdr *nlh) @@ -355,13 +465,13 @@ nlmsg_data (const struct nlmsghdr *nlh) static inline void * nlmsg_tail (const struct nlmsghdr *nlh) { - return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); + return (unsigned char *) nlh + NLMSG_ALIGN (nlh->nlmsg_len); } struct nlmsghdr *nlmsg_hdr (struct nl_msg *n); static inline int -nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) +nlmsg_valid_hdr (const struct nlmsghdr *nlh, int hdrlen) { if (nlh->nlmsg_len < nlmsg_size (hdrlen)) return 0; @@ -384,8 +494,8 @@ nlmsg_attrlen (const struct nlmsghdr *nlh, int hdrlen) static inline struct nlattr * nlmsg_attrdata (const struct nlmsghdr *nlh, int hdrlen) { - unsigned char *data = nlmsg_data(nlh); - return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); + unsigned char *data = nlmsg_data (nlh); + return (struct nlattr *) (data + NLMSG_ALIGN (hdrlen)); } static inline struct nlattr * @@ -396,8 +506,19 @@ nlmsg_find_attr (struct nlmsghdr *nlh, int hdrlen, int attrtype) attrtype); } -int nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); +int nlmsg_parse (struct nlmsghdr *nlh, + int hdrlen, + struct nlattr *tb[], + int maxtype, + const struct nla_policy *policy); + +#define nlmsg_parse_arr(nlh, hdrlen, tb, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + G_STATIC_ASSERT_EXPR ((hdrlen) >= 0); \ + \ + nlmsg_parse ((nlh), (hdrlen), (tb), G_N_ELEMENTS (tb) - 1, (policy)); \ + }) struct nlmsghdr *nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags); @@ -499,8 +620,20 @@ struct nlattr *genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen); int genlmsg_len (const struct genlmsghdr *gnlh); int genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen); int genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen); -int genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); + +int genlmsg_parse (struct nlmsghdr *nlh, + int hdrlen, + struct nlattr *tb[], + int maxtype, + const struct nla_policy *policy); + +#define genlmsg_parse_arr(nlh, hdrlen, tb, policy) \ + ({ \ + _nl_static_assert_tb ((tb), (policy)); \ + G_STATIC_ASSERT_EXPR ((hdrlen) >= 0); \ + \ + genlmsg_parse ((nlh), (hdrlen), (tb), G_N_ELEMENTS (tb) - 1, (policy)); \ + }) int genl_ctrl_resolve (struct nl_sock *sk, const char *name); diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 772d4667..93cd0b3c 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -22,9 +22,7 @@ #include "nm-platform-utils.h" -#include #include -#include #include #include #include @@ -86,7 +84,7 @@ socket_handle_init (SocketHandle *shandle, int ifindex) shandle->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (shandle->fd < 0) { shandle->ifindex = 0; - return -errno; + return -NM_ERRNO_NATIVE (errno); } shandle->ifindex = ifindex; @@ -159,8 +157,8 @@ ethtool_call_handle (SocketHandle *shandle, gpointer edata) shandle->ifindex, _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), shandle->ifname, - strerror (errsv)); - return -errsv; + nm_strerror_native (errsv)); + return -NM_ERRNO_NATIVE (errsv); } nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: success", @@ -183,7 +181,7 @@ ethtool_call_ifindex (int ifindex, gpointer edata) nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), - g_strerror (-r)); + nm_strerror_native (-r)); return r; } @@ -489,7 +487,7 @@ nmp_utils_ethtool_get_features (int ifindex) nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, "get-features", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -620,7 +618,7 @@ nmp_utils_ethtool_set_features (int ifindex, nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, "set-features", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -656,7 +654,7 @@ nmp_utils_ethtool_set_features (int ifindex, nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failure setting features (%s)", ifindex, "set-features", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -766,7 +764,7 @@ nmp_utils_ethtool_supports_vlans (int ifindex) nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, "support-vlans", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -805,7 +803,7 @@ nmp_utils_ethtool_get_peer_ifindex (int ifindex) nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, "get-peer-ifindex", - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -894,7 +892,7 @@ nmp_utils_ethtool_get_link_settings (int ifindex, | ADVERTISED_1000baseT_Full \ | ADVERTISED_10000baseT_Full ) -static inline guint32 +static guint32 get_baset_mode (guint32 speed, NMPlatformLinkDuplexType duplex) { if (duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN) @@ -1045,13 +1043,14 @@ nmp_utils_mii_supports_carrier_detect (int ifindex) int r; struct ifreq ifr; struct mii_ioctl_data *mii; + int errsv; g_return_val_if_fail (ifindex > 0, FALSE); if ((r = socket_handle_init (&shandle, ifindex)) < 0) { nm_log_trace (LOGD_PLATFORM, "mii[%d]: carrier-detect no: failed creating ethtool socket: %s", ifindex, - g_strerror (-r)); + nm_strerror_native (-r)); return FALSE; } @@ -1059,7 +1058,8 @@ nmp_utils_mii_supports_carrier_detect (int ifindex) memcpy (ifr.ifr_name, shandle.ifname, IFNAMSIZ); if (ioctl (shandle.fd, SIOCGMIIPHY, &ifr) < 0) { - nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, shandle.ifname, strerror (errno)); + errsv = errno; + nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, shandle.ifname, nm_strerror_native (errsv)); return FALSE; } @@ -1068,7 +1068,8 @@ nmp_utils_mii_supports_carrier_detect (int ifindex) mii->reg_num = MII_BMSR; if (ioctl (shandle.fd, SIOCGMIIREG, &ifr) != 0) { - nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, shandle.ifname, strerror (errno)); + errsv = errno; + nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, shandle.ifname, nm_strerror_native (errsv)); return FALSE; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 4bb31b17..fe0cb662 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -23,13 +23,11 @@ #include "nm-platform.h" #include -#include #include #include #include #include #include -#include #include #include #include @@ -41,7 +39,7 @@ #include "nm-core-internal.h" #include "nm-utils/nm-dedup-multi.h" #include "nm-utils/nm-udev-utils.h" -#include "nm-utils/nm-errno.h" +#include "nm-utils/nm-secret-utils.h" #include "nm-core-utils.h" #include "nm-platform-utils.h" @@ -1985,6 +1983,24 @@ nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatf /*****************************************************************************/ +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_flags_to_string, NMPlatformWireGuardChangeFlags, + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS, "replace-peers"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY, "has-private-key"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT, "has-listen-port"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK, "has-fwmark"), +); + +NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_peer_flags_to_string, NMPlatformWireGuardChangePeerFlags, + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE, "none"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME, "remove"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY, "psk"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL, "ka"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT, "ep"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS, "aips"), + NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS, "remove-aips"), +); + int nm_platform_link_wireguard_add (NMPlatform *self, const char *name, @@ -1998,8 +2014,9 @@ nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers) + NMPlatformWireGuardChangeFlags change_flags) { _CHECK_SELF (self, klass, -NME_BUG); @@ -2008,6 +2025,7 @@ nm_platform_link_wireguard_change (NMPlatform *self, if (_LOGD_ENABLED ()) { char buf_lnk[256]; char buf_peers[512]; + char buf_change_flags[100]; buf_peers[0] = '\0'; if (peers_len > 0) { @@ -2020,25 +2038,31 @@ nm_platform_link_wireguard_change (NMPlatform *self, nm_utils_strbuf_append_str (&b, &len, " { "); nm_platform_wireguard_peer_to_string (&peers[i], b, len); nm_utils_strbuf_seek_end (&b, &len); + if (peer_flags) { + nm_utils_strbuf_append (&b, &len, + " (%s)", + _wireguard_change_peer_flags_to_string (peer_flags[i], buf_change_flags, sizeof (buf_change_flags))); + } nm_utils_strbuf_append_str (&b, &len, " } "); } nm_utils_strbuf_append_str (&b, &len, "}"); } - _LOG3D ("link: change wireguard ifindex %d, %s, %u peers%s%s", + _LOG3D ("link: change wireguard ifindex %d, %s, (%s), %u peers%s", ifindex, nm_platform_lnk_wireguard_to_string (lnk_wireguard, buf_lnk, sizeof (buf_lnk)), + _wireguard_change_flags_to_string (change_flags, buf_change_flags, sizeof (buf_change_flags)), peers_len, - buf_peers, - replace_peers ? " (replace-peers)" : " (update-peers)"); + buf_peers); } return klass->link_wireguard_change (self, ifindex, lnk_wireguard, peers, + peer_flags, peers_len, - replace_peers); + change_flags); } /*****************************************************************************/ @@ -2893,7 +2917,7 @@ nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_pe * nm_platform_link_tun_get_properties: * @self: the #NMPlatform instance * @ifindex: the ifindex to look up - * @out_properties: (out): (allow-none): return the read properties + * @out_properties: (out) (allow-none): return the read properties * * Only recent versions of kernel export tun properties via netlink. * So, if that's the case, then we have the NMPlatformLnkTun instance @@ -4218,7 +4242,7 @@ nm_platform_ip_route_get_prune_list (NMPlatform *self, * at the end of the operation. Note that if @routes contains * the same route, then it will not be deleted. @routes overrules * @routes_prune list. - * @out_temporary_not_available: (allow-none): (out): routes that could + * @out_temporary_not_available: (allow-none) (out): routes that could * currently not be synced. The caller shall keep them and try later again. * * Returns: %TRUE on success. @@ -5610,6 +5634,7 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g char s_sockaddr[NM_UTILS_INET_ADDRSTRLEN + 100]; char s_endpoint[20 + sizeof (s_sockaddr)]; char s_addr[NM_UTILS_INET_ADDRSTRLEN]; + char s_keepalive[100]; guint i; nm_utils_to_string_buffer_init (&buf, &len); @@ -5627,18 +5652,22 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g nm_utils_strbuf_append (&buf, &len, "public-key %s" - "%s" /* preshared-key */ - "%s" /* endpoint */ + "%s" /* preshared-key */ + "%s" /* endpoint */ " rx %"G_GUINT64_FORMAT " tx %"G_GUINT64_FORMAT + "%s" /* persistent-keepalive */ "%s", /* allowed-ips */ public_key_b64, - nm_utils_memeqzero (peer->preshared_key, sizeof (peer->preshared_key)) + nm_utils_memeqzero_secret (peer->preshared_key, sizeof (peer->preshared_key)) ? "" : " preshared-key (hidden)", s_endpoint, peer->rx_bytes, peer->tx_bytes, + peer->persistent_keepalive_interval > 0 + ? nm_sprintf_buf (s_keepalive, " keepalive %u", (guint) peer->persistent_keepalive_interval) + : "", peer->allowed_ips_len > 0 ? " allowed-ips" : ""); @@ -5676,7 +5705,7 @@ nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *bu ? " public-key " : "", public_b64 ?: "", - nm_utils_memeqzero (lnk->private_key, sizeof (lnk->private_key)) + nm_utils_memeqzero_secret (lnk->private_key, sizeof (lnk->private_key)) ? "" : " private-key (hidden)", lnk->listen_port, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 412ac597..37aa58fd 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -29,7 +29,6 @@ #include "nm-setting-wired.h" #include "nm-setting-wireless.h" #include "nm-setting-ip-tunnel.h" -#include "nm-utils/nm-errno.h" #define NM_TYPE_PLATFORM (nm_platform_get_type ()) #define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform)) @@ -749,11 +748,35 @@ typedef enum { } NMPlatformLinkDuplexType; typedef enum { - NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS = (1LL << 0), - NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL = (1LL << 1), - NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF = (1LL << 2), + NM_PLATFORM_KERNEL_SUPPORT_EXTENDED_IFA_FLAGS = (1LL << 0), + NM_PLATFORM_KERNEL_SUPPORT_USER_IPV6LL = (1LL << 1), + NM_PLATFORM_KERNEL_SUPPORT_RTA_PREF = (1LL << 2), } NMPlatformKernelSupportFlags; +typedef enum { + 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), +} NMPlatformWireGuardChangeFlags; + +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; + /*****************************************************************************/ struct _NMPlatformPrivate; @@ -831,8 +854,9 @@ typedef struct { int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const struct _NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers); + NMPlatformWireGuardChangeFlags change_flags); gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link); gboolean (*link_vlan_change) (NMPlatform *self, @@ -1394,8 +1418,9 @@ int nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, const struct _NMPWireGuardPeer *peers, + const NMPlatformWireGuardChangePeerFlags *peer_flags, guint peers_len, - gboolean replace_peers); + NMPlatformWireGuardChangeFlags change_flags); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index f1092fe9..f34dc83d 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -19,15 +19,26 @@ */ #include "nm-default.h" + #include "nmp-netns.h" #include -#include #include #include #include +#include + +/*****************************************************************************/ -#include "NetworkManagerUtils.h" +/* NOTE: NMPNetns and all code used here must be thread-safe! */ + +/* we may not call logging functions from the main-thread alone. Hence, we + * require locking from nm-logging. Indicate that by setting NM_THREAD_SAFE_ON_MAIN_THREAD + * to zero. */ +#undef NM_THREAD_SAFE_ON_MAIN_THREAD +#define NM_THREAD_SAFE_ON_MAIN_THREAD 0 + +/*****************************************************************************/ #define PROC_SELF_NS_MNT "/proc/self/ns/mnt" #define PROC_SELF_NS_NET "/proc/self/ns/net" @@ -116,49 +127,81 @@ typedef struct { int ns_types; } NetnsInfo; -static void _stack_push (NMPNetns *netns, int ns_types); +static void _stack_push (GArray *netns_stack, + NMPNetns *netns, + int ns_types); static NMPNetns *_netns_new (GError **error); /*****************************************************************************/ -static GArray *netns_stack = NULL; +static NMPNetns * +_netns_get (NetnsInfo *info) +{ + nm_assert (!info || NMP_IS_NETNS (info->netns)); + return info ? info->netns : NULL; +} + +/*****************************************************************************/ + +static _nm_thread_local GArray *_netns_stack = NULL; static void -_stack_ensure_init_impl (void) +_netns_stack_clear_cb (gpointer data) { - NMPNetns *netns; - GError *error = NULL; + NetnsInfo *info = data; - nm_assert (!netns_stack); + nm_assert (NMP_IS_NETNS (info->netns)); + g_object_unref (info->netns); +} - netns_stack = g_array_new (FALSE, FALSE, sizeof (NetnsInfo)); +static GArray * +_netns_stack_get_impl (void) +{ + gs_unref_object NMPNetns *netns = NULL; + gs_free_error GError *error = NULL; + pthread_key_t key; + GArray *s; + + s = g_array_new (FALSE, FALSE, sizeof (NetnsInfo)); + g_array_set_clear_func (s, _netns_stack_clear_cb); + _netns_stack = s; /* at the bottom of the stack we must try to create a netns instance * that we never pop. It's the base to which we need to return. */ - netns = _netns_new (&error); - if (!netns) { - /* don't know how to recover from this error. Netns are not supported. */ _LOGE (NULL, "failed to create initial netns: %s", error->message); - g_clear_error (&error); - return; + return s; } - _stack_push (netns, _CLONE_NS_ALL); + /* we leak this instance inside the stack. */ + _stack_push (s, netns, _CLONE_NS_ALL); - /* we leak this instance inside netns_stack. It cannot be popped. */ - g_object_unref (netns); + /* finally, register a destructor function to cleanup the array. If we fail + * to do so, we will leak NMPNetns instances (and their file descriptor) when the + * thread exits. */ + if (pthread_key_create (&key, (void (*) (void *)) g_array_unref) != 0) + _LOGE (NULL, "failure to initialize thread-local storage"); + else if (pthread_setspecific (key, s) != 0) + _LOGE (NULL, "failure to set thread-local storage"); + + return s; } -#define _stack_ensure_init() \ - G_STMT_START { \ - if (G_UNLIKELY (!netns_stack)) { \ - _stack_ensure_init_impl (); \ - } \ - } G_STMT_END + +#define _netns_stack_get() \ + ({ \ + GArray *_s = _netns_stack; \ + \ + if (G_UNLIKELY (!_s)) \ + _s = _netns_stack_get_impl (); \ + _s; \ + }) + +/*****************************************************************************/ static NMPNetns * -_stack_current_netns (int ns_types) +_stack_current_netns (GArray *netns_stack, + int ns_types) { guint j; @@ -179,7 +222,9 @@ _stack_current_netns (int ns_types) } static int -_stack_current_ns_types (NMPNetns *netns, int ns_types) +_stack_current_ns_types (GArray *netns_stack, + NMPNetns *netns, + int ns_types) { const int ns_types_check[] = { _CLONE_NS_ALL_V }; guint i, j; @@ -212,27 +257,25 @@ _stack_current_ns_types (NMPNetns *netns, int ns_types) } static NetnsInfo * -_stack_peek (void) +_stack_peek (GArray *netns_stack) { - nm_assert (netns_stack); - if (netns_stack->len > 0) return &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1)); return NULL; } static NetnsInfo * -_stack_bottom (void) +_stack_bottom (GArray *netns_stack) { - nm_assert (netns_stack); - if (netns_stack->len > 0) return &g_array_index (netns_stack, NetnsInfo, 0); return NULL; } static void -_stack_push (NMPNetns *netns, int ns_types) +_stack_push (GArray *netns_stack, + NMPNetns *netns, + int ns_types) { NetnsInfo *info; @@ -244,13 +287,15 @@ _stack_push (NMPNetns *netns, int ns_types) g_array_set_size (netns_stack, netns_stack->len + 1); info = &g_array_index (netns_stack, NetnsInfo, (netns_stack->len - 1)); - info->netns = g_object_ref (netns); - info->ns_types = ns_types; - info->count = 1; + *info = (NetnsInfo) { + .netns = g_object_ref (netns), + .ns_types = ns_types, + .count = 1, + }; } static void -_stack_pop (void) +_stack_pop (GArray *netns_stack) { NetnsInfo *info; @@ -262,13 +307,11 @@ _stack_pop (void) nm_assert (NMP_IS_NETNS (info->netns)); nm_assert (info->count == 1); - g_object_unref (info->netns); - g_array_set_size (netns_stack, netns_stack->len - 1); } static guint -_stack_size (void) +_stack_size (GArray *netns_stack) { nm_assert (netns_stack); @@ -289,7 +332,7 @@ _netns_new (GError **error) errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "Failed opening netns: %s", - g_strerror (errsv)); + nm_strerror_native (errsv)); errno = errsv; return NULL; } @@ -299,7 +342,7 @@ _netns_new (GError **error) errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "Failed opening mntns: %s", - g_strerror (errsv)); + nm_strerror_native (errsv)); nm_close (fd_net); errno = errsv; return NULL; @@ -332,31 +375,33 @@ _setns (NMPNetns *self, int type) } static gboolean -_netns_switch_push (NMPNetns *self, int ns_types) +_netns_switch_push (GArray *netns_stack, + NMPNetns *self, + int ns_types) { int errsv; if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) - && !_stack_current_ns_types (self, CLONE_NEWNET) + && !_stack_current_ns_types (netns_stack, self, CLONE_NEWNET) && _setns (self, CLONE_NEWNET) != 0) { errsv = errno; - _LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); + _LOGE (self, "failed to switch netns: %s", nm_strerror_native (errsv)); return FALSE; } if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS) - && !_stack_current_ns_types (self, CLONE_NEWNS) + && !_stack_current_ns_types (netns_stack, self, CLONE_NEWNS) && _setns (self, CLONE_NEWNS) != 0) { errsv = errno; - _LOGE (self, "failed to switch mntns: %s", g_strerror (errsv)); + _LOGE (self, "failed to switch mntns: %s", nm_strerror_native (errsv)); /* try to fix the mess by returning to the previous netns. */ if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) - && !_stack_current_ns_types (self, CLONE_NEWNET)) { - self = _stack_current_netns (CLONE_NEWNET); + && !_stack_current_ns_types (netns_stack, self, CLONE_NEWNET)) { + self = _stack_current_netns (netns_stack, CLONE_NEWNET); if ( self && _setns (self, CLONE_NEWNET) != 0) { errsv = errno; - _LOGE (self, "failed to restore netns: %s", g_strerror (errsv)); + _LOGE (self, "failed to restore netns: %s", nm_strerror_native (errsv)); } } return FALSE; @@ -366,33 +411,36 @@ _netns_switch_push (NMPNetns *self, int ns_types) } static gboolean -_netns_switch_pop (NMPNetns *self, int ns_types) +_netns_switch_pop (GArray *netns_stack, + NMPNetns *self, + int ns_types) { int errsv; NMPNetns *current; int success = TRUE; if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNET) - && (!self || !_stack_current_ns_types (self, CLONE_NEWNET))) { - current = _stack_current_netns (CLONE_NEWNET); + && ( !self + || !_stack_current_ns_types (netns_stack, self, CLONE_NEWNET))) { + current = _stack_current_netns (netns_stack, CLONE_NEWNET); if (!current) { g_warn_if_reached (); success = FALSE; } else if (_setns (current, CLONE_NEWNET) != 0) { errsv = errno; - _LOGE (self, "failed to switch netns: %s", g_strerror (errsv)); + _LOGE (self, "failed to switch netns: %s", nm_strerror_native (errsv)); success = FALSE; } } if ( NM_FLAGS_HAS (ns_types, CLONE_NEWNS) - && (!self || !_stack_current_ns_types (self, CLONE_NEWNS))) { - current = _stack_current_netns (CLONE_NEWNS); + && (!self || !_stack_current_ns_types (netns_stack, self, CLONE_NEWNS))) { + current = _stack_current_netns (netns_stack, CLONE_NEWNS); if (!current) { g_warn_if_reached (); success = FALSE; } else if (_setns (current, CLONE_NEWNS) != 0) { errsv = errno; - _LOGE (self, "failed to switch mntns: %s", g_strerror (errsv)); + _LOGE (self, "failed to switch mntns: %s", nm_strerror_native (errsv)); success = FALSE; } } @@ -423,32 +471,31 @@ nmp_netns_get_fd_mnt (NMPNetns *self) static gboolean _nmp_netns_push_type (NMPNetns *self, int ns_types) { + GArray *netns_stack = _netns_stack_get (); NetnsInfo *info; char sbuf[100]; - _stack_ensure_init (); - - info = _stack_peek (); + info = _stack_peek (netns_stack); g_return_val_if_fail (info, FALSE); if (info->netns == self && info->ns_types == ns_types) { info->count++; _LOGt (self, "push#%u* %s (increase count to %d)", - _stack_size () - 1, + _stack_size (netns_stack) - 1, _ns_types_to_str (ns_types, ns_types, sbuf), info->count); return TRUE; } _LOGD (self, "push#%u %s", - _stack_size (), + _stack_size (netns_stack), _ns_types_to_str (ns_types, - _stack_current_ns_types (self, ns_types), + _stack_current_ns_types (netns_stack, self, ns_types), sbuf)); - if (!_netns_switch_push (self, ns_types)) + if (!_netns_switch_push (netns_stack, self, ns_types)) return FALSE; - _stack_push (self, ns_types); + _stack_push (netns_stack, self, ns_types); return TRUE; } @@ -472,14 +519,13 @@ nmp_netns_push_type (NMPNetns *self, int ns_types) NMPNetns * nmp_netns_new (void) { + GArray *netns_stack = _netns_stack_get (); NMPNetns *self; int errsv; GError *error = NULL; unsigned long mountflags = 0; - _stack_ensure_init (); - - if (!_stack_peek ()) { + if (!_stack_peek (netns_stack)) { /* there are no netns instances. We cannot create a new one * (because after unshare we couldn't return to the original one). */ errno = ENOTSUP; @@ -488,19 +534,19 @@ nmp_netns_new (void) if (unshare (_CLONE_NS_ALL) != 0) { errsv = errno; - _LOGE (NULL, "failed to create new net and mnt namespace: %s", g_strerror (errsv)); + _LOGE (NULL, "failed to create new net and mnt namespace: %s", nm_strerror_native (errsv)); return NULL; } if (mount ("", "/", "none", MS_SLAVE | MS_REC, NULL) != 0) { errsv = errno; - _LOGE (NULL, "failed mount --make-rslave: %s", g_strerror (errsv)); + _LOGE (NULL, "failed mount --make-rslave: %s", nm_strerror_native (errsv)); goto err_out; } if (umount2 ("/sys", MNT_DETACH) != 0) { errsv = errno; - _LOGE (NULL, "failed umount /sys: %s", g_strerror (errsv)); + _LOGE (NULL, "failed umount /sys: %s", nm_strerror_native (errsv)); goto err_out; } @@ -509,7 +555,7 @@ nmp_netns_new (void) if (mount ("sysfs", "/sys", "sysfs", mountflags, NULL) != 0) { errsv = errno; - _LOGE (NULL, "failed mount /sys: %s", g_strerror (errsv)); + _LOGE (NULL, "failed mount /sys: %s", nm_strerror_native (errsv)); goto err_out; } @@ -521,11 +567,11 @@ nmp_netns_new (void) goto err_out; } - _stack_push (self, _CLONE_NS_ALL); + _stack_push (netns_stack, self, _CLONE_NS_ALL); return self; err_out: - _netns_switch_pop (NULL, _CLONE_NS_ALL); + _netns_switch_pop (netns_stack, NULL, _CLONE_NS_ALL); errno = errsv; return NULL; } @@ -533,14 +579,13 @@ err_out: gboolean nmp_netns_pop (NMPNetns *self) { + GArray *netns_stack = _netns_stack_get (); NetnsInfo *info; int ns_types; g_return_val_if_fail (NMP_IS_NETNS (self), FALSE); - _stack_ensure_init (); - - info = _stack_peek (); + info = _stack_peek (netns_stack); g_return_val_if_fail (info, FALSE); g_return_val_if_fail (info->netns == self, FALSE); @@ -548,52 +593,42 @@ nmp_netns_pop (NMPNetns *self) if (info->count > 1) { info->count--; _LOGt (self, "pop#%u* (decrease count to %d)", - _stack_size () - 1, info->count); + _stack_size (netns_stack) - 1, info->count); return TRUE; } g_return_val_if_fail (info->count == 1, FALSE); /* cannot pop the original netns. */ - g_return_val_if_fail (_stack_size () > 1, FALSE); + g_return_val_if_fail (_stack_size (netns_stack) > 1, FALSE); - _LOGD (self, "pop#%u", _stack_size () - 1); + _LOGD (self, "pop#%u", _stack_size (netns_stack) - 1); ns_types = info->ns_types; - _stack_pop (); + _stack_pop (netns_stack); - return _netns_switch_pop (self, ns_types); + return _netns_switch_pop (netns_stack, self, ns_types); } NMPNetns * nmp_netns_get_current (void) { - NetnsInfo *info; - - _stack_ensure_init (); - - info = _stack_peek (); - return info ? info->netns : NULL; + return _netns_get (_stack_peek (_netns_stack_get ())); } NMPNetns * nmp_netns_get_initial (void) { - NetnsInfo *info; - - _stack_ensure_init (); - - info = _stack_bottom (); - return info ? info->netns : NULL; + return _netns_get (_stack_bottom (_netns_stack_get ())); } gboolean nmp_netns_is_initial (void) { - if (G_UNLIKELY (!netns_stack)) - return TRUE; + GArray *netns_stack = _netns_stack_get (); - return nmp_netns_get_current () == nmp_netns_get_initial (); + return ( _netns_get (_stack_peek (netns_stack)) + == _netns_get (_stack_bottom (netns_stack))); } /*****************************************************************************/ @@ -618,7 +653,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) errsv = errno; if (errsv != EEXIST) { _LOGE (self, "bind: failed to create directory %s: %s", - dirname, g_strerror (errsv)); + dirname, nm_strerror_native (errsv)); return FALSE; } } @@ -626,7 +661,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) if ((fd = creat (filename, S_IRUSR | S_IRGRP | S_IROTH)) == -1) { errsv = errno; _LOGE (self, "bind: failed to create %s: %s", - filename, g_strerror (errsv)); + filename, nm_strerror_native (errsv)); return FALSE; } nm_close (fd); @@ -634,7 +669,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) if (mount (PROC_SELF_NS_NET, filename, "none", MS_BIND, NULL) != 0) { errsv = errno; _LOGE (self, "bind: failed to mount %s to %s: %s", - PROC_SELF_NS_NET, filename, g_strerror (errsv)); + PROC_SELF_NS_NET, filename, nm_strerror_native (errsv)); unlink (filename); return FALSE; } @@ -642,7 +677,7 @@ nmp_netns_bind_to_path (NMPNetns *self, const char *filename, int *out_fd) if (out_fd) { if ((fd = open (filename, O_RDONLY | O_CLOEXEC)) == -1) { errsv = errno; - _LOGE (self, "bind: failed to open %s: %s", filename, g_strerror (errsv)); + _LOGE (self, "bind: failed to open %s: %s", filename, nm_strerror_native (errsv)); umount2 (filename, MNT_DETACH); unlink (filename); return FALSE; @@ -663,12 +698,12 @@ nmp_netns_bind_to_path_destroy (NMPNetns *self, const char *filename) if (umount2 (filename, MNT_DETACH) != 0) { errsv = errno; - _LOGE (self, "bind: failed to unmount2 %s: %s", filename, g_strerror (errsv)); + _LOGE (self, "bind: failed to unmount2 %s: %s", filename, nm_strerror_native (errsv)); return FALSE; } if (unlink (filename) != 0) { errsv = errno; - _LOGE (self, "bind: failed to unlink %s: %s", filename, g_strerror (errsv)); + _LOGE (self, "bind: failed to unlink %s: %s", filename, nm_strerror_native (errsv)); return FALSE; } return TRUE; diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 80e65b49..6ec6fea1 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -1545,13 +1545,13 @@ _vt_cmd_plobj_id_hash_update (tfilter, NMPlatformTfilter, { obj->handle); }) -static inline void +static void _vt_cmd_plobj_hash_update_ip4_route (const NMPlatformObject *obj, NMHashState *h) { return nm_platform_ip4_route_hash_update ((const NMPlatformIP4Route *) obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, h); } -static inline void +static void _vt_cmd_plobj_hash_update_ip6_route (const NMPlatformObject *obj, NMHashState *h) { return nm_platform_ip6_route_hash_update ((const NMPlatformIP6Route *) obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, h); @@ -2519,10 +2519,10 @@ nmp_cache_remove_netlink (NMPCache *cache, * afterwards. Hence, during a dump, every update should move the object to the * end of the list, to obtain the correct order. That means, to use NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, * instead of NM_DEDUP_MULTI_IDX_MODE_APPEND. - * @out_obj_old: (allow-none): (out): return the object with same ID as @obj_hand_over, + * @out_obj_old: (allow-none) (out): return the object with same ID as @obj_hand_over, * that was in the cache before update. If an object is returned, the caller must * unref it afterwards. - * @out_obj_new: (allow-none): (out): return the object from the cache after update. + * @out_obj_new: (allow-none) (out): return the object from the cache after update. * The caller must unref this object. * * Returns: how the cache changed. @@ -2920,15 +2920,15 @@ nmp_cache_update_link_master_connected (NMPCache *cache, /*****************************************************************************/ void -nmp_cache_dirty_set_all (NMPCache *cache, NMPObjectType obj_type) +nmp_cache_dirty_set_all (NMPCache *cache, + const NMPLookup *lookup) { - NMPObject obj_needle; - nm_assert (cache); + nm_assert (lookup); nm_dedup_multi_index_dirty_set_head (cache->multi_idx, - _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE), - _nmp_object_stackinit_from_type (&obj_needle, obj_type)); + _idx_type_get (cache, lookup->cache_id_type), + &lookup->selector_obj); } /*****************************************************************************/ @@ -2977,7 +2977,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_data = sizeof (NMPObjectLink), .sizeof_public = sizeof (NMPlatformLink), .obj_type_name = "link", - .addr_family = AF_UNSPEC, .rtm_gettype = RTM_GETLINK, .signal_type_id = NM_PLATFORM_SIGNAL_ID_LINK, .signal_type = NM_PLATFORM_SIGNAL_LINK_CHANGED, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 4649441b..525e1440 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -31,6 +31,18 @@ struct udev_device; /*****************************************************************************/ +/* "struct __kernel_timespec" uses "long long", but we use gint64. In practice, + * these are the same types. */ +G_STATIC_ASSERT (sizeof (long long) == sizeof (gint64)); + +typedef struct { + /* like "struct __kernel_timespec". */ + gint64 tv_sec; + gint64 tv_nsec; +} NMPTimespec64; + +/*****************************************************************************/ + typedef union { struct sockaddr sa; struct sockaddr_in in; @@ -72,7 +84,8 @@ typedef struct { typedef struct _NMPWireGuardPeer { NMSockAddrUnion endpoint; - struct timespec last_handshake_time; + NMPTimespec64 last_handshake_time; + guint64 rx_bytes; guint64 tx_bytes; @@ -771,7 +784,8 @@ NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, const NMPObject **out_obj_old, const NMPObject **out_obj_new); -void nmp_cache_dirty_set_all (NMPCache *cache, NMPObjectType obj_type); +void nmp_cache_dirty_set_all (NMPCache *cache, + const NMPLookup *lookup); NMPCache *nmp_cache_new (NMDedupMultiIndex *multi_idx, gboolean use_udev); void nmp_cache_free (NMPCache *cache); diff --git a/src/platform/tests/meson.build b/src/platform/tests/meson.build index 3704e2ac..8086a46c 100644 --- a/src/platform/tests/meson.build +++ b/src/platform/tests/meson.build @@ -1,14 +1,14 @@ test_units = [ - ['test-link-fake', 'test-link.c', test_nm_dep_fake, 30], - ['test-link-linux', 'test-link.c', test_nm_dep_linux, 180], - ['test-address-fake', 'test-address.c', test_nm_dep_fake, 30], - ['test-address-linux', 'test-address.c', test_nm_dep_linux, 30], - ['test-general', 'test-general.c', test_nm_dep, 30], - ['test-nmp-object', 'test-nmp-object.c', test_nm_dep, 30], - ['test-route-fake', 'test-route.c', test_nm_dep_fake, 30], - ['test-route-linux', 'test-route.c', test_nm_dep_linux, 30], - ['test-cleanup-fake', 'test-cleanup.c', test_nm_dep_fake, 30], - ['test-cleanup-linux', 'test-cleanup.c', test_nm_dep_linux, 30], + ['test-link-fake', 'test-link.c', test_nm_dep_fake, default_test_timeout], + ['test-link-linux', 'test-link.c', test_nm_dep_linux, 900], + ['test-address-fake', 'test-address.c', test_nm_dep_fake, default_test_timeout], + ['test-address-linux', 'test-address.c', test_nm_dep_linux, default_test_timeout], + ['test-general', 'test-general.c', test_nm_dep, default_test_timeout], + ['test-nmp-object', 'test-nmp-object.c', test_nm_dep, default_test_timeout], + ['test-route-fake', 'test-route.c', test_nm_dep_fake, default_test_timeout], + ['test-route-linux', 'test-route.c', test_nm_dep_linux, default_test_timeout], + ['test-cleanup-fake', 'test-cleanup.c', test_nm_dep_fake, default_test_timeout], + ['test-cleanup-linux', 'test-cleanup.c', test_nm_dep_linux, default_test_timeout], ] foreach test_unit: test_units diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 8e29b5ce..c510710b 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -1840,7 +1840,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) if (e != 0) { errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "pipe() failed with %d (%s)", errsv, strerror (errsv)); + "pipe() failed with %d (%s)", errsv, nm_strerror_native (errsv)); return FALSE; } @@ -1848,7 +1848,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) if (e != 0) { errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "pipe() failed with %d (%s)", errsv, strerror (errsv)); + "pipe() failed with %d (%s)", errsv, nm_strerror_native (errsv)); nm_close (pipefd_c2p[0]); nm_close (pipefd_c2p[1]); return FALSE; @@ -1858,7 +1858,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) if (pid < 0) { errsv = errno; g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "fork() failed with %d (%s)", errsv, strerror (errsv)); + "fork() failed with %d (%s)", errsv, nm_strerror_native (errsv)); nm_close (pipefd_c2p[0]); nm_close (pipefd_c2p[1]); nm_close (pipefd_p2c[0]); @@ -1919,7 +1919,7 @@ nmtstp_namespace_create (int unshare_flags, GError **error) "child process failed for unknown reason"); } else { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "child process signaled failure %d (%s)", errsv, strerror (errsv)); + "child process signaled failure %d (%s)", errsv, nm_strerror_native (errsv)); } nm_close (pipefd_p2c[1]); kill (pid, SIGKILL); @@ -2074,14 +2074,14 @@ main (int argc, char **argv) if (unshare (CLONE_NEWNET | CLONE_NEWNS) != 0) { errsv = errno; - g_error ("unshare(CLONE_NEWNET|CLONE_NEWNS) failed with %s (%d)", strerror (errsv), errsv); + g_error ("unshare(CLONE_NEWNET|CLONE_NEWNS) failed with %s (%d)", nm_strerror_native (errsv), errsv); } /* We need a read-only /sys so that the platform knows there's no udev. */ mount (NULL, "/sys", "sysfs", MS_SLAVE, NULL); if (mount ("sys", "/sys", "sysfs", MS_RDONLY, NULL) != 0) { errsv = errno; - g_error ("mount(\"/sys\") failed with %s (%d)", strerror (errsv), errsv); + g_error ("mount(\"/sys\") failed with %s (%d)", nm_strerror_native (errsv), errsv); } } diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 048fd9dd..aa1f5460 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index bfd33058..71324301 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -860,9 +860,9 @@ _test_wireguard_change (NMPlatform *platform, if ((i % 2) == 1) { endpoint = (NMSockAddrUnion) { .in = { - .sin_family = AF_INET, - .sin_addr = nmtst_inet4_from_string (nm_sprintf_buf (s_addr, "192.168.7.%d", i)), - .sin_port = htons (14000 + i), + .sin_family = AF_INET, + .sin_addr.s_addr = nmtst_inet4_from_string (nm_sprintf_buf (s_addr, "192.168.7.%d", i)), + .sin_port = htons (14000 + i), }, }; } else { @@ -912,8 +912,12 @@ _test_wireguard_change (NMPlatform *platform, ifindex, &lnk_wireguard, (const NMPWireGuardPeer *) peers->data, + NULL, peers->len, - TRUE); + NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK + | NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS); g_assert (NMTST_NM_ERR_SUCCESS (r)); } @@ -2393,7 +2397,7 @@ _test_netns_check_skip (void) support_errsv = errno; } if (!support) { - _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", g_strerror (support_errsv)); + _LOGD ("setns() failed with \"%s\". This indicates missing support (valgrind?)", nm_strerror_native (support_errsv)); g_test_skip ("No netns support (setns failed)"); return TRUE; } @@ -2983,6 +2987,69 @@ test_sysctl_netns_switch (void) /*****************************************************************************/ +static gpointer +_test_netns_mt_thread (gpointer data) +{ + NMPNetns *netns1 = data; + gs_unref_object NMPNetns *netns2 = NULL; + NMPNetns *netns_bottom; + NMPNetns *initial; + + netns_bottom = nmp_netns_get_initial (); + g_assert (netns_bottom); + + /* I don't know why, but we need to create a new netns here at least once. + * Otherwise, setns(, CLONE_NEWNS) below fails with EINVAL (???). + * + * Something is not right here, but what? */ + netns2 = nmp_netns_new (); + nmp_netns_pop (netns2); + g_clear_object (&netns2); + + nmp_netns_push (netns1); + nmp_netns_push_type (netns_bottom, CLONE_NEWNET); + nmp_netns_push_type (netns_bottom, CLONE_NEWNS); + nmp_netns_push_type (netns1, CLONE_NEWNS); + nmp_netns_pop (netns1); + nmp_netns_pop (netns_bottom); + nmp_netns_pop (netns_bottom); + nmp_netns_pop (netns1); + + initial = nmp_netns_get_initial (); + g_assert (NMP_IS_NETNS (initial)); + return g_object_ref (initial); +} + +static void +test_netns_mt (void) +{ + gs_unref_object NMPNetns *netns1 = NULL; + NMPNetns *initial_from_other_thread; + GThread *th; + + if (_test_netns_check_skip ()) + return; + + netns1 = nmp_netns_new (); + g_assert (NMP_NETNS (netns1)); + nmp_netns_pop (netns1); + + th = g_thread_new ("nm-test-netns-mt", _test_netns_mt_thread, netns1); + initial_from_other_thread = g_thread_join (th); + g_assert (NMP_IS_NETNS (initial_from_other_thread)); + + if (nmtst_get_rand_bool ()) { + nmp_netns_push (initial_from_other_thread); + nmp_netns_pop (initial_from_other_thread); + } + + g_object_add_weak_pointer (G_OBJECT (initial_from_other_thread), (gpointer *) &initial_from_other_thread); + g_object_unref (initial_from_other_thread); + g_assert (initial_from_other_thread == NULL); +} + +/*****************************************************************************/ + static void ethtool_features_dump (const NMEthtoolFeatureStates *features) { @@ -3137,6 +3204,8 @@ _nmtstp_setup_tests (void) g_test_add_vtable ("/general/netns/push", 0, NULL, _test_netns_setup, test_netns_push, _test_netns_teardown); g_test_add_vtable ("/general/netns/bind-to-path", 0, NULL, _test_netns_setup, test_netns_bind_to_path, _test_netns_teardown); + g_test_add_func ("/general/netns/mt", test_netns_mt); + g_test_add_func ("/general/sysctl/rename", test_sysctl_rename); g_test_add_func ("/general/sysctl/netns-switch", test_sysctl_netns_switch); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 4c0f686f..2619ec52 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -767,7 +767,7 @@ test_ip (gconstpointer test_data) const int EX_ = -1; struct { int ifindex; - } iface_data[10] = { 0 }; + } iface_data[10] = { { 0 }, }; int order_idx[G_N_ELEMENTS (iface_data)] = { 0 }; guint order_len; guint try; diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c index 0df3d2d8..4f7ede97 100644 --- a/src/platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/platform/wifi/nm-wifi-utils-nl80211.c @@ -24,15 +24,12 @@ #include "nm-wifi-utils-nl80211.h" -#include -#include #include #include #include #include #include -#include "nm-utils/nm-errno.h" #include "platform/nm-netlink.h" #include "nm-wifi-utils-private.h" #include "platform/nm-platform.h" @@ -184,8 +181,10 @@ nl80211_iface_info_handler (struct nl_msg *msg, void *arg) struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + NULL) < 0) return NL_SKIP; if (!tb[NL80211_ATTR_IFTYPE]) @@ -279,16 +278,18 @@ nl80211_get_wake_on_wlan_handler (struct nl_msg *msg, void *arg) struct nlattr *trig[NUM_NL80211_WOWLAN_TRIG]; struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - nla_parse (attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); + nla_parse_arr (attrs, + genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), + NULL); if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) return NL_SKIP; - nla_parse (trig, MAX_NL80211_WOWLAN_TRIG, - nla_data (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), - nla_len (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), - NULL); + nla_parse_arr (trig, + nla_data (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + nla_len (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + NULL); *wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE; if (trig[NL80211_WOWLAN_TRIG_ANY]) @@ -415,33 +416,35 @@ find_ssid (guint8 *ies, guint32 ies_len, static int nl80211_bss_dump_handler (struct nl_msg *msg, void *arg) { + static const struct nla_policy bss_policy[] = { + [NL80211_BSS_TSF] = { .type = NLA_U64 }, + [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, + [NL80211_BSS_BSSID] = { .minlen = ETH_ALEN }, + [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, + [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, + [NL80211_BSS_INFORMATION_ELEMENTS] = { }, + [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, + [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, + [NL80211_BSS_STATUS] = { .type = NLA_U32 }, + }; struct nl80211_bss_info *info = arg; struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct nlattr *bss[NL80211_BSS_MAX + 1]; - static const struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = { - [NL80211_BSS_TSF] = { .type = NLA_U64 }, - [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 }, - [NL80211_BSS_BSSID] = { }, - [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 }, - [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 }, - [NL80211_BSS_INFORMATION_ELEMENTS] = { }, - [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 }, - [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 }, - [NL80211_BSS_STATUS] = { .type = NLA_U32 }, - }; + struct nlattr *bss[G_N_ELEMENTS (bss_policy)]; guint32 status; - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + NULL) < 0) return NL_SKIP; if (tb[NL80211_ATTR_BSS] == NULL) return NL_SKIP; - if (nla_parse_nested (bss, NL80211_BSS_MAX, - tb[NL80211_ATTR_BSS], - bss_policy)) + if (nla_parse_nested_arr (bss, + tb[NL80211_ATTR_BSS], + bss_policy)) return NL_SKIP; if (bss[NL80211_BSS_STATUS] == NULL) @@ -461,21 +464,22 @@ nl80211_bss_dump_handler (struct nl_msg *msg, void *arg) info->freq = nla_get_u32 (bss[NL80211_BSS_FREQUENCY]); if (bss[NL80211_BSS_SIGNAL_UNSPEC]) - info->beacon_signal = - nla_get_u8 (bss[NL80211_BSS_SIGNAL_UNSPEC]); + info->beacon_signal = nla_get_u8 (bss[NL80211_BSS_SIGNAL_UNSPEC]); if (bss[NL80211_BSS_SIGNAL_MBM]) - info->beacon_signal = - nl80211_xbm_to_percent (nla_get_u32 (bss[NL80211_BSS_SIGNAL_MBM]), 100); + info->beacon_signal = nl80211_xbm_to_percent (nla_get_u32 (bss[NL80211_BSS_SIGNAL_MBM]), 100); if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) { guint8 *ssid; guint32 ssid_len; find_ssid (nla_data (bss[NL80211_BSS_INFORMATION_ELEMENTS]), - nla_len (bss[NL80211_BSS_INFORMATION_ELEMENTS]), - &ssid, &ssid_len); - if (ssid && ssid_len && ssid_len <= sizeof (info->ssid)) { + nla_len (bss[NL80211_BSS_INFORMATION_ELEMENTS]), + &ssid, + &ssid_len); + if ( ssid + && ssid_len + && ssid_len <= sizeof (info->ssid)) { memcpy (info->ssid, ssid, ssid_len); info->ssid_len = ssid_len; } @@ -550,49 +554,50 @@ struct nl80211_station_info { static int nl80211_station_handler (struct nl_msg *msg, void *arg) { - struct nl80211_station_info *info = arg; - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1]; - struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1]; - static const struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = { + static const struct nla_policy stats_policy[] = { [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 }, - [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, - [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, - [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, - [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, - [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, - [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, - [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, - [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, + [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 }, + [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 }, + [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 }, + [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED }, + [NL80211_STA_INFO_LLID] = { .type = NLA_U16 }, + [NL80211_STA_INFO_PLID] = { .type = NLA_U16 }, + [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 }, }; - - static const struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = { - [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, - [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, + static const struct nla_policy rate_policy[] = { + [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 }, + [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 }, [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG }, - [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, + [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, }; + struct nlattr *rinfo[G_N_ELEMENTS (rate_policy)]; + struct nlattr *sinfo[G_N_ELEMENTS (stats_policy)]; + struct nl80211_station_info *info = arg; + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + NULL) < 0) return NL_SKIP; if (tb[NL80211_ATTR_STA_INFO] == NULL) return NL_SKIP; - if (nla_parse_nested (sinfo, NL80211_STA_INFO_MAX, - tb[NL80211_ATTR_STA_INFO], - stats_policy)) + if (nla_parse_nested_arr (sinfo, + tb[NL80211_ATTR_STA_INFO], + stats_policy)) return NL_SKIP; if (sinfo[NL80211_STA_INFO_TX_BITRATE] == NULL) return NL_SKIP; - if (nla_parse_nested (rinfo, NL80211_RATE_INFO_MAX, - sinfo[NL80211_STA_INFO_TX_BITRATE], - rate_policy)) + if (nla_parse_nested_arr (rinfo, + sinfo[NL80211_STA_INFO_TX_BITRATE], + rate_policy)) return NL_SKIP; if (rinfo[NL80211_RATE_INFO_BITRATE] == NULL) @@ -717,37 +722,40 @@ struct nl80211_device_info { static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) { + static const struct nla_policy freq_policy[] = { + [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, + [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, +#ifdef NL80211_FREQUENCY_ATTR_NO_IR + [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, +#else + [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, +#endif + [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, + [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, + }; struct nlattr *tb[NL80211_ATTR_MAX + 1]; struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); struct nl80211_device_info *info = arg; NMWifiUtilsNl80211 *self = info->self; struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; - struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *tb_freq[G_N_ELEMENTS (freq_policy)]; struct nlattr *nl_band; struct nlattr *nl_freq; int rem_freq; int rem_band; int freq_idx; - static const struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { - [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, - [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG }, -#ifdef NL80211_FREQUENCY_ATTR_NO_IR - [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, -#else - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, -#endif - [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG }, - [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 }, - }; + #ifdef NL80211_FREQUENCY_ATTR_NO_IR - G_STATIC_ASSERT (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR && NL80211_FREQUENCY_ATTR_NO_IBSS == NL80211_FREQUENCY_ATTR_NO_IR); + G_STATIC_ASSERT_EXPR (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR && NL80211_FREQUENCY_ATTR_NO_IBSS == NL80211_FREQUENCY_ATTR_NO_IR); #else - G_STATIC_ASSERT (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN != NL80211_FREQUENCY_ATTR_NO_IBSS); + G_STATIC_ASSERT_EXPR (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN != NL80211_FREQUENCY_ATTR_NO_IBSS); #endif - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + NULL) < 0) return NL_SKIP; if ( tb[NL80211_ATTR_WIPHY] == NULL @@ -793,14 +801,17 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) info->num_freqs = 0; nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { - if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band, - NULL) < 0) + if (nla_parse_nested_arr (tb_band, + nl_band, + NULL) < 0) return NL_SKIP; - nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], + nla_for_each_nested (nl_freq, + tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - if (nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nl_freq, freq_policy) < 0) + if (nla_parse_nested_arr (tb_freq, + nl_freq, + freq_policy) < 0) continue; if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) @@ -815,21 +826,22 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) freq_idx = 0; nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { - if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band, - NULL) < 0) + if (nla_parse_nested_arr (tb_band, + nl_band, + NULL) < 0) return NL_SKIP; nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - if (nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX, - nl_freq, freq_policy) < 0) + if (nla_parse_nested_arr (tb_freq, + nl_freq, + freq_policy) < 0) continue; if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; - info->freqs[freq_idx] = - nla_get_u32 (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + info->freqs[freq_idx] = nla_get_u32 (tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); info->caps |= NM_WIFI_DEVICE_CAP_FREQ_VALID; @@ -844,11 +856,10 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) /* Read security/encryption support */ if (tb[NL80211_ATTR_CIPHER_SUITES]) { - int num; - int i; - __u32 *ciphers = nla_data (tb[NL80211_ATTR_CIPHER_SUITES]); + guint32 *ciphers = nla_data (tb[NL80211_ATTR_CIPHER_SUITES]); + guint i, num; - num = nla_len (tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof (__u32); + num = nla_len (tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof (guint32); for (i = 0; i < num; i++) { switch (ciphers[i]) { case WLAN_CIPHER_SUITE_WEP40: diff --git a/src/platform/wifi/nm-wifi-utils-wext.c b/src/platform/wifi/nm-wifi-utils-wext.c index 597f3152..3aa1720a 100644 --- a/src/platform/wifi/nm-wifi-utils-wext.c +++ b/src/platform/wifi/nm-wifi-utils-wext.c @@ -23,8 +23,6 @@ #include "nm-wifi-utils-wext.h" -#include -#include #include #include #include @@ -117,7 +115,7 @@ get_ifname (int ifindex, char *buffer, const char *op) errsv = errno; _LOGW (LOGD_PLATFORM | LOGD_WIFI, "error getting interface name for ifindex %d, operation '%s': %s (%d)", - ifindex, op, g_strerror (errsv), errsv); + ifindex, op, nm_strerror_native (errsv), errsv); return FALSE; } @@ -129,15 +127,17 @@ wifi_wext_get_mode_ifname (NMWifiUtils *data, const char *ifname) { NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; + int errsv; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, ifname); if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) { - if (errno != ENODEV) { + errsv = errno; + if (errsv != ENODEV) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "(%s): error %d getting card mode", - ifname, errno); + ifname, errsv); } return NM_802_11_MODE_UNKNOWN; } @@ -253,7 +253,7 @@ wifi_wext_get_freq (NMWifiUtils *data) if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting frequency: %s", - ifname, strerror (errno)); + ifname, nm_strerror_native (errno)); return 0; } @@ -291,7 +291,7 @@ wifi_wext_get_bssid (NMWifiUtils *data, guint8 *out_bssid) if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting associated BSSID: %s", - ifname, strerror (errno)); + ifname, nm_strerror_native (errno)); return FALSE; } memcpy (out_bssid, &(wrq.u.ap_addr.sa_data), ETH_ALEN); @@ -429,7 +429,7 @@ wifi_wext_get_qual (NMWifiUtils *data) if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting signal strength: %s", - ifname, strerror (errno)); + ifname, nm_strerror_native (errno)); return -1; } @@ -476,7 +476,7 @@ wifi_wext_set_mesh_channel (NMWifiUtils *data, guint32 channel) if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) { _LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, "(%s): error setting channel to %d: %s", - ifname, channel, strerror (errno)); + ifname, channel, nm_strerror_native (errno)); return FALSE; } @@ -506,15 +506,15 @@ wifi_wext_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len) if (ioctl (wext->fd, SIOCSIWESSID, &wrq) == 0) return TRUE; - if (errno != ENODEV) { + errsv = errno; + if (errsv != ENODEV) { gs_free char *ssid_str = NULL; - errsv = errno; _LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, "(%s): error setting SSID to %s: %s", ifname, (ssid_str = _nm_utils_ssid_to_string_arr (ssid, len)), - strerror (errsv)); + nm_strerror_native (errsv)); } return FALSE; @@ -545,6 +545,7 @@ wext_get_range_ifname (NMWifiUtilsWext *wext, int i = 26; gboolean success = FALSE; struct iwreq wrq; + int errsv; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, ifname); @@ -561,11 +562,14 @@ wext_get_range_ifname (NMWifiUtilsWext *wext, *response_len = wrq.u.data.length; success = TRUE; break; - } else if (errno != EAGAIN) { - _LOGE (LOGD_PLATFORM | LOGD_WIFI, - "(%s): couldn't get driver range information (%d).", - ifname, errno); - break; + } else { + errsv = errno; + if (errsv != EAGAIN) { + _LOGE (LOGD_PLATFORM | LOGD_WIFI, + "(%s): couldn't get driver range information (%d).", + ifname, errsv); + break; + } } g_usleep (G_USEC_PER_SEC / 4); diff --git a/src/platform/wifi/nm-wifi-utils.c b/src/platform/wifi/nm-wifi-utils.c index 25d71c6a..96071faa 100644 --- a/src/platform/wifi/nm-wifi-utils.c +++ b/src/platform/wifi/nm-wifi-utils.c @@ -25,7 +25,6 @@ #include #include -#include #include #include "nm-wifi-utils-private.h" diff --git a/src/platform/wpan/nm-wpan-utils.c b/src/platform/wpan/nm-wpan-utils.c index f8708bc6..b7a51e9b 100644 --- a/src/platform/wpan/nm-wpan-utils.c +++ b/src/platform/wpan/nm-wpan-utils.c @@ -23,7 +23,6 @@ #include -#include "nm-utils/nm-errno.h" #include "platform/linux/nl802154.h" #include "platform/nm-netlink.h" #include "platform/nm-platform-utils.h" @@ -154,17 +153,19 @@ struct nl802154_interface { static int nl802154_get_interface_handler (struct nl_msg *msg, void *arg) { + static const struct nla_policy nl802154_policy[] = { + [NL802154_ATTR_PAN_ID] = { .type = NLA_U16 }, + [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16 }, + }; + struct nlattr *tb[G_N_ELEMENTS (nl802154_policy)]; struct nl802154_interface *info = arg; struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - struct nlattr *tb[NL802154_ATTR_MAX + 1] = { 0, }; - static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX + 1] = { - [NL802154_ATTR_PAN_ID] = { .type = NLA_U16 }, - [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16 }, - }; - if (nla_parse (tb, NL802154_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), nl802154_policy) < 0) - return NL_SKIP; + if (nla_parse_arr (tb, + genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), + nl802154_policy) < 0) + return NL_SKIP; if (tb[NL802154_ATTR_PAN_ID]) info->pan_id = le16toh (nla_get_u16 (tb[NL802154_ATTR_PAN_ID])); -- cgit 1.3.0-6-gf8a5