diff options
| author | Michael Biebl <biebl@debian.org> | 2018-05-11 22:08:45 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-05-11 22:08:45 +0200 |
| commit | ee9c73a923909e23a649407be77e25235d769e25 (patch) | |
| tree | e21c923621fa278e737da693df9eb60ea31a6067 /src/platform | |
| parent | f60117b41d5433be1b4a96d82cd11d0c3dce9b63 (diff) | |
New upstream version 1.10.8 upstream/1.10.8
Diffstat (limited to 'src/platform')
24 files changed, 1036 insertions, 3489 deletions
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 06dd7e13..be430152 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -938,6 +938,7 @@ wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs) static void wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running) { + ; } static guint32 diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 0ed8fa06..e5961c7e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -21,7 +21,6 @@ #include "nm-linux-platform.h" -#include <poll.h> #include <endian.h> #include <errno.h> #include <unistd.h> @@ -37,14 +36,14 @@ #include <linux/if_link.h> #include <linux/if_tun.h> #include <linux/if_tunnel.h> -#include <linux/ip6_tunnel.h> +#include <netlink/netlink.h> +#include <netlink/msg.h> #include <libudev.h> #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-setting-vlan.h" -#include "nm-netlink.h" #include "nm-core-utils.h" #include "nmp-object.h" #include "nmp-netns.h" @@ -80,6 +79,10 @@ enum { #define VLAN_FLAG_MVRP 0x8 +/* nm-internal error codes for libnl. Make sure they don't overlap. */ +#define _NLE_NM_NOBUFS 500 +#define _NLE_MSG_TRUNC 501 + /*****************************************************************************/ #define IFQDISCSIZ 32 @@ -124,18 +127,6 @@ enum { #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) #endif -#define IFLA_TUN_UNSPEC 0 -#define IFLA_TUN_OWNER 1 -#define IFLA_TUN_GROUP 2 -#define IFLA_TUN_TYPE 3 -#define IFLA_TUN_PI 4 -#define IFLA_TUN_VNET_HDR 5 -#define IFLA_TUN_PERSIST 6 -#define IFLA_TUN_MULTI_QUEUE 7 -#define IFLA_TUN_NUM_QUEUES 8 -#define IFLA_TUN_NUM_DISABLED_QUEUES 9 -#define __IFLA_TUN_MAX 10 -#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) static const gboolean RTA_PREF_SUPPORTED_AT_COMPILETIME = (RTA_MAX >= 20 /* RTA_PREF */); @@ -292,7 +283,7 @@ typedef enum { #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)) + if (NM_FLAGS_HAS (flags_all, iflags)) typedef enum { /* Negative values are errors from kernel. Add dummy member to @@ -306,9 +297,13 @@ typedef enum { WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS, } WaitForNlResponseResult; +typedef void (*WaitForNlResponseCallback) (NMPlatform *platform, + guint32 seq_number, + WaitForNlResponseResult seq_result, + gpointer user_data); + static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data); static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink); static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name); @@ -333,9 +328,7 @@ wait_for_nl_response_to_plerr (WaitForNlResponseResult seq_result) } static const char * -wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, - const char *errmsg, - char *buf, gsize buf_size) +wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, char *buf, gsize buf_size) { char *buf0 = buf; @@ -350,13 +343,8 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, nm_utils_strbuf_append_str (&buf, &buf_size, "failure"); break; default: - if (seq_result < 0) { - nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s%s%s)", - -((int) seq_result), - g_strerror (-((int) seq_result)), - errmsg ? " - " : "", - errmsg ?: ""); - } + if (seq_result < 0) + nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s)", -((int) seq_result), g_strerror (-((int) seq_result))); else nm_utils_strbuf_append (&buf, &buf_size, "internal failure %d", (int) seq_result); break; @@ -550,7 +538,8 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL }, { NM_LINK_TYPE_PPP, "ppp", NULL, "ppp" }, { NM_LINK_TYPE_SIT, "sit", "sit", NULL }, - { NM_LINK_TYPE_TUN, "tun", "tun", NULL }, + { NM_LINK_TYPE_TAP, "tap", NULL, NULL }, + { NM_LINK_TYPE_TUN, "tun", NULL, NULL }, { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, @@ -811,25 +800,36 @@ _linktype_get_type (NMPlatform *platform, && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE) && nm_streq (ifname, obj->link.name) && ( !kind - || nm_streq0 (kind, obj->link.kind))) { + || !g_strcmp0 (kind, obj->link.kind))) { nm_assert (obj->link.kind == g_intern_string (obj->link.kind)); *out_kind = obj->link.kind; return obj->link.type; } } - /* we intern kind to not require us to keep the pointer alive. Essentially - * leaking it in a global cache. That should be safe enough, because the - * kind comes only from kernel messages, which depend on the number of - * available drivers. So, there is not the danger that we leak uncontrolled - * many kinds. */ *out_kind = g_intern_string (kind); if (kind) { for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (nm_streq0 (kind, linktypes[i].rtnl_type)) { + if (g_strcmp0 (kind, linktypes[i].rtnl_type) == 0) return linktypes[i].nm_type; + } + + if (!strcmp (kind, "tun")) { + NMPlatformTunProperties props; + + if ( platform + && nm_platform_link_tun_get_properties (platform, ifindex, &props)) { + if (!g_strcmp0 (props.mode, "tap")) + return NM_LINK_TYPE_TAP; + if (!g_strcmp0 (props.mode, "tun")) + return NM_LINK_TYPE_TUN; } + + /* try guessing the type using the link flags instead... */ + if (flags & IFF_POINTOPOINT) + return NM_LINK_TYPE_TUN; + return NM_LINK_TYPE_TAP; } } @@ -951,6 +951,137 @@ _nl_addattr_l (struct nlmsghdr *n, return TRUE; } +static void +_nm_auto_nl_msg_cleanup (void *ptr) +{ + nlmsg_free (*((struct nl_msg **) ptr)); +} +#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) + +static const char * +_nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) +{ + const char *b; + const char *s; + guint flags, flags_before; + const char *prefix; + + nm_utils_to_string_buffer_init (&buf, &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; + } + + if (s) + nm_utils_strbuf_append_str (&buf, &len, s); + else + nm_utils_strbuf_append (&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); + + flags = hdr->nlmsg_flags; + + if (!flags) { + nm_utils_strbuf_append_str (&buf, &len, ", flags 0"); + goto flags_done; + } + +#define _F(f, n) \ + G_STMT_START { \ + if (NM_FLAGS_ALL (flags, f)) { \ + flags &= ~(f); \ + nm_utils_strbuf_append (&buf, &len, "%s%s", prefix, n); \ + if (!flags) \ + goto flags_done; \ + prefix = ","; \ + } \ + } G_STMT_END + + prefix = ", flags "; + flags_before = flags; + _F (NLM_F_REQUEST, "request"); + _F (NLM_F_MULTI, "multi"); + _F (NLM_F_ACK, "ack"); + _F (NLM_F_ECHO, "echo"); + _F (NLM_F_DUMP_INTR, "dump_intr"); + _F (0x20 /*NLM_F_DUMP_FILTERED*/, "dump_filtered"); + + if (flags_before != flags) + prefix = ";"; + + switch (hdr->nlmsg_type) { + case RTM_NEWLINK: + case RTM_NEWADDR: + case RTM_NEWROUTE: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: + _F (NLM_F_REPLACE, "replace"); + _F (NLM_F_EXCL, "excl"); + _F (NLM_F_CREATE, "create"); + _F (NLM_F_APPEND, "append"); + break; + case RTM_GETLINK: + case RTM_GETADDR: + case RTM_GETROUTE: + case RTM_DELQDISC: + case RTM_DELTFILTER: + _F (NLM_F_DUMP, "dump"); + _F (NLM_F_ROOT, "root"); + _F (NLM_F_MATCH, "match"); + _F (NLM_F_ATOMIC, "atomic"); + break; + } + +#undef _F + + if (flags_before != flags) + prefix = ";"; + nm_utils_strbuf_append (&buf, &len, "%s0x%04x", prefix, flags); + +flags_done: + + nm_utils_strbuf_append (&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq); + + return b; +} + +static int +_nl_nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, + const struct nla_policy *policy) +{ + return nla_parse (tb, maxtype, head, len, (struct nla_policy *) policy); +} +#define nla_parse(...) _nl_nla_parse(__VA_ARGS__) + +static int +_nl_nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], + int maxtype, const struct nla_policy *policy) +{ + return nlmsg_parse (nlh, hdrlen, tb, maxtype, (struct nla_policy *) policy); +} +#define nlmsg_parse(...) _nl_nlmsg_parse(__VA_ARGS__) + +static int +_nl_nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, + const struct nla_policy *policy) +{ + return nla_parse_nested (tb, maxtype, nla, (struct nla_policy *) policy); +} +#define nla_parse_nested(...) _nl_nla_parse_nested(__VA_ARGS__) + /****************************************************************** * NMPObject/netlink functions ******************************************************************/ @@ -1161,7 +1292,6 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) [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; @@ -1196,8 +1326,6 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) } if (tb[IFLA_IPTUN_PROTO]) props->proto = nla_get_u8 (tb[IFLA_IPTUN_PROTO]); - if (tb[IFLA_IPTUN_FLAGS]) - props->flags = nla_get_u32 (tb[IFLA_IPTUN_FLAGS]); return obj; } @@ -1377,60 +1505,6 @@ _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] = { - [IFLA_TUN_OWNER] = { .type = NLA_U32 }, - [IFLA_TUN_GROUP] = { .type = NLA_U32 }, - [IFLA_TUN_TYPE] = { .type = NLA_U8 }, - [IFLA_TUN_PI] = { .type = NLA_U8 }, - [IFLA_TUN_VNET_HDR] = { .type = NLA_U8 }, - [IFLA_TUN_PERSIST] = { .type = NLA_U8 }, - [IFLA_TUN_MULTI_QUEUE] = { .type = NLA_U8 }, - [IFLA_TUN_NUM_QUEUES] = { .type = NLA_U32 }, - [IFLA_TUN_NUM_DISABLED_QUEUES] = { .type = NLA_U32 }, - }; - struct nlattr *tb[IFLA_TUN_MAX + 1]; - int err; - NMPObject *obj; - NMPlatformLnkTun *props; - - if (!info_data || !nm_streq0 (kind, "tun")) - return NULL; - - err = nla_parse_nested (tb, IFLA_TUN_MAX, info_data, policy); - if (err < 0) - return NULL; - - if (!tb[IFLA_TUN_TYPE]) { - /* we require at least a type. */ - return NULL; - } - - obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_TUN, NULL); - props = &obj->lnk_tun; - - props->type = nla_get_u8 (tb[IFLA_TUN_TYPE]); - - props->pi = !!nla_get_u8_cond (tb, IFLA_TUN_PI, FALSE); - props->vnet_hdr = !!nla_get_u8_cond (tb, IFLA_TUN_VNET_HDR, FALSE); - props->multi_queue = !!nla_get_u8_cond (tb, IFLA_TUN_MULTI_QUEUE, FALSE); - props->persist = !!nla_get_u8_cond (tb, IFLA_TUN_PERSIST, FALSE); - - if (tb[IFLA_TUN_OWNER]) { - props->owner_valid = TRUE; - props->owner = nla_get_u32 (tb[IFLA_TUN_OWNER]); - } - if (tb[IFLA_TUN_GROUP]) { - props->group_valid = TRUE; - props->group = nla_get_u32 (tb[IFLA_TUN_GROUP]); - } - return obj; -} - -/*****************************************************************************/ - static gboolean _vlan_qos_mapping_from_nla (struct nlattr *nlattr, const NMVlanQosMapping **out_map, @@ -1862,9 +1936,6 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_SIT: lnk_data = _parse_lnk_sit (nl_info_kind, nl_info_data); break; - case NM_LINK_TYPE_TUN: - lnk_data = _parse_lnk_tun (nl_info_kind, nl_info_data); - break; case NM_LINK_TYPE_VLAN: lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data); break; @@ -2594,7 +2665,8 @@ _nl_msg_new_link (int nlmsg_type, nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK)); - msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!(msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags))) + g_return_val_if_reached (NULL); if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -2636,6 +2708,8 @@ _nl_msg_new_address (int nlmsg_type, nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWADDR, RTM_DELADDR)); msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + g_return_val_if_reached (NULL); if (scope == -1) { /* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */ @@ -2748,6 +2822,8 @@ _nl_msg_new_route (int nlmsg_type, nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); msg = nlmsg_alloc_simple (nlmsg_type, (int) nlmsgflags); + if (!msg) + g_return_val_if_reached (NULL); if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -2845,6 +2921,8 @@ _nl_msg_new_qdisc (int nlmsg_type, }; msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + return NULL; if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -2919,6 +2997,8 @@ _nl_msg_new_tfilter (int nlmsg_type, }; msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + return NULL; if (nlmsg_append (msg, &tcm, sizeof (tcm), NLMSG_ALIGNTO) < 0) goto nla_put_failure; @@ -2960,7 +3040,6 @@ typedef struct { DelayedActionWaitForNlResponseType response_type; gint64 timeout_abs_ns; WaitForNlResponseResult *out_seq_result; - char **out_errmsg; union { gint *out_refresh_all_in_progess; NMPObject **out_route_get; @@ -3421,7 +3500,7 @@ delayed_action_to_string_full (DelayedActionType action_type, gpointer user_data (timeout < 0 ? -timeout : timeout) % NM_UTILS_NS_PER_SECOND, (int) data->response_type, data->seq_result ? ", " : "", - data->seq_result ? wait_for_nl_response_to_string (data->seq_result, NULL, b, sizeof (b)) : ""); + data->seq_result ? wait_for_nl_response_to_string (data->seq_result, b, sizeof (b)) : ""); } else nm_utils_strbuf_append_str (&buf, &buf_size, " (any)"); break; @@ -3503,58 +3582,27 @@ delayed_action_wait_for_nl_response_complete (NMPlatform *platform, } static void -delayed_action_wait_for_nl_response_complete_check (NMPlatform *platform, - WaitForNlResponseResult force_result, - guint32 *out_next_seq_number, - gint64 *out_next_timeout_abs_ns, - gint64 *p_now_ns) +delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform, + WaitForNlResponseResult fallback_result) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - guint i; - guint32 next_seq_number = 0; - gint64 next_timeout_abs_ns = 0; - gint now_ns = 0; - - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) { - const DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i); - - if (data->seq_result) - delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result); - else if ( p_now_ns - && ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) >= data->timeout_abs_ns)) { - /* the caller can optionally check for timeout by providing a p_now_ns argument. */ - delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); - } else if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) - delayed_action_wait_for_nl_response_complete (platform, i, force_result); - else { - if ( next_seq_number == 0 - || next_timeout_abs_ns > data->timeout_abs_ns) { - next_seq_number = data->seq_number; - next_timeout_abs_ns = data->timeout_abs_ns; - } - i++; - } - } - if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) { - nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); - nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0); - } + if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { + while (priv->delayed_action.list_wait_for_nl_response->len > 0) { + const DelayedActionWaitForNlResponseData *data; + guint idx = priv->delayed_action.list_wait_for_nl_response->len - 1; + WaitForNlResponseResult r; - NM_SET_OUT (out_next_seq_number, next_seq_number); - NM_SET_OUT (out_next_timeout_abs_ns, next_timeout_abs_ns); - NM_SET_OUT (p_now_ns, now_ns); -} + data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx); -static void -delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform, - WaitForNlResponseResult fallback_result) -{ - delayed_action_wait_for_nl_response_complete_check (platform, - fallback_result, - NULL, - NULL, - NULL); + /* prefer the result that we already have. */ + r = data->seq_result ? : fallback_result; + + delayed_action_wait_for_nl_response_complete (platform, idx, r); + } + } + nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); + nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0); } /*****************************************************************************/ @@ -3737,7 +3785,6 @@ static void delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -3745,7 +3792,6 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, .seq_number = seq_number, .timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)), .out_seq_result = out_seq_result, - .out_errmsg = out_errmsg, .response_type = response_type, .response.out_data = response_out_data, }; @@ -3930,46 +3976,40 @@ cache_on_change (NMPlatform *platform, && (obj_new && obj_new->_link.netlink.is_in_netlink) && (!obj_old || !obj_old->_link.netlink.is_in_netlink)) { - gboolean re_request_link = FALSE; - const NMPlatformLnkTun *lnk_tun; - - if ( !obj_new->_link.netlink.lnk - && NM_IN_SET (obj_new->link.type, NM_LINK_TYPE_GRE, - NM_LINK_TYPE_IP6TNL, - NM_LINK_TYPE_INFINIBAND, - NM_LINK_TYPE_MACVLAN, - NM_LINK_TYPE_MACVLAN, - NM_LINK_TYPE_SIT, - NM_LINK_TYPE_TUN, - NM_LINK_TYPE_VLAN, - NM_LINK_TYPE_VXLAN)) { + if (!obj_new->_link.netlink.lnk) { /* certain link-types also come with a IFLA_INFO_DATA/lnk_data. It may happen that * kernel didn't send this notification, thus when we first learn about a link * that lacks an lnk_data we re-request it again. * * For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */ - re_request_link = TRUE; - } else if ( obj_new->link.type == NM_LINK_TYPE_TUN - && obj_new->_link.netlink.lnk - && (lnk_tun = &(obj_new->_link.netlink.lnk)->lnk_tun) - && !lnk_tun->persist - && lnk_tun->pi - && !lnk_tun->vnet_hdr - && !lnk_tun->multi_queue - && !lnk_tun->owner_valid - && !lnk_tun->group_valid) { - /* kernel has/had a know issue that the first notification for TUN device would - * be sent with invalid parameters. The message looks like that kind, so refetch - * it. */ - re_request_link = TRUE; - } else if ( obj_new->link.type == NM_LINK_TYPE_VETH - && obj_new->link.parent == 0) { + switch (obj_new->link.type) { + case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_IP6TNL: + case NM_LINK_TYPE_INFINIBAND: + case NM_LINK_TYPE_MACVLAN: + case NM_LINK_TYPE_MACVTAP: + case NM_LINK_TYPE_SIT: + case NM_LINK_TYPE_VLAN: + case NM_LINK_TYPE_VXLAN: + delayed_action_schedule (platform, + DELAYED_ACTION_TYPE_REFRESH_LINK, + GINT_TO_POINTER (obj_new->link.ifindex)); + break; + default: + break; + } + } + if ( obj_new->link.type == NM_LINK_TYPE_VETH + && obj_new->link.parent == 0) { /* the initial notification when adding a veth pair can lack the parent/IFLA_LINK * (https://bugzilla.redhat.com/show_bug.cgi?id=1285827). * Request it again. */ - re_request_link = TRUE; - } else if ( obj_new->link.type == NM_LINK_TYPE_ETHERNET - && obj_new->link.addr.len == 0) { + delayed_action_schedule (platform, + DELAYED_ACTION_TYPE_REFRESH_LINK, + GINT_TO_POINTER (obj_new->link.ifindex)); + } + if ( obj_new->link.type == NM_LINK_TYPE_ETHERNET + && obj_new->link.addr.len == 0) { /* Due to a kernel bug, we sometimes receive spurious NEWLINK * messages after a wifi interface has disappeared. Since the * link is not present anymore we can't determine its type and @@ -3977,9 +4017,6 @@ cache_on_change (NMPlatform *platform, * specified. Request the link again to check if it really * exists. https://bugzilla.redhat.com/show_bug.cgi?id=1302037 */ - re_request_link = TRUE; - } - if (re_request_link) { delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (obj_new->link.ifindex)); @@ -4030,10 +4067,8 @@ cache_on_change (NMPlatform *platform, static guint32 _nlh_seq_next_get (NMLinuxPlatformPrivate *priv) { - /* generate a new sequence number, but never return zero. - * Wrapping numbers are not a problem, because we don't rely - * on strictly increasing sequence numbers. */ - return (++priv->nlh_seq_next) ?: (++priv->nlh_seq_next); + /* generate a new sequence number, but skip zero. */ + return priv->nlh_seq_next++ ?: priv->nlh_seq_next++; } /** @@ -4044,13 +4079,12 @@ _nlh_seq_next_get (NMLinuxPlatformPrivate *priv) * @response_type: * @response_out_data: * - * Returns: 0 on success or a negative errno. + * Returns: 0 on success or a negative errno. Beware, it's an errno, not nlerror. */ static int _nl_send_nlmsghdr (NMPlatform *platform, struct nlmsghdr *nlhdr, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -4095,7 +4129,7 @@ again: } } - delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, out_errmsg, + delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, response_type, response_out_data); return 0; } @@ -4114,7 +4148,6 @@ static int _nl_send_nlmsg (NMPlatform *platform, struct nl_msg *nlmsg, WaitForNlResponseResult *out_seq_result, - char **out_errmsg, DelayedActionWaitForNlResponseType response_type, gpointer response_out_data) { @@ -4133,7 +4166,7 @@ _nl_send_nlmsg (NMPlatform *platform, return nle; } - delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, out_errmsg, + delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, response_type, response_out_data); return 0; } @@ -4171,7 +4204,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha 0, 0); if (nlmsg) { - nle = _nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-request-link: %d %s: failed sending netlink request \"%s\" (%d)", ifindex, name ?: "", @@ -4230,6 +4263,8 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio * because we need the sequence number. */ nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + if (!nlmsg) + continue; if ( klass->obj_type == NMP_OBJECT_TYPE_QDISC || klass->obj_type == NMP_OBJECT_TYPE_TFILTER) { @@ -4246,7 +4281,7 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio if (nle < 0) continue; - if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progess) < 0) { + if (_nl_send_nlmsg (platform, nlmsg, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progess) < 0) { nm_assert (*out_refresh_all_in_progess > 0); *out_refresh_all_in_progess -= 1; } @@ -4290,7 +4325,7 @@ event_seq_check_refresh_all (NMPlatform *platform, guint32 seq_number) } static void -event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResult seq_result, const char *msg) +event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResult seq_result) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); DelayedActionWaitForNlResponseData *data; @@ -4309,13 +4344,11 @@ event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResu /* We potentially receive many parts partial responses for the same sequence number. * Thus, we only remember the result, and collect it later. */ if (data->seq_result < 0) { - /* we already saw an error for this sequence number. + /* we already saw an error for this seqence number. * Preserve it. */ } else if ( seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) data->seq_result = seq_result; - if (data->out_errmsg && !*data->out_errmsg) - *data->out_errmsg = g_strdup (msg); return; } } @@ -4358,7 +4391,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event obj = nmp_object_new_from_nl (platform, cache, msg, id_only); if (!obj) { _LOGT ("event-notification: %s: ignore", - nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); + _nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); return; } @@ -4376,7 +4409,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event } _LOGT ("event-notification: %s%s: %s", - nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)), + _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, @@ -4514,14 +4547,13 @@ do_add_link_with_lookup (NMPlatform *platform, { const NMPObject *obj = NULL; WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; NMPCache *cache = nm_platform_get_cache (platform); event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", name, @@ -4541,7 +4573,7 @@ do_add_link_with_lookup (NMPlatform *platform, "do-add-link[%s/%s]: %s", name, nm_link_type_to_string (link_type), - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); if (out_link) { obj = nmp_cache_lookup_link_full (cache, 0, name, FALSE, link_type, NULL, NULL); @@ -4558,7 +4590,6 @@ do_add_addrroute (NMPlatform *platform, gboolean suppress_netlink_failure) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; @@ -4568,7 +4599,7 @@ do_add_addrroute (NMPlatform *platform, event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, @@ -4589,7 +4620,7 @@ do_add_addrroute (NMPlatform *platform, "do-add-%s[%s]: %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); if (NMP_OBJECT_GET_TYPE (obj_id) == NMP_OBJECT_TYPE_IP6_ADDRESS) { /* In rare cases, the object is not yet ready as we received the ACK from @@ -4610,7 +4641,6 @@ static gboolean do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; gboolean success; @@ -4618,7 +4648,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, @@ -4650,7 +4680,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg * "do-delete-%s[%s]: %s%s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf)), + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)), log_detail); if (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), @@ -4681,7 +4711,6 @@ do_change_link (NMPlatform *platform, nm_auto_pop_netns NMPNetns *netns = NULL; int nle; WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; char s_buf[256]; NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS; NMLogLevel log_level = LOGL_DEBUG; @@ -4697,7 +4726,7 @@ do_change_link (NMPlatform *platform, } retry: - nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { log_level = LOGL_ERR; log_detail_free = g_strdup_printf (", failure sending netlink request: %s (%d)", @@ -4754,7 +4783,7 @@ out: "do-change-link[%d]: %s changing link: %s%s", ifindex, log_result, - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf)), + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)), log_detail); return result; } @@ -4831,12 +4860,6 @@ link_refresh (NMPlatform *platform, int ifindex) return !!nm_platform_link_get_obj (platform, ifindex, TRUE); } -static void -refresh_all (NMPlatform *platform, NMPObjectType obj_type) -{ - do_request_one_type (platform, obj_type); -} - static gboolean link_set_netns (NMPlatform *platform, int ifindex, @@ -5369,7 +5392,6 @@ link_ip6tnl_add (NMPlatform *platform, & IP6_FLOWINFO_TCLASS_MASK; NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo)); NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto); - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLAGS, props->flags); nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); @@ -5593,62 +5615,6 @@ nla_put_failure: } static gboolean -link_tun_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkTun *props, - const NMPlatformLink **out_link, - int *out_fd) -{ - const NMPObject *obj; - struct ifreq ifr = { }; - nm_auto_close int fd = -1; - - nm_assert (NM_IN_SET (props->type, IFF_TAP, IFF_TUN)); - nm_assert (props->persist || out_fd); - - fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC); - if (fd < 0) - return FALSE; - - nm_utils_ifname_cpy (ifr.ifr_name, name); - ifr.ifr_flags = ((short) props->type) - | ((short) IFF_TUN_EXCL) - | (!props->pi ? (short) IFF_NO_PI : (short) 0) - | ( props->vnet_hdr ? (short) IFF_VNET_HDR : (short) 0) - | ( props->multi_queue ? (short) NM_IFF_MULTI_QUEUE : (short) 0); - if (ioctl (fd, TUNSETIFF, &ifr)) - return FALSE; - - if (props->owner_valid) { - if (ioctl (fd, TUNSETOWNER, (uid_t) props->owner)) - return FALSE; - } - - if (props->group_valid) { - if (ioctl (fd, TUNSETGROUP, (gid_t) props->group)) - return FALSE; - } - - if (props->persist) { - if (ioctl (fd, TUNSETPERSIST, 1)) - return FALSE; - } - - do_request_link (platform, 0, name); - obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform), - 0, name, FALSE, - NM_LINK_TYPE_TUN, - NULL, NULL); - - if (!obj) - return FALSE; - - NM_SET_OUT (out_link, &obj->link); - NM_SET_OUT (out_fd, nm_steal_fd (&fd)); - return TRUE; -} - -static gboolean link_vxlan_add (NMPlatform *platform, const char *name, const NMPlatformLnkVxlan *props, @@ -5888,6 +5854,64 @@ link_vlan_change (NMPlatform *platform, return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; } +static int +tun_add (NMPlatform *platform, const char *name, gboolean tap, + gint64 owner, gint64 group, gboolean pi, gboolean vnet_hdr, + gboolean multi_queue, const NMPlatformLink **out_link) +{ + const NMPObject *obj; + struct ifreq ifr = { }; + int fd; + + fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC); + if (fd < 0) + return FALSE; + + nm_utils_ifname_cpy (ifr.ifr_name, name); + ifr.ifr_flags = tap ? IFF_TAP : IFF_TUN; + + if (!pi) + ifr.ifr_flags |= IFF_NO_PI; + if (vnet_hdr) + ifr.ifr_flags |= IFF_VNET_HDR; + if (multi_queue) + ifr.ifr_flags |= NM_IFF_MULTI_QUEUE; + + if (ioctl (fd, TUNSETIFF, &ifr)) { + nm_close (fd); + return FALSE; + } + + if (owner >= 0 && owner < G_MAXINT32) { + if (ioctl (fd, TUNSETOWNER, (uid_t) owner)) { + nm_close (fd); + return FALSE; + } + } + + if (group >= 0 && group < G_MAXINT32) { + if (ioctl (fd, TUNSETGROUP, (gid_t) group)) { + nm_close (fd); + return FALSE; + } + } + + if (ioctl (fd, TUNSETPERSIST, 1)) { + nm_close (fd); + return FALSE; + } + do_request_link (platform, 0, name); + obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform), + 0, name, FALSE, + tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, + NULL, NULL); + if (out_link) + *out_link = obj ? &obj->link : NULL; + + nm_close (fd); + return !!obj; +} + static gboolean link_enslave (NMPlatform *platform, int master, int slave) { @@ -6429,7 +6453,7 @@ ip_route_get (NMPlatform *platform, } seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - nle = _nl_send_nlmsghdr (platform, &req.n, &seq_result, NULL, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, &route); + nle = _nl_send_nlmsghdr (platform, &req.n, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, &route); if (nle < 0) { _LOGE ("get-route: failure sending netlink request \"%s\" (%d)", g_strerror (-nle), -nle); @@ -6468,7 +6492,6 @@ qdisc_add (NMPlatform *platform, const NMPlatformQdisc *qdisc) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -6477,7 +6500,7 @@ qdisc_add (NMPlatform *platform, event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, msg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-qdisc: failed sending netlink request \"%s\" (%d)", nl_geterror (nle), -nle); @@ -6492,7 +6515,7 @@ qdisc_add (NMPlatform *platform, ? LOGL_DEBUG : LOGL_WARN, "do-add-qdisc: %s", - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return NM_PLATFORM_ERROR_SUCCESS; @@ -6508,7 +6531,6 @@ tfilter_add (NMPlatform *platform, const NMPlatformTfilter *tfilter) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char *errmsg = NULL; int nle; char s_buf[256]; nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -6517,7 +6539,7 @@ tfilter_add (NMPlatform *platform, event_handler_read_netlink (platform, FALSE); - nle = _nl_send_nlmsg (platform, msg, &seq_result, &errmsg, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _nl_send_nlmsg (platform, msg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); if (nle < 0) { _LOGE ("do-add-tfilter: failed sending netlink request \"%s\" (%d)", nl_geterror (nle), -nle); @@ -6532,7 +6554,7 @@ tfilter_add (NMPlatform *platform, ? LOGL_DEBUG : LOGL_WARN, "do-add-tfilter: %s", - wait_for_nl_response_to_string (seq_result, errmsg, s_buf, sizeof (s_buf))); + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) return NM_PLATFORM_ERROR_SUCCESS; @@ -6563,12 +6585,15 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); struct nl_sock *sk = priv->nlh; - int n; - int err = 0; - gboolean multipart = 0; - gboolean interrupted = FALSE; + int n, err = 0, multipart = 0, interrupted = 0; struct nlmsghdr *hdr; WaitForNlResponseResult seq_result; + + /* + nla is passed on to not only to nl_recv() but may also be passed + to a function pointer provided by the caller which may or may not + initialize the variable. Thomas Graf. + */ struct sockaddr_nl nla = {0}; nm_auto_free struct ucred *creds = NULL; nm_auto_free unsigned char *buf = NULL; @@ -6576,28 +6601,56 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events) continue_reading: g_clear_pointer (&buf, free); g_clear_pointer (&creds, free); + errno = 0; n = nl_recv (sk, &nla, &buf, &creds); if (n <= 0) { - - if (n == -NLE_MSG_TRUNC) { - int buf_size; - - /* the message receive buffer was too small. We lost one message, which - * is unfortunate. Try to double the buffer size for the next time. */ - buf_size = nl_socket_get_msg_buf_size (sk); - if (buf_size < 512*1024) { - buf_size *= 2; - _LOGT ("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", buf_size); - if (nl_socket_set_msg_buf_size (sk, buf_size) < 0) - nm_assert_not_reached (); - if (!handle_events) - goto continue_reading; - } + /* workaround libnl3 <= 3.2.15 returning danling pointers in case nl_recv() + * fails. Fixed by libnl3 69468517d0de1675d80f24661ff57a5dbac7275c. */ + buf = NULL; + creds = NULL; + } + + switch (n) { + case 0: + /* Work around a libnl bug fixed in 3.2.22 (375a6294) */ + if (errno == EAGAIN) { + /* EAGAIN is equal to EWOULDBLOCK. If it would not be, we'd have to + * workaround libnl3 mapping EWOULDBLOCK to -NLE_FAILURE. */ + G_STATIC_ASSERT (EAGAIN == EWOULDBLOCK); + n = -NLE_AGAIN; + } + break; + case -NLE_MSG_TRUNC: { + int buf_size; + + /* the message receive buffer was too small. We lost one message, which + * is unfortunate. Try to double the buffer size for the next time. */ + buf_size = nl_socket_get_msg_buf_size (sk); + if (buf_size < 512*1024) { + buf_size *= 2; + _LOGT ("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", buf_size); + if (nl_socket_set_msg_buf_size (sk, buf_size) < 0) + nm_assert_not_reached (); + if (!handle_events) + goto continue_reading; } + n = -_NLE_MSG_TRUNC; + break; + } + case -NLE_NOMEM: + if (errno == ENOBUFS) { + /* we are very much interested in a overrun of the receive buffer. + * nl_recv() maps all kinds of errors to NLE_NOMEM, so check also + * for errno explicitly. And if so, hack our own return code to signal + * the overrun. */ + n = -_NLE_NM_NOBUFS; + } + break; + } + if (n <= 0) return n; - } hdr = (struct nlmsghdr *) buf; while (nlmsg_ok (hdr, n)) { @@ -6606,9 +6659,12 @@ continue_reading: gboolean process_valid_msg = FALSE; guint32 seq_number; char buf_nlmsghdr[400]; - const char *extack_msg = NULL; - msg = nlmsg_alloc_convert (hdr); + msg = nlmsg_convert (hdr); + if (!msg) { + err = -NLE_NOMEM; + goto out; + } nlmsg_set_proto (msg, NETLINK_ROUTE); nlmsg_set_src (msg, &nla); @@ -6623,13 +6679,13 @@ continue_reading: } _LOGt ("netlink: recvmsg: new message %s", - nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); + _nl_nlmsghdr_to_str (hdr, buf_nlmsghdr, sizeof (buf_nlmsghdr))); if (creds) nlmsg_set_creds (msg, creds); if (hdr->nlmsg_flags & NLM_F_MULTI) - multipart = TRUE; + multipart = 1; if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { /* @@ -6637,7 +6693,7 @@ continue_reading: * all messages until a NLMSG_DONE is * received and report the inconsistency. */ - interrupted = TRUE; + interrupted = 1; } /* Other side wishes to see an ack for this message */ @@ -6652,7 +6708,7 @@ continue_reading: * usually the end of a message and therefore we slip * out of the loop by default. the user may overrule * this action by skipping this packet. */ - multipart = FALSE; + multipart = 0; seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } else if (hdr->nlmsg_type == NLMSG_NOOP) { /* Message to be ignored, the default action is to @@ -6679,28 +6735,10 @@ continue_reading: } else if (e->error) { int errsv = e->error > 0 ? e->error : -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] = { - [NLMSGERR_ATTR_MSG] = { .type = NLA_STRING }, - [NLMSGERR_ATTR_OFFS] = { .type = NLA_U32 }, - }; - struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; - 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 (tb[NLMSGERR_ATTR_MSG]) - extack_msg = nla_get_string (tb[NLMSGERR_ATTR_MSG]); - } - } - /* Error message reported back from kernel. */ - _LOGD ("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", + _LOGD ("netlink: recvmsg: error message from kernel: %s (%d) for request %d", strerror (errsv), errsv, - NM_PRINT_FMT_QUOTED (extack_msg, " \"", extack_msg, "\"", ""), nlmsg_hdr (msg)->nlmsg_seq); seq_result = -errsv; } else @@ -6729,7 +6767,7 @@ continue_reading: seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } - event_seq_check (platform, seq_number, seq_result, extack_msg); + event_seq_check (platform, seq_number, seq_result); if (abort_parsing) goto stop; @@ -6749,9 +6787,9 @@ stop: * Repeat reading. */ goto continue_reading; } - +out: if (interrupted) - return -NLE_DUMP_INTR; + err = -NLE_DUMP_INTR; return err; } @@ -6762,50 +6800,46 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) { nm_auto_pop_netns NMPNetns *netns = NULL; NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int r; + int r, nle; struct pollfd pfd; gboolean any = FALSE; + gint64 now_ns; int timeout_ms; + guint i; struct { guint32 seq_number; gint64 timeout_abs_ns; - gint64 now_ns; - } next; + } data_next; - if (!nm_platform_netns_push (platform, &netns)) { - delayed_action_wait_for_nl_response_complete_all (platform, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS); + if (!nm_platform_netns_push (platform, &netns)) return FALSE; - } - for (;;) { - for (;;) { - int nle; + while (TRUE) { + + while (TRUE) { nle = event_handler_recvmsgs (platform, TRUE); if (nle < 0) { switch (nle) { - case -EAGAIN: + case -NLE_AGAIN: goto after_read; case -NLE_DUMP_INTR: _LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); break; - case -NLE_MSG_TRUNC: - case -ENOBUFS: + case -_NLE_MSG_TRUNC: + case -_NLE_NM_NOBUFS: _LOGI ("netlink: read: %s. Need to resynchronize platform cache", ({ const char *_reason = "unknown"; switch (nle) { - case -NLE_MSG_TRUNC: _reason = "message truncated"; break; - case -ENOBUFS: _reason = "too many netlink events"; break; + case -_NLE_MSG_TRUNC: _reason = "message truncated"; break; + case -_NLE_NM_NOBUFS: _reason = "too many netlink events"; break; } _reason; })); event_handler_recvmsgs (platform, FALSE); - delayed_action_wait_for_nl_response_complete_all (platform, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); - + delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | @@ -6829,23 +6863,39 @@ after_read: if (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) return any; - delayed_action_wait_for_nl_response_complete_check (platform, - WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN, - &next.seq_number, - &next.timeout_abs_ns, - &next.now_ns); + now_ns = 0; + data_next.seq_number = 0; + data_next.timeout_abs_ns = 0; + + for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) { + DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i); + + if (data->seq_result) + delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result); + else if ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) > data->timeout_abs_ns) + delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); + else { + i++; + + if ( data_next.seq_number == 0 + || data_next.timeout_abs_ns > data->timeout_abs_ns) { + data_next.seq_number = data->seq_number; + data_next.timeout_abs_ns = data->timeout_abs_ns; + } + } + } if ( !wait_for_acks || !NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) return any; - nm_assert (next.seq_number); - nm_assert (next.now_ns > 0); - nm_assert (next.timeout_abs_ns > next.now_ns); + nm_assert (data_next.seq_number); + nm_assert (data_next.timeout_abs_ns > 0); + nm_assert (now_ns > 0); - _LOGT ("netlink: read: wait for ACK for sequence number %u...", next.seq_number); + _LOGT ("netlink: read: wait for ACK for sequence number %u...", data_next.seq_number); - timeout_ms = (next.timeout_abs_ns - next.now_ns) / (NM_UTILS_NS_PER_SECOND / 1000); + timeout_ms = (data_next.timeout_abs_ns - now_ns) / (NM_UTILS_NS_PER_SECOND / 1000); memset (&pfd, 0, sizeof (pfd)); pfd.fd = nl_socket_get_fd (priv->nlh); @@ -6856,7 +6906,6 @@ after_read: /* timeout and there is nothing to read. */ goto after_read; } - if (r < 0) { int errsv = errno; @@ -6998,10 +7047,11 @@ nm_linux_platform_init (NMLinuxPlatform *self) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (self); + priv->nlh_seq_next = 1; priv->delayed_action.list_master_connected = g_ptr_array_new (); priv->delayed_action.list_refresh_link = g_ptr_array_new (); priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData)); - priv->wifi_data = g_hash_table_new_full (nm_direct_hash, NULL, NULL, (GDestroyNotify) wifi_utils_unref); + priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit); } static void @@ -7047,10 +7097,6 @@ constructed (GObject *_object) nle = nl_socket_set_buffer_size (priv->nlh, 8*1024*1024, 0); g_assert (!nle); - nle = nl_socket_set_ext_ack (priv->nlh, TRUE); - if (nle) - _LOGD ("could not enable extended acks on netlink socket"); - /* explicitly set the msg buffer size and disable MSG_PEEK. * If we later encounter NLE_MSG_TRUNC, we will adjust the buffer size. */ nl_socket_disable_msg_peek (priv->nlh); @@ -7130,8 +7176,7 @@ dispose (GObject *object) _LOGD ("dispose"); - delayed_action_wait_for_nl_response_complete_all (platform, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); + delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); priv->delayed_action.flags = DELAYED_ACTION_TYPE_NONE; g_ptr_array_set_size (priv->delayed_action.list_master_connected, 0); @@ -7181,7 +7226,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_add = link_add; platform_class->link_delete = link_delete; - platform_class->refresh_all = refresh_all; platform_class->link_refresh = link_refresh; platform_class->link_set_netns = link_set_netns; @@ -7220,6 +7264,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_vlan_change = link_vlan_change; platform_class->link_vxlan_add = link_vxlan_add; + platform_class->tun_add = tun_add; + platform_class->infiniband_partition_add = infiniband_partition_add; platform_class->infiniband_partition_delete = infiniband_partition_delete; @@ -7244,7 +7290,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_macvlan_add = link_macvlan_add; platform_class->link_ipip_add = link_ipip_add; platform_class->link_sit_add = link_sit_add; - platform_class->link_tun_add = link_tun_add; platform_class->object_delete = object_delete; platform_class->ip4_address_add = ip4_address_add; diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c deleted file mode 100644 index 4cb19780..00000000 --- a/src/platform/nm-netlink.c +++ /dev/null @@ -1,1491 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-platform.c - Handle runtime kernel networking configuration - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-netlink.h" - -#include <unistd.h> -#include <fcntl.h> - -/*****************************************************************************/ - -#ifndef SOL_NETLINK -#define SOL_NETLINK 270 -#endif - -/*****************************************************************************/ - -#define NL_SOCK_PASSCRED (1<<1) -#define NL_MSG_PEEK (1<<3) -#define NL_MSG_PEEK_EXPLICIT (1<<4) -#define NL_NO_AUTO_ACK (1<<5) - -#ifndef NETLINK_EXT_ACK -#define NETLINK_EXT_ACK 11 -#endif - -#define NL_MSG_CRED_PRESENT 1 - -struct nl_msg { - int nm_protocol; - int nm_flags; - struct sockaddr_nl nm_src; - struct sockaddr_nl nm_dst; - struct ucred nm_creds; - struct nlmsghdr * nm_nlh; - size_t nm_size; - int nm_refcnt; -}; - -struct nl_sock { - struct sockaddr_nl s_local; - struct sockaddr_nl s_peer; - int s_fd; - int s_proto; - unsigned int s_seq_next; - unsigned int s_seq_expect; - int s_flags; - size_t s_bufsize; -}; - -/*****************************************************************************/ - -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int, - NM_UTILS_LOOKUP_DEFAULT (NULL), - NM_UTILS_LOOKUP_ITEM (NLE_UNSPEC, "NLE_UNSPEC"), - NM_UTILS_LOOKUP_ITEM (NLE_BUG, "NLE_BUG"), - NM_UTILS_LOOKUP_ITEM (NLE_NATIVE_ERRNO, "NLE_NATIVE_ERRNO"), - - NM_UTILS_LOOKUP_ITEM (NLE_ATTRSIZE, "NLE_ATTRSIZE"), - NM_UTILS_LOOKUP_ITEM (NLE_BAD_SOCK, "NLE_BAD_SOCK"), - NM_UTILS_LOOKUP_ITEM (NLE_DUMP_INTR, "NLE_DUMP_INTR"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_OVERFLOW, "NLE_MSG_OVERFLOW"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_TOOSHORT, "NLE_MSG_TOOSHORT"), - NM_UTILS_LOOKUP_ITEM (NLE_MSG_TRUNC, "NLE_MSG_TRUNC"), - NM_UTILS_LOOKUP_ITEM (NLE_SEQ_MISMATCH, "NLE_SEQ_MISMATCH"), -) - -const char * -nl_geterror (int err) -{ - const char *s; - - err = nl_errno (err); - - if (err >= _NLE_BASE) { - s = _geterror (err); - if (s) - return s; - } - return g_strerror (err); -} - -/*****************************************************************************/ - -NM_UTILS_ENUM2STR_DEFINE (nl_nlmsgtype2str, int, - NM_UTILS_ENUM2STR (NLMSG_NOOP, "NOOP"), - NM_UTILS_ENUM2STR (NLMSG_ERROR, "ERROR"), - NM_UTILS_ENUM2STR (NLMSG_DONE, "DONE"), - NM_UTILS_ENUM2STR (NLMSG_OVERRUN, "OVERRUN"), -); - -NM_UTILS_FLAGS2STR_DEFINE (nl_nlmsg_flags2str, int, - NM_UTILS_FLAGS2STR (NLM_F_REQUEST, "REQUEST"), - NM_UTILS_FLAGS2STR (NLM_F_MULTI, "MULTI"), - NM_UTILS_FLAGS2STR (NLM_F_ACK, "ACK"), - NM_UTILS_FLAGS2STR (NLM_F_ECHO, "ECHO"), - NM_UTILS_FLAGS2STR (NLM_F_ROOT, "ROOT"), - NM_UTILS_FLAGS2STR (NLM_F_MATCH, "MATCH"), - NM_UTILS_FLAGS2STR (NLM_F_ATOMIC, "ATOMIC"), - NM_UTILS_FLAGS2STR (NLM_F_REPLACE, "REPLACE"), - NM_UTILS_FLAGS2STR (NLM_F_EXCL, "EXCL"), - NM_UTILS_FLAGS2STR (NLM_F_CREATE, "CREATE"), - NM_UTILS_FLAGS2STR (NLM_F_APPEND, "APPEND"), -); - -/*****************************************************************************/ - -const char * -nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len) -{ - const char *b; - const char *s; - guint flags, flags_before; - const char *prefix; - - if (!nm_utils_to_string_buffer_init_null (hdr, &buf, &len)) - return buf; - - 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; - } - - if (s) - nm_utils_strbuf_append_str (&buf, &len, s); - else - nm_utils_strbuf_append (&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); - - flags = hdr->nlmsg_flags; - - if (!flags) { - nm_utils_strbuf_append_str (&buf, &len, ", flags 0"); - goto flags_done; - } - -#define _F(f, n) \ - G_STMT_START { \ - if (NM_FLAGS_ALL (flags, f)) { \ - flags &= ~(f); \ - nm_utils_strbuf_append (&buf, &len, "%s%s", prefix, n); \ - if (!flags) \ - goto flags_done; \ - prefix = ","; \ - } \ - } G_STMT_END - - prefix = ", flags "; - flags_before = flags; - _F (NLM_F_REQUEST, "request"); - _F (NLM_F_MULTI, "multi"); - _F (NLM_F_ACK, "ack"); - _F (NLM_F_ECHO, "echo"); - _F (NLM_F_DUMP_INTR, "dump_intr"); - _F (0x20 /*NLM_F_DUMP_FILTERED*/, "dump_filtered"); - - if (flags_before != flags) - prefix = ";"; - - switch (hdr->nlmsg_type) { - case RTM_NEWLINK: - case RTM_NEWADDR: - case RTM_NEWROUTE: - case RTM_NEWQDISC: - case RTM_NEWTFILTER: - _F (NLM_F_REPLACE, "replace"); - _F (NLM_F_EXCL, "excl"); - _F (NLM_F_CREATE, "create"); - _F (NLM_F_APPEND, "append"); - break; - case RTM_GETLINK: - case RTM_GETADDR: - case RTM_GETROUTE: - case RTM_DELQDISC: - case RTM_DELTFILTER: - _F (NLM_F_DUMP, "dump"); - _F (NLM_F_ROOT, "root"); - _F (NLM_F_MATCH, "match"); - _F (NLM_F_ATOMIC, "atomic"); - break; - } - -#undef _F - - if (flags_before != flags) - prefix = ";"; - nm_utils_strbuf_append (&buf, &len, "%s0x%04x", prefix, flags); - -flags_done: - - nm_utils_strbuf_append (&buf, &len, ", seq %u", (unsigned) hdr->nlmsg_seq); - - return b; -} - -/*****************************************************************************/ - -struct nlmsghdr * -nlmsg_hdr (struct nl_msg *n) -{ - return n->nm_nlh; -} - -void * -nlmsg_reserve (struct nl_msg *n, size_t len, int pad) -{ - char *buf = (char *) n->nm_nlh; - size_t nlmsg_len = n->nm_nlh->nlmsg_len; - size_t tlen; - - if (len > n->nm_size) - return NULL; - - tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; - - if ((tlen + nlmsg_len) > n->nm_size) - return NULL; - - buf += nlmsg_len; - n->nm_nlh->nlmsg_len += tlen; - - if (tlen > len) - memset(buf + len, 0, tlen - len); - - return buf; -} - -/*****************************************************************************/ - -static int - get_default_page_size (void) -{ - static int val = 0; - int v; - - if (G_UNLIKELY (val == 0)) { - v = getpagesize (); - g_assert (v > 0); - val = v; - } - return val; -} - -struct nlattr * -nla_reserve (struct nl_msg *msg, int attrtype, int attrlen) -{ - struct nlattr *nla; - int tlen; - - if (attrlen < 0) - return NULL; - - tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen); - - if (tlen > msg->nm_size) - return NULL; - - nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh); - nla->nla_type = attrtype; - nla->nla_len = nla_attr_size(attrlen); - - if (attrlen) - memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); - msg->nm_nlh->nlmsg_len = tlen; - - return nla; -} - -struct nl_msg * -nlmsg_alloc_size (size_t len) -{ - struct nl_msg *nm; - - if (len < sizeof (struct nlmsghdr)) - len = sizeof (struct nlmsghdr); - - nm = g_slice_new0 (struct nl_msg); - - nm->nm_refcnt = 1; - nm->nm_protocol = -1; - nm->nm_size = len; - nm->nm_nlh = g_malloc0 (len); - nm->nm_nlh->nlmsg_len = nlmsg_total_size (0); - return nm; -} - -/** - * Allocate a new netlink message with the default maximum payload size. - * - * Allocates a new netlink message without any further payload. The - * maximum payload size defaults to PAGESIZE or as otherwise specified - * with nlmsg_set_default_size(). - * - * @return Newly allocated netlink message or NULL. - */ -struct nl_msg * -nlmsg_alloc (void) -{ - return nlmsg_alloc_size (get_default_page_size ()); -} - -/** - * Allocate a new netlink message with maximum payload size specified. - */ -struct nl_msg * -nlmsg_alloc_inherit (struct nlmsghdr *hdr) -{ - struct nl_msg *nm; - - nm = nlmsg_alloc (); - if (hdr) { - struct nlmsghdr *new = nm->nm_nlh; - - new->nlmsg_type = hdr->nlmsg_type; - new->nlmsg_flags = hdr->nlmsg_flags; - new->nlmsg_seq = hdr->nlmsg_seq; - new->nlmsg_pid = hdr->nlmsg_pid; - } - - return nm; -} - -struct nl_msg * -nlmsg_alloc_convert (struct nlmsghdr *hdr) -{ - struct nl_msg *nm; - - nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len)); - memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); - return nm; -} - -struct nl_msg * -nlmsg_alloc_simple (int nlmsgtype, int flags) -{ - struct nlmsghdr nlh = { - .nlmsg_type = nlmsgtype, - .nlmsg_flags = flags, - }; - - return nlmsg_alloc_inherit (&nlh); -} - -int -nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad) -{ - void *tmp; - - tmp = nlmsg_reserve (n, len, pad); - if (tmp == NULL) - return -ENOMEM; - - memcpy(tmp, data, len); - return 0; -} - -int -nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy) -{ - if (!nlmsg_valid_hdr(nlh, hdrlen)) - return -NLE_MSG_TOOSHORT; - - return nla_parse (tb, maxtype, nlmsg_attrdata(nlh, hdrlen), - nlmsg_attrlen(nlh, hdrlen), policy); -} - -struct nlmsghdr * -nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, - int type, int payload, int flags) -{ - struct nlmsghdr *nlh; - - if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) - g_return_val_if_reached (NULL); - - nlh = (struct nlmsghdr *) n->nm_nlh; - nlh->nlmsg_type = type; - nlh->nlmsg_flags = flags; - nlh->nlmsg_pid = pid; - nlh->nlmsg_seq = seq; - - if (payload > 0 && - nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) - return NULL; - - 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--; - - if (dstsize > 0) { - size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; - - memset(dst, 0, dstsize); - memcpy(dst, src, len); - } - - return srclen; -} - -int -nla_memcpy (void *dest, const struct nlattr *src, int count) -{ - int minlen; - - if (!src) - return 0; - - minlen = NM_MIN (count, (int) nla_len (src)); - memcpy(dest, nla_data(src), minlen); - - return minlen; -} - -int -nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data) -{ - struct nlattr *nla; - - nla = nla_reserve(msg, attrtype, datalen); - if (!nla) { - if (datalen < 0) - g_return_val_if_reached (-NLE_BUG); - - return -ENOMEM; - } - - if (datalen > 0) - memcpy (nla_data(nla), data, datalen); - - return 0; -} - -struct nlattr * -nla_find (const struct nlattr *head, int len, int attrtype) -{ - const struct nlattr *nla; - int rem; - - nla_for_each_attr (nla, head, len, rem) { - if (nla_type (nla) == attrtype) - return (struct nlattr*)nla; - } - - return NULL; -} - -void -nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr) -{ - ssize_t len; - - len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) attr; - if (len < 0) - g_return_if_reached (); - else if (len > 0) { - msg->nm_nlh->nlmsg_len -= len; - memset(nlmsg_tail(msg->nm_nlh), 0, len); - } -} - -struct nlattr * -nla_nest_start (struct nl_msg *msg, int attrtype) -{ - struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh); - - if (nla_put(msg, attrtype, 0, NULL) < 0) - return NULL; - - return start; -} - -static int -_nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) -{ - size_t pad, len; - - len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start; - - if ( len > USHRT_MAX - || (!keep_empty && len == NLA_HDRLEN)) { - /* - * Max nlattr size exceeded or empty nested attribute, trim the - * attribute header again - */ - nla_nest_cancel(msg, start); - - /* Return error only if nlattr size was exceeded */ - return (len == NLA_HDRLEN) ? 0 : -NLE_ATTRSIZE; - } - - start->nla_len = len; - - pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; - if (pad > 0) { - /* - * Data inside attribute does not end at a alignment boundry. - * Pad accordingly and accoun for the additional space in - * the message. nlmsg_reserve() may never fail in this situation, - * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. - */ - if (!nlmsg_reserve(msg, pad, 0)) - g_return_val_if_reached (-NLE_BUG); - } - - return 0; -} - -int -nla_nest_end (struct nl_msg *msg, struct nlattr *start) -{ - return _nest_end (msg, start, 0); -} - -static const uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = { - [NLA_U8] = sizeof (uint8_t), - [NLA_U16] = sizeof (uint16_t), - [NLA_U32] = sizeof (uint32_t), - [NLA_U64] = sizeof (uint64_t), - [NLA_STRING] = 1, - [NLA_FLAG] = 0, -}; - -static int -validate_nla (const struct nlattr *nla, int maxtype, - const struct nla_policy *policy) -{ - const struct nla_policy *pt; - unsigned int minlen = 0; - int type = nla_type(nla); - - if (type < 0 || type > maxtype) - return 0; - - pt = &policy[type]; - - if (pt->type > NLA_TYPE_MAX) - g_return_val_if_reached (-NLE_BUG); - - if (pt->minlen) - minlen = pt->minlen; - else if (pt->type != NLA_UNSPEC) - minlen = nla_attr_minlen[pt->type]; - - if (nla_len(nla) < minlen) - return -NLE_UNSPEC; - - if (pt->maxlen && nla_len(nla) > pt->maxlen) - return -NLE_UNSPEC; - - if (pt->type == NLA_STRING) { - const char *data = nla_data(nla); - if (data[nla_len(nla) - 1] != '\0') - return -NLE_UNSPEC; - } - - return 0; -} - -int -nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, - const struct nla_policy *policy) -{ - struct nlattr *nla; - int rem, err; - - memset(tb, 0, sizeof (struct nlattr *) * (maxtype + 1)); - - nla_for_each_attr(nla, head, len, rem) { - int type = nla_type(nla); - - if (type > maxtype) - continue; - - if (policy) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) - goto errout; - } - - tb[type] = nla; - } - - err = 0; -errout: - return err; -} - -/*****************************************************************************/ - -void nlmsg_free (struct nl_msg *msg) -{ - if (!msg) - return; - - if (msg->nm_refcnt < 1) - g_return_if_reached (); - - msg->nm_refcnt--; - - if (msg->nm_refcnt <= 0) { - g_free (msg->nm_nlh); - g_slice_free (struct nl_msg, msg); - } -} - -int -nlmsg_get_proto (struct nl_msg *msg) -{ - return msg->nm_protocol; -} - -void -nlmsg_set_proto (struct nl_msg *msg, int protocol) -{ - msg->nm_protocol = protocol; -} - -void -nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr) -{ - memcpy (&msg->nm_src, addr, sizeof (*addr)); -} - -struct ucred * -nlmsg_get_creds (struct nl_msg *msg) -{ - if (msg->nm_flags & NL_MSG_CRED_PRESENT) - return &msg->nm_creds; - return NULL; -} - -void -nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds) -{ - memcpy (&msg->nm_creds, creds, sizeof (*creds)); - msg->nm_flags |= NL_MSG_CRED_PRESENT; -} - -/*****************************************************************************/ - -void * -genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family, - int hdrlen, int flags, uint8_t cmd, uint8_t version) -{ - struct nlmsghdr *nlh; - struct genlmsghdr hdr = { - .cmd = cmd, - .version = version, - }; - - nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags); - if (nlh == NULL) - return NULL; - - memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr)); - - return (char *) nlmsg_data (nlh) + GENL_HDRLEN; -} - -void * -genlmsg_data (const struct genlmsghdr *gnlh) -{ - return ((unsigned char *) gnlh + GENL_HDRLEN); -} - -void * -genlmsg_user_hdr (const struct genlmsghdr *gnlh) -{ - return genlmsg_data (gnlh); -} - -struct genlmsghdr * -genlmsg_hdr (struct nlmsghdr *nlh) -{ - return nlmsg_data (nlh); -} - -void * -genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen) -{ - return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen); -} - -struct nlattr * -genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen) -{ - return genlmsg_user_data (gnlh, hdrlen); -} - -int -genlmsg_len (const struct genlmsghdr *gnlh) -{ - const struct nlmsghdr *nlh; - - nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN); - return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); -} - -int -genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen) -{ - return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen); -} - -int -genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen) -{ - struct genlmsghdr *ghdr; - - if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN)) - return 0; - - ghdr = nlmsg_data (nlh); - if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen)) - return 0; - - return 1; -} - -int -genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy) -{ - struct genlmsghdr *ghdr; - - if (!genlmsg_valid_hdr (nlh, hdrlen)) - return -NLE_MSG_TOOSHORT; - - ghdr = nlmsg_data (nlh); - return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen), - genlmsg_attrlen (ghdr, hdrlen), policy); -} - -static int -_genl_parse_getfamily (struct nl_msg *msg, void *arg) -{ - static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { - [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, - [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, - .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 nlmsghdr *nlh = nlmsg_hdr (msg); - gint32 *response_data = arg; - - if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy)) - return NL_SKIP; - - if (tb[CTRL_ATTR_FAMILY_ID]) - *response_data = nla_get_u16 (tb[CTRL_ATTR_FAMILY_ID]); - - return NL_STOP; -} - -int -genl_ctrl_resolve (struct nl_sock *sk, const char *name) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - int result = -ENOMEM; - gint32 response_data = -1; - const struct nl_cb cb = { - .valid_cb = _genl_parse_getfamily, - .valid_arg = &response_data, - }; - - msg = nlmsg_alloc (); - - if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, - 0, 0, CTRL_CMD_GETFAMILY, 1)) - goto out; - - if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0) - goto out; - - result = nl_send_auto (sk, msg); - if (result < 0) - goto out; - - result = nl_recvmsgs (sk, &cb); - if (result < 0) - goto out; - - /* If search was successful, request may be ACKed after data */ - result = nl_wait_for_ack (sk, NULL); - if (result < 0) - goto out; - - if (response_data > 0) - result = response_data; - else - result = -ENOENT; - -out: - return result; -} - -/*****************************************************************************/ - -struct nl_sock * -nl_socket_alloc (void) -{ - struct nl_sock *sk; - - sk = g_slice_new0 (struct nl_sock); - - sk->s_fd = -1; - sk->s_local.nl_family = AF_NETLINK; - sk->s_peer.nl_family = AF_NETLINK; - sk->s_seq_expect = sk->s_seq_next = time(NULL); - - return sk; -} - -void -nl_socket_free (struct nl_sock *sk) -{ - if (!sk) - return; - - if (sk->s_fd >= 0) - nm_close (sk->s_fd); - g_slice_free (struct nl_sock, sk); -} - -int -nl_socket_get_fd (const struct nl_sock *sk) -{ - return sk->s_fd; -} - -uint32_t -nl_socket_get_local_port (const struct nl_sock *sk) -{ - return sk->s_local.nl_pid; -} - -size_t -nl_socket_get_msg_buf_size (struct nl_sock *sk) -{ - return sk->s_bufsize; -} - -int -nl_socket_set_passcred (struct nl_sock *sk, int state) -{ - int err; - - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_PASSCRED, - &state, sizeof (state)); - if (err < 0) - return -nl_syserr2nlerr (errno); - - if (state) - sk->s_flags |= NL_SOCK_PASSCRED; - else - sk->s_flags &= ~NL_SOCK_PASSCRED; - - return 0; -} - -int -nl_socket_set_msg_buf_size (struct nl_sock *sk, size_t bufsize) -{ - sk->s_bufsize = bufsize; - - return 0; -} - -struct sockaddr_nl * -nlmsg_get_dst (struct nl_msg *msg) -{ - return &msg->nm_dst; -} - -int -nl_socket_set_nonblocking (const struct nl_sock *sk) -{ - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) - return -nl_syserr2nlerr (errno); - - return 0; -} - -int -nl_socket_set_buffer_size (struct nl_sock *sk, int rxbuf, int txbuf) -{ - int err; - - if (rxbuf <= 0) - rxbuf = 32768; - - if (txbuf <= 0) - txbuf = 32768; - - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_SNDBUF, - &txbuf, sizeof (txbuf)); - if (err < 0) { - return -nl_syserr2nlerr (errno); - } - - err = setsockopt (sk->s_fd, SOL_SOCKET, SO_RCVBUF, - &rxbuf, sizeof (rxbuf)); - if (err < 0) { - return -nl_syserr2nlerr (errno); - } - - return 0; -} - -int -nl_socket_add_memberships (struct nl_sock *sk, int group, ...) -{ - int err; - va_list ap; - - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - va_start(ap, group); - - while (group != 0) { - if (group < 0) { - va_end(ap); - g_return_val_if_reached (-NLE_BUG); - } - - err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, - &group, sizeof (group)); - if (err < 0) { - va_end(ap); - return -nl_syserr2nlerr (errno); - } - - group = va_arg(ap, int); - } - - va_end(ap); - - return 0; -} - -int -nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable) -{ - int err, val; - - if (sk->s_fd == -1) - return -NLE_BAD_SOCK; - - val = !!enable; - err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof (val)); - if (err < 0) - return -nl_syserr2nlerr (errno); - - return 0; -} - -void nl_socket_disable_msg_peek (struct nl_sock *sk) -{ - sk->s_flags |= NL_MSG_PEEK_EXPLICIT; - sk->s_flags &= ~NL_MSG_PEEK; -} - -int -nl_connect (struct nl_sock *sk, int protocol) -{ - int err; - socklen_t addrlen; - struct sockaddr_nl local = { 0 }; - - if (sk->s_fd != -1) - return -NLE_BAD_SOCK; - - sk->s_fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); - if (sk->s_fd < 0) { - err = -nl_syserr2nlerr (errno); - goto errout; - } - - err = nl_socket_set_buffer_size(sk, 0, 0); - if (err < 0) - goto errout; - - nm_assert (sk->s_local.nl_pid == 0); - - err = bind (sk->s_fd, (struct sockaddr*) &sk->s_local, - sizeof (sk->s_local)); - if (err != 0) { - err = -nl_syserr2nlerr (errno); - goto errout; - } - - addrlen = sizeof (local); - err = getsockname (sk->s_fd, (struct sockaddr *) &local, - &addrlen); - if (err < 0) { - err = -nl_syserr2nlerr (errno); - goto errout; - } - - if (addrlen != sizeof (local)) { - err = -NLE_UNSPEC; - goto errout; - } - - if (local.nl_family != AF_NETLINK) { - err = -NLE_UNSPEC; - goto errout; - } - - sk->s_local = local; - sk->s_proto = protocol; - - return 0; - -errout: - if (sk->s_fd != -1) { - close(sk->s_fd); - sk->s_fd = -1; - } - return err; -} - -/*****************************************************************************/ - -static void -_cb_init (struct nl_cb *dst, const struct nl_cb *src) -{ - nm_assert (dst); - - if (src) - *dst = *src; - else - memset (dst, 0, sizeof (*dst)); -} - -static int ack_wait_handler(struct nl_msg *msg, void *arg) -{ - return NL_STOP; -} - -int -nl_wait_for_ack (struct nl_sock *sk, - const struct nl_cb *cb) -{ - struct nl_cb cb2; - - _cb_init (&cb2, cb); - cb2.ack_cb = ack_wait_handler; - return nl_recvmsgs (sk, &cb2); -} - -#define NL_CB_CALL(cb, type, msg) \ -do { \ - const struct nl_cb *_cb = (cb); \ - \ - if (_cb->type##_cb) { \ - err = _cb->type##_cb ((msg), _cb->type##_arg); \ - switch (err) { \ - case NL_OK: \ - err = 0; \ - break; \ - case NL_SKIP: \ - goto skip; \ - case NL_STOP: \ - goto stop; \ - default: \ - goto out; \ - } \ - } \ -} while (0) - -int -nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb) -{ - int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0; - gs_free unsigned char *buf = NULL; - struct nlmsghdr *hdr; - struct sockaddr_nl nla = { 0 }; - gs_free struct ucred *creds = NULL; - -continue_reading: - n = nl_recv (sk, &nla, &buf, &creds); - if (n <= 0) - return n; - - hdr = (struct nlmsghdr *) buf; - while (nlmsg_ok (hdr, n)) { - nm_auto_nlmsg struct nl_msg *msg = NULL; - - msg = nlmsg_alloc_convert (hdr); - - nlmsg_set_proto (msg, sk->s_proto); - nlmsg_set_src (msg, &nla); - if (creds) - nlmsg_set_creds (msg, creds); - - nrecv++; - - /* Only do sequence checking if auto-ack mode is enabled */ - if (!(sk->s_flags & NL_NO_AUTO_ACK)) { - if (hdr->nlmsg_seq != sk->s_seq_expect) { - err = -NLE_SEQ_MISMATCH; - goto out; - } - } - - if (hdr->nlmsg_type == NLMSG_DONE || - hdr->nlmsg_type == NLMSG_ERROR || - hdr->nlmsg_type == NLMSG_NOOP || - hdr->nlmsg_type == NLMSG_OVERRUN) { - /* We can't check for !NLM_F_MULTI since some netlink - * users in the kernel are broken. */ - sk->s_seq_expect++; - } - - if (hdr->nlmsg_flags & NLM_F_MULTI) - multipart = 1; - - if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { - /* - * We have to continue reading to clear - * all messages until a NLMSG_DONE is - * received and report the inconsistency. - */ - interrupted = 1; - } - - /* messages terminates a multipart message, this is - * usually the end of a message and therefore we slip - * out of the loop by default. the user may overrule - * this action by skipping this packet. */ - if (hdr->nlmsg_type == NLMSG_DONE) { - multipart = 0; - NL_CB_CALL(cb, finish, msg); - } - - /* Message to be ignored, the default action is to - * skip this message if no callback is specified. The - * user may overrule this action by returning - * NL_PROCEED. */ - else if (hdr->nlmsg_type == NLMSG_NOOP) - goto skip; - - /* Data got lost, report back to user. The default action is to - * quit parsing. The user may overrule this action by retuning - * NL_SKIP or NL_PROCEED (dangerous) */ - else if (hdr->nlmsg_type == NLMSG_OVERRUN) { - err = -NLE_MSG_OVERFLOW; - goto out; - } - - /* Message carries a nlmsgerr */ - else if (hdr->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *e = nlmsg_data(hdr); - - if (hdr->nlmsg_len < nlmsg_size(sizeof (*e))) { - /* Truncated error message, the default action - * is to stop parsing. The user may overrule - * this action by returning NL_SKIP or - * NL_PROCEED (dangerous) */ - err = -NLE_MSG_TRUNC; - goto out; - } - if (e->error) { - /* Error message reported back from kernel. */ - if (cb->err_cb) { - err = cb->err_cb (&nla, e, - cb->err_arg); - if (err < 0) - goto out; - else if (err == NL_SKIP) - goto skip; - else if (err == NL_STOP) { - err = -e->error; - goto out; - } - } else { - err = -e->error; - goto out; - } - } else - NL_CB_CALL(cb, ack, msg); - } else { - /* Valid message (not checking for MULTIPART bit to - * get along with broken kernels. NL_SKIP has no - * effect on this. */ - NL_CB_CALL(cb, valid, msg); - } -skip: - err = 0; - hdr = nlmsg_next(hdr, &n); - } - - if (multipart) { - /* Multipart message not yet complete, continue reading */ - nm_clear_g_free (&creds); - nm_clear_g_free (&buf); - - goto continue_reading; - } - -stop: - err = 0; - -out: - if (interrupted) - err = -NLE_DUMP_INTR; - - return err ?: nrecv; -} - -int -nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) -{ - int ret; - - if (sk->s_fd < 0) - return -NLE_BAD_SOCK; - - nlmsg_set_src (msg, &sk->s_local); - - ret = sendmsg(sk->s_fd, hdr, 0); - if (ret < 0) - return -nl_syserr2nlerr (errno); - - return ret; -} - -int -nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen) -{ - struct sockaddr_nl *dst; - struct ucred *creds; - struct msghdr hdr = { - .msg_name = (void *) &sk->s_peer, - .msg_namelen = sizeof (struct sockaddr_nl), - .msg_iov = iov, - .msg_iovlen = iovlen, - }; - char buf[CMSG_SPACE(sizeof (struct ucred))]; - - /* Overwrite destination if specified in the message itself, defaults - * to the peer address of the socket. - */ - dst = nlmsg_get_dst(msg); - if (dst->nl_family == AF_NETLINK) - hdr.msg_name = dst; - - /* Add credentials if present. */ - creds = nlmsg_get_creds(msg); - if (creds != NULL) { - struct cmsghdr *cmsg; - - hdr.msg_control = buf; - hdr.msg_controllen = sizeof (buf); - - cmsg = CMSG_FIRSTHDR(&hdr); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_CREDENTIALS; - cmsg->cmsg_len = CMSG_LEN(sizeof (struct ucred)); - memcpy(CMSG_DATA(cmsg), creds, sizeof (struct ucred)); - } - - return nl_sendmsg(sk, msg, &hdr); -} - -void -nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg) -{ - struct nlmsghdr *nlh; - - nlh = nlmsg_hdr(msg); - if (nlh->nlmsg_pid == NL_AUTO_PORT) - nlh->nlmsg_pid = nl_socket_get_local_port(sk); - - if (nlh->nlmsg_seq == NL_AUTO_SEQ) - nlh->nlmsg_seq = sk->s_seq_next++; - - if (msg->nm_protocol == -1) - msg->nm_protocol = sk->s_proto; - - nlh->nlmsg_flags |= NLM_F_REQUEST; - - if (!(sk->s_flags & NL_NO_AUTO_ACK)) - nlh->nlmsg_flags |= NLM_F_ACK; -} - -int -nl_send (struct nl_sock *sk, struct nl_msg *msg) -{ - struct iovec iov = { - .iov_base = (void *) nlmsg_hdr(msg), - .iov_len = nlmsg_hdr(msg)->nlmsg_len, - }; - - return nl_send_iovec(sk, msg, &iov, 1); -} - -int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) -{ - nl_complete_msg(sk, msg); - - return nl_send(sk, msg); -} - -int -nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, - unsigned char **buf, struct ucred **creds) -{ - ssize_t n; - int flags = 0; - static int page_size = 0; - struct iovec iov; - struct msghdr msg = { - .msg_name = (void *) nla, - .msg_namelen = sizeof (struct sockaddr_nl), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - gs_free struct ucred* tmpcreds = NULL; - int retval; - - nm_assert (nla); - nm_assert (buf && !*buf); - nm_assert (!creds || !*creds); - - if ( (sk->s_flags & NL_MSG_PEEK) - || ( !(sk->s_flags & NL_MSG_PEEK_EXPLICIT) - && sk->s_bufsize == 0)) - flags |= MSG_PEEK | MSG_TRUNC; - - if (page_size == 0) - page_size = getpagesize() * 4; - - iov.iov_len = sk->s_bufsize ? : page_size; - iov.iov_base = g_malloc (iov.iov_len); - - if ( creds - && (sk->s_flags & NL_SOCK_PASSCRED)) { - msg.msg_controllen = CMSG_SPACE (sizeof (struct ucred)); - msg.msg_control = g_malloc (msg.msg_controllen); - } - -retry: - n = recvmsg(sk->s_fd, &msg, flags); - if (!n) { - retval = 0; - goto abort; - } - - if (n < 0) { - if (errno == EINTR) - goto retry; - - retval = -nl_syserr2nlerr (errno); - goto abort; - } - - if (msg.msg_flags & MSG_CTRUNC) { - if (msg.msg_controllen == 0) { - retval = -NLE_MSG_TRUNC; - goto abort; - } - - msg.msg_controllen *= 2; - msg.msg_control = g_realloc (msg.msg_control, msg.msg_controllen); - goto retry; - } - - if ( iov.iov_len < n - || (msg.msg_flags & MSG_TRUNC)) { - /* respond with error to an incomplete message */ - if (flags == 0) { - retval = -NLE_MSG_TRUNC; - goto abort; - } - - /* Provided buffer is not long enough, enlarge it - * to size of n (which should be total length of the message) - * and try again. */ - iov.iov_base = g_realloc (iov.iov_base, n); - iov.iov_len = n; - flags = 0; - goto retry; - } - - if (flags != 0) { - /* Buffer is big enough, do the actual reading */ - flags = 0; - goto retry; - } - - if (msg.msg_namelen != sizeof (struct sockaddr_nl)) { - retval = -NLE_UNSPEC; - goto abort; - } - - if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) { - struct cmsghdr *cmsg; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level != SOL_SOCKET) - continue; - if (cmsg->cmsg_type != SCM_CREDENTIALS) - continue; - tmpcreds = g_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds)); - break; - } - } - - retval = n; - -abort: - g_free (msg.msg_control); - - if (retval <= 0) { - g_free (iov.iov_base); - return retval; - } - - *buf = iov.iov_base; - NM_SET_OUT (creds, g_steal_pointer (&tmpcreds)); - return retval; -} diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h deleted file mode 100644 index c0dc09c4..00000000 --- a/src/platform/nm-netlink.h +++ /dev/null @@ -1,511 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* nm-platform.c - Handle runtime kernel networking configuration - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NM_NETLINK_H__ -#define __NM_NETLINK_H__ - -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <linux/genetlink.h> - -/*****************************************************************************/ -#define _NLE_BASE 100000 -#define NLE_UNSPEC (_NLE_BASE + 0) -#define NLE_BUG (_NLE_BASE + 1) -#define NLE_NATIVE_ERRNO (_NLE_BASE + 2) -#define NLE_SEQ_MISMATCH (_NLE_BASE + 3) -#define NLE_MSG_TRUNC (_NLE_BASE + 4) -#define NLE_MSG_TOOSHORT (_NLE_BASE + 5) -#define NLE_DUMP_INTR (_NLE_BASE + 6) -#define NLE_ATTRSIZE (_NLE_BASE + 7) -#define NLE_BAD_SOCK (_NLE_BASE + 8) -#define NLE_NOADDR (_NLE_BASE + 9) -#define NLE_MSG_OVERFLOW (_NLE_BASE + 10) - -#define _NLE_BASE_END (_NLE_BASE + 11) - -#define NLMSGERR_ATTR_UNUSED 0 -#define NLMSGERR_ATTR_MSG 1 -#define NLMSGERR_ATTR_OFFS 2 -#define NLMSGERR_ATTR_COOKIE 3 -#define NLMSGERR_ATTR_MAX 3 - -#ifndef NLM_F_ACK_TLVS -#define NLM_F_ACK_TLVS 0x200 -#endif - -static inline int -nl_errno (int err) -{ - /* the error codes from our netlink implementation are plain errno - * extended with our own error in a particular range starting from - * _NLE_BASE. - * - * However, often we encode errors as negative values. This function - * normalizes the error and returns its positive value. */ - return err >= 0 - ? err - : ((err == G_MININT) ? NLE_BUG : -errno); -} - -static inline int -nl_syserr2nlerr (int err) -{ - if (err == G_MININT) - return NLE_NATIVE_ERRNO; - if (err < 0) - err = -err; - return (err >= _NLE_BASE && err < _NLE_BASE_END) - ? NLE_NATIVE_ERRNO - : err; -} - -const char *nl_geterror (int err); - -/*****************************************************************************/ - -/* Basic attribute data types */ -enum { - NLA_UNSPEC, /* Unspecified type, binary data chunk */ - NLA_U8, /* 8 bit integer */ - NLA_U16, /* 16 bit integer */ - NLA_U32, /* 32 bit integer */ - NLA_U64, /* 64 bit integer */ - NLA_STRING, /* NUL terminated character string */ - NLA_FLAG, /* Flag */ - NLA_MSECS, /* Micro seconds (64bit) */ - NLA_NESTED, /* Nested attributes */ - NLA_NESTED_COMPAT, - NLA_NUL_STRING, - NLA_BINARY, - NLA_S8, - NLA_S16, - NLA_S32, - NLA_S64, - __NLA_TYPE_MAX, -}; - -#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) - -struct nl_msg; - -/*****************************************************************************/ - -const char *nl_nlmsgtype2str (int type, char *buf, size_t size); - -const char *nl_nlmsg_flags2str (int flags, char *buf, size_t len); - -const char *nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len); - -/*****************************************************************************/ - -struct nla_policy { - /* Type of attribute or NLA_UNSPEC */ - uint16_t type; - - /* Minimal length of payload required */ - uint16_t minlen; - - /* Maximal length of payload allowed */ - uint16_t maxlen; -}; - -/*****************************************************************************/ - -static inline int -nla_attr_size(int payload) -{ - nm_assert (payload >= 0); - - return NLA_HDRLEN + payload; -} - -static inline int -nla_total_size (int payload) -{ - return NLA_ALIGN (nla_attr_size (payload)); -} - -static inline int -nla_padlen (int payload) -{ - return nla_total_size(payload) - nla_attr_size(payload); -} - -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; -} - -static inline int -nla_type (const struct nlattr *nla) -{ - return nla->nla_type & NLA_TYPE_MASK; -} - -static inline void * -nla_data (const struct nlattr *nla) -{ - nm_assert (nla); - return (char *) nla + NLA_HDRLEN; -} - -static inline uint8_t -nla_get_u8 (const struct nlattr *nla) -{ - return *(const uint8_t *) nla_data (nla); -} - -static inline uint8_t -nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_val) -{ - nm_assert (tb); - nm_assert (attr >= 0); - - return tb[attr] ? nla_get_u8 (tb[attr]) : default_val; -} - -static inline uint16_t -nla_get_u16 (const struct nlattr *nla) -{ - return *(const uint16_t *) nla_data (nla); -} - -static inline uint32_t -nla_get_u32(const struct nlattr *nla) -{ - return *(const uint32_t *) nla_data (nla); -} - -uint64_t nla_get_u64 (const struct nlattr *nla); - -static inline char * -nla_get_string (const struct nlattr *nla) -{ - 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); - -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); -} - -#define NLA_PUT(msg, attrtype, attrlen, data) \ - do { \ - if (nla_put(msg, attrtype, attrlen, data) < 0) \ - goto nla_put_failure; \ - } while(0) - -#define NLA_PUT_TYPE(msg, type, attrtype, value) \ - do { \ - type __tmp = value; \ - NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \ - } while(0) - -#define NLA_PUT_U8(msg, attrtype, value) \ - NLA_PUT_TYPE(msg, uint8_t, attrtype, value) - -#define NLA_PUT_U16(msg, 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) - -#define NLA_PUT_U64(msg, 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) - -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 >= sizeof(*nla) && - nla->nla_len >= sizeof(*nla) && - nla->nla_len <= remaining; -} - -static inline struct nlattr * -nla_next(const struct nlattr *nla, int *remaining) -{ - int totlen = NLA_ALIGN(nla->nla_len); - - *remaining -= totlen; - return (struct nlattr *) ((char *) nla + totlen); -} - -#define nla_for_each_attr(pos, head, len, rem) \ - for (pos = head, rem = len; \ - 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))) - -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, - const struct nla_policy *policy); - -static inline int -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); -} - -/*****************************************************************************/ - -struct nl_msg *nlmsg_alloc (void); - -struct nl_msg *nlmsg_alloc_size (size_t max); - -struct nl_msg *nlmsg_alloc_inherit (struct nlmsghdr *hdr); - -struct nl_msg *nlmsg_alloc_convert (struct nlmsghdr *hdr); - -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); - -void nlmsg_free (struct nl_msg *msg); - -static inline int -nlmsg_size (int payload) -{ - nm_assert (payload >= 0 && payload < G_MAXINT - NLMSG_HDRLEN - 4); - return NLMSG_HDRLEN + payload; -} - -static inline int -nlmsg_total_size (int payload) -{ - return NLMSG_ALIGN (nlmsg_size (payload)); -} - -static inline int -nlmsg_ok (const struct nlmsghdr *nlh, int remaining) -{ - 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); - - *remaining -= totlen; - - return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); -} - -int nlmsg_get_proto (struct nl_msg *msg); -void nlmsg_set_proto (struct nl_msg *msg, int protocol); - -void nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr); - -struct ucred *nlmsg_get_creds (struct nl_msg *msg); -void nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds); - -static inline void -_nm_auto_nl_msg_cleanup (struct nl_msg **ptr) -{ - nlmsg_free (*ptr); -} -#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) - -static inline void * -nlmsg_data (const struct nlmsghdr *nlh) -{ - return (unsigned char *) nlh + NLMSG_HDRLEN; -} - -static inline void * -nlmsg_tail (const struct nlmsghdr *nlh) -{ - 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) -{ - if (nlh->nlmsg_len < nlmsg_size (hdrlen)) - return 0; - - return 1; -} - -static inline int -nlmsg_datalen (const struct nlmsghdr *nlh) -{ - return nlh->nlmsg_len - NLMSG_HDRLEN; -} - -static inline int -nlmsg_attrlen (const struct nlmsghdr *nlh, int hdrlen) -{ - return NM_MAX ((int) (nlmsg_datalen (nlh) - NLMSG_ALIGN (hdrlen)), 0); -} - -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)); -} - -static inline struct nlattr * -nlmsg_find_attr (struct nlmsghdr *nlh, int hdrlen, int attrtype) -{ - return nla_find (nlmsg_attrdata (nlh, hdrlen), - nlmsg_attrlen (nlh, hdrlen), - attrtype); -} - -int nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], - int maxtype, const struct nla_policy *policy); - -struct nlmsghdr *nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, - int type, int payload, int flags); - -/*****************************************************************************/ - -#define NL_AUTO_PORT 0 -#define NL_AUTO_SEQ 0 - -struct nl_sock; - -struct nl_sock *nl_socket_alloc (void); - -void nl_socket_free (struct nl_sock *sk); - -int nl_socket_get_fd (const struct nl_sock *sk); - -struct sockaddr_nl *nlmsg_get_dst (struct nl_msg *msg); - -size_t nl_socket_get_msg_buf_size (struct nl_sock *sk); -int nl_socket_set_msg_buf_size (struct nl_sock *sk, size_t bufsize); - -int nl_socket_set_buffer_size (struct nl_sock *sk, int rxbuf, int txbuf); - -int nl_socket_set_passcred (struct nl_sock *sk, int state); - -int nl_socket_set_nonblocking (const struct nl_sock *sk); - -void nl_socket_disable_msg_peek (struct nl_sock *sk); - -uint32_t nl_socket_get_local_port (const struct nl_sock *sk); - -int nl_socket_add_memberships (struct nl_sock *sk, int group, ...); - -int nl_connect (struct nl_sock *sk, int protocol); - -int nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, - unsigned char **buf, struct ucred **creds); - -int nl_send (struct nl_sock *sk, struct nl_msg *msg); - -int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg); - -/*****************************************************************************/ - -enum nl_cb_action { - /* Proceed with wathever would come next */ - NL_OK, - /* Skip this message */ - NL_SKIP, - /* Stop parsing altogether and discard remaining messages */ - NL_STOP, -}; - -typedef int (*nl_recvmsg_msg_cb_t) (struct nl_msg *msg, void *arg); - -typedef int (*nl_recvmsg_err_cb_t) (struct sockaddr_nl *nla, - struct nlmsgerr *nlerr, void *arg); - -struct nl_cb { - nl_recvmsg_msg_cb_t valid_cb; - void * valid_arg; - - nl_recvmsg_msg_cb_t finish_cb; - void * finish_arg; - - nl_recvmsg_msg_cb_t ack_cb; - void * ack_arg; - - nl_recvmsg_err_cb_t err_cb; - void * err_arg; -}; - -int nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr); - -int nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen); - -void nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg); - -int nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb); - -int nl_wait_for_ack (struct nl_sock *sk, - const struct nl_cb *cb); - -int nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable); - -/*****************************************************************************/ - -void *genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family, - int hdrlen, int flags, uint8_t cmd, uint8_t version); -void *genlmsg_data (const struct genlmsghdr *gnlh); -void *genlmsg_user_hdr (const struct genlmsghdr *gnlh); -struct genlmsghdr *genlmsg_hdr (struct nlmsghdr *nlh); -void *genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen); -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 genl_ctrl_resolve (struct nl_sock *sk, const char *name); - -/*****************************************************************************/ - -#endif /* __NM_NETLINK_H__ */ diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 114bf4b3..b664e8a9 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -589,8 +589,6 @@ nmp_utils_ip_config_source_coerce_to_rtprot (NMIPConfigSource source) switch (source) { case NM_IP_CONFIG_SOURCE_KERNEL: return RTPROT_KERNEL; - case NM_IP_CONFIG_SOURCE_IP6LL: - return RTPROT_KERNEL; case NM_IP_CONFIG_SOURCE_DHCP: return RTPROT_DHCP; case NM_IP_CONFIG_SOURCE_NDISC: @@ -658,7 +656,6 @@ nmp_utils_ip_config_source_to_string (NMIPConfigSource source, char *buf, gsize case NM_IP_CONFIG_SOURCE_KERNEL: s = "kernel"; break; case NM_IP_CONFIG_SOURCE_SHARED: s = "shared"; break; case NM_IP_CONFIG_SOURCE_IP4LL: s = "ipv4ll"; break; - case NM_IP_CONFIG_SOURCE_IP6LL: s = "ipv6ll"; break; case NM_IP_CONFIG_SOURCE_PPP: s = "ppp"; break; case NM_IP_CONFIG_SOURCE_WWAN: s = "wwan"; break; case NM_IP_CONFIG_SOURCE_VPN: s = "vpn"; break; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 84d862d2..c7ed90e3 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -353,45 +353,6 @@ nm_platform_process_events (NMPlatform *self) klass->process_events (self); } -const NMPlatformLink * -nm_platform_process_events_ensure_link (NMPlatform *self, - int ifindex, - const char *ifname) -{ - const NMPObject *obj; - gboolean refreshed = FALSE; - - g_return_val_if_fail (NM_IS_PLATFORM (self), NULL); - - if (ifindex <= 0 && !ifname) - return NULL; - - /* we look into the cache, whether a link for given ifindex/ifname - * exits. If not, we poll the netlink socket, maybe the event - * with the link is waiting. - * - * Then we try again to find the object. - * - * If the link is already cached the first time, we avoid polling - * the netlink socket. */ -again: - obj = nmp_cache_lookup_link_full (nm_platform_get_cache (self), - ifindex, - ifname, - FALSE, /* also invisible. We don't care here whether udev is ready */ - NM_LINK_TYPE_NONE, - NULL, NULL); - if (obj) - return NMP_OBJECT_CAST_LINK (obj); - if (!refreshed) { - refreshed = TRUE; - nm_platform_process_events (self); - goto again; - } - - return NULL; -} - /*****************************************************************************/ /** @@ -636,11 +597,11 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) * further by moving children/slaves to the end. */ g_ptr_array_sort_with_data (links, _link_get_all_presort, GINT_TO_POINTER (sort_by_name)); - unseen = g_hash_table_new (nm_direct_hash, NULL); + unseen = g_hash_table_new (g_direct_hash, g_direct_equal); for (i = 0; i < links->len; i++) { item = NMP_OBJECT_CAST_LINK (links->pdata[i]); nm_assert (item->ifindex > 0); - if (!g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL)) + if (!nm_g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL)) nm_assert_not_reached (); } @@ -1157,21 +1118,6 @@ nm_platform_link_supports_slaves (NMPlatform *self, int ifindex) } /** - * nm_platform_refresh_all: - * @self: platform instance - * @obj_type: The object type to request. - * - * Resync and re-request all objects from kernel of a certain @obj_type. - */ -void -nm_platform_refresh_all (NMPlatform *self, NMPObjectType obj_type) -{ - _CHECK_SELF_VOID (self, klass); - - klass->refresh_all (self, obj_type); -} - -/** * nm_platform_link_refresh: * @self: platform instance * @ifindex: Interface index @@ -1379,26 +1325,30 @@ gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length) { const NMPlatformLink *pllink; + gconstpointer a = NULL; + guint8 l = 0; _CHECK_SELF (self, klass, NULL); + if (length) + *length = 0; + g_return_val_if_fail (ifindex > 0, NULL); pllink = nm_platform_link_get (self, ifindex); - - if ( !pllink - || pllink->addr.len <= 0) { - NM_SET_OUT (length, 0); - return NULL; - } - - if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX) { - NM_SET_OUT (length, 0); - g_return_val_if_reached (NULL); + if (pllink && pllink->addr.len > 0) { + if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX) { + if (length) + *length = 0; + g_return_val_if_reached (NULL); + } + a = pllink->addr.data; + l = pllink->addr.len; } - NM_SET_OUT (length, pllink->addr.len); - return pllink->addr.data; + if (length) + *length = l; + return a; } /** @@ -1894,12 +1844,6 @@ nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLin return _link_get_lnk (self, ifindex, NM_LINK_TYPE_SIT, out_link); } -const NMPlatformLnkTun * -nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk (self, ifindex, NM_LINK_TYPE_TUN, out_link); -} - const NMPlatformLnkVlan * nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -2046,43 +1990,33 @@ nm_platform_link_vxlan_add (NMPlatform *self, * @vnet_hdr: whether to set the IFF_VNET_HDR flag * @multi_queue: whether to set the IFF_MULTI_QUEUE flag * @out_link: on success, the link object - * @out_fd: (allow-none): if give, return the file descriptor for the - * created device. Note that when creating a non-persistent device, - * this argument is mandatory, otherwise it makes no sense - * to create such an interface. - * The caller is responsible for closing this file descriptor. * * Create a TUN or TAP interface. */ NMPlatformError nm_platform_link_tun_add (NMPlatform *self, const char *name, - const NMPlatformLnkTun *props, - const NMPlatformLink **out_link, - int *out_fd) + gboolean tap, + gint64 owner, + gint64 group, + gboolean pi, + gboolean vnet_hdr, + gboolean multi_queue, + const NMPlatformLink **out_link) { - char b[255]; NMPlatformError plerr; _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); - g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); - g_return_val_if_fail (NM_IN_SET (props->type, IFF_TUN, IFF_TAP), NM_PLATFORM_ERROR_BUG); - - /* creating a non-persistant device requires that the caller handles - * the file descriptor. */ - g_return_val_if_fail (props->persist || out_fd, NM_PLATFORM_ERROR_BUG); - NM_SET_OUT (out_fd, -1); - - plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_TUN, out_link); + plerr = _link_add_check_existing (self, name, tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, out_link); if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("link: adding tun '%s' %s", - name, nm_platform_lnk_tun_to_string (props, b, sizeof (b))); - if (!klass->link_tun_add (self, name, props, out_link, out_fd)) + _LOGD ("link: adding %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT, + tap ? "tap" : "tun", name, owner, group); + if (!klass->tun_add (self, name, tap, owner, group, pi, vnet_hdr, multi_queue, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; return NM_PLATFORM_ERROR_SUCCESS; } @@ -2686,100 +2620,44 @@ nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_pe return TRUE; } -/** - * 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 - * - * Only recent versions of kernel export tun properties via netlink. - * So, if that's the case, then we have the NMPlatformLnkTun instance - * in the platform cache ready to return. Otherwise, this function - * falls back reading sysctl to obtain the tun properties. That - * is racy, because querying sysctl means that the object might - * be already removed from cache (while NM didn't yet process the - * netlink message). - * - * Hence, to lookup the tun properties, you always need to use this - * function, and use it with care knowing that it might obtain its - * data by reading sysctl. Note that we don't want to add this workaround - * to the platform cache itself, because the cache should (mainly) - * contain data from netlink. To access the sysctl side channel, the - * user needs to do explicitly. - * - * Returns: #TRUE, if the properties could be read. */ gboolean -nm_platform_link_tun_get_properties (NMPlatform *self, - int ifindex, - NMPlatformLnkTun *out_properties) +nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props) { - const NMPObject *plobj; - const NMPObject *pllnk; + nm_auto_close int dirfd = -1; char ifname[IFNAMSIZ]; - gint64 owner; - gint64 group; gint64 flags; - + gboolean success = TRUE; _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (props, FALSE); - /* we consider also invisible links (those that are not yet in udev). */ - plobj = nm_platform_link_get_obj (self, ifindex, FALSE); - if (!plobj) - return FALSE; - if (NMP_OBJECT_CAST_LINK (plobj)->type != NM_LINK_TYPE_TUN) - return FALSE; - - pllnk = plobj->_link.netlink.lnk; - if (pllnk) { - nm_assert (NMP_OBJECT_GET_TYPE (pllnk) == NMP_OBJECT_TYPE_LNK_TUN); - nm_assert (NMP_OBJECT_GET_CLASS (pllnk)->lnk_link_type == NM_LINK_TYPE_TUN); + memset (props, 0, sizeof (*props)); + props->owner = -1; + props->group = -1; - /* recent kernels expose tun properties via netlink and thus we have them - * in the platform cache. */ - NM_SET_OUT (out_properties, pllnk->lnk_tun); - return TRUE; - } - - /* fallback to reading sysctl. */ - { - nm_auto_close int dirfd = -1; + dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname); + if (dirfd < 0) + return FALSE; - dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname); - if (dirfd < 0) - return FALSE; + props->owner = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "owner"), 10, -1, G_MAXINT64, -1); + if (errno) + success = FALSE; - owner = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "owner"), 10, -1, G_MAXUINT32, -2); - if (owner == -2) - return FALSE; + props->group = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "group"), 10, -1, G_MAXINT64, -1); + if (errno) + success = FALSE; - group = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "group"), 10, -1, G_MAXUINT32, -2); - if (group == -2) - return FALSE; - - flags = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "tun_flags"), 16, 0, G_MAXINT64, -1); - if (flags == -1) - return FALSE; - } + flags = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "tun_flags"), 16, 0, G_MAXINT64, -1); + if (flags >= 0) { + props->mode = ((flags & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "tun" : "tap"; + props->no_pi = !!(flags & IFF_NO_PI); + props->vnet_hdr = !!(flags & IFF_VNET_HDR); + props->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE); + } else + success = FALSE; - if (out_properties) { - memset (out_properties, 0, sizeof (*out_properties)); - if (owner != -1) { - out_properties->owner_valid = TRUE; - out_properties->owner = owner; - } - if (group != -1) { - out_properties->group_valid = TRUE; - out_properties->group = group; - } - out_properties->type = (flags & TUN_TYPE_MASK); - out_properties->pi = !(flags & IFF_NO_PI); - out_properties->vnet_hdr = !!(flags & IFF_VNET_HDR); - out_properties->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE); - out_properties->persist = !!(flags & IFF_PERSIST); - } - return TRUE; + return success; } gboolean @@ -3054,7 +2932,7 @@ nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel (const NMPObject *ob * @user_data: user data for @predicate * * Returns the result of lookup in a GPtrArray. The result array contains - * references objects from the cache, its destroy function will unref them. + * references objects from the cache, it's destroy function will unref them. * * The user must unref the GPtrArray, which will also unref the NMPObject * elements. @@ -3233,68 +3111,24 @@ nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr addr } static gboolean -_addr_array_clean_expired (int addr_family, int ifindex, GPtrArray *array, guint32 now, GHashTable **idx) +array_contains_ip6_address (const GPtrArray *addresses, const NMPlatformIP6Address *address, gint32 now) { + guint len = addresses ? addresses->len : 0; guint i; - gboolean any_addrs = FALSE; - - nm_assert_addr_family (addr_family); - nm_assert (ifindex > 0); - nm_assert (now > 0); - if (!array) - return FALSE; - - /* remove all addresses that are already expired. */ - for (i = 0; i < array->len; i++) { - const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS (array->pdata[i]); - -#if NM_MORE_ASSERTS > 10 - nm_assert (a); - nm_assert (a->ifindex == ifindex); - { - const NMPObject *o = NMP_OBJECT_UP_CAST (a); - guint j; - - nm_assert (NMP_OBJECT_GET_CLASS (o)->addr_family == addr_family); - for (j = i + 1; j < array->len; j++) { - const NMPObject *o2 = array->pdata[j]; - - nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_GET_TYPE (o2)); - nm_assert (!nmp_object_id_equal (o, o2)); - } - } -#endif - - if ( addr_family == AF_INET6 - && NM_FLAGS_HAS (a->n_ifa_flags, IFA_F_TEMPORARY)) { - /* temporary addresses are never added explicitly by NetworkManager but - * kernel adds them via mngtempaddr flag. - * - * We drop them from this list. */ - goto clear_and_next; - } + for (i = 0; i < len; i++) { + NMPlatformIP6Address *candidate = NMP_OBJECT_CAST_IP6_ADDRESS (addresses->pdata[i]); - if (!nm_utils_lifetime_get (a->timestamp, a->lifetime, a->preferred, - now, NULL)) - goto clear_and_next; + if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) { + guint32 lifetime, preferred; - if (idx) { - if (G_UNLIKELY (!*idx)) { - *idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal); - } - if (!g_hash_table_add (*idx, (gpointer) NMP_OBJECT_UP_CAST (a))) - nm_assert_not_reached (); + if (nm_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, + now, &lifetime, &preferred)) + return TRUE; } - any_addrs = TRUE; - continue; - -clear_and_next: - nmp_object_unref (g_steal_pointer (&array->pdata[i])); } - return any_addrs; + return FALSE; } static gboolean @@ -3345,7 +3179,7 @@ ip4_addr_subnets_build_index (const GPtrArray *addresses, nm_assert (addresses && addresses->len); - subnets = g_hash_table_new (nm_direct_hash, NULL); + subnets = g_hash_table_new (NULL, NULL); /* Build a hash table of all addresses per subnet */ for (i = 0; i < addresses->len; i++) { @@ -3478,8 +3312,39 @@ nm_platform_ip4_address_sync (NMPlatform *self, _CHECK_SELF (self, klass, FALSE); - if (!_addr_array_clean_expired (AF_INET, ifindex, known_addresses, now, &known_addresses_idx)) - known_addresses = NULL; + if (known_addresses) { + /* remove all addresses that are already expired. */ + for (i = 0; i < known_addresses->len; i++) { + const NMPObject *o; + + o = known_addresses->pdata[i]; + nm_assert (o); + + known_address = NMP_OBJECT_CAST_IP4_ADDRESS (known_addresses->pdata[i]); + + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) + goto delete_and_next; + + if (G_UNLIKELY (!known_addresses_idx)) { + known_addresses_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal); + } + if (!nm_g_hash_table_insert (known_addresses_idx, (gpointer) o, (gpointer) o)) { + /* duplicate? Keep only the first instance. */ + goto delete_and_next; + } + + continue; +delete_and_next: + nmp_object_unref (o); + known_addresses->pdata[i] = NULL; + } + + if ( !known_addresses_idx + || g_hash_table_size (known_addresses_idx) == 0) + known_addresses = NULL; + } plat_addresses = nm_platform_lookup_clone (self, nmp_lookup_init_object (&lookup, @@ -3576,9 +3441,8 @@ nm_platform_ip4_address_sync (NMPlatform *self, known_address = NMP_OBJECT_CAST_IP4_ADDRESS (o); - lifetime = nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, - now, &preferred); - if (!lifetime) + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) goto delete_and_next2; if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, @@ -3600,15 +3464,9 @@ delete_and_next2: * nm_platform_ip6_address_sync: * @self: platform instance * @ifindex: Interface index - * @known_addresses: List of addresses. The list will be modified and only - * addresses that were successfully added will be kept in the list. - * That means, expired addresses and addresses that could not be added - * will be dropped. - * Hence, the input argument @known_addresses is also an output argument - * telling which addresses were succesfully added. - * Addresses are removed by unrefing the instance via nmp_object_unref() - * and leaving a NULL tombstone. - * @full_sync: Also remove link-local and temporary addresses. + * @known_addresses: List of IPv6 addresses, as NMPObject. The list + * is not modified. + * @keep_link_local: Don't remove link-local address * * A convenience function to synchronize addresses for a specific interface * with the least possible disturbance. It simply removes addresses that are @@ -3619,117 +3477,32 @@ delete_and_next2: gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, - GPtrArray *known_addresses, - gboolean full_sync) + const GPtrArray *known_addresses, + gboolean keep_link_local) { gs_unref_ptrarray GPtrArray *plat_addresses = NULL; + NMPlatformIP6Address *address; gint32 now = nm_utils_get_monotonic_timestamp_s (); - guint i_plat, i_know; - gs_unref_hashtable GHashTable *known_addresses_idx = NULL; + guint i; NMPLookup lookup; guint32 ifa_flags; - if (!_addr_array_clean_expired (AF_INET6, ifindex, known_addresses, now, &known_addresses_idx)) - known_addresses = NULL; - - /* @plat_addresses is in decreasing priority order (highest priority addresses first), contrary to - * @known_addresses which is in increasing priority order (lowest priority addresses first). */ + /* Delete unknown addresses */ plat_addresses = nm_platform_lookup_clone (self, nmp_lookup_init_object (&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex), NULL, NULL); - if (plat_addresses) { - guint known_addresses_len; - - known_addresses_len = known_addresses ? known_addresses->len : 0; - - /* First, compare every address whether it is still a "known address", that is, whether - * to keep it or to delete it. - * - * If we don't find a matching valid address in @known_addresses, we will delete - * plat_addr. - * - * Certain addresses, like temporary addresses, are ignored by this function - * if not run with full_sync. These addresses are usually not managed by NetworkManager - * directly, or at least, they are not managed via nm_platform_ip6_address_sync(). - * Only in full_sync mode, we really want to get rid of them (usually, when we take - * the interface down). - * - * Note that we mark handled addresses by setting it to %NULL in @plat_addresses array. */ - for (i_plat = 0; i_plat < plat_addresses->len; i_plat++) { - const NMPObject *plat_obj = plat_addresses->pdata[i_plat]; - const NMPObject *know_obj; - const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS (plat_obj); - - if (NM_FLAGS_HAS (plat_addr->n_ifa_flags, IFA_F_TEMPORARY)) { - if (!full_sync) { - /* just mark as handled, without actually deleting the address. */ - goto clear_and_next; - } - } else if (known_addresses_idx) { - know_obj = g_hash_table_lookup (known_addresses_idx, plat_obj); - if ( know_obj - && plat_addr->plen == NMP_OBJECT_CAST_IP6_ADDRESS (know_obj)->plen) { - /* technically, plen is not part of the ID for IPv6 addresses and thus - * @plat_addr is essentially the same address as @know_addr (regrading - * its identity, not its other attributes). - * However, we cannot modify an existing addresses' plen without - * removing and readding it. Thus, only keep plat_addr, if the plen - * matches. - * - * keep this one, and continue */ - continue; - } - } - - nm_platform_ip6_address_delete (self, ifindex, plat_addr->address, plat_addr->plen); -clear_and_next: - nmp_object_unref (g_steal_pointer (&plat_addresses->pdata[i_plat])); - } + for (i = 0; i < plat_addresses->len; i++) { + address = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[i]); - /* Next, we must preserve the priority of the routes. That is, source address - * selection will choose addresses in the order as they are reported by kernel. - * Note that the order in @plat_addresses of the remaining matches is highest - * priority first. - * We need to compare this to the order in @known_addresses (which has lowest - * priority first). - * - * If we find a first discrepancy, we need to delete all remaining addresses - * from that point on, because below we must re-add all the addresses in the - * right order to get their priority right. */ - i_plat = plat_addresses->len; - i_know = 0; - while (i_plat > 0) { - const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[--i_plat]); - - if (!plat_addr) + /* Leave link local address management to the kernel */ + if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address)) continue; - for (; i_know < known_addresses_len; i_know++) { - const NMPlatformIP6Address *know_addr = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i_know]); - - if (!know_addr) - continue; - - if (IN6_ARE_ADDR_EQUAL (&plat_addr->address, &know_addr->address)) { - /* we have a match. Mark address as handled. */ - i_know++; - goto next_plat; - } - - /* all remainging addresses need to be removed as well, so that we can - * re-add them in the correct order. Signal that, by setting @i_know - * so that the next @i_plat iteration, we won't enter the loop and - * delete the address right away */ - i_know = known_addresses_len; - break; - } - - nm_platform_ip6_address_delete (self, ifindex, plat_addr->address, plat_addr->plen); -next_plat: - ; + if (!array_contains_ip6_address (known_addresses, address, now)) + nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen); } } @@ -3740,18 +3513,19 @@ next_plat: ? IFA_F_NOPREFIXROUTE : 0; - /* Add missing addresses. New addresses are added by kernel with top - * priority. - */ - for (i_know = 0; i_know < known_addresses->len; i_know++) { - const NMPlatformIP6Address *known_address = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i_know]); + /* Add missing addresses */ + for (i = 0; i < known_addresses->len; i++) { + const NMPlatformIP6Address *known_address = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i]); guint32 lifetime, preferred; - if (!known_address) + if (NM_FLAGS_HAS (known_address->n_ifa_flags, IFA_F_TEMPORARY)) { + /* Kernel manages these */ continue; + } - lifetime = nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, - now, &preferred); + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) + continue; if (!nm_platform_ip6_address_add (self, ifindex, known_address->address, known_address->plen, known_address->peer_address, @@ -3779,7 +3553,7 @@ nm_platform_ip_address_flush (NMPlatform *self, if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) success &= nm_platform_ip4_address_sync (self, ifindex, NULL); if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) - success &= nm_platform_ip6_address_sync (self, ifindex, NULL, TRUE); + success &= nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE); return success; } @@ -3918,8 +3692,7 @@ nm_platform_ip_route_sync (NMPlatform *self, for (i_type = 0; routes && i_type < 2; i_type++) { for (i = 0; i < routes->len; i++) { - NMPlatformError plerr, plerr2; - gboolean gateway_route_added = FALSE; + NMPlatformError plerr; conf_o = routes->pdata[i]; @@ -3939,7 +3712,7 @@ nm_platform_ip_route_sync (NMPlatform *self, routes_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash, (GEqualFunc) nmp_object_id_equal); } - if (!g_hash_table_insert (routes_idx, (gpointer) conf_o, (gpointer) conf_o)) { + if (!nm_g_hash_table_insert (routes_idx, (gpointer) conf_o, (gpointer) conf_o)) { _LOGD ("route-sync: skip adding duplicate route %s", nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1))); continue; @@ -3965,7 +3738,6 @@ nm_platform_ip_route_sync (NMPlatform *self, } } -sync_route_add: plerr = nm_platform_ip_route_add (self, NMP_NLM_FLAG_APPEND | NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE, @@ -3990,11 +3762,6 @@ sync_route_add: nmp_object_to_string (plat_entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf2, sizeof (sbuf2))); } } - } else if (NMP_OBJECT_CAST_IP_ROUTE (conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) { - _LOGD ("route-sync: ignore failure to add IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)), - nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err))); } else if ( -((int) plerr) == EINVAL && out_temporary_not_available && _err_inval_due_to_ipv6_tentative_pref_src (self, conf_o)) { @@ -4004,66 +3771,25 @@ sync_route_add: if (!*out_temporary_not_available) *out_temporary_not_available = g_ptr_array_new_full (0, (GDestroyNotify) nmp_object_unref); g_ptr_array_add (*out_temporary_not_available, (gpointer) nmp_object_ref (conf_o)); - } else if ( !gateway_route_added - && ( ( -((int) plerr) == ENETUNREACH - && vt->is_ip4 - && !!NMP_OBJECT_CAST_IP4_ROUTE (conf_o)->gateway) - || ( -((int) plerr) == EHOSTUNREACH - && !vt->is_ip4 - && !IN6_IS_ADDR_UNSPECIFIED (&NMP_OBJECT_CAST_IP6_ROUTE (conf_o)->gateway)))) { - NMPObject oo; - - if (vt->is_ip4) { - const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (conf_o); - - nmp_object_stackinit (&oo, - NMP_OBJECT_TYPE_IP4_ROUTE, - &((NMPlatformIP4Route) { - .network = r->gateway, - .plen = 32, - .metric = r->metric, - .rt_source = r->rt_source, - .table_coerced = r->table_coerced, - })); - } else { - const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (conf_o); - - nmp_object_stackinit (&oo, - NMP_OBJECT_TYPE_IP6_ROUTE, - &((NMPlatformIP6Route) { - .network = r->gateway, - .plen = 128, - .metric = r->metric, - .rt_source = r->rt_source, - .table_coerced = r->table_coerced, - })); - } - - _LOGD ("route-sync: failure to add IPv%c route: %s: %s; try adding direct route to gateway %s", + } else if (NMP_OBJECT_CAST_IP_ROUTE (conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) { + _LOGD ("route-sync: ignore failure to add IPv%c route: %s: %s", vt->is_ip4 ? '4' : '6', nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)), - nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err)), - nmp_object_to_string (&oo, NMP_OBJECT_TO_STRING_PUBLIC, sbuf2, sizeof (sbuf2))); - - plerr2 = nm_platform_ip_route_add (self, - NMP_NLM_FLAG_APPEND - | NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE, - &oo); - - if (plerr2 != NM_PLATFORM_ERROR_SUCCESS) { - _LOGD ("route-sync: failure to add gateway IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)), - nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err))); - } - - gateway_route_added = TRUE; - goto sync_route_add; + nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err))); } else { - _LOGW ("route-sync: failure to add IPv%c route: %s: %s", + const char *reason = ""; + + if ( -((int) plerr) == ENETUNREACH + && ( vt->is_ip4 + ? !!NMP_OBJECT_CAST_IP4_ROUTE (conf_o)->gateway + : !IN6_IS_ADDR_UNSPECIFIED (&NMP_OBJECT_CAST_IP6_ROUTE (conf_o)->gateway))) + reason = "; is the gateway directly reachable?"; + + _LOGW ("route-sync: failure to add IPv%c route: %s: %s%s", vt->is_ip4 ? '4' : '6', nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)), - nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err))); + nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err)), + reason); success = FALSE; } } @@ -4987,7 +4713,6 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi "%s" /* encap limit */ "%s" /* flow label */ "%s" /* proto */ - " flags 0x%x" "", nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)), nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)), @@ -4996,8 +4721,7 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi lnk->tclass == 1 ? " tclass inherit" : nm_sprintf_buf (str_tclass, " tclass 0x%x", lnk->tclass), nm_sprintf_buf (str_encap, " encap-limit %u", lnk->encap_limit), nm_sprintf_buf (str_flow, " flow-label 0x05%x", lnk->flow_label), - nm_sprintf_buf (str_proto, " proto %u", lnk->proto), - (guint) lnk->flags); + nm_sprintf_buf (str_proto, " proto %u", lnk->proto)); return buf; } @@ -5118,43 +4842,6 @@ nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len } const char * -nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len) -{ - char str_owner[50]; - char str_group[50]; - char str_type[50]; - const char *type; - - if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) - return buf; - - if (lnk->type == IFF_TUN) - type = "tun"; - else if (lnk->type == IFF_TAP) - type = "tap"; - else - type = nm_sprintf_buf (str_type, "tun type %u", (guint) lnk->type); - - g_snprintf (buf, len, - "%s" /* type */ - "%s" /* pi */ - "%s" /* vnet_hdr */ - "%s" /* multi_queue */ - "%s" /* persist */ - "%s" /* owner */ - "%s" /* group */ - "", - type, - lnk->pi ? " pi" : "", - lnk->vnet_hdr ? " vnet_hdr" : "", - lnk->multi_queue ? " multi_queue" : "", - lnk->persist ? " persist" : "", - lnk->owner_valid ? nm_sprintf_buf (str_owner, " owner %u", (guint) lnk->owner) : "", - lnk->group_valid ? nm_sprintf_buf (str_group, " group %u", (guint) lnk->group) : ""); - return buf; -} - -const char * nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len) { char *b; @@ -5356,10 +5043,10 @@ NM_UTILS_FLAGS2STR_DEFINE (nm_platform_addr_flags2str, unsigned, NM_UTILS_FLAGS2STR (IFA_F_OPTIMISTIC, "optimistic"), NM_UTILS_FLAGS2STR (IFA_F_HOMEADDRESS, "homeaddress"), NM_UTILS_FLAGS2STR (IFA_F_DEPRECATED, "deprecated"), + NM_UTILS_FLAGS2STR (IFA_F_TENTATIVE, "tentative"), NM_UTILS_FLAGS2STR (IFA_F_PERMANENT, "permanent"), NM_UTILS_FLAGS2STR (IFA_F_MANAGETEMPADDR, "mngtmpaddr"), NM_UTILS_FLAGS2STR (IFA_F_NOPREFIXROUTE, "noprefixroute"), - NM_UTILS_FLAGS2STR (IFA_F_TENTATIVE, "tentative"), ); NM_UTILS_ENUM2STR_DEFINE (nm_platform_route_scope2str, int, @@ -5850,8 +5537,7 @@ nm_platform_lnk_ip6tnl_hash_update (const NMPlatformLnkIp6Tnl *obj, NMHashState obj->tclass, obj->encap_limit, obj->proto, - obj->flow_label, - obj->flags); + obj->flow_label); } int @@ -5866,7 +5552,6 @@ nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6 NM_CMP_FIELD (a, b, encap_limit); NM_CMP_FIELD (a, b, flow_label); NM_CMP_FIELD (a, b, proto); - NM_CMP_FIELD (a, b, flags); return 0; } @@ -5985,38 +5670,6 @@ nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b) } void -nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h) -{ - nm_hash_update_vals (h, - obj->type, - obj->owner, - obj->group, - NM_HASH_COMBINE_BOOLS (guint8, - obj->owner_valid, - obj->group_valid, - obj->pi, - obj->vnet_hdr, - obj->multi_queue, - obj->persist)); -} - -int -nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b) -{ - NM_CMP_SELF (a, b); - NM_CMP_FIELD (a, b, type); - NM_CMP_FIELD (a, b, owner); - NM_CMP_FIELD (a, b, group); - NM_CMP_FIELD_BOOL (a, b, owner_valid); - NM_CMP_FIELD_BOOL (a, b, group_valid); - NM_CMP_FIELD_BOOL (a, b, pi); - NM_CMP_FIELD_BOOL (a, b, vnet_hdr); - NM_CMP_FIELD_BOOL (a, b, multi_queue); - NM_CMP_FIELD_BOOL (a, b, persist); - return 0; -} - -void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h) { nm_hash_update_vals (h, @@ -6607,13 +6260,14 @@ nm_platform_cache_update_emit_signal (NMPlatform *self, const NMPObject *o; const NMPClass *klass; - nm_assert (NM_IN_SET ((NMPlatformSignalChangeType) cache_op, NM_PLATFORM_SIGNAL_NONE, - NM_PLATFORM_SIGNAL_ADDED, - NM_PLATFORM_SIGNAL_CHANGED, - NM_PLATFORM_SIGNAL_REMOVED)); + nm_assert (NM_IN_SET ((NMPlatformSignalChangeType) cache_op, (NMPlatformSignalChangeType) NMP_CACHE_OPS_UNCHANGED, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_SIGNAL_REMOVED)); ASSERT_nmp_cache_ops (nm_platform_get_cache (self), cache_op, obj_old, obj_new); + nm_assert (NM_IN_SET (nm_platform_netns_get (self), + NULL, + nmp_netns_get_current ())); + NMTST_ASSERT_PLATFORM_NETNS_CURRENT (self); switch (cache_op) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index e6cef63b..f6bf02bf 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -25,7 +25,6 @@ #include <linux/if.h> #include <linux/if_addr.h> #include <linux/if_link.h> -#include <linux/ip6_tunnel.h> #include "nm-dbus-interface.h" #include "nm-core-types-internal.h" @@ -33,7 +32,6 @@ #include "nm-core-utils.h" #include "nm-setting-vlan.h" #include "nm-setting-wired.h" -#include "nm-setting-ip-tunnel.h" #define NM_TYPE_PLATFORM (nm_platform_get_type ()) #define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform)) @@ -171,34 +169,6 @@ typedef enum { /*< skip >*/ NM_PLATFORM_ERROR_CANT_SET_MTU, } NMPlatformError; -typedef enum { - - /* match-flags are strictly inclusive. That means, - * by default nothing is matched, but if you enable a particular - * flag, a candidate that matches passes the check. - * - * In other words: adding more flags can only extend the result - * set of matching objects. - * - * Also, the flags form partitions. Like, an address can be either of - * ADDRTYPE_NORMAL or ADDRTYPE_LINKLOCAL, but never both. Same for - * the ADDRSTATE match types. - */ - NM_PLATFORM_MATCH_WITH_NONE = 0, - - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL = (1LL << 0), - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL = (1LL << 1), - NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY = NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL, - - NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4), - NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED, -} NMPlatformMatchFlags; - #define NM_PLATFORM_LINK_OTHER_NETNS (-1) #define __NMPlatformObject_COMMON \ @@ -284,8 +254,6 @@ struct _NMPlatformObject { __NMPlatformObject_COMMON; }; -#define NM_PLATFORM_IP_ADDRESS_CAST(address) \ - NM_CONSTCAST (NMPlatformIPAddress, (address), NMPlatformIPXAddress, NMPlatformIP4Address, NMPlatformIP6Address) #define __NMPlatformIPAddress_COMMON \ __NMPlatformObject_COMMON; \ @@ -434,7 +402,7 @@ typedef union { * do not exist from the point-of-view of platform users. * Such a route is not alive, according to nmp_object_is_alive(). * - * NOTE: currently we ignore all flags except RTM_F_CLONED + * XXX: currently we ignore all flags except RTM_F_CLONED * and RTNH_F_ONLINK for IPv4. * We also may not properly consider the flags as part of the ID * in route-cmp. */ \ @@ -636,7 +604,6 @@ typedef struct { guint8 encap_limit; guint8 proto; guint flow_label; - guint32 flags; } NMPlatformLnkIp6Tnl; typedef struct { @@ -684,21 +651,6 @@ typedef struct { } NMPlatformLnkSit; typedef struct { - guint32 owner; - guint32 group; - - guint8 type; - - bool owner_valid:1; - bool group_valid:1; - - bool pi:1; - bool vnet_hdr:1; - bool multi_queue:1; - bool persist:1; -} NMPlatformLnkTun; - -typedef struct { /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ guint16 id; NMVlanFlags flags; @@ -725,6 +677,15 @@ typedef struct { bool l3miss:1; } NMPlatformLnkVxlan; +typedef struct { + gint64 owner; + gint64 group; + const char *mode; + bool no_pi:1; + bool vnet_hdr:1; + bool multi_queue:1; +} NMPlatformTunProperties; + typedef enum { NM_PLATFORM_LINK_DUPLEX_UNKNOWN, NM_PLATFORM_LINK_DUPLEX_HALF, @@ -753,8 +714,6 @@ typedef struct { gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value); char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path); - void (*refresh_all) (NMPlatform *self, NMPObjectType obj_type); - gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type, @@ -850,15 +809,12 @@ typedef struct { const NMPlatformLnkSit *props, const NMPlatformLink **out_link); - gboolean (*link_tun_add) (NMPlatform *platform, - const char *name, - const NMPlatformLnkTun *props, - const NMPlatformLink **out_link, - int *out_fd); - gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link); gboolean (*infiniband_partition_delete) (NMPlatform *, int parent, int p_key); + gboolean (*tun_add) (NMPlatform *platform, const char *name, gboolean tap, gint64 owner, gint64 group, gboolean pi, + gboolean vnet_hdr, gboolean multi_queue, const NMPlatformLink **out_link); + gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps); gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, guint8 *bssid); GByteArray *(*wifi_get_ssid) (NMPlatform *, int ifindex); @@ -1072,8 +1028,6 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char const char *nm_platform_if_indextoname (NMPlatform *self, int ifindex, char *out_ifname/* of size IFNAMSIZ */); int nm_platform_if_nametoindex (NMPlatform *self, const char *ifname); -void nm_platform_refresh_all (NMPlatform *self, NMPObjectType obj_type); - const NMPObject *nm_platform_link_get_obj (NMPlatform *self, int ifindex, gboolean visible_only); @@ -1117,21 +1071,7 @@ gboolean nm_platform_link_is_connected (NMPlatform *self, int ifindex); gboolean nm_platform_link_uses_arp (NMPlatform *self, int ifindex); guint32 nm_platform_link_get_mtu (NMPlatform *self, int ifindex); gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex); - gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length); - -static inline GBytes * -nm_platform_link_get_address_as_bytes (NMPlatform *self, int ifindex) -{ - gconstpointer p; - gsize l; - - p = nm_platform_link_get_address (self, ifindex, &l); - return p - ? g_bytes_new (p, l) - : NULL; -} - int nm_platform_link_get_master (NMPlatform *self, int slave); gboolean nm_platform_link_can_assume (NMPlatform *self, int ifindex); @@ -1143,10 +1083,6 @@ const char *nm_platform_link_get_type_name (NMPlatform *self, int ifindex); gboolean nm_platform_link_refresh (NMPlatform *self, int ifindex); void nm_platform_process_events (NMPlatform *self); -const NMPlatformLink *nm_platform_process_events_ensure_link (NMPlatform *self, - int ifindex, - const char *ifname); - gboolean nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmware); gboolean nm_platform_link_set_down (NMPlatform *self, int ifindex); gboolean nm_platform_link_set_arp (NMPlatform *self, int ifindex); @@ -1196,7 +1132,6 @@ const NMPlatformLnkMacsec *nm_platform_link_get_lnk_macsec (NMPlatform *self, in const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkMacvtap *nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); @@ -1224,6 +1159,16 @@ NMPlatformError nm_platform_link_vxlan_add (NMPlatform *self, const NMPlatformLnkVxlan *props, const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_tun_add (NMPlatform *self, + const char *name, + gboolean tap, + gint64 owner, + gint64 group, + gboolean pi, + gboolean vnet_hdr, + gboolean multi_queue, + const NMPlatformLink **out_link); + NMPlatformError nm_platform_link_infiniband_add (NMPlatform *self, int parent, int p_key, @@ -1234,9 +1179,7 @@ NMPlatformError nm_platform_link_infiniband_delete (NMPlatform *self, gboolean nm_platform_link_infiniband_get_properties (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode); gboolean nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex); -gboolean nm_platform_link_tun_get_properties (NMPlatform *self, - int ifindex, - NMPlatformLnkTun *out_properties); +gboolean nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties); gboolean nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps); gboolean nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid); @@ -1284,11 +1227,6 @@ NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const char *name, const NMPlatformLnkSit *props, const NMPlatformLink **out_link); -NMPlatformError nm_platform_link_tun_add (NMPlatform *self, - const char *name, - const NMPlatformLnkTun *props, - const NMPlatformLink **out_link, - int *out_fd); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); @@ -1313,8 +1251,8 @@ gboolean nm_platform_ip6_address_add (NMPlatform *self, guint32 flags); gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address); gboolean nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen); -gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresses); -gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresses, gboolean full_sync); +gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresse); +gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GPtrArray *known_addresses, gboolean keep_link_local); gboolean nm_platform_ip_address_flush (NMPlatform *self, int addr_family, int ifindex); @@ -1372,7 +1310,6 @@ const char *nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char * const char *nm_platform_lnk_macsec_to_string (const NMPlatformLnkMacsec *lnk, char *buf, gsize len); const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len); -const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len); const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len); @@ -1396,7 +1333,6 @@ int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpI int nm_platform_lnk_macsec_cmp (const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b); int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b); int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b); -int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b); int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); @@ -1432,7 +1368,6 @@ void nm_platform_lnk_ipip_hash_update (const NMPlatformLnkIpIp *obj, NMHashState void nm_platform_lnk_macsec_hash_update (const NMPlatformLnkMacsec *obj, NMHashState *h); void nm_platform_lnk_macvlan_hash_update (const NMPlatformLnkMacvlan *obj, NMHashState *h); void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState *h); -void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h); void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index f1092fe9..d8561aef 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -200,8 +200,8 @@ _stack_current_ns_types (NMPNetns *netns, int ns_types) } for (i = 0; i < G_N_ELEMENTS (ns_types_check); i++) { - if ( NM_FLAGS_ANY (ns_types, ns_types_check[i]) - && NM_FLAGS_ANY (info->ns_types, ns_types_check[i])) { + if ( NM_FLAGS_HAS (ns_types, ns_types_check[i]) + && NM_FLAGS_HAS (info->ns_types, ns_types_check[i])) { res = NM_FLAGS_SET (res, ns_types_check[i]); ns_types = NM_FLAGS_UNSET (ns_types, ns_types_check[i]); } diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 29bb999b..1a9b9325 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -325,7 +325,7 @@ _vlan_xgress_qos_mappings_cmp (guint n_map, static void _vlan_xgress_qos_mappings_cpy (guint *dst_n_map, - NMVlanQosMapping **dst_map, + const NMVlanQosMapping **dst_map, guint src_n_map, const NMVlanQosMapping *src_map) { @@ -388,7 +388,7 @@ _nmp_object_fixup_link_udev_fields (NMPObject **obj_new, NMPObject *obj_orig, gb /* The link contains internal fields that are combined by * properties from netlink and udev. Update those properties */ - /* When a link is not in netlink, its udev fields don't matter. */ + /* When a link is not in netlink, it's udev fields don't matter. */ if (obj->_link.netlink.is_in_netlink) { driver = _link_get_driver (obj->_link.udev.device, obj->link.kind, @@ -532,7 +532,7 @@ _nmp_object_stackinit_from_type (NMPObject *obj, NMPObjectType obj_type) } const NMPObject * -nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, gconstpointer plobj) +nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformObject *plobj) { const NMPClass *klass = nmp_class_from_type (obj_type); @@ -865,6 +865,12 @@ _vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2) return c; } +gboolean +nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) +{ + return nmp_object_cmp (obj1, obj2) == 0; +} + /* @src is a const object, which is not entirely correct for link types, where * we increase the ref count for src->_link.udev.device. * Hence, nmp_object_copy() can violate the const promise of @src. @@ -916,11 +922,11 @@ _vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src) { dst->lnk_vlan = src->lnk_vlan; _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_ingress_qos_map, - NM_UNCONST_PPTR (NMVlanQosMapping, &dst->_lnk_vlan.ingress_qos_map), + &dst->_lnk_vlan.ingress_qos_map, src->_lnk_vlan.n_ingress_qos_map, src->_lnk_vlan.ingress_qos_map); _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_egress_qos_map, - NM_UNCONST_PPTR (NMVlanQosMapping, &dst->_lnk_vlan.egress_qos_map), + &dst->_lnk_vlan.egress_qos_map, src->_lnk_vlan.n_egress_qos_map, src->_lnk_vlan.egress_qos_map); } @@ -1082,7 +1088,7 @@ nmp_object_id_hash (const NMPObject *obj) NMHashState h; if (!obj) - return nm_hash_static (914932607u); + return 0; nm_hash_init (&h, 914932607u); nmp_object_id_hash_update (obj, &h); @@ -1526,6 +1532,8 @@ const NMPLookup * nmp_lookup_init_obj_type (NMPLookup *lookup, NMPObjectType obj_type) { + NMPObject *o; + nm_assert (lookup); switch (obj_type) { @@ -1536,7 +1544,7 @@ nmp_lookup_init_obj_type (NMPLookup *lookup, case NMP_OBJECT_TYPE_IP6_ROUTE: case NMP_OBJECT_TYPE_QDISC: case NMP_OBJECT_TYPE_TFILTER: - _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); + o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L (lookup); default: @@ -1768,54 +1776,6 @@ nmp_cache_lookup_link_full (const NMPCache *cache, /*****************************************************************************/ -static NMDedupMultiIdxMode -_obj_get_add_mode (const NMPObject *obj) -{ - /* new objects are usually appended to the list. Except for - * addresses, which are prepended during `ip address add`. - * - * Actually, for routes it is more complicated, because depending on - * `ip route append`, `ip route replace`, `ip route prepend`, the object - * will be added at the tail, at the front, or even replace an element - * in the list. However, that is handled separately by nmp_cache_update_netlink_route() - * and of no concern here. */ - if (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), - NMP_OBJECT_TYPE_IP4_ADDRESS, - NMP_OBJECT_TYPE_IP6_ADDRESS)) - return NM_DEDUP_MULTI_IDX_MODE_PREPEND; - return NM_DEDUP_MULTI_IDX_MODE_APPEND; -} - -static void -_idxcache_update_order_for_dump (NMPCache *cache, - const NMDedupMultiEntry *entry) -{ - const NMPClass *klass; - const guint8 *i_idx_type; - const NMDedupMultiEntry *entry2; - - nm_dedup_multi_entry_reorder (entry, NULL, TRUE); - - klass = NMP_OBJECT_GET_CLASS (entry->obj); - for (i_idx_type = klass->supported_cache_ids; *i_idx_type; i_idx_type++) { - NMPCacheIdType id_type = *i_idx_type; - - if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE) - continue; - - entry2 = nm_dedup_multi_index_lookup_obj (cache->multi_idx, - _idx_type_get (cache, id_type), - entry->obj); - if (!entry2) - continue; - - nm_assert (entry2 != entry); - nm_assert (entry2->obj == entry->obj); - - nm_dedup_multi_entry_reorder (entry2, NULL, TRUE); - } -} - static void _idxcache_update_other_cache_ids (NMPCache *cache, NMPCacheIdType cache_id_type, @@ -1875,7 +1835,7 @@ _idxcache_update_other_cache_ids (NMPCache *cache, obj_new, is_dump ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE - : _obj_get_add_mode (obj_new), + : NM_DEDUP_MULTI_IDX_MODE_APPEND, is_dump ? NULL : entry_order, @@ -1953,7 +1913,7 @@ _idxcache_update (NMPCache *cache, obj_new, is_dump ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE - : _obj_get_add_mode (obj_new), + : NM_DEDUP_MULTI_IDX_MODE_APPEND, NULL, entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING, NULL, @@ -2210,8 +2170,6 @@ nmp_cache_update_netlink (NMPCache *cache, } if (nmp_object_equal (obj_old, obj_hand_over)) { - if (is_dump) - _idxcache_update_order_for_dump (cache, entry_old); nm_dedup_multi_entry_set_dirty (entry_old, FALSE); NM_SET_OUT (out_obj_new, nmp_object_ref (obj_old)); return NMP_CACHE_OPS_UNCHANGED; @@ -2285,8 +2243,6 @@ nmp_cache_update_netlink_route (NMPCache *cache, } if (nmp_object_equal (entry_old->obj, obj_hand_over)) { - if (is_dump) - _idxcache_update_order_for_dump (cache, entry_old); nm_dedup_multi_entry_set_dirty (entry_old, FALSE); goto update_done; } @@ -2310,8 +2266,9 @@ update_done: * properly find @obj_replaced. */ resync_required = FALSE; entry_replace = NULL; - if (is_dump) + if (is_dump) { goto out; + } if (!entry_new) { if ( NM_FLAGS_HAS (nlmsgflags, NLM_F_REPLACE) @@ -2326,8 +2283,6 @@ update_done: goto out; } - /* FIXME: for routes, we only maintain the order correctly for the BY_WEAK_ID - * index. For all other indexes their order becomes messed up. */ entry_cur = _lookup_entry_with_idx_type (cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, entry_new->obj); @@ -2780,17 +2735,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_sit_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp, }, - [NMP_OBJECT_TYPE_LNK_TUN - 1] = { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_TUN, - .sizeof_data = sizeof (NMPObjectLnkTun), - .sizeof_public = sizeof (NMPlatformLnkTun), - .obj_type_name = "tun", - .lnk_link_type = NM_LINK_TYPE_TUN, - .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_tun_to_string, - .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_tun_hash_update, - .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_tun_cmp, - }, [NMP_OBJECT_TYPE_LNK_VLAN - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_VLAN, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index f473f462..e17b17b0 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -88,7 +88,7 @@ typedef enum { /*< skip >*/ /* Consider all the destination fields of a route, that is, the ID without the ifindex * and gateway (meaning: network/plen,metric). * The reason for this is that `ip route change` can replace an existing route - * and modify its ifindex/gateway. Effectively, that means it deletes an existing + * and modify it's ifindex/gateway. Effectively, that means it deletes an existing * route and adds a different one (as the ID of the route changes). However, it only * sends one RTM_NEWADDR notification without notifying about the deletion. We detect * that by having this index to contain overlapping routes which require special @@ -197,10 +197,6 @@ typedef struct { } NMPObjectLnkSit; typedef struct { - NMPlatformLnkTun _public; -} NMPObjectLnkTun; - -typedef struct { NMPlatformLnkVlan _public; guint n_ingress_qos_map; @@ -269,9 +265,6 @@ struct _NMPObject { NMPlatformLnkSit lnk_sit; NMPObjectLnkSit _lnk_sit; - NMPlatformLnkTun lnk_tun; - NMPObjectLnkTun _lnk_tun; - NMPlatformLnkVlan lnk_vlan; NMPObjectLnkVlan _lnk_vlan; @@ -467,8 +460,6 @@ nmp_object_ref (const NMPObject *obj) static inline void nmp_object_unref (const NMPObject *obj) { - nm_assert (!obj || NMP_OBJECT_IS_VALID (obj)); - nm_dedup_multi_obj_unref ((const NMDedupMultiObj *) obj); } @@ -490,7 +481,7 @@ nmp_object_unref (const NMPObject *obj) NMPObject *nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plob); NMPObject *nmp_object_new_link (int ifindex); -const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, gconstpointer plobj); +const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformObject *plobj); static inline NMPObject * nmp_object_stackinit_obj (NMPObject *obj, const NMPObject *src) @@ -508,13 +499,7 @@ const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifinde const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size); void nmp_object_hash_update (const NMPObject *obj, NMHashState *h); int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2); - -static inline gboolean -nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) -{ - return nmp_object_cmp (obj1, obj2) == 0; -} - +gboolean nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2); void nmp_object_copy (NMPObject *dst, const NMPObject *src, gboolean id_only); NMPObject *nmp_object_clone (const NMPObject *obj, gboolean id_only); @@ -739,16 +724,6 @@ const NMDedupMultiEntry *nm_platform_lookup_entry (NMPlatform *platform, NMPCacheIdType cache_id_type, const NMPObject *obj); -static inline const NMPObject * -nm_platform_lookup_obj (NMPlatform *platform, - NMPCacheIdType cache_id_type, - const NMPObject *obj) -{ - return nm_dedup_multi_entry_get_obj (nm_platform_lookup_entry (platform, - cache_id_type, - obj)); -} - static inline const NMDedupMultiHeadEntry * nm_platform_lookup_obj_type (NMPlatform *platform, NMPObjectType obj_type) diff --git a/src/platform/tests/meson.build b/src/platform/tests/meson.build deleted file mode 100644 index 0571efac..00000000 --- a/src/platform/tests/meson.build +++ /dev/null @@ -1,37 +0,0 @@ -test_units = [ - ['test-link-fake', 'test-link.c', 60], - ['test-link-linux', 'test-link.c', 60], - ['test-address-fake', 'test-address.c'], - ['test-address-linux', 'test-address.c'], - ['test-general', 'test-general.c'], - ['test-nmp-object', 'test-nmp-object.c'], - ['test-route-fake', 'test-route.c'], - ['test-route-linux', 'test-route.c'], - ['test-cleanup-fake', 'test-cleanup.c'], - ['test-cleanup-linux', 'test-cleanup.c'], -] - -foreach test_unit: test_units - exe = executable( - 'platform-' + test_unit[0], - test_unit[1], - dependencies: test_nm_dep, - c_args: test_cflags_platform - ) - - test( - 'platform/' + test_unit[0], - test_script, - timeout: test_unit.length() > 2 ? test_unit[2] : 30, - args: test_args + [exe.full_path()] - ) -endforeach - -test = 'monitor' - -executable( - test, - test + '.c', - dependencies: test_nm_dep, - c_args: test_cflags_platform -) diff --git a/src/platform/tests/monitor.c b/src/platform/tests/monitor.c index f0e3e6cf..e1220052 100644 --- a/src/platform/tests/monitor.c +++ b/src/platform/tests/monitor.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index ddef8853..93851ff7 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -148,7 +149,7 @@ test_ip6_address_general (void) /* Add address again (aka update) */ nmtstp_ip6_address_add (NULL, EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); - accept_signals (address_changed, 0, 2); + accept_signals (address_changed, 0, 1); /* Test address listing */ addresses = nmtstp_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index a213b31f..937cd12c 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 7885c083..d56e681e 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -23,7 +24,6 @@ #include <sched.h> #include <sys/wait.h> #include <fcntl.h> -#include <linux/if_tun.h> #include "test-common.h" @@ -628,10 +628,7 @@ nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms) const NMPlatformLink * nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 timeout_ms) { - return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, - timeout_ms - ? nm_utils_get_monotonic_timestamp_ms () + timeout_ms - : 0); + return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); } const NMPlatformLink * @@ -639,7 +636,6 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType { const NMPlatformLink *plink; gint64 now; - gboolean waited_once = FALSE; _init_platform (&platform, FALSE); @@ -651,24 +647,29 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType && (expected_link_type == NM_LINK_TYPE_NONE || plink->type == expected_link_type)) return plink; - if (until_ms == 0) { - /* don't wait, don't even poll the socket. */ - return NULL; - } - - if ( waited_once - && until_ms < now) { - /* timeout reached (+ we already waited for a signal at least once). */ + if (until_ms < now) return NULL; - } - waited_once = TRUE; - /* regardless of whether timeout is already reached, we poll the netlink - * socket a bit. */ nmtstp_wait_for_signal (platform, until_ms - now); } } +const NMPlatformLink * +nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms) +{ + return nmtstp_assert_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); +} + +const NMPlatformLink * +nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms) +{ + const NMPlatformLink *plink; + + plink = nmtstp_wait_for_link_until (platform, ifname, expected_link_type, until_ms); + g_assert (plink); + return plink; +} + /*****************************************************************************/ int @@ -1283,10 +1284,6 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, const NMPlatformLink *pllink = NULL; gboolean success; char buffer[INET6_ADDRSTRLEN]; - char encap[20]; - char tclass[20]; - gboolean encap_ignore; - gboolean tclass_inherit; g_assert (nm_utils_is_valid_iface_name (name, NULL)); @@ -1312,18 +1309,15 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, g_assert_not_reached (); } - encap_ignore = NM_FLAGS_HAS (lnk->flags, IP6_TNL_F_IGN_ENCAP_LIMIT); - tclass_inherit = NM_FLAGS_HAS (lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS); - - success = !nmtstp_run_command ("ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %s encaplimit %s flowlabel %x", + success = !nmtstp_run_command ("ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %02x encaplimit %u flowlabel %x", name, mode, dev, nm_utils_inet6_ntop (&lnk->local, NULL), nm_utils_inet6_ntop (&lnk->remote, buffer), lnk->ttl, - tclass_inherit ? "inherit" : nm_sprintf_buf (tclass, "%02x", lnk->tclass), - encap_ignore ? "none" : nm_sprintf_buf (encap, "%u", lnk->encap_limit), + lnk->tclass, + lnk->encap_limit, lnk->flow_label); if (success) pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_IP6TNL, 100); @@ -1469,70 +1463,6 @@ nmtstp_link_sit_add (NMPlatform *platform, } const NMPlatformLink * -nmtstp_link_tun_add (NMPlatform *platform, - gboolean external_command, - const char *name, - const NMPlatformLnkTun *lnk, - int *out_fd) -{ - const NMPlatformLink *pllink = NULL; - NMPlatformError plerr; - int err; - - g_assert (nm_utils_is_valid_iface_name (name, NULL)); - g_assert (lnk); - g_assert (NM_IN_SET (lnk->type, IFF_TUN, IFF_TAP)); - g_assert (!out_fd || *out_fd == -1); - - if (!lnk->persist) { - /* ip tuntap does not support non-persistent devices. - * - * Add this device only via NMPlatform. */ - if (external_command == -1) - external_command = FALSE; - } - - external_command = nmtstp_run_command_check_external (external_command); - - _init_platform (&platform, external_command); - - if (external_command) { - g_assert (lnk->persist); - - err = nmtstp_run_command ("ip tuntap add" - " mode %s" - "%s" /* user */ - "%s" /* group */ - "%s" /* pi */ - "%s" /* vnet_hdr */ - "%s" /* multi_queue */ - " name %s", - lnk->type == IFF_TUN ? "tun" : "tap", - lnk->owner_valid ? nm_sprintf_bufa (100, " user %u", (guint) lnk->owner) : "", - lnk->group_valid ? nm_sprintf_bufa (100, " group %u", (guint) lnk->group) : "", - lnk->pi ? " pi" : "", - lnk->vnet_hdr ? " vnet_hdr" : "", - lnk->multi_queue ? " multi_queue" : "", - name); - /* Older versions of iproute2 don't support adding devices. - * On failure, fallback to using platform code. */ - if (err == 0) - pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_TUN, 100); - else - g_error ("failure to add tun/tap device via ip-route"); - } else { - g_assert (lnk->persist || out_fd); - plerr = nm_platform_link_tun_add (platform, name, lnk, &pllink, out_fd); - g_assert_cmpint (plerr, ==, NM_PLATFORM_ERROR_SUCCESS); - } - - g_assert (pllink); - g_assert_cmpint (pllink->type, ==, NM_LINK_TYPE_TUN); - g_assert_cmpstr (pllink->name, ==, name); - return pllink; -} - -const NMPlatformLink * nmtstp_link_vxlan_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index bd02b0d7..fb406a3f 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -1,21 +1,3 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright 2016 - 2017 Red Hat, Inc. - */ - #include <stdlib.h> #include <unistd.h> #include <syslog.h> @@ -129,11 +111,8 @@ const NMPlatformLink *nmtstp_wait_for_link_until (NMPlatform *platform, const ch g_assert_not_reached (); \ } G_STMT_END -#define nmtstp_assert_wait_for_link(platform, ifname, expected_link_type, timeout_ms) \ - nmtst_assert_nonnull (nmtstp_wait_for_link (platform, ifname, expected_link_type, timeout_ms)) - -#define nmtstp_assert_wait_for_link_until(platform, ifname, expected_link_type, until_ms) \ - nmtst_assert_nonnull (nmtstp_wait_for_link_until (platform, ifname, expected_link_type, until_ms)) +const NMPlatformLink *nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms); +const NMPlatformLink *nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms); /*****************************************************************************/ @@ -310,11 +289,6 @@ const NMPlatformLink *nmtstp_link_sit_add (NMPlatform *platform, gboolean external_command, const char *name, const NMPlatformLnkSit *lnk); -const NMPlatformLink *nmtstp_link_tun_add (NMPlatform *platform, - gboolean external_command, - const char *name, - const NMPlatformLnkTun *lnk, - int *out_fd); const NMPlatformLink *nmtstp_link_vxlan_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index dcd600ee..ef78cc24 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -23,7 +24,6 @@ #include <sys/mount.h> #include <sys/stat.h> #include <sys/types.h> -#include <linux/if_tun.h> #include "platform/nmp-object.h" #include "platform/nmp-netns.h" @@ -698,8 +698,6 @@ test_software_detect (gconstpointer user_data) const NMPObject *lnk; guint i_step; const gboolean ext = test_data->external_command; - NMPlatformLnkTun lnk_tun; - nm_auto_close int tun_fd = -1; nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME); ifindex_parent = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; @@ -763,27 +761,13 @@ test_software_detect (gconstpointer user_data) gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_tunnel", NULL) != 0; } - switch (test_data->test_mode) { - case 0: - lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::15"); - lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::16"); - lnk_ip6tnl.parent_ifindex = ifindex_parent; - lnk_ip6tnl.tclass = 20; - lnk_ip6tnl.encap_limit = 6; - lnk_ip6tnl.flow_label = 1337; - lnk_ip6tnl.proto = IPPROTO_IPV6; - break; - case 1: - lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::17"); - lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::18"); - lnk_ip6tnl.parent_ifindex = ifindex_parent; - lnk_ip6tnl.tclass = 0; - lnk_ip6tnl.encap_limit = 0; - lnk_ip6tnl.flow_label = 1338; - lnk_ip6tnl.proto = IPPROTO_IPV6; - lnk_ip6tnl.flags = IP6_TNL_F_IGN_ENCAP_LIMIT | IP6_TNL_F_USE_ORIG_TCLASS; - break; - } + lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::15"); + lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::16"); + lnk_ip6tnl.parent_ifindex = ifindex_parent; + lnk_ip6tnl.tclass = 20; + lnk_ip6tnl.encap_limit = 6; + lnk_ip6tnl.flow_label = 1337; + lnk_ip6tnl.proto = IPPROTO_IPV6; if (!nmtstp_link_ip6tnl_add (NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { if (gracefully_skip) { @@ -895,38 +879,6 @@ test_software_detect (gconstpointer user_data) g_assert (nmtstp_link_vxlan_add (NULL, ext, DEVICE_NAME, &lnk_vxlan)); break; } - case NM_LINK_TYPE_TUN: { - gboolean owner_valid = nmtst_get_rand_bool (); - gboolean group_valid = nmtst_get_rand_bool (); - - switch (test_data->test_mode) { - case 0: - lnk_tun = (NMPlatformLnkTun) { - .type = nmtst_get_rand_bool () ? IFF_TUN : IFF_TAP, - .owner = owner_valid ? getuid () : 0, - .owner_valid = owner_valid, - .group = group_valid ? getgid () : 0, - .group_valid = group_valid, - .pi = nmtst_get_rand_bool (), - .vnet_hdr = nmtst_get_rand_bool (), - .multi_queue = nmtst_get_rand_bool (), - - /* if we add the device via iproute2 (external), we can only - * create persistent devices. */ - .persist = (ext == 1) ? TRUE : nmtst_get_rand_bool (), - }; - break; - default: - g_assert_not_reached (); - break; - } - - g_assert (nmtstp_link_tun_add (NULL, ext, DEVICE_NAME, &lnk_tun, - (!lnk_tun.persist || nmtst_get_rand_bool ()) - ? &tun_fd - : NULL)); - break; - } default: g_assert_not_reached (); } @@ -957,13 +909,7 @@ test_software_detect (gconstpointer user_data) lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, test_data->link_type, &plink); g_assert (plink); g_assert_cmpint (plink->ifindex, ==, ifindex); - - if ( !lnk - && test_data->link_type == NM_LINK_TYPE_TUN) { - /* this is ok. Kernel apparently does not support tun properties via netlink. We - * fetch them from sysfs below. */ - } else - g_assert (lnk); + g_assert (lnk); switch (test_data->link_type) { case NM_LINK_TYPE_GRE: { @@ -985,31 +931,15 @@ test_software_detect (gconstpointer user_data) case NM_LINK_TYPE_IP6TNL: { const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl; - switch (test_data->test_mode) { - case 0: - g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); - nmtst_assert_ip6_address (&plnk->local, "fd01::15"); - nmtst_assert_ip6_address (&plnk->remote, "fd01::16"); - g_assert_cmpint (plnk->ttl, ==, 0); - g_assert_cmpint (plnk->tclass, ==, 20); - g_assert_cmpint (plnk->encap_limit, ==, 6); - g_assert_cmpint (plnk->flow_label, ==, 1337); - g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6); - break; - case 1: - g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); - nmtst_assert_ip6_address (&plnk->local, "fd01::17"); - nmtst_assert_ip6_address (&plnk->remote, "fd01::18"); - g_assert_cmpint (plnk->ttl, ==, 0); - g_assert_cmpint (plnk->flow_label, ==, 1338); - g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6); - g_assert_cmpint (plnk->flags & 0xFFFF, /* ignore kernel internal flags */ - ==, - IP6_TNL_F_IGN_ENCAP_LIMIT | IP6_TNL_F_USE_ORIG_TCLASS); - break; - } + g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip6_address (&plnk->local, "fd01::15"); + nmtst_assert_ip6_address (&plnk->remote, "fd01::16"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->tclass, ==, 20); + g_assert_cmpint (plnk->encap_limit, ==, 6); + g_assert_cmpint (plnk->flow_label, ==, 1337); + g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6); break; } case NM_LINK_TYPE_IPIP: { @@ -1052,27 +982,6 @@ test_software_detect (gconstpointer user_data) g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE); break; } - case NM_LINK_TYPE_TUN: { - const NMPlatformLnkTun *plnk; - NMPlatformLnkTun lnk_tun2; - - g_assert ((lnk ? &lnk->lnk_tun : NULL) == nm_platform_link_get_lnk_tun (NM_PLATFORM_GET, ifindex, NULL)); - - /* kernel might not expose tun options via netlink. Either way, try - * to read them (either from platform cache, or fallback to sysfs). - * See also: rh#1547213. */ - if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, - ifindex, - &lnk_tun2)) - g_assert_not_reached (); - - plnk = lnk ? &lnk->lnk_tun : &lnk_tun2; - if (lnk) - g_assert (memcmp (plnk, &lnk_tun2, sizeof (NMPlatformLnkTun)) == 0); - - g_assert (nm_platform_lnk_tun_cmp (plnk, &lnk_tun) == 0); - break; - } case NM_LINK_TYPE_VLAN: { const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan; @@ -2339,7 +2248,7 @@ test_netns_push (gpointer fixture, gconstpointer test_data) p = pl_base; for (j = nstack; j >= 1; ) { j--; - if (NM_FLAGS_ANY (stack[j].ns_types, ns_type)) { + if (NM_FLAGS_HAS (stack[j].ns_types, ns_type)) { p = stack[j].pl; break; } @@ -2637,13 +2546,11 @@ _nmtstp_setup_tests (void) g_test_add_func ("/link/external", test_external); test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0); - test_software_detect_add ("/link/software/detect/ip6tnl/0", NM_LINK_TYPE_IP6TNL, 0); - test_software_detect_add ("/link/software/detect/ip6tnl/1", NM_LINK_TYPE_IP6TNL, 1); + test_software_detect_add ("/link/software/detect/ip6tnl", NM_LINK_TYPE_IP6TNL, 0); test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0); test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0); test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0); test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0); - test_software_detect_add ("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0); test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0); test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0); test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1); diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index 047d7a85..3228de83 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -54,20 +54,27 @@ test_obj_base (void) gs_unref_object GCancellable *obj_cancellable = g_cancellable_new (); nm_auto_nmpobj NMPObject *obj_link = nmp_object_new_link (10); - g_assert (&g->g_type_instance == (void *) &o->_class); - g_assert (&g->g_type_instance.g_class == (void *) &o->_class); +#define STATIC_ASSERT(cond) \ + G_STMT_START { \ + G_STATIC_ASSERT (cond); \ + G_STATIC_ASSERT_EXPR (cond); \ + g_assert (cond); \ + } G_STMT_END - g_assert (sizeof (o->parent.parent) == sizeof (GTypeInstance)); + STATIC_ASSERT (&g->g_type_instance == (void *) &o->_class); + STATIC_ASSERT (&g->g_type_instance.g_class == (void *) &o->_class); - g_assert (&c->parent == (void *) c); - g_assert (&c->parent.parent.g_type_class == (void *) c); - g_assert (&c->parent.parent.g_type == (void *) c); - g_assert (&c->parent.parent.g_type == &k->g_type); + STATIC_ASSERT (sizeof (o->parent.parent) == sizeof (GTypeInstance)); - g_assert (sizeof (c->parent.parent) == sizeof (GTypeClass)); + STATIC_ASSERT (&c->parent == (void *) c); + STATIC_ASSERT (&c->parent.parent.g_type_class == (void *) c); + STATIC_ASSERT (&c->parent.parent.g_type == (void *) c); + STATIC_ASSERT (&c->parent.parent.g_type == &k->g_type); - g_assert (&o->parent == (void *) o); - g_assert (&o->parent.klass == (void *) &o->_class); + STATIC_ASSERT (sizeof (c->parent.parent) == sizeof (GTypeClass)); + + STATIC_ASSERT (&o->parent == (void *) o); + STATIC_ASSERT (&o->parent.klass == (void *) &o->_class); obj = (NMObjBaseInst *) obj_cancellable; g_assert (!NMP_CLASS_IS_VALID ((NMPClass *) obj->klass)); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 85b14b57..13648f16 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -1,5 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* +/* NetworkManager audit support + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c index db187a1f..a5f25b02 100644 --- a/src/platform/wifi/wifi-utils-nl80211.c +++ b/src/platform/wifi/wifi-utils-nl80211.c @@ -22,17 +22,17 @@ #include "nm-default.h" -#include "wifi-utils-nl80211.h" - #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include <net/ethernet.h> #include <unistd.h> +#include <netlink/netlink.h> +#include <netlink/msg.h> #include <linux/nl80211.h> -#include "platform/nm-netlink.h" #include "wifi-utils-private.h" +#include "wifi-utils-nl80211.h" #include "platform/nm-platform.h" #include "platform/nm-platform-utils.h" #include "nm-utils.h" @@ -46,14 +46,223 @@ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } G_STMT_END +/*****************************************************************************/ + +static int +_nl_nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, + const struct nla_policy *policy) +{ + return nla_parse (tb, maxtype, head, len, (struct nla_policy *) policy); +} +#define nla_parse(...) _nl_nla_parse(__VA_ARGS__) + +static int +_nl_nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, + const struct nla_policy *policy) +{ + return nla_parse_nested (tb, maxtype, nla, (struct nla_policy *) policy); +} +#define nla_parse_nested(...) _nl_nla_parse_nested(__VA_ARGS__) + +/***************************************************************************** + * Copied from libnl3/genl: + *****************************************************************************/ + +static void * +genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family, + int hdrlen, int flags, uint8_t cmd, uint8_t version) +{ + struct nlmsghdr *nlh; + struct genlmsghdr hdr = { + .cmd = cmd, + .version = version, + }; + + nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags); + if (nlh == NULL) + return NULL; + + memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr)); + + return (char *) nlmsg_data (nlh) + GENL_HDRLEN; +} + +static void * +genlmsg_data (const struct genlmsghdr *gnlh) +{ + return ((unsigned char *) gnlh + GENL_HDRLEN); +} + +static void * +genlmsg_user_hdr (const struct genlmsghdr *gnlh) +{ + return genlmsg_data (gnlh); +} + +static struct genlmsghdr * +genlmsg_hdr (struct nlmsghdr *nlh) +{ + return nlmsg_data (nlh); +} + +static void * +genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen) +{ + return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen); +} + +static struct nlattr * +genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen) +{ + return genlmsg_user_data (gnlh, hdrlen); +} + +static int +genlmsg_len (const struct genlmsghdr *gnlh) +{ + const struct nlmsghdr *nlh; + + nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN); + return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); +} + +static int +genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen) +{ + return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen); +} + +static int +genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen) +{ + struct genlmsghdr *ghdr; + + if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN)) + return 0; + + ghdr = nlmsg_data (nlh); + if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen)) + return 0; + + return 1; +} + +static int +genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], + int maxtype, const struct nla_policy *policy) +{ + struct genlmsghdr *ghdr; + + if (!genlmsg_valid_hdr (nlh, hdrlen)) + return -NLE_MSG_TOOSHORT; + + ghdr = nlmsg_data (nlh); + return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen), + genlmsg_attrlen (ghdr, hdrlen), policy); +} + +/***************************************************************************** + * Reimplementation of libnl3/genl functions: + *****************************************************************************/ + +static int +probe_response (struct nl_msg *msg, void *arg) +{ + static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { + [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, + [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, + .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 nlmsghdr *nlh = nlmsg_hdr (msg); + gint32 *response_data = arg; + + if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy)) + return NL_SKIP; + + if (tb[CTRL_ATTR_FAMILY_ID]) + *response_data = nla_get_u16 (tb[CTRL_ATTR_FAMILY_ID]); + + return NL_STOP; +} + +static int +genl_ctrl_resolve (struct nl_sock *sk, const char *name) +{ + struct nl_msg *msg; + struct nl_cb *cb, *orig; + int rc; + int result = -NLE_OBJ_NOTFOUND; + gint32 response_data = -1; + + if (!(orig = nl_socket_get_cb (sk))) + goto out; + + cb = nl_cb_clone (orig); + nl_cb_put (orig); + if (!cb) + goto out; + + msg = nlmsg_alloc (); + if (!msg) + goto out_cb_free; + + if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, + 0, 0, CTRL_CMD_GETFAMILY, 1)) + goto out_msg_free; + + if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0) + goto out_msg_free; + + rc = nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response, &response_data); + if (rc < 0) + goto out_msg_free; + + rc = nl_send_auto_complete (sk, msg); + if (rc < 0) + goto out_msg_free; + + rc = nl_recvmsgs (sk, cb); + if (rc < 0) + goto out_msg_free; + + /* If search was successful, request may be ACKed after data */ + rc = nl_wait_for_ack (sk); + if (rc < 0) + goto out_msg_free; + + if (response_data > 0) + result = response_data; + +out_msg_free: + nlmsg_free (msg); +out_cb_free: + nl_cb_put (cb); +out: + if (result >= 0) + _LOGD (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result); + else + _LOGE (LOGD_WIFI, "genl_ctrl_resolve: failed resolve \"%s\"", name); + return result; +} + +/***************************************************************************** + * </libn-genl-3> + *****************************************************************************/ + typedef struct { WifiData parent; struct nl_sock *nl_sock; - guint32 *freqs; int id; + struct nl_cb *nl_cb; + guint32 *freqs; int num_freqs; int phy; - bool can_wowlan:1; } WifiDataNl80211; static int @@ -83,16 +292,19 @@ error_handler (struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) static struct nl_msg * _nl80211_alloc_msg (int id, int ifindex, int phy, guint32 cmd, guint32 flags) { - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; msg = nlmsg_alloc (); - genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0); - NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex); - if (phy != -1) - NLA_PUT_U32 (msg, NL80211_ATTR_WIPHY, phy); - return g_steal_pointer (&msg); + if (msg) { + genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0); + NLA_PUT_U32 (msg, NL80211_ATTR_IFINDEX, ifindex); + if (phy != -1) + NLA_PUT_U32 (msg, NL80211_ATTR_WIPHY, phy); + } + return msg; -nla_put_failure: + nla_put_failure: + nlmsg_free (msg); return NULL; } @@ -102,37 +314,42 @@ nl80211_alloc_msg (WifiDataNl80211 *nl80211, guint32 cmd, guint32 flags) return _nl80211_alloc_msg (nl80211->id, nl80211->parent.ifindex, nl80211->phy, cmd, flags); } +/* NOTE: this function consumes 'msg' */ static int _nl80211_send_and_recv (struct nl_sock *nl_sock, + struct nl_cb *nl_cb, struct nl_msg *msg, int (*valid_handler) (struct nl_msg *, void *), void *valid_data) { - int err; - int done = 0; - const struct nl_cb cb = { - .err_cb = error_handler, - .err_arg = &done, - .finish_cb = finish_handler, - .finish_arg = &done, - .ack_cb = ack_handler, - .ack_arg = &done, - .valid_cb = valid_handler, - .valid_arg = valid_data, - }; + struct nl_cb *cb; + int err, done; g_return_val_if_fail (msg != NULL, -ENOMEM); - err = nl_send_auto (nl_sock, msg); + cb = nl_cb_clone (nl_cb); + if (!cb) { + err = -ENOMEM; + goto out; + } + + err = nl_send_auto_complete (nl_sock, msg); if (err < 0) - return err; + goto out; + + done = 0; + nl_cb_err (cb, NL_CB_CUSTOM, error_handler, &done); + nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &done); + nl_cb_set (cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &done); + if (valid_handler) + nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data); /* Loop until one of our NL callbacks says we're done; on success * done will be 1, on error it will be < 0. */ while (!done) { - err = nl_recvmsgs (nl_sock, &cb); - if (err < 0 && err != -EAGAIN) { + err = nl_recvmsgs (nl_sock, cb); + if (err && err != -NLE_AGAIN) { /* Kernel scan list can change while we are dumping it, as new scan * results from H/W can arrive. BSS info is assured to be consistent * and we don't need consistent view of whole scan list. Hence do @@ -147,9 +364,12 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock, break; } } - - if (err >= 0 && done < 0) + if (err == 0 && done < 0) err = done; + + out: + nl_cb_put (cb); + nlmsg_free (msg); return err; } @@ -159,7 +379,7 @@ nl80211_send_and_recv (WifiDataNl80211 *nl80211, int (*valid_handler) (struct nl_msg *, void *), void *valid_data) { - return _nl80211_send_and_recv (nl80211->nl_sock, msg, + return _nl80211_send_and_recv (nl80211->nl_sock, nl80211->nl_cb, msg, valid_handler, valid_data); } @@ -170,6 +390,8 @@ wifi_nl80211_deinit (WifiData *parent) if (nl80211->nl_sock) nl_socket_free (nl80211->nl_sock); + if (nl80211->nl_cb) + nl_cb_put (nl80211->nl_cb); g_free (nl80211->freqs); } @@ -213,12 +435,12 @@ wifi_nl80211_get_mode (WifiData *data) struct nl80211_iface_info iface_info = { .mode = NM_802_11_MODE_UNKNOWN, }; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_INTERFACE, 0); if (nl80211_send_and_recv (nl80211, msg, nl80211_iface_info_handler, - &iface_info) < 0) + &iface_info) < 0) return NM_802_11_MODE_UNKNOWN; return iface_info.mode; @@ -228,7 +450,7 @@ static gboolean wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode) { WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; int err; msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_INTERFACE, 0); @@ -248,7 +470,7 @@ wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode) } err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); - return err >= 0; + return err ? FALSE : TRUE; nla_put_failure: nlmsg_free (msg); @@ -259,14 +481,14 @@ static gboolean wifi_nl80211_set_powersave (WifiData *data, guint32 powersave) { WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; int err; msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_POWER_SAVE, 0); NLA_PUT_U32 (msg, NL80211_ATTR_PS_STATE, powersave == 1 ? NL80211_PS_ENABLED : NL80211_PS_DISABLED); err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); - return err >= 0; + return err ? FALSE : TRUE; nla_put_failure: nlmsg_free (msg); @@ -296,7 +518,7 @@ struct nl80211_bss_info { gboolean valid; }; -#define WLAN_EID_SSID 0 +#define WLAN_EID_SSID 0 static void find_ssid (guint8 *ies, guint32 ies_len, @@ -396,7 +618,7 @@ static void nl80211_get_bss_info (WifiDataNl80211 *nl80211, struct nl80211_bss_info *bss_info) { - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; memset (bss_info, 0, sizeof (*bss_info)); @@ -520,7 +742,7 @@ static void nl80211_get_ap_info (WifiDataNl80211 *nl80211, struct nl80211_station_info *sta_info) { - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; struct nl80211_bss_info bss_info; memset (sta_info, 0, sizeof (*sta_info)); @@ -568,38 +790,35 @@ wifi_nl80211_get_qual (WifiData *data) return sta_info.signal; } +#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS static gboolean wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running) { WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; int err; msg = nl80211_alloc_msg (nl80211, - running - ? 98 /* NL80211_CMD_CRIT_PROTOCOL_START */ - : 99 /* NL80211_CMD_CRIT_PROTOCOL_STOP */, + running ? NL80211_CMD_CRIT_PROTOCOL_START : + NL80211_CMD_CRIT_PROTOCOL_STOP, 0); /* Despite the DHCP name, we're using this for any type of IP addressing, * DHCPv4, DHCPv6, and IPv6 SLAAC. */ - NLA_PUT_U16 (msg, - 179 /* NL80211_ATTR_CRIT_PROT_ID */, - 1 /* NL80211_CRIT_PROTO_DHCP */); + NLA_PUT_U16 (msg, NL80211_ATTR_CRIT_PROT_ID, NL80211_CRIT_PROTO_DHCP); if (running) { /* Give DHCP 5 seconds to complete */ - NLA_PUT_U16 (msg, - 180 /* NL80211_ATTR_MAX_CRIT_PROT_DURATION */, - 5000); + NLA_PUT_U16 (msg, NL80211_ATTR_MAX_CRIT_PROT_DURATION, 5000); } err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); - return err >= 0; + return err ? FALSE : TRUE; nla_put_failure: nlmsg_free (msg); return FALSE; } +#endif struct nl80211_wowlan_info { gboolean enabled; @@ -628,14 +847,12 @@ static gboolean wifi_nl80211_get_wowlan (WifiData *data) { WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; struct nl80211_wowlan_info info; - if (!nl80211->can_wowlan) - return FALSE; - msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0); nl80211_send_and_recv (nl80211, msg, nl80211_wowlan_handler, &info); + return info.enabled; } @@ -845,22 +1062,8 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) WifiData * wifi_nl80211_init (int ifindex) { - static const WifiDataClass klass = { - .struct_size = sizeof (WifiDataNl80211), - .get_mode = wifi_nl80211_get_mode, - .set_mode = wifi_nl80211_set_mode, - .set_powersave = wifi_nl80211_set_powersave, - .get_freq = wifi_nl80211_get_freq, - .find_freq = wifi_nl80211_find_freq, - .get_bssid = wifi_nl80211_get_bssid, - .get_rate = wifi_nl80211_get_rate, - .get_qual = wifi_nl80211_get_qual, - .get_wowlan = wifi_nl80211_get_wowlan, - .indicate_addressing_running = wifi_nl80211_indicate_addressing_running, - .deinit = wifi_nl80211_deinit, - }; WifiDataNl80211 *nl80211; - nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nl_msg *msg; struct nl80211_device_info device_info = {}; char ifname[IFNAMSIZ]; @@ -870,7 +1073,19 @@ wifi_nl80211_init (int ifindex) nm_sprintf_buf (ifname, "if %d", ifindex); } - nl80211 = wifi_data_new (&klass, ifindex); + nl80211 = wifi_data_new (ifindex, sizeof (*nl80211)); + nl80211->parent.get_mode = wifi_nl80211_get_mode; + nl80211->parent.set_mode = wifi_nl80211_set_mode; + nl80211->parent.set_powersave = wifi_nl80211_set_powersave; + nl80211->parent.get_freq = wifi_nl80211_get_freq; + nl80211->parent.find_freq = wifi_nl80211_find_freq; + nl80211->parent.get_bssid = wifi_nl80211_get_bssid; + nl80211->parent.get_rate = wifi_nl80211_get_rate; + nl80211->parent.get_qual = wifi_nl80211_get_qual; +#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS + nl80211->parent.indicate_addressing_running = wifi_nl80211_indicate_addressing_running; +#endif + nl80211->parent.deinit = wifi_nl80211_deinit; nl80211->nl_sock = nl_socket_alloc (); if (nl80211->nl_sock == NULL) @@ -880,10 +1095,12 @@ wifi_nl80211_init (int ifindex) goto error; nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211"); - if (nl80211->id < 0) { - _LOGD (LOGD_WIFI, "genl_ctrl_resolve: failed to resolve \"nl80211\""); + if (nl80211->id < 0) + goto error; + + nl80211->nl_cb = nl_cb_alloc (NL_CB_DEFAULT); + if (nl80211->nl_cb == NULL) goto error; - } nl80211->phy = -1; @@ -936,15 +1153,18 @@ wifi_nl80211_init (int ifindex) nl80211->freqs = device_info.freqs; nl80211->num_freqs = device_info.num_freqs; nl80211->parent.caps = device_info.caps; - nl80211->can_wowlan = device_info.can_wowlan; + + if (device_info.can_wowlan) + nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan; _LOGI (LOGD_PLATFORM | LOGD_WIFI, "(%s): using nl80211 for WiFi device control", ifname); + return (WifiData *) nl80211; error: - wifi_utils_unref ((WifiData *) nl80211); + wifi_utils_deinit ((WifiData *) nl80211); return NULL; } diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h index 59386514..11a0f060 100644 --- a/src/platform/wifi/wifi-utils-private.h +++ b/src/platform/wifi/wifi-utils-private.h @@ -24,8 +24,9 @@ #include "nm-dbus-interface.h" #include "wifi-utils.h" -typedef struct { - gsize struct_size; +struct WifiData { + int ifindex; + NMDeviceWifiCapabilities caps; NM80211Mode (*get_mode) (WifiData *data); @@ -65,14 +66,9 @@ typedef struct { gboolean (*set_mesh_ssid) (WifiData *data, const guint8 *ssid, gsize len); gboolean (*indicate_addressing_running) (WifiData *data, gboolean running); -} WifiDataClass; - -struct WifiData { - const WifiDataClass *klass; - int ifindex; - NMDeviceWifiCapabilities caps; }; -gpointer wifi_data_new (const WifiDataClass *klass, int ifindex); +gpointer wifi_data_new (int ifindex, gsize len); +void wifi_data_free (WifiData *data); #endif /* __WIFI_UTILS_PRIVATE_H__ */ diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c index c8744f79..c4d3c999 100644 --- a/src/platform/wifi/wifi-utils-wext.c +++ b/src/platform/wifi/wifi-utils-wext.c @@ -21,14 +21,17 @@ #include "nm-default.h" -#include "wifi-utils-wext.h" - #include <errno.h> #include <string.h> #include <sys/ioctl.h> #include <net/ethernet.h> #include <unistd.h> +#include "wifi-utils-private.h" +#include "wifi-utils-wext.h" +#include "nm-utils.h" +#include "platform/nm-platform-utils.h" + /* Hacks necessary to #include wireless.h; yay for WEXT */ #ifndef __user #define __user @@ -38,10 +41,6 @@ #include <sys/socket.h> #include <linux/wireless.h> -#include "wifi-utils-private.h" -#include "nm-utils.h" -#include "platform/nm-platform-utils.h" - typedef struct { WifiData parent; int fd; @@ -629,21 +628,6 @@ wext_get_caps (WifiDataWext *wext, const char *ifname, struct iw_range *range) WifiData * wifi_wext_init (int ifindex, gboolean check_scan) { - static const WifiDataClass klass = { - .struct_size = sizeof (WifiDataWext), - .get_mode = wifi_wext_get_mode, - .set_mode = wifi_wext_set_mode, - .set_powersave = wifi_wext_set_powersave, - .get_freq = wifi_wext_get_freq, - .find_freq = wifi_wext_find_freq, - .get_bssid = wifi_wext_get_bssid, - .get_rate = wifi_wext_get_rate, - .get_qual = wifi_wext_get_qual, - .deinit = wifi_wext_deinit, - .get_mesh_channel = wifi_wext_get_mesh_channel, - .set_mesh_channel = wifi_wext_set_mesh_channel, - .set_mesh_ssid = wifi_wext_set_mesh_ssid, - }; WifiDataWext *wext; struct iw_range range; guint32 response_len = 0; @@ -658,7 +642,19 @@ wifi_wext_init (int ifindex, gboolean check_scan) return NULL; } - wext = wifi_data_new (&klass, ifindex); + wext = wifi_data_new (ifindex, sizeof (*wext)); + wext->parent.get_mode = wifi_wext_get_mode; + wext->parent.set_mode = wifi_wext_set_mode; + wext->parent.set_powersave = wifi_wext_set_powersave; + wext->parent.get_freq = wifi_wext_get_freq; + wext->parent.find_freq = wifi_wext_find_freq; + wext->parent.get_bssid = wifi_wext_get_bssid; + wext->parent.get_rate = wifi_wext_get_rate; + wext->parent.get_qual = wifi_wext_get_qual; + wext->parent.deinit = wifi_wext_deinit; + wext->parent.get_mesh_channel = wifi_wext_get_mesh_channel; + wext->parent.set_mesh_channel = wifi_wext_set_mesh_channel; + wext->parent.set_mesh_ssid = wifi_wext_set_mesh_ssid; wext->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (wext->fd < 0) @@ -734,7 +730,7 @@ wifi_wext_init (int ifindex, gboolean check_scan) return (WifiData *) wext; error: - wifi_utils_unref ((WifiData *) wext); + wifi_utils_deinit ((WifiData *) wext); return NULL; } diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c index 8818dc9d..d0052121 100644 --- a/src/platform/wifi/wifi-utils.c +++ b/src/platform/wifi/wifi-utils.c @@ -38,19 +38,22 @@ #include "platform/nm-platform-utils.h" gpointer -wifi_data_new (const WifiDataClass *klass, int ifindex) +wifi_data_new (int ifindex, gsize len) { WifiData *data; - nm_assert (klass); - nm_assert (klass->struct_size > sizeof (WifiData)); - - data = g_malloc0 (klass->struct_size); - data->klass = klass; + data = g_malloc0 (len); data->ifindex = ifindex; return data; } +void +wifi_data_free (WifiData *data) +{ + memset (data, 0, sizeof (*data)); + g_free (data); +} + /*****************************************************************************/ WifiData * @@ -82,14 +85,14 @@ wifi_utils_get_caps (WifiData *data) { g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE); - return data->caps; + return data->caps; } NM80211Mode wifi_utils_get_mode (WifiData *data) { g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN); - return data->klass->get_mode (data); + return data->get_mode (data); } gboolean @@ -101,7 +104,7 @@ wifi_utils_set_mode (WifiData *data, const NM80211Mode mode) || (mode == NM_802_11_MODE_ADHOC), FALSE); /* nl80211 probably doesn't need this */ - return data->klass->set_mode ? data->klass->set_mode (data, mode) : TRUE; + return data->set_mode ? data->set_mode (data, mode) : TRUE; } gboolean @@ -109,14 +112,14 @@ wifi_utils_set_powersave (WifiData *data, guint32 powersave) { g_return_val_if_fail (data != NULL, FALSE); - return data->klass->set_powersave ? data->klass->set_powersave (data, powersave) : TRUE; + return data->set_powersave ? data->set_powersave (data, powersave) : TRUE; } guint32 wifi_utils_get_freq (WifiData *data) { g_return_val_if_fail (data != NULL, 0); - return data->klass->get_freq (data); + return data->get_freq (data); } guint32 @@ -124,7 +127,7 @@ wifi_utils_find_freq (WifiData *data, const guint32 *freqs) { g_return_val_if_fail (data != NULL, 0); g_return_val_if_fail (freqs != NULL, 0); - return data->klass->find_freq (data, freqs); + return data->find_freq (data, freqs); } gboolean @@ -134,40 +137,38 @@ wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid) g_return_val_if_fail (out_bssid != NULL, FALSE); memset (out_bssid, 0, ETH_ALEN); - return data->klass->get_bssid (data, out_bssid); + return data->get_bssid (data, out_bssid); } guint32 wifi_utils_get_rate (WifiData *data) { g_return_val_if_fail (data != NULL, 0); - return data->klass->get_rate (data); + return data->get_rate (data); } int wifi_utils_get_qual (WifiData *data) { g_return_val_if_fail (data != NULL, 0); - return data->klass->get_qual (data); + return data->get_qual (data); } gboolean wifi_utils_get_wowlan (WifiData *data) { g_return_val_if_fail (data != NULL, 0); - - if (!data->klass->get_wowlan) + if (!data->get_wowlan) return FALSE; - return data->klass->get_wowlan (data); + return data->get_wowlan (data); } void -wifi_utils_unref (WifiData *data) +wifi_utils_deinit (WifiData *data) { g_return_if_fail (data != NULL); - - data->klass->deinit (data); - g_free (data); + data->deinit (data); + wifi_data_free (data); } gboolean @@ -190,8 +191,8 @@ guint32 wifi_utils_get_mesh_channel (WifiData *data) { g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->klass->get_mesh_channel != NULL, FALSE); - return data->klass->get_mesh_channel (data); + g_return_val_if_fail (data->get_mesh_channel != NULL, FALSE); + return data->get_mesh_channel (data); } gboolean @@ -199,24 +200,24 @@ wifi_utils_set_mesh_channel (WifiData *data, guint32 channel) { g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (channel <= 13, FALSE); - g_return_val_if_fail (data->klass->set_mesh_channel != NULL, FALSE); - return data->klass->set_mesh_channel (data, channel); + g_return_val_if_fail (data->set_mesh_channel != NULL, FALSE); + return data->set_mesh_channel (data, channel); } gboolean wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) { g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->klass->set_mesh_ssid != NULL, FALSE); - return data->klass->set_mesh_ssid (data, ssid, len); + g_return_val_if_fail (data->set_mesh_ssid != NULL, FALSE); + return data->set_mesh_ssid (data, ssid, len); } gboolean wifi_utils_indicate_addressing_running (WifiData *data, gboolean running) { g_return_val_if_fail (data != NULL, FALSE); - if (data->klass->indicate_addressing_running) - return data->klass->indicate_addressing_running (data, running); + if (data->indicate_addressing_running) + return data->indicate_addressing_running (data, running); return FALSE; } diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h index 2633e965..705717b0 100644 --- a/src/platform/wifi/wifi-utils.h +++ b/src/platform/wifi/wifi-utils.h @@ -34,7 +34,7 @@ WifiData *wifi_utils_init (int ifindex, gboolean check_scan); int wifi_utils_get_ifindex (WifiData *data); -void wifi_utils_unref (WifiData *data); +void wifi_utils_deinit (WifiData *data); NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data); |