summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-02-18 08:13:35 +0100
committerThomas Haller <thaller@redhat.com>2021-02-24 12:48:17 +0100
commit24393744572316d4371ce2ff2c112fb6c3226448 (patch)
tree67887fd4983f5c0ef702ee534becc5f446d08629 /shared
parent39225258d6a8fb0612c4576a75ac24d572742372 (diff)
downloadNetworkManager-24393744572316d4371ce2ff2c112fb6c3226448.tar.gz
build: move "shared/nm-platform" to "src/libnm-platform"
Diffstat (limited to 'shared')
-rw-r--r--shared/meson.build21
-rw-r--r--shared/nm-platform/nm-netlink.c1518
-rw-r--r--shared/nm-platform/nm-netlink.h616
-rw-r--r--shared/nm-platform/nm-platform-utils.c1807
-rw-r--r--shared/nm-platform/nm-platform-utils.h73
-rw-r--r--shared/nm-platform/nmp-base.h94
-rw-r--r--shared/nm-platform/nmp-netns.c767
-rw-r--r--shared/nm-platform/nmp-netns.h56
-rw-r--r--shared/nm-platform/tests/meson.build17
-rw-r--r--shared/nm-platform/tests/test-nm-platform.c116
10 files changed, 0 insertions, 5085 deletions
diff --git a/shared/meson.build b/shared/meson.build
index 955d80eadb..e07c66cca3 100644
--- a/shared/meson.build
+++ b/shared/meson.build
@@ -202,27 +202,6 @@ libnm_log_null = static_library(
dependencies: glib_nm_default_dep,
)
-libnm_platform = static_library(
- 'nm-platform',
- sources: [
- 'nm-platform/nm-netlink.c',
- 'nm-platform/nm-platform-utils.c',
- 'nm-platform/nmp-netns.c',
- ],
- dependencies: [
- glib_nm_default_dep,
- ],
-)
-
-libnm_platform_dep = declare_dependency(
- include_directories: shared_inc,
- dependencies: [
- libnm_glib_aux_dep_link,
- ],
- link_with: libnm_platform,
-)
-
if enable_tests
subdir('nm-glib-aux/tests')
- subdir('nm-platform/tests')
endif
diff --git a/shared/nm-platform/nm-netlink.c b/shared/nm-platform/nm-netlink.c
deleted file mode 100644
index 7a6d7e045b..0000000000
--- a/shared/nm-platform/nm-netlink.c
+++ /dev/null
@@ -1,1518 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.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
-
-struct nl_msg {
- int nm_protocol;
- struct sockaddr_nl nm_src;
- struct sockaddr_nl nm_dst;
- struct ucred nm_creds;
- struct nlmsghdr * nm_nlh;
- size_t nm_size;
- bool nm_creds_has : 1;
-};
-
-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_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_GETLINK:
- s = "RTM_GETLINK";
- break;
- case RTM_NEWLINK:
- s = "RTM_NEWLINK";
- break;
- case RTM_DELLINK:
- s = "RTM_DELLINK";
- break;
- case RTM_SETLINK:
- s = "RTM_SETLINK";
- break;
- case RTM_GETADDR:
- s = "RTM_GETADDR";
- break;
- case RTM_NEWADDR:
- s = "RTM_NEWADDR";
- break;
- case RTM_DELADDR:
- s = "RTM_DELADDR";
- break;
- case RTM_GETROUTE:
- s = "RTM_GETROUTE";
- break;
- case RTM_NEWROUTE:
- s = "RTM_NEWROUTE";
- break;
- case RTM_DELROUTE:
- s = "RTM_DELROUTE";
- break;
- case RTM_GETRULE:
- s = "RTM_GETRULE";
- break;
- case RTM_NEWRULE:
- s = "RTM_NEWRULE";
- break;
- case RTM_DELRULE:
- s = "RTM_DELRULE";
- break;
- case RTM_GETQDISC:
- s = "RTM_GETQDISC";
- break;
- case RTM_NEWQDISC:
- s = "RTM_NEWQDISC";
- break;
- case RTM_DELQDISC:
- s = "RTM_DELQDISC";
- break;
- case RTM_GETTFILTER:
- s = "RTM_GETTFILTER";
- break;
- case RTM_NEWTFILTER:
- s = "RTM_NEWTFILTER";
- break;
- case RTM_DELTFILTER:
- s = "RTM_DELTFILTER";
- break;
- case NLMSG_NOOP:
- s = "NLMSG_NOOP";
- break;
- case NLMSG_ERROR:
- s = "NLMSG_ERROR";
- break;
- case NLMSG_DONE:
- s = "NLMSG_DONE";
- break;
- case NLMSG_OVERRUN:
- s = "NLMSG_OVERRUN";
- break;
- default:
- s = NULL;
- break;
- }
-
- if (s)
- 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;
-
- nm_assert(pad >= 0);
-
- 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;
-}
-
-/*****************************************************************************/
-
-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_new(struct nl_msg);
- *nm = (struct nl_msg){
- .nm_protocol = -1,
- .nm_size = len,
- .nm_nlh = g_malloc0(len),
- };
- nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
- return nm;
-}
-
-/**
- * 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(nm_utils_getpagesize());
-}
-
-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 nl_msg *nm;
- struct nlmsghdr *new;
-
- nm = nlmsg_alloc();
- new = nm->nm_nlh;
- new->nlmsg_type = nlmsgtype;
- new->nlmsg_flags = flags;
- return nm;
-}
-
-void
-nlmsg_free(struct nl_msg *msg)
-{
- if (!msg)
- return;
-
- g_free(msg->nm_nlh);
- g_slice_free(struct nl_msg, msg);
-}
-
-/*****************************************************************************/
-
-int
-nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad)
-{
- void *tmp;
-
- nm_assert(n);
- nm_assert(data);
- nm_assert(len > 0);
- nm_assert(pad >= 0);
-
- tmp = nlmsg_reserve(n, len, pad);
- if (tmp == NULL)
- return -ENOMEM;
-
- 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 -NME_NL_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;
-}
-
-size_t
-nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
-{
- const char *src;
- size_t srclen;
- size_t len;
-
- /* - Always writes @dstsize bytes to @dst
- * - Copies the first non-NUL characters to @dst.
- * Any characters after the first NUL bytes in @nla are ignored.
- * - If the string @nla is longer than @dstsize, the string
- * gets truncated. @dst will always be NUL terminated. */
-
- if (G_UNLIKELY(dstsize <= 1)) {
- if (dstsize == 1)
- dst[0] = '\0';
- if (nla && (srclen = nla_len(nla)) > 0)
- return strnlen(nla_data(nla), srclen);
- return 0;
- }
-
- nm_assert(dst);
-
- if (nla) {
- srclen = nla_len(nla);
- if (srclen > 0) {
- src = nla_data(nla);
- srclen = strnlen(src, srclen);
- if (srclen > 0) {
- len = NM_MIN(dstsize - 1, srclen);
- memcpy(dst, src, len);
- memset(&dst[len], 0, dstsize - len);
- return srclen;
- }
- }
- }
-
- memset(dst, 0, dstsize);
- return 0;
-}
-
-size_t
-nla_memcpy(void *dst, const struct nlattr *nla, size_t dstsize)
-{
- size_t len;
- int srclen;
-
- if (!nla)
- return 0;
-
- srclen = nla_len(nla);
-
- if (srclen <= 0) {
- nm_assert(srclen == 0);
- return 0;
- }
-
- len = NM_MIN((size_t) srclen, dstsize);
- if (len > 0) {
- /* there is a crucial difference between nla_strlcpy() and nla_memcpy().
- * The former always write @dstsize bytes (akin to strncpy()), here, we only
- * write the bytes that we actually have (leaving the remainder undefined). */
- memcpy(dst, nla_data(nla), len);
- }
-
- return srclen;
-}
-
-int
-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(-NME_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, NLA_F_NESTED | 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 : -NME_NL_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 boundary.
- * Pad accordingly and account 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(-NME_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(-NME_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 -NME_UNSPEC;
-
- if (pt->maxlen && nla_len(nla) > pt->maxlen)
- return -NME_UNSPEC;
-
- if (pt->type == NLA_STRING) {
- const char *data;
-
- nm_assert(minlen > 0);
-
- data = nla_data(nla);
- if (data[nla_len(nla) - 1] != '\0')
- return -NME_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, nmerr;
-
- 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) {
- nmerr = validate_nla(nla, maxtype, policy);
- if (nmerr < 0)
- return nmerr;
- }
-
- tb[type] = nla;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-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_creds_has)
- return &msg->nm_creds;
- return NULL;
-}
-
-void
-nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
-{
- if (creds) {
- memcpy(&msg->nm_creds, creds, sizeof(*creds));
- msg->nm_creds_has = TRUE;
- } else
- msg->nm_creds_has = FALSE;
-}
-
-/*****************************************************************************/
-
-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 -NME_NL_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_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[G_N_ELEMENTS(ctrl_policy)];
- struct nlmsghdr *nlh = nlmsg_hdr(msg);
- gint32 * response_data = arg;
-
- if (genlmsg_parse_arr(nlh, 0, tb, ctrl_policy) < 0)
- 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 nmerr;
- 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))
- return -ENOMEM;
-
- nmerr = nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, name);
- if (nmerr < 0)
- return nmerr;
-
- nmerr = nl_send_auto(sk, msg);
- if (nmerr < 0)
- return nmerr;
-
- nmerr = nl_recvmsgs(sk, &cb);
- if (nmerr < 0)
- return nmerr;
-
- /* If search was successful, request may be ACKed after data */
- nmerr = nl_wait_for_ack(sk, NULL);
- if (nmerr < 0)
- return nmerr;
-
- if (response_data < 0)
- return -NME_UNSPEC;
-
- return response_data;
-}
-
-/*****************************************************************************/
-
-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 -NME_NL_BAD_SOCK;
-
- err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state));
- if (err < 0)
- return -nm_errno_from_native(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 -NME_NL_BAD_SOCK;
-
- if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
- return -nm_errno_from_native(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 -NME_NL_BAD_SOCK;
-
- err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof(txbuf));
- if (err < 0) {
- return -nm_errno_from_native(errno);
- }
-
- err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, &rxbuf, sizeof(rxbuf));
- if (err < 0) {
- return -nm_errno_from_native(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 -NME_NL_BAD_SOCK;
-
- va_start(ap, group);
-
- while (group != 0) {
- if (group < 0) {
- va_end(ap);
- g_return_val_if_reached(-NME_BUG);
- }
-
- err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
- if (err < 0) {
- int errsv = errno;
-
- va_end(ap);
- return -nm_errno_from_native(errsv);
- }
-
- 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 -NME_NL_BAD_SOCK;
-
- val = !!enable;
- err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof(val));
- if (err < 0)
- return -nm_errno_from_native(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, nmerr;
- socklen_t addrlen;
- struct sockaddr_nl local = {0};
-
- if (sk->s_fd != -1)
- return -NME_NL_BAD_SOCK;
-
- sk->s_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
- if (sk->s_fd < 0) {
- nmerr = -nm_errno_from_native(errno);
- goto errout;
- }
-
- nmerr = nl_socket_set_buffer_size(sk, 0, 0);
- if (nmerr < 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) {
- nmerr = -nm_errno_from_native(errno);
- goto errout;
- }
-
- addrlen = sizeof(local);
- err = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen);
- if (err < 0) {
- nmerr = -nm_errno_from_native(errno);
- goto errout;
- }
-
- if (addrlen != sizeof(local)) {
- nmerr = -NME_UNSPEC;
- goto errout;
- }
-
- if (local.nl_family != AF_NETLINK) {
- nmerr = -NME_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 nmerr;
-}
-
-/*****************************************************************************/
-
-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 && _cb->type##_cb) { \
- /* the returned value here must be either a negative
- * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \
- nmerr = _cb->type##_cb((msg), _cb->type##_arg); \
- switch (nmerr) { \
- case NL_OK: \
- nm_assert(nmerr == 0); \
- break; \
- case NL_SKIP: \
- goto skip; \
- case NL_STOP: \
- goto stop; \
- default: \
- if (nmerr >= 0) { \
- nm_assert_not_reached(); \
- nmerr = -NME_BUG; \
- } \
- goto out; \
- } \
- } \
- } while (0)
-
-int
-nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb)
-{
- int n, nmerr = 0, multipart = 0, interrupted = 0, nrecv = 0;
- gs_free unsigned char *buf = NULL;
- struct nlmsghdr * hdr;
- struct sockaddr_nl nla = {0};
- struct ucred creds;
- gboolean creds_has;
-
-continue_reading:
- n = nl_recv(sk, &nla, &buf, &creds, &creds_has);
- 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);
- nlmsg_set_creds(msg, creds_has ? &creds : NULL);
-
- 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) {
- nmerr = -NME_NL_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 returning
- * NL_SKIP or NL_PROCEED (dangerous) */
- else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
- nmerr = -NME_NL_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) */
- nmerr = -NME_NL_MSG_TRUNC;
- goto out;
- }
- if (e->error) {
- /* Error message reported back from kernel. */
- if (cb && cb->err_cb) {
- /* the returned value here must be either a negative
- * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */
- nmerr = cb->err_cb(&nla, e, cb->err_arg);
- if (nmerr < 0)
- goto out;
- else if (nmerr == NL_SKIP)
- goto skip;
- else if (nmerr == NL_STOP) {
- nmerr = -nm_errno_from_native(e->error);
- goto out;
- }
- nm_assert(nmerr == NL_OK);
- } else {
- nmerr = -nm_errno_from_native(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:
- nmerr = 0;
- hdr = nlmsg_next(hdr, &n);
- }
-
- if (multipart) {
- /* Multipart message not yet complete, continue reading */
- nm_clear_g_free(&buf);
-
- nmerr = 0;
- goto continue_reading;
- }
-
-stop:
- nmerr = 0;
-
-out:
- if (interrupted)
- nmerr = -NME_NL_DUMP_INTR;
-
- nm_assert(nmerr <= 0);
- return nmerr ?: nrecv;
-}
-
-int
-nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
-{
- int ret;
-
- if (sk->s_fd < 0)
- return -NME_NL_BAD_SOCK;
-
- nlmsg_set_src(msg, &sk->s_local);
-
- ret = sendmsg(sk->s_fd, hdr, 0);
- if (ret < 0)
- return -nm_errno_from_native(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 * out_creds,
- gboolean * out_creds_has)
-{
- ssize_t n;
- int flags = 0;
- struct iovec iov;
- struct msghdr msg = {
- .msg_name = (void *) nla,
- .msg_namelen = sizeof(struct sockaddr_nl),
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
- struct ucred tmpcreds;
- gboolean tmpcreds_has = FALSE;
- int retval;
- int errsv;
-
- nm_assert(nla);
- nm_assert(buf && !*buf);
- nm_assert(!out_creds_has == !out_creds);
-
- if ((sk->s_flags & NL_MSG_PEEK)
- || (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0))
- flags |= MSG_PEEK | MSG_TRUNC;
-
- iov.iov_len = sk->s_bufsize ?: (((size_t) nm_utils_getpagesize()) * 4u);
- iov.iov_base = g_malloc(iov.iov_len);
-
- if (out_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) {
- errsv = errno;
- if (errsv == EINTR)
- goto retry;
- retval = -nm_errno_from_native(errsv);
- goto abort;
- }
-
- if (msg.msg_flags & MSG_CTRUNC) {
- if (msg.msg_controllen == 0) {
- retval = -NME_NL_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 = -NME_NL_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 = -NME_UNSPEC;
- goto abort;
- }
-
- if (out_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;
- memcpy(&tmpcreds, CMSG_DATA(cmsg), sizeof(tmpcreds));
- tmpcreds_has = TRUE;
- break;
- }
- }
-
- retval = n;
-
-abort:
- g_free(msg.msg_control);
-
- if (retval <= 0) {
- g_free(iov.iov_base);
- return retval;
- }
-
- *buf = iov.iov_base;
- if (out_creds && tmpcreds_has)
- *out_creds = tmpcreds;
- NM_SET_OUT(out_creds_has, tmpcreds_has);
- return retval;
-}
diff --git a/shared/nm-platform/nm-netlink.h b/shared/nm-platform/nm-netlink.h
deleted file mode 100644
index 8de42531d3..0000000000
--- a/shared/nm-platform/nm-netlink.h
+++ /dev/null
@@ -1,616 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * 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>
-
-#include "nm-std-aux/unaligned.h"
-
-/*****************************************************************************/
-
-#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
-
-/*****************************************************************************/
-
-/* 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 asserts that @tb and @policy are suitable arguments to nla_parse(). */
-#define _nl_static_assert_tb(tb, policy) \
- G_STMT_START \
- { \
- G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(tb) > 0); \
- \
- /* We allow @policy to be either a C array or NULL. The sizeof()
- * must either match the expected array size or the sizeof(NULL),
- * but not both. */ \
- G_STATIC_ASSERT_EXPR((sizeof(policy) == G_N_ELEMENTS(tb) * sizeof(struct nla_policy)) \
- ^ (sizeof(policy) == sizeof(NULL))); \
- } \
- G_STMT_END
-
-/*****************************************************************************/
-
-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)
-{
- nm_assert(nla);
- nm_assert(nla->nla_len >= NLA_HDRLEN);
-
- return ((int) nla->nla_len) - NLA_HDRLEN;
-}
-
-static inline int
-nla_type(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= 0);
-
- return nla->nla_type & NLA_TYPE_MASK;
-}
-
-static inline void *
-nla_data(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= 0);
-
- return &(((char *) nla)[NLA_HDRLEN]);
-}
-
-#define nla_data_as(type, nla) \
- ({ \
- const struct nlattr *_nla = (nla); \
- \
- nm_assert(nla_len(_nla) >= sizeof(type)); \
- \
- /* note that casting the pointer is undefined behavior in C, if
- * the data has wrong alignment. Netlink data is aligned to 4 bytes,
- * that means, if the alignment is larger than 4, this is invalid. */ \
- G_STATIC_ASSERT_EXPR(_nm_alignof(type) <= NLA_ALIGNTO); \
- \
- (type *) nla_data(_nla); \
- })
-
-static inline uint8_t
-nla_get_u8(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= sizeof(uint8_t));
-
- return *((const uint8_t *) nla_data(nla));
-}
-
-static inline int8_t
-nla_get_s8(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= sizeof(int8_t));
-
- return *((const int8_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)
-{
- nm_assert(nla_len(nla) >= sizeof(uint16_t));
-
- return *((const uint16_t *) nla_data(nla));
-}
-
-static inline uint32_t
-nla_get_u32(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= sizeof(uint32_t));
-
- return *((const uint32_t *) nla_data(nla));
-}
-
-static inline int32_t
-nla_get_s32(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= sizeof(int32_t));
-
- return *((const int32_t *) nla_data(nla));
-}
-
-static inline uint64_t
-nla_get_u64(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= sizeof(uint64_t));
-
- return unaligned_read_ne64(nla_data(nla));
-}
-
-static inline uint64_t
-nla_get_be64(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= sizeof(uint64_t));
-
- return unaligned_read_be64(nla_data(nla));
-}
-
-static inline char *
-nla_get_string(const struct nlattr *nla)
-{
- nm_assert(nla_len(nla) >= 0);
-
- return (char *) nla_data(nla);
-}
-
-size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize);
-
-size_t nla_memcpy(void *dst, const struct nlattr *nla, size_t dstsize);
-
-#define nla_memcpy_checked_size(dst, nla, dstsize) \
- G_STMT_START \
- { \
- void *const _dst = (dst); \
- const struct nlattr *const _nla = (nla); \
- const size_t _dstsize = (dstsize); \
- size_t _srcsize; \
- \
- /* assert that, if @nla is given, that it has the exact expected
- * size. This implies that the caller previously verified the length
- * of the attribute (via minlen/maxlen at nla_parse()). */ \
- \
- if (_nla) { \
- _srcsize = nla_memcpy(_dst, _nla, _dstsize); \
- nm_assert(_srcsize == _dstsize); \
- } \
- } \
- G_STMT_END
-
-int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data);
-
-static inline int
-nla_put_string(struct nl_msg *msg, int attrtype, const char *str)
-{
- nm_assert(str);
-
- return nla_put(msg, attrtype, strlen(str) + 1, str);
-}
-
-static inline int
-nla_put_uint8(struct nl_msg *msg, int attrtype, uint8_t val)
-{
- return nla_put(msg, attrtype, sizeof(val), &val);
-}
-
-static inline int
-nla_put_uint16(struct nl_msg *msg, int attrtype, uint16_t val)
-{
- return nla_put(msg, attrtype, sizeof(val), &val);
-}
-
-static inline int
-nla_put_uint32(struct nl_msg *msg, int attrtype, uint32_t val)
-{
- return nla_put(msg, attrtype, sizeof(val), &val);
-}
-
-#define NLA_PUT(msg, attrtype, attrlen, data) \
- G_STMT_START \
- { \
- if (nla_put(msg, attrtype, attrlen, data) < 0) \
- goto nla_put_failure; \
- } \
- G_STMT_END
-
-#define NLA_PUT_TYPE(msg, type, attrtype, value) \
- G_STMT_START \
- { \
- type __nla_tmp = value; \
- NLA_PUT(msg, attrtype, sizeof(type), &__nla_tmp); \
- } \
- G_STMT_END
-
-#define NLA_PUT_U8(msg, attrtype, value) NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
-
-#define NLA_PUT_S8(msg, attrtype, value) NLA_PUT_TYPE(msg, int8_t, attrtype, value)
-
-#define NLA_PUT_U16(msg, attrtype, value) NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
-
-#define NLA_PUT_U32(msg, attrtype, value) NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
-
-#define NLA_PUT_S32(msg, attrtype, value) NLA_PUT_TYPE(msg, int32_t, attrtype, value)
-
-#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)
-
-#define NLA_PUT_FLAG(msg, attrtype) NLA_PUT(msg, attrtype, 0, NULL)
-
-struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype);
-
-static inline int
-nla_ok(const struct nlattr *nla, int remaining)
-{
- return remaining >= (int) sizeof(*nla) && nla->nla_len >= sizeof(*nla)
- && 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);
-
-#define nla_parse_arr(tb, head, len, policy) \
- ({ \
- _nl_static_assert_tb((tb), (policy)); \
- \
- nla_parse((tb), G_N_ELEMENTS(tb) - 1, (head), (len), (policy)); \
- })
-
-static inline int
-nla_parse_nested(struct nlattr * tb[],
- int maxtype,
- struct nlattr * nla,
- const struct nla_policy *policy)
-{
- return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
-}
-
-#define nla_parse_nested_arr(tb, nla, policy) \
- ({ \
- _nl_static_assert_tb((tb), (policy)); \
- \
- nla_parse_nested((tb), G_N_ELEMENTS(tb) - 1, (nla), (policy)); \
- })
-
-/*****************************************************************************/
-
-struct nl_msg *nlmsg_alloc(void);
-
-struct nl_msg *nlmsg_alloc_size(size_t max);
-
-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, const void *data, size_t len, int pad);
-
-#define nlmsg_append_struct(n, data) nlmsg_append(n, (data), sizeof(*(data)), NLMSG_ALIGNTO)
-
-void nlmsg_free(struct nl_msg *msg);
-
-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);
-
-#define nlmsg_parse_arr(nlh, hdrlen, tb, policy) \
- ({ \
- _nl_static_assert_tb((tb), (policy)); \
- G_STATIC_ASSERT_EXPR((hdrlen) >= 0); \
- \
- nlmsg_parse((nlh), (hdrlen), (tb), G_N_ELEMENTS(tb) - 1, (policy)); \
- })
-
-struct nlmsghdr *
-nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags);
-
-/*****************************************************************************/
-
-#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 * out_creds,
- gboolean * out_creds_has);
-
-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);
-
-#define genlmsg_parse_arr(nlh, hdrlen, tb, policy) \
- ({ \
- _nl_static_assert_tb((tb), (policy)); \
- G_STATIC_ASSERT_EXPR((hdrlen) >= 0); \
- \
- genlmsg_parse((nlh), (hdrlen), (tb), G_N_ELEMENTS(tb) - 1, (policy)); \
- })
-
-int genl_ctrl_resolve(struct nl_sock *sk, const char *name);
-
-/*****************************************************************************/
-
-#endif /* __NM_NETLINK_H__ */
diff --git a/shared/nm-platform/nm-platform-utils.c b/shared/nm-platform/nm-platform-utils.c
deleted file mode 100644
index c1c5b1a356..0000000000
--- a/shared/nm-platform/nm-platform-utils.c
+++ /dev/null
@@ -1,1807 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nm-platform-utils.h"
-
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <linux/ethtool.h>
-#include <linux/sockios.h>
-#include <linux/mii.h>
-#include <linux/if.h>
-#include <linux/version.h>
-#include <linux/rtnetlink.h>
-#include <fcntl.h>
-#include <libudev.h>
-
-#include "nm-base/nm-ethtool-base.h"
-#include "nm-log-core/nm-logging.h"
-
-/*****************************************************************************/
-
-#define ONOFF(bool_val) ((bool_val) ? "on" : "off")
-
-/******************************************************************************
- * utils
- *****************************************************************************/
-
-extern char *if_indextoname(unsigned __ifindex, char *__ifname);
-unsigned if_nametoindex(const char *__ifname);
-
-const char *
-nmp_utils_if_indextoname(int ifindex, char *out_ifname /*IFNAMSIZ*/)
-{
- g_return_val_if_fail(ifindex > 0, NULL);
- g_return_val_if_fail(out_ifname, NULL);
-
- return if_indextoname(ifindex, out_ifname);
-}
-
-int
-nmp_utils_if_nametoindex(const char *ifname)
-{
- g_return_val_if_fail(ifname, 0);
-
- return if_nametoindex(ifname);
-}
-
-/*****************************************************************************/
-
-NM_UTILS_LOOKUP_STR_DEFINE(nm_platform_link_duplex_type_to_string,
- NMPlatformLinkDuplexType,
- NM_UTILS_LOOKUP_DEFAULT_WARN(NULL),
- NM_UTILS_LOOKUP_STR_ITEM(NM_PLATFORM_LINK_DUPLEX_UNKNOWN, "unknown"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_PLATFORM_LINK_DUPLEX_FULL, "full"),
- NM_UTILS_LOOKUP_STR_ITEM(NM_PLATFORM_LINK_DUPLEX_HALF, "half"), );
-
-/*****************************************************************************/
-
-typedef struct {
- int fd;
- const int ifindex;
- char ifname[IFNAMSIZ];
-} SocketHandle;
-
-#define SOCKET_HANDLE_INIT(_ifindex) \
- { \
- .fd = -1, .ifindex = (_ifindex), \
- }
-
-static void
-_nm_auto_socket_handle(SocketHandle *shandle)
-{
- if (shandle->fd >= 0)
- nm_close(shandle->fd);
-}
-
-#define nm_auto_socket_handle nm_auto(_nm_auto_socket_handle)
-
-/*****************************************************************************/
-
-typedef enum {
- IOCTL_CALL_DATA_TYPE_NONE,
- IOCTL_CALL_DATA_TYPE_IFRDATA,
- IOCTL_CALL_DATA_TYPE_IFRU,
-} IoctlCallDataType;
-
-static int
-_ioctl_call(const char * log_ioctl_type,
- const char * log_subtype,
- unsigned long int ioctl_request,
- int ifindex,
- int * inout_fd,
- char * inout_ifname,
- IoctlCallDataType edata_type,
- gpointer edata,
- gsize edata_size,
- struct ifreq * out_ifreq)
-{
- nm_auto_close int fd_close = -1;
- int fd;
- int r;
- gpointer edata_backup = NULL;
- gs_free gpointer edata_backup_free = NULL;
- guint try_count;
- char known_ifnames[2][IFNAMSIZ];
- const char * failure_reason = NULL;
- struct ifreq ifr;
-
- nm_assert(ifindex > 0);
- nm_assert(NM_IN_SET(edata_type,
- IOCTL_CALL_DATA_TYPE_NONE,
- IOCTL_CALL_DATA_TYPE_IFRDATA,
- IOCTL_CALL_DATA_TYPE_IFRU));
- nm_assert(edata_type != IOCTL_CALL_DATA_TYPE_NONE || edata_size == 0);
- nm_assert(edata_type != IOCTL_CALL_DATA_TYPE_IFRDATA || edata_size > 0);
- nm_assert(edata_type != IOCTL_CALL_DATA_TYPE_IFRU
- || (edata_size > 0 && edata_size <= sizeof(ifr.ifr_ifru)));
- nm_assert(edata_size == 0 || edata);
-
- /* open a file descriptor (or use the one provided). */
- if (inout_fd && *inout_fd >= 0)
- fd = *inout_fd;
- else {
- fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (fd < 0) {
- r = -NM_ERRNO_NATIVE(errno);
- failure_reason = "failed creating socket or ioctl";
- goto out;
- }
- if (inout_fd)
- *inout_fd = fd;
- else
- fd_close = fd;
- }
-
- /* resolve the ifindex to name (or use the one provided). */
- if (inout_ifname && inout_ifname[0])
- nm_utils_ifname_cpy(known_ifnames[0], inout_ifname);
- else {
- if (!nmp_utils_if_indextoname(ifindex, known_ifnames[0])) {
- failure_reason = "cannot resolve ifindex";
- r = -ENODEV;
- goto out;
- }
- if (inout_ifname)
- nm_utils_ifname_cpy(inout_ifname, known_ifnames[0]);
- }
-
- /* we might need to retry the request. Backup edata so that we can
- * restore it on retry. */
- if (edata_size > 0)
- edata_backup = nm_memdup_maybe_a(500, edata, edata_size, &edata_backup_free);
-
- try_count = 0;
-
-again:
-{
- const char *ifname = known_ifnames[try_count % 2];
-
- nm_assert(ifindex > 0);
- nm_assert(ifname && nm_utils_ifname_valid_kernel(ifname, NULL));
- nm_assert(fd >= 0);
-
- memset(&ifr, 0, sizeof(ifr));
- nm_utils_ifname_cpy(ifr.ifr_name, ifname);
- if (edata_type == IOCTL_CALL_DATA_TYPE_IFRDATA)
- ifr.ifr_data = edata;
- else if (edata_type == IOCTL_CALL_DATA_TYPE_IFRU)
- memcpy(&ifr.ifr_ifru, edata, NM_MIN(edata_size, sizeof(ifr.ifr_ifru)));
-
- if (ioctl(fd, ioctl_request, &ifr) < 0) {
- r = -NM_ERRNO_NATIVE(errno);
- nm_log_trace(LOGD_PLATFORM,
- "%s[%d]: %s, %s: failed: %s",
- log_ioctl_type,
- ifindex,
- log_subtype,
- ifname,
- nm_strerror_native(-r));
- } else {
- r = 0;
- nm_log_trace(LOGD_PLATFORM,
- "%s[%d]: %s, %s: success",
- log_ioctl_type,
- ifindex,
- log_subtype,
- ifname);
- }
-}
-
- try_count++;
-
- /* resolve the name again to see whether the ifindex still has the same name. */
- if (!nmp_utils_if_indextoname(ifindex, known_ifnames[try_count % 2])) {
- /* we could not find the ifindex again. Probably the device just got
- * removed.
- *
- * In both cases we return the error code we got from ioctl above.
- * Either it failed because the device was gone already or it still
- * managed to complete the call. In both cases, the error code is good. */
- failure_reason =
- "cannot resolve ifindex after ioctl call. Probably the device was just removed";
- goto out;
- }
-
- /* check whether the ifname changed in the meantime. If yes, would render the result
- * invalid. Note that this cannot detect every race regarding renames, for example:
- *
- * - if_indextoname(#10) gives eth0
- * - rename(#10) => eth0_tmp
- * - rename(#11) => eth0
- * - ioctl(eth0) (wrongly fetching #11, formerly eth1)
- * - rename(#11) => eth_something
- * - rename(#10) => eth0
- * - if_indextoname(#10) gives eth0
- */
- if (!nm_streq(known_ifnames[0], known_ifnames[1])) {
- gboolean retry;
-
- /* we detected a possible(!) rename.
- *
- * For getters it's straight forward to just retry the call.
- *
- * For setters we also always retry. If our previous call operated on the right device,
- * calling it again should have no bad effect (just setting the same thing more than once).
- *
- * The only potential bad thing is if there was a race involving swapping names, and we just
- * set the ioctl option on the wrong device. But then the bad thing already happenned and
- * we cannot detect it (nor do anything about it). At least, we can retry and set the
- * option on the right interface. */
- retry = (try_count < 5);
-
- nm_log_trace(LOGD_PLATFORM,
- "%s[%d]: %s: rename detected from \"%s\" to \"%s\". %s",
- log_ioctl_type,
- ifindex,
- log_subtype,
- known_ifnames[(try_count - 1) % 2],
- known_ifnames[try_count % 2],
- retry ? "Retry" : "No retry");
- if (inout_ifname)
- nm_utils_ifname_cpy(inout_ifname, known_ifnames[try_count % 2]);
- if (retry) {
- if (edata_size > 0)
- memcpy(edata, edata_backup, edata_size);
- goto again;
- }
- }
-
-out:
- if (failure_reason) {
- nm_log_trace(LOGD_PLATFORM,
- "%s[%d]: %s: %s: %s",
- log_ioctl_type,
- ifindex,
- log_subtype,
- failure_reason,
- r < 0 ? nm_strerror_native(-r) : "assume success");
- }
- if (r >= 0)
- NM_SET_OUT(out_ifreq, ifr);
- return r;
-}
-
-/******************************************************************************
- * ethtool
- *****************************************************************************/
-
-static NM_UTILS_ENUM2STR_DEFINE(_ethtool_cmd_to_string,
- guint32,
- NM_UTILS_ENUM2STR(ETHTOOL_GCOALESCE, "ETHTOOL_GCOALESCE"),
- NM_UTILS_ENUM2STR(ETHTOOL_GDRVINFO, "ETHTOOL_GDRVINFO"),
- NM_UTILS_ENUM2STR(ETHTOOL_GFEATURES, "ETHTOOL_GFEATURES"),
- NM_UTILS_ENUM2STR(ETHTOOL_GLINK, "ETHTOOL_GLINK"),
- NM_UTILS_ENUM2STR(ETHTOOL_GPERMADDR, "ETHTOOL_GPERMADDR"),
- NM_UTILS_ENUM2STR(ETHTOOL_GRINGPARAM, "ETHTOOL_GRINGPARAM"),
- NM_UTILS_ENUM2STR(ETHTOOL_GSET, "ETHTOOL_GSET"),
- NM_UTILS_ENUM2STR(ETHTOOL_GSSET_INFO, "ETHTOOL_GSSET_INFO"),
- NM_UTILS_ENUM2STR(ETHTOOL_GSTATS, "ETHTOOL_GSTATS"),
- NM_UTILS_ENUM2STR(ETHTOOL_GSTRINGS, "ETHTOOL_GSTRINGS"),
- NM_UTILS_ENUM2STR(ETHTOOL_GWOL, "ETHTOOL_GWOL"),
- NM_UTILS_ENUM2STR(ETHTOOL_SCOALESCE, "ETHTOOL_SCOALESCE"),
- NM_UTILS_ENUM2STR(ETHTOOL_SFEATURES, "ETHTOOL_SFEATURES"),
- NM_UTILS_ENUM2STR(ETHTOOL_SRINGPARAM, "ETHTOOL_SRINGPARAM"),
- NM_UTILS_ENUM2STR(ETHTOOL_SSET, "ETHTOOL_SSET"),
- NM_UTILS_ENUM2STR(ETHTOOL_SWOL, "ETHTOOL_SWOL"), );
-
-static const char *
-_ethtool_edata_to_string(gpointer edata, gsize edata_size, char *sbuf, gsize sbuf_len)
-{
- nm_assert(edata);
- nm_assert(edata_size >= sizeof(guint32));
- nm_assert((((intptr_t) edata) % _nm_alignof(guint32)) == 0);
-
- return _ethtool_cmd_to_string(*((guint32 *) edata), sbuf, sbuf_len);
-}
-
-/*****************************************************************************/
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
- #define ethtool_cmd_speed(pedata) ((pedata)->speed)
-
- #define ethtool_cmd_speed_set(pedata, speed) \
- G_STMT_START \
- { \
- (pedata)->speed = (guint16)(speed); \
- } \
- G_STMT_END
-#endif
-
-static int
-_ethtool_call_handle(SocketHandle *shandle, gpointer edata, gsize edata_size)
-{
- char sbuf[50];
-
- return _ioctl_call("ethtool",
- _ethtool_edata_to_string(edata, edata_size, sbuf, sizeof(sbuf)),
- SIOCETHTOOL,
- shandle->ifindex,
- &shandle->fd,
- shandle->ifname,
- IOCTL_CALL_DATA_TYPE_IFRDATA,
- edata,
- edata_size,
- NULL);
-}
-
-static int
-_ethtool_call_once(int ifindex, gpointer edata, gsize edata_size)
-{
- char sbuf[50];
-
- return _ioctl_call("ethtool",
- _ethtool_edata_to_string(edata, edata_size, sbuf, sizeof(sbuf)),
- SIOCETHTOOL,
- ifindex,
- NULL,
- NULL,
- IOCTL_CALL_DATA_TYPE_IFRDATA,
- edata,
- edata_size,
- NULL);
-}
-
-/*****************************************************************************/
-
-static struct ethtool_gstrings *
-ethtool_get_stringset(SocketHandle *shandle, int stringset_id)
-{
- struct {
- struct ethtool_sset_info info;
- guint32 sentinel;
- } sset_info = {
- .info.cmd = ETHTOOL_GSSET_INFO,
- .info.reserved = 0,
- .info.sset_mask = (1ULL << stringset_id),
- };
- const guint32 * pdata;
- gs_free struct ethtool_gstrings *gstrings = NULL;
- gsize gstrings_len;
- guint32 i, len;
-
- if (_ethtool_call_handle(shandle, &sset_info, sizeof(sset_info)) < 0)
- return NULL;
- if (!sset_info.info.sset_mask)
- return NULL;
-
- pdata = (guint32 *) sset_info.info.data;
-
- len = *pdata;
-
- gstrings_len = sizeof(*gstrings) + (len * ETH_GSTRING_LEN);
- gstrings = g_malloc0(gstrings_len);
- gstrings->cmd = ETHTOOL_GSTRINGS;
- gstrings->string_set = stringset_id;
- gstrings->len = len;
- if (gstrings->len > 0) {
- if (_ethtool_call_handle(shandle, gstrings, gstrings_len) < 0)
- return NULL;
- for (i = 0; i < gstrings->len; i++) {
- /* ensure NUL terminated */
- gstrings->data[i * ETH_GSTRING_LEN + (ETH_GSTRING_LEN - 1)] = '\0';
- }
- }
-
- return g_steal_pointer(&gstrings);
-}
-
-static int
-ethtool_gstrings_find(const struct ethtool_gstrings *gstrings, const char *needle)
-{
- guint32 i;
-
- /* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN.
- * that means, we cannot possibly request longer names. */
- nm_assert(needle && strlen(needle) < ETH_GSTRING_LEN);
-
- for (i = 0; i < gstrings->len; i++) {
- if (nm_streq((char *) &gstrings->data[i * ETH_GSTRING_LEN], needle))
- return i;
- }
- return -1;
-}
-
-static int
-ethtool_get_stringset_index(SocketHandle *shandle, int stringset_id, const char *needle)
-{
- gs_free struct ethtool_gstrings *gstrings = NULL;
-
- /* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN.
- * that means, we cannot possibly request longer names. */
- nm_assert(needle && strlen(needle) < ETH_GSTRING_LEN);
-
- gstrings = ethtool_get_stringset(shandle, stringset_id);
- if (gstrings)
- return ethtool_gstrings_find(gstrings, needle);
- return -1;
-}
-
-/*****************************************************************************/
-
-static const NMEthtoolFeatureInfo _ethtool_feature_infos[_NM_ETHTOOL_ID_FEATURE_NUM] = {
-#define ETHT_FEAT(eid, ...) \
- { \
- .ethtool_id = eid, .n_kernel_names = NM_NARG(__VA_ARGS__), \
- .kernel_names = ((const char *const[]){__VA_ARGS__}), \
- }
-
- /* the order does only matter for one thing: if it happens that more than one NMEthtoolID
- * reference the same kernel-name, then the one that is mentioned *later* will win in
- * case these NMEthtoolIDs are set. That mostly only makes sense for ethtool-ids which
- * refer to multiple features ("feature-tso"), while also having more specific ids
- * ("feature-tx-tcp-segmentation"). */
-
- /* names from ethtool utility, which are aliases for multiple features. */
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_SG, "tx-scatter-gather", "tx-scatter-gather-fraglist"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TSO,
- "tx-tcp-segmentation",
- "tx-tcp-ecn-segmentation",
- "tx-tcp-mangleid-segmentation",
- "tx-tcp6-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX,
- "tx-checksum-ipv4",
- "tx-checksum-ip-generic",
- "tx-checksum-ipv6",
- "tx-checksum-fcoe-crc",
- "tx-checksum-sctp"),
-
- /* names from ethtool utility, which are aliases for one feature. */
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_GRO, "rx-gro"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_GSO, "tx-generic-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_LRO, "rx-lro"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_NTUPLE, "rx-ntuple-filter"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX, "rx-checksum"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RXHASH, "rx-hashing"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RXVLAN, "rx-vlan-hw-parse"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TXVLAN, "tx-vlan-hw-insert"),
-
- /* names of features, as known by kernel. */
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD, "esp-hw-offload"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD, "esp-tx-csum-hw-offload"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_FCOE_MTU, "fcoe-mtu"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_HIGHDMA, "highdma"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD, "hw-tc-offload"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD, "l2-fwd-offload"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_LOOPBACK, "loopback"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_MACSEC_HW_OFFLOAD, "macsec-hw-offload"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_ALL, "rx-all"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_FCS, "rx-fcs"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_GRO_HW, "rx-gro-hw"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_GRO_LIST, "rx-gro-list"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_UDP_GRO_FORWARDING, "rx-udp-gro-forwarding"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD, "rx-udp_tunnel-port-offload"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER, "rx-vlan-filter"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER, "rx-vlan-stag-filter"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE, "rx-vlan-stag-hw-parse"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD, "tls-hw-record"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TLS_HW_RX_OFFLOAD, "tls-hw-rx-offload"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD, "tls-hw-tx-offload"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC, "tx-checksum-fcoe-crc"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4, "tx-checksum-ipv4"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6, "tx-checksum-ipv6"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC, "tx-checksum-ip-generic"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP, "tx-checksum-sctp"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION, "tx-esp-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION, "tx-fcoe-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION, "tx-gre-csum-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION, "tx-gre-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GSO_LIST, "tx-gso-list"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL, "tx-gso-partial"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST, "tx-gso-robust"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION, "tx-ipxip4-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION, "tx-ipxip6-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY, "tx-nocache-copy"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER, "tx-scatter-gather"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST, "tx-scatter-gather-fraglist"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION, "tx-sctp-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION, "tx-tcp6-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION, "tx-tcp-ecn-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION, "tx-tcp-mangleid-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION, "tx-tcp-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_TUNNEL_REMCSUM_SEGMENTATION,
- "tx-tunnel-remcsum-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION, "tx-udp-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, "tx-udp_tnl-csum-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, "tx-udp_tnl-segmentation"),
- ETHT_FEAT(NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, "tx-vlan-stag-hw-insert"),
-};
-
-/* the number of kernel features that we handle. It essentially is the sum of all
- * kernel_names. So, all ethtool-ids that reference exactly one kernel-name
- * (_NM_ETHTOOL_ID_FEATURE_NUM) + some extra, for ethtool-ids that are aliases
- * for multiple kernel-names. */
-#define N_ETHTOOL_KERNEL_FEATURES (((guint) _NM_ETHTOOL_ID_FEATURE_NUM) + 8u)
-
-static void
-_ASSERT_ethtool_feature_infos(void)
-{
-#if NM_MORE_ASSERTS > 10
- guint i, k, n;
- bool found[_NM_ETHTOOL_ID_FEATURE_NUM] = {};
-
- G_STATIC_ASSERT_EXPR(G_N_ELEMENTS(_ethtool_feature_infos) == _NM_ETHTOOL_ID_FEATURE_NUM);
-
- n = 0;
- for (i = 0; i < G_N_ELEMENTS(_ethtool_feature_infos); i++) {
- NMEthtoolFeatureState kstate;
- const NMEthtoolFeatureInfo *inf = &_ethtool_feature_infos[i];
-
- g_assert(inf->ethtool_id >= _NM_ETHTOOL_ID_FEATURE_FIRST);
- g_assert(inf->ethtool_id <= _NM_ETHTOOL_ID_FEATURE_LAST);
- g_assert(inf->n_kernel_names > 0);
-
- for (k = 0; k < i; k++)
- g_assert(inf->ethtool_id != _ethtool_feature_infos[k].ethtool_id);
-
- g_assert(!found[_NM_ETHTOOL_ID_FEATURE_AS_IDX(inf->ethtool_id)]);
- found[_NM_ETHTOOL_ID_FEATURE_AS_IDX(inf->ethtool_id)] = TRUE;
-
- kstate.idx_kernel_name = inf->n_kernel_names - 1;
- g_assert((guint) kstate.idx_kernel_name == (guint)(inf->n_kernel_names - 1));
-
- n += inf->n_kernel_names;
- for (k = 0; k < inf->n_kernel_names; k++) {
- const char *name = inf->kernel_names[k];
-
- g_assert(nm_utils_strv_find_first((char **) inf->kernel_names, k, name) < 0);
-
- /* these offload features are only informational and cannot be set from user-space
- * (NETIF_F_NEVER_CHANGE). We should not track them in _ethtool_feature_infos. */
- g_assert(!nm_streq(name, "netns-local"));
- g_assert(!nm_streq(name, "tx-lockless"));
- g_assert(!nm_streq(name, "vlan-challenged"));
- }
- }
-
- for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++)
- g_assert(found[i]);
-
- g_assert(n == N_ETHTOOL_KERNEL_FEATURES);
-#endif
-}
-
-static NMEthtoolFeatureStates *
-ethtool_get_features(SocketHandle *shandle)
-{
- gs_free NMEthtoolFeatureStates * states = NULL;
- gs_free struct ethtool_gstrings *ss_features = NULL;
-
- _ASSERT_ethtool_feature_infos();
-
- ss_features = ethtool_get_stringset(shandle, ETH_SS_FEATURES);
- if (!ss_features)
- return NULL;
-
- if (ss_features->len > 0) {
- gs_free struct ethtool_gfeatures * gfeatures_free = NULL;
- struct ethtool_gfeatures * gfeatures;
- gsize gfeatures_len;
- guint idx;
- const NMEthtoolFeatureState * states_list0 = NULL;
- const NMEthtoolFeatureState *const *states_plist0 = NULL;
- guint states_plist_n = 0;
-
- gfeatures_len = sizeof(struct ethtool_gfeatures)
- + (NM_DIV_ROUND_UP(ss_features->len, 32u) * sizeof(gfeatures->features[0]));
- gfeatures = nm_malloc0_maybe_a(300, gfeatures_len, &gfeatures_free);
- gfeatures->cmd = ETHTOOL_GFEATURES;
- gfeatures->size = NM_DIV_ROUND_UP(ss_features->len, 32u);
- if (_ethtool_call_handle(shandle, gfeatures, gfeatures_len) < 0)
- return NULL;
-
- for (idx = 0; idx < G_N_ELEMENTS(_ethtool_feature_infos); idx++) {
- const NMEthtoolFeatureInfo *info = &_ethtool_feature_infos[idx];
- guint idx_kernel_name;
-
- for (idx_kernel_name = 0; idx_kernel_name < info->n_kernel_names; idx_kernel_name++) {
- NMEthtoolFeatureState *kstate;
- const char * kernel_name = info->kernel_names[idx_kernel_name];
- int i_feature;
- guint i_block;
- guint32 i_flag;
-
- i_feature = ethtool_gstrings_find(ss_features, kernel_name);
- if (i_feature < 0)
- continue;
-
- i_block = ((guint) i_feature) / 32u;
- i_flag = (guint32)(1u << (((guint) i_feature) % 32u));
-
- if (!states) {
- states = g_malloc0(
- sizeof(NMEthtoolFeatureStates)
- + (N_ETHTOOL_KERNEL_FEATURES * sizeof(NMEthtoolFeatureState))
- + ((N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS(_ethtool_feature_infos))
- * sizeof(NMEthtoolFeatureState *)));
- states_list0 = &states->states_list[0];
- states_plist0 = (gpointer) &states_list0[N_ETHTOOL_KERNEL_FEATURES];
- states->n_ss_features = ss_features->len;
- }
-
- nm_assert(states->n_states < N_ETHTOOL_KERNEL_FEATURES);
- kstate = (NMEthtoolFeatureState *) &states_list0[states->n_states];
- states->n_states++;
-
- kstate->info = info;
- kstate->idx_ss_features = i_feature;
- kstate->idx_kernel_name = idx_kernel_name;
- kstate->available = !!(gfeatures->features[i_block].available & i_flag);
- kstate->requested = !!(gfeatures->features[i_block].requested & i_flag);
- kstate->active = !!(gfeatures->features[i_block].active & i_flag);
- kstate->never_changed = !!(gfeatures->features[i_block].never_changed & i_flag);
-
- nm_assert(states_plist_n
- < N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS(_ethtool_feature_infos));
-
- if (!states->states_indexed[_NM_ETHTOOL_ID_FEATURE_AS_IDX(info->ethtool_id)])
- states->states_indexed[_NM_ETHTOOL_ID_FEATURE_AS_IDX(info->ethtool_id)] =
- &states_plist0[states_plist_n];
- ((const NMEthtoolFeatureState **) states_plist0)[states_plist_n] = kstate;
- states_plist_n++;
- }
-
- if (states && states->states_indexed[_NM_ETHTOOL_ID_FEATURE_AS_IDX(info->ethtool_id)]) {
- nm_assert(states_plist_n
- < N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS(_ethtool_feature_infos));
- nm_assert(!states_plist0[states_plist_n]);
- states_plist_n++;
- }
- }
- }
-
- return g_steal_pointer(&states);
-}
-
-NMEthtoolFeatureStates *
-nmp_utils_ethtool_get_features(int ifindex)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
- NMEthtoolFeatureStates * features;
-
- g_return_val_if_fail(ifindex > 0, 0);
-
- features = ethtool_get_features(&shandle);
-
- if (!features) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: failure getting features",
- ifindex,
- "get-features");
- return NULL;
- }
-
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: retrieved kernel features",
- ifindex,
- "get-features");
- return features;
-}
-
-static const char *
-_ethtool_feature_state_to_string(char * buf,
- gsize buf_size,
- const NMEthtoolFeatureState *s,
- const char * prefix)
-{
- int l;
-
- l = g_snprintf(buf,
- buf_size,
- "%s %s%s",
- prefix ?: "",
- ONOFF(s->active),
- (!s->available || s->never_changed)
- ? ", [fixed]"
- : ((s->requested != s->active)
- ? (s->requested ? ", [requested on]" : ", [requested off]")
- : ""));
- nm_assert(l < buf_size);
- return buf;
-}
-
-gboolean
-nmp_utils_ethtool_set_features(
- int ifindex,
- const NMEthtoolFeatureStates *features,
- const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
- gboolean do_set /* or reset */)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
- gs_free struct ethtool_sfeatures * sfeatures_free = NULL;
- struct ethtool_sfeatures * sfeatures;
- gsize sfeatures_len;
- int r;
- guint i, j;
- struct {
- const NMEthtoolFeatureState *f_state;
- NMOptionBool requested;
- } set_states[N_ETHTOOL_KERNEL_FEATURES];
- guint set_states_n = 0;
- gboolean success = TRUE;
-
- g_return_val_if_fail(ifindex > 0, 0);
- g_return_val_if_fail(features, 0);
- g_return_val_if_fail(requested, 0);
-
- nm_assert(features->n_states <= N_ETHTOOL_KERNEL_FEATURES);
-
- for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) {
- const NMEthtoolFeatureState *const *states_indexed;
-
- if (requested[i] == NM_OPTION_BOOL_DEFAULT)
- continue;
-
- if (!(states_indexed = features->states_indexed[i])) {
- if (do_set) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: set feature %s: skip (not found)",
- ifindex,
- "set-features",
- nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname);
- success = FALSE;
- }
- continue;
- }
-
- for (j = 0; states_indexed[j]; j++) {
- const NMEthtoolFeatureState *s = states_indexed[j];
- char sbuf[255];
-
- if (set_states_n >= G_N_ELEMENTS(set_states))
- g_return_val_if_reached(FALSE);
-
- if (s->never_changed) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: %s feature %s (%s): %s, %s (skip feature marked as "
- "never changed)",
- ifindex,
- "set-features",
- do_set ? "set" : "reset",
- nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname,
- s->info->kernel_names[s->idx_kernel_name],
- ONOFF(do_set ? requested[i] == NM_OPTION_BOOL_TRUE : s->active),
- _ethtool_feature_state_to_string(sbuf,
- sizeof(sbuf),
- s,
- do_set ? " currently:" : " before:"));
- continue;
- }
-
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: %s feature %s (%s): %s, %s",
- ifindex,
- "set-features",
- do_set ? "set" : "reset",
- nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname,
- s->info->kernel_names[s->idx_kernel_name],
- ONOFF(do_set ? requested[i] == NM_OPTION_BOOL_TRUE : s->active),
- _ethtool_feature_state_to_string(sbuf,
- sizeof(sbuf),
- s,
- do_set ? " currently:" : " before:"));
-
- if (do_set && (!s->available || s->never_changed)
- && (s->active != (requested[i] == NM_OPTION_BOOL_TRUE))) {
- /* we request to change a flag which kernel reported as fixed.
- * While the ethtool operation will silently succeed, mark the request
- * as failure. */
- success = FALSE;
- }
-
- set_states[set_states_n].f_state = s;
- set_states[set_states_n].requested = requested[i];
- set_states_n++;
- }
- }
-
- if (set_states_n == 0) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: no feature requested",
- ifindex,
- "set-features");
- return TRUE;
- }
-
- sfeatures_len =
- sizeof(struct ethtool_sfeatures)
- + (NM_DIV_ROUND_UP(features->n_ss_features, 32U) * sizeof(sfeatures->features[0]));
- sfeatures = nm_malloc0_maybe_a(300, sfeatures_len, &sfeatures_free);
- sfeatures->cmd = ETHTOOL_SFEATURES;
- sfeatures->size = NM_DIV_ROUND_UP(features->n_ss_features, 32U);
-
- for (i = 0; i < set_states_n; i++) {
- const NMEthtoolFeatureState *s = set_states[i].f_state;
- guint i_block;
- guint32 i_flag;
- gboolean is_requested;
-
- i_block = s->idx_ss_features / 32u;
- i_flag = (guint32)(1u << (s->idx_ss_features % 32u));
-
- sfeatures->features[i_block].valid |= i_flag;
-
- if (do_set)
- is_requested = (set_states[i].requested == NM_OPTION_BOOL_TRUE);
- else
- is_requested = s->active;
-
- if (is_requested)
- sfeatures->features[i_block].requested |= i_flag;
- else
- sfeatures->features[i_block].requested &= ~i_flag;
- }
-
- r = _ethtool_call_handle(&shandle, sfeatures, sfeatures_len);
- if (r < 0) {
- success = FALSE;
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: failure setting features (%s)",
- ifindex,
- "set-features",
- nm_strerror_native(-r));
- return FALSE;
- }
-
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: %s",
- ifindex,
- "set-features",
- success ? "successfully setting features"
- : "at least some of the features were not successfully set");
- return success;
-}
-
-static gboolean
-ethtool_get_coalesce(SocketHandle *shandle, NMEthtoolCoalesceState *coalesce)
-{
- struct ethtool_coalesce eth_data;
-
- eth_data.cmd = ETHTOOL_GCOALESCE;
-
- if (_ethtool_call_handle(shandle, &eth_data, sizeof(struct ethtool_coalesce)) != 0)
- return FALSE;
-
- *coalesce = (NMEthtoolCoalesceState){
- .s = {
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS)] =
- eth_data.rx_coalesce_usecs,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES)] =
- eth_data.rx_max_coalesced_frames,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ)] =
- eth_data.rx_coalesce_usecs_irq,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ)] =
- eth_data.rx_max_coalesced_frames_irq,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS)] =
- eth_data.tx_coalesce_usecs,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES)] =
- eth_data.tx_max_coalesced_frames,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ)] =
- eth_data.tx_coalesce_usecs_irq,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ)] =
- eth_data.tx_max_coalesced_frames_irq,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS)] =
- eth_data.stats_block_coalesce_usecs,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX)] =
- eth_data.use_adaptive_rx_coalesce,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX)] =
- eth_data.use_adaptive_tx_coalesce,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW)] =
- eth_data.pkt_rate_low,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW)] =
- eth_data.rx_coalesce_usecs_low,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW)] =
- eth_data.rx_max_coalesced_frames_low,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW)] =
- eth_data.tx_coalesce_usecs_low,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW)] =
- eth_data.tx_max_coalesced_frames_low,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH)] =
- eth_data.pkt_rate_high,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH)] =
- eth_data.rx_coalesce_usecs_high,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH)] =
- eth_data.rx_max_coalesced_frames_high,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH)] =
- eth_data.tx_coalesce_usecs_high,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH)] =
- eth_data.tx_max_coalesced_frames_high,
- [_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL)] =
- eth_data.rate_sample_interval,
- }};
- return TRUE;
-}
-
-gboolean
-nmp_utils_ethtool_get_coalesce(int ifindex, NMEthtoolCoalesceState *coalesce)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-
- g_return_val_if_fail(ifindex > 0, FALSE);
- g_return_val_if_fail(coalesce, FALSE);
-
- if (!ethtool_get_coalesce(&shandle, coalesce)) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: failure getting coalesce settings",
- ifindex,
- "get-coalesce");
- return FALSE;
- }
-
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: retrieved kernel coalesce settings",
- ifindex,
- "get-coalesce");
- return TRUE;
-}
-
-static gboolean
-ethtool_set_coalesce(SocketHandle *shandle, const NMEthtoolCoalesceState *coalesce)
-{
- struct ethtool_coalesce eth_data;
- gboolean success;
-
- nm_assert(shandle);
- nm_assert(coalesce);
-
- eth_data = (struct ethtool_coalesce){
- .cmd = ETHTOOL_SCOALESCE,
- .rx_coalesce_usecs =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS)],
- .rx_max_coalesced_frames =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES)],
- .rx_coalesce_usecs_irq =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ)],
- .rx_max_coalesced_frames_irq =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ)],
- .tx_coalesce_usecs =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS)],
- .tx_max_coalesced_frames =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES)],
- .tx_coalesce_usecs_irq =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ)],
- .tx_max_coalesced_frames_irq =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ)],
- .stats_block_coalesce_usecs =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS)],
- .use_adaptive_rx_coalesce =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX)],
- .use_adaptive_tx_coalesce =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX)],
- .pkt_rate_low =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW)],
- .rx_coalesce_usecs_low =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW)],
- .rx_max_coalesced_frames_low =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW)],
- .tx_coalesce_usecs_low =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW)],
- .tx_max_coalesced_frames_low =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW)],
- .pkt_rate_high =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH)],
- .rx_coalesce_usecs_high =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH)],
- .rx_max_coalesced_frames_high =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH)],
- .tx_coalesce_usecs_high =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH)],
- .tx_max_coalesced_frames_high =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH)],
- .rate_sample_interval =
- coalesce->s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL)],
- };
-
- success = (_ethtool_call_handle(shandle, &eth_data, sizeof(struct ethtool_coalesce)) == 0);
- return success;
-}
-
-gboolean
-nmp_utils_ethtool_set_coalesce(int ifindex, const NMEthtoolCoalesceState *coalesce)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-
- g_return_val_if_fail(ifindex > 0, FALSE);
- g_return_val_if_fail(coalesce, FALSE);
-
- if (!ethtool_set_coalesce(&shandle, coalesce)) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: failure setting coalesce settings",
- ifindex,
- "set-coalesce");
- return FALSE;
- }
-
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: set kernel coalesce settings",
- ifindex,
- "set-coalesce");
- return TRUE;
-}
-
-static gboolean
-ethtool_get_ring(SocketHandle *shandle, NMEthtoolRingState *ring)
-{
- struct ethtool_ringparam eth_data;
-
- eth_data.cmd = ETHTOOL_GRINGPARAM;
-
- if (_ethtool_call_handle(shandle, &eth_data, sizeof(struct ethtool_ringparam)) != 0)
- return FALSE;
-
- ring->rx_pending = eth_data.rx_pending;
- ring->rx_jumbo_pending = eth_data.rx_jumbo_pending;
- ring->rx_mini_pending = eth_data.rx_mini_pending;
- ring->tx_pending = eth_data.tx_pending;
-
- return TRUE;
-}
-
-gboolean
-nmp_utils_ethtool_get_ring(int ifindex, NMEthtoolRingState *ring)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-
- g_return_val_if_fail(ifindex > 0, FALSE);
- g_return_val_if_fail(ring, FALSE);
-
- if (!ethtool_get_ring(&shandle, ring)) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: failure getting ring settings",
- ifindex,
- "get-ring");
- return FALSE;
- }
-
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: retrieved kernel ring settings",
- ifindex,
- "get-ring");
- return TRUE;
-}
-
-static gboolean
-ethtool_set_ring(SocketHandle *shandle, const NMEthtoolRingState *ring)
-{
- gboolean success;
- struct ethtool_ringparam eth_data;
-
- g_return_val_if_fail(shandle, FALSE);
- g_return_val_if_fail(ring, FALSE);
-
- eth_data = (struct ethtool_ringparam){
- .cmd = ETHTOOL_SRINGPARAM,
- .rx_pending = ring->rx_pending,
- .rx_jumbo_pending = ring->rx_jumbo_pending,
- .rx_mini_pending = ring->rx_mini_pending,
- .tx_pending = ring->tx_pending,
- };
-
- success = (_ethtool_call_handle(shandle, &eth_data, sizeof(struct ethtool_ringparam)) == 0);
- return success;
-}
-
-gboolean
-nmp_utils_ethtool_set_ring(int ifindex, const NMEthtoolRingState *ring)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-
- g_return_val_if_fail(ifindex > 0, FALSE);
- g_return_val_if_fail(ring, FALSE);
-
- if (!ethtool_set_ring(&shandle, ring)) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %s: failure setting ring settings",
- ifindex,
- "set-ring");
- return FALSE;
- }
-
- nm_log_trace(LOGD_PLATFORM, "ethtool[%d]: %s: set kernel ring settings", ifindex, "set-ring");
- return TRUE;
-}
-
-/*****************************************************************************/
-
-gboolean
-nmp_utils_ethtool_get_driver_info(int ifindex, NMPUtilsEthtoolDriverInfo *data)
-{
- struct ethtool_drvinfo *drvinfo;
-
- G_STATIC_ASSERT_EXPR(sizeof(*data) == sizeof(*drvinfo));
- G_STATIC_ASSERT_EXPR(offsetof(NMPUtilsEthtoolDriverInfo, driver)
- == offsetof(struct ethtool_drvinfo, driver));
- G_STATIC_ASSERT_EXPR(offsetof(NMPUtilsEthtoolDriverInfo, version)
- == offsetof(struct ethtool_drvinfo, version));
- G_STATIC_ASSERT_EXPR(offsetof(NMPUtilsEthtoolDriverInfo, fw_version)
- == offsetof(struct ethtool_drvinfo, fw_version));
- G_STATIC_ASSERT_EXPR(sizeof(data->driver) == sizeof(drvinfo->driver));
- G_STATIC_ASSERT_EXPR(sizeof(data->version) == sizeof(drvinfo->version));
- G_STATIC_ASSERT_EXPR(sizeof(data->fw_version) == sizeof(drvinfo->fw_version));
-
- g_return_val_if_fail(ifindex > 0, FALSE);
- g_return_val_if_fail(data, FALSE);
-
- drvinfo = (struct ethtool_drvinfo *) data;
- *drvinfo = (struct ethtool_drvinfo){
- .cmd = ETHTOOL_GDRVINFO,
- };
- return _ethtool_call_once(ifindex, drvinfo, sizeof(*drvinfo)) >= 0;
-}
-
-gboolean
-nmp_utils_ethtool_get_permanent_address(int ifindex, guint8 *buf, size_t *length)
-{
- struct {
- struct ethtool_perm_addr e;
- guint8 _extra_data[_NM_UTILS_HWADDR_LEN_MAX + 1];
- } edata = {
- .e.cmd = ETHTOOL_GPERMADDR,
- .e.size = _NM_UTILS_HWADDR_LEN_MAX,
- };
- const guint8 *pdata;
-
- guint i;
-
- g_return_val_if_fail(ifindex > 0, FALSE);
-
- if (_ethtool_call_once(ifindex, &edata, sizeof(edata)) < 0)
- return FALSE;
-
- if (edata.e.size > _NM_UTILS_HWADDR_LEN_MAX)
- return FALSE;
- if (edata.e.size < 1)
- return FALSE;
-
- pdata = (const guint8 *) edata.e.data;
-
- if (NM_IN_SET(pdata[0], 0, 0xFF)) {
- /* Some drivers might return a permanent address of all zeros.
- * Reject that (rh#1264024)
- *
- * Some drivers return a permanent address of all ones. Reject that too */
- for (i = 1; i < edata.e.size; i++) {
- if (pdata[0] != pdata[i])
- goto not_all_0or1;
- }
- return FALSE;
- }
-
-not_all_0or1:
- memcpy(buf, pdata, edata.e.size);
- *length = edata.e.size;
- return TRUE;
-}
-
-gboolean
-nmp_utils_ethtool_supports_carrier_detect(int ifindex)
-{
- struct ethtool_cmd edata = {.cmd = ETHTOOL_GLINK};
-
- g_return_val_if_fail(ifindex > 0, FALSE);
-
- /* We ignore the result. If the ETHTOOL_GLINK call succeeded, then we
- * assume the device supports carrier-detect, otherwise we assume it
- * doesn't.
- */
- return _ethtool_call_once(ifindex, &edata, sizeof(edata)) >= 0;
-}
-
-gboolean
-nmp_utils_ethtool_supports_vlans(int ifindex)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
- gs_free struct ethtool_gfeatures * features_free = NULL;
- struct ethtool_gfeatures * features;
- gsize features_len;
- int idx, block, bit, size;
-
- g_return_val_if_fail(ifindex > 0, FALSE);
-
- idx = ethtool_get_stringset_index(&shandle, ETH_SS_FEATURES, "vlan-challenged");
- if (idx < 0) {
- nm_log_dbg(LOGD_PLATFORM,
- "ethtool[%d]: vlan-challenged ethtool feature does not exist?",
- ifindex);
- return FALSE;
- }
-
- block = idx / 32;
- bit = idx % 32;
- size = block + 1;
-
- features_len = sizeof(*features) + (size * sizeof(struct ethtool_get_features_block));
- features = nm_malloc0_maybe_a(300, features_len, &features_free);
- features->cmd = ETHTOOL_GFEATURES;
- features->size = size;
-
- if (_ethtool_call_handle(&shandle, features, features_len) < 0)
- return FALSE;
-
- return !(features->features[block].active & (1 << bit));
-}
-
-int
-nmp_utils_ethtool_get_peer_ifindex(int ifindex)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
- gsize stats_len;
- gs_free struct ethtool_stats * stats_free = NULL;
- struct ethtool_stats * stats;
- int peer_ifindex_stat;
-
- g_return_val_if_fail(ifindex > 0, 0);
-
- peer_ifindex_stat = ethtool_get_stringset_index(&shandle, ETH_SS_STATS, "peer_ifindex");
- if (peer_ifindex_stat < 0) {
- nm_log_dbg(LOGD_PLATFORM, "ethtool[%d]: peer_ifindex stat does not exist?", ifindex);
- return FALSE;
- }
-
- stats_len = sizeof(*stats) + (peer_ifindex_stat + 1) * sizeof(guint64);
- stats = nm_malloc0_maybe_a(300, stats_len, &stats_free);
- stats->cmd = ETHTOOL_GSTATS;
- stats->n_stats = peer_ifindex_stat + 1;
- if (_ethtool_call_handle(&shandle, stats, stats_len) < 0)
- return 0;
-
- return stats->data[peer_ifindex_stat];
-}
-
-gboolean
-nmp_utils_ethtool_get_wake_on_lan(int ifindex)
-{
- struct ethtool_wolinfo wol = {
- .cmd = ETHTOOL_GWOL,
- };
-
- g_return_val_if_fail(ifindex > 0, FALSE);
-
- if (_ethtool_call_once(ifindex, &wol, sizeof(wol)) < 0)
- return FALSE;
-
- return wol.wolopts != 0;
-}
-
-gboolean
-nmp_utils_ethtool_get_link_settings(int ifindex,
- gboolean * out_autoneg,
- guint32 * out_speed,
- NMPlatformLinkDuplexType *out_duplex)
-{
- struct ethtool_cmd edata = {
- .cmd = ETHTOOL_GSET,
- };
-
- g_return_val_if_fail(ifindex > 0, FALSE);
-
- if (_ethtool_call_once(ifindex, &edata, sizeof(edata)) < 0)
- return FALSE;
-
- NM_SET_OUT(out_autoneg, (edata.autoneg == AUTONEG_ENABLE));
-
- if (out_speed) {
- guint32 speed;
-
- speed = ethtool_cmd_speed(&edata);
- if (speed == G_MAXUINT16 || speed == G_MAXUINT32)
- speed = 0;
-
- *out_speed = speed;
- }
-
- if (out_duplex) {
- switch (edata.duplex) {
- case DUPLEX_HALF:
- *out_duplex = NM_PLATFORM_LINK_DUPLEX_HALF;
- break;
- case DUPLEX_FULL:
- *out_duplex = NM_PLATFORM_LINK_DUPLEX_FULL;
- break;
- default: /* DUPLEX_UNKNOWN */
- *out_duplex = NM_PLATFORM_LINK_DUPLEX_UNKNOWN;
- break;
- }
- }
-
- return TRUE;
-}
-
-#define ADVERTISED_INVALID 0
-#define BASET_ALL_MODES \
- (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half \
- | ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full \
- | ADVERTISED_10000baseT_Full)
-
-static guint32
-get_baset_mode(guint32 speed, NMPlatformLinkDuplexType duplex)
-{
- if (duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN)
- return ADVERTISED_INVALID;
-
- if (duplex == NM_PLATFORM_LINK_DUPLEX_HALF) {
- switch (speed) {
- case 10:
- return ADVERTISED_10baseT_Half;
- case 100:
- return ADVERTISED_100baseT_Half;
- case 1000:
- return ADVERTISED_1000baseT_Half;
- default:
- return ADVERTISED_INVALID;
- }
- } else {
- switch (speed) {
- case 10:
- return ADVERTISED_10baseT_Full;
- case 100:
- return ADVERTISED_100baseT_Full;
- case 1000:
- return ADVERTISED_1000baseT_Full;
- case 10000:
- return ADVERTISED_10000baseT_Full;
- default:
- return ADVERTISED_INVALID;
- }
- }
-}
-
-gboolean
-nmp_utils_ethtool_set_link_settings(int ifindex,
- gboolean autoneg,
- guint32 speed,
- NMPlatformLinkDuplexType duplex)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
- struct ethtool_cmd edata = {
- .cmd = ETHTOOL_GSET,
- };
-
- g_return_val_if_fail(ifindex > 0, FALSE);
- g_return_val_if_fail((speed && duplex != NM_PLATFORM_LINK_DUPLEX_UNKNOWN)
- || (!speed && duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN),
- FALSE);
-
- /* retrieve first current settings */
- if (_ethtool_call_handle(&shandle, &edata, sizeof(edata)) < 0)
- return FALSE;
-
- /* FIXME: try first new ETHTOOL_GLINKSETTINGS/SLINKSETTINGS API
- * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3f1ac7a700d039c61d8d8b99f28d605d489a60cf
- */
-
- /* then change the needed ones */
- edata.cmd = ETHTOOL_SSET;
- if (autoneg) {
- edata.autoneg = AUTONEG_ENABLE;
- if (!speed)
- edata.advertising = edata.supported;
- else {
- guint32 mode;
-
- mode = get_baset_mode(speed, duplex);
-
- if (!mode) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: %uBASE-T %s duplex mode cannot be advertised",
- ifindex,
- speed,
- nm_platform_link_duplex_type_to_string(duplex));
- return FALSE;
- }
- if (!(edata.supported & mode)) {
- nm_log_trace(LOGD_PLATFORM,
- "ethtool[%d]: device does not support %uBASE-T %s duplex mode",
- ifindex,
- speed,
- nm_platform_link_duplex_type_to_string(duplex));
- return FALSE;
- }
- edata.advertising = (edata.supported & ~BASET_ALL_MODES) | mode;
- }
- } else {
- edata.autoneg = AUTONEG_DISABLE;
-
- if (speed)
- ethtool_cmd_speed_set(&edata, speed);
-
- switch (duplex) {
- case NM_PLATFORM_LINK_DUPLEX_HALF:
- edata.duplex = DUPLEX_HALF;
- break;
- case NM_PLATFORM_LINK_DUPLEX_FULL:
- edata.duplex = DUPLEX_FULL;
- break;
- case NM_PLATFORM_LINK_DUPLEX_UNKNOWN:
- break;
- default:
- g_return_val_if_reached(FALSE);
- }
- }
-
- return _ethtool_call_handle(&shandle, &edata, sizeof(edata)) >= 0;
-}
-
-gboolean
-nmp_utils_ethtool_set_wake_on_lan(int ifindex,
- _NMSettingWiredWakeOnLan wol,
- const char * wol_password)
-{
- struct ethtool_wolinfo wol_info = {
- .cmd = ETHTOOL_SWOL,
- .wolopts = 0,
- };
-
- g_return_val_if_fail(ifindex > 0, FALSE);
-
- if (wol == _NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE)
- return TRUE;
-
- nm_log_dbg(LOGD_PLATFORM,
- "ethtool[%d]: setting Wake-on-LAN options 0x%x, password '%s'",
- ifindex,
- (unsigned) wol,
- wol_password);
-
- if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_PHY))
- wol_info.wolopts |= WAKE_PHY;
- if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST))
- wol_info.wolopts |= WAKE_UCAST;
- if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST))
- wol_info.wolopts |= WAKE_MCAST;
- if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST))
- wol_info.wolopts |= WAKE_BCAST;
- if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_ARP))
- wol_info.wolopts |= WAKE_ARP;
- if (NM_FLAGS_HAS(wol, _NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC))
- wol_info.wolopts |= WAKE_MAGIC;
-
- if (wol_password) {
- if (!_nm_utils_hwaddr_aton_exact(wol_password, wol_info.sopass, ETH_ALEN)) {
- nm_log_dbg(LOGD_PLATFORM,
- "ethtool[%d]: couldn't parse Wake-on-LAN password '%s'",
- ifindex,
- wol_password);
- return FALSE;
- }
- wol_info.wolopts |= WAKE_MAGICSECURE;
- }
-
- return _ethtool_call_once(ifindex, &wol_info, sizeof(wol_info)) >= 0;
-}
-
-/******************************************************************************
- * mii
- *****************************************************************************/
-
-gboolean
-nmp_utils_mii_supports_carrier_detect(int ifindex)
-{
- nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
- int r;
- struct ifreq ifr;
- struct mii_ioctl_data * mii;
-
- g_return_val_if_fail(ifindex > 0, FALSE);
-
- r = _ioctl_call("mii",
- "SIOCGMIIPHY",
- SIOCGMIIPHY,
- shandle.ifindex,
- &shandle.fd,
- shandle.ifname,
- IOCTL_CALL_DATA_TYPE_NONE,
- NULL,
- 0,
- &ifr);
- if (r < 0)
- return FALSE;
-
- /* If we can read the BMSR register, we assume that the card supports MII link detection */
- mii = (struct mii_ioctl_data *) &ifr.ifr_ifru;
- mii->reg_num = MII_BMSR;
-
- r = _ioctl_call("mii",
- "SIOCGMIIREG",
- SIOCGMIIREG,
- shandle.ifindex,
- &shandle.fd,
- shandle.ifname,
- IOCTL_CALL_DATA_TYPE_IFRU,
- mii,
- sizeof(*mii),
- &ifr);
- if (r < 0)
- return FALSE;
-
- mii = (struct mii_ioctl_data *) &ifr.ifr_ifru;
- nm_log_trace(LOGD_PLATFORM,
- "mii[%d,%s]: carrier-detect yes: SIOCGMIIREG result 0x%X",
- ifindex,
- shandle.ifname,
- mii->val_out);
- return TRUE;
-}
-
-/******************************************************************************
- * udev
- *****************************************************************************/
-
-const char *
-nmp_utils_udev_get_driver(struct udev_device *udevice)
-{
- struct udev_device *parent = NULL, *grandparent = NULL;
- const char * driver, *subsys;
-
- driver = udev_device_get_driver(udevice);
- if (driver)
- goto out;
-
- /* Try the parent */
- parent = udev_device_get_parent(udevice);
- if (parent) {
- driver = udev_device_get_driver(parent);
- if (!driver) {
- /* Try the grandparent if it's an ibmebus device or if the
- * subsys is NULL which usually indicates some sort of
- * platform device like a 'gadget' net interface.
- */
- subsys = udev_device_get_subsystem(parent);
- if ((g_strcmp0(subsys, "ibmebus") == 0) || (subsys == NULL)) {
- grandparent = udev_device_get_parent(parent);
- if (grandparent)
- driver = udev_device_get_driver(grandparent);
- }
- }
- }
-
-out:
- /* Intern the string so we don't have to worry about memory
- * management in NMPlatformLink. */
- return g_intern_string(driver);
-}
-
-/******************************************************************************
- * utils
- *****************************************************************************/
-
-NMIPConfigSource
-nmp_utils_ip_config_source_from_rtprot(guint8 rtprot)
-{
- return ((int) rtprot) + 1;
-}
-
-NMIPConfigSource
-nmp_utils_ip_config_source_round_trip_rtprot(NMIPConfigSource source)
-{
- /* when adding a route to kernel for a give @source, the resulting route
- * will be put into the cache with a source of NM_IP_CONFIG_SOURCE_RTPROT_*.
- * This function returns that. */
- return nmp_utils_ip_config_source_from_rtprot(
- nmp_utils_ip_config_source_coerce_to_rtprot(source));
-}
-
-guint8
-nmp_utils_ip_config_source_coerce_to_rtprot(NMIPConfigSource source)
-{
- /* when adding a route to kernel, we coerce the @source field
- * to rtm_protocol. This is not lossless as we map different
- * source values to the same RTPROT uint8 value. */
- if (source <= NM_IP_CONFIG_SOURCE_UNKNOWN)
- return RTPROT_UNSPEC;
-
- if (source <= _NM_IP_CONFIG_SOURCE_RTPROT_LAST)
- return source - 1;
-
- 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:
- return RTPROT_RA;
-
- default:
- return RTPROT_STATIC;
- }
-}
-
-NMIPConfigSource
-nmp_utils_ip_config_source_coerce_from_rtprot(NMIPConfigSource source)
-{
- /* When we receive a route from kernel and put it into the platform cache,
- * we preserve the protocol field by converting it to a NMIPConfigSource
- * via nmp_utils_ip_config_source_from_rtprot().
- *
- * However, that is not the inverse of nmp_utils_ip_config_source_coerce_to_rtprot().
- * Instead, to go back to the original value, you need another step:
- * nmp_utils_ip_config_source_coerce_from_rtprot (nmp_utils_ip_config_source_from_rtprot (rtprot)).
- *
- * This might partly restore the original source value, but of course that
- * is not really possible because nmp_utils_ip_config_source_coerce_to_rtprot()
- * is not injective.
- * */
- switch (source) {
- case NM_IP_CONFIG_SOURCE_RTPROT_UNSPEC:
- return NM_IP_CONFIG_SOURCE_UNKNOWN;
-
- case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
- case NM_IP_CONFIG_SOURCE_RTPROT_REDIRECT:
- return NM_IP_CONFIG_SOURCE_KERNEL;
-
- case NM_IP_CONFIG_SOURCE_RTPROT_RA:
- return NM_IP_CONFIG_SOURCE_NDISC;
-
- case NM_IP_CONFIG_SOURCE_RTPROT_DHCP:
- return NM_IP_CONFIG_SOURCE_DHCP;
-
- default:
- return NM_IP_CONFIG_SOURCE_USER;
- }
-}
-
-const char *
-nmp_utils_ip_config_source_to_string(NMIPConfigSource source, char *buf, gsize len)
-{
- const char *s = NULL;
- nm_utils_to_string_buffer_init(&buf, &len);
-
- if (!len)
- return buf;
-
- switch (source) {
- case NM_IP_CONFIG_SOURCE_UNKNOWN:
- s = "unknown";
- break;
-
- case NM_IP_CONFIG_SOURCE_RTPROT_UNSPEC:
- s = "rt-unspec";
- break;
- case NM_IP_CONFIG_SOURCE_RTPROT_REDIRECT:
- s = "rt-redirect";
- break;
- case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
- s = "rt-kernel";
- break;
- case NM_IP_CONFIG_SOURCE_RTPROT_BOOT:
- s = "rt-boot";
- break;
- case NM_IP_CONFIG_SOURCE_RTPROT_STATIC:
- s = "rt-static";
- break;
- case NM_IP_CONFIG_SOURCE_RTPROT_DHCP:
- s = "rt-dhcp";
- break;
- case NM_IP_CONFIG_SOURCE_RTPROT_RA:
- s = "rt-ra";
- break;
-
- 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;
- case NM_IP_CONFIG_SOURCE_DHCP:
- s = "dhcp";
- break;
- case NM_IP_CONFIG_SOURCE_NDISC:
- s = "ndisc";
- break;
- case NM_IP_CONFIG_SOURCE_USER:
- s = "user";
- break;
- default:
- break;
- }
-
- if (source >= 1 && source <= 0x100) {
- if (s)
- g_snprintf(buf, len, "%s", s);
- else
- g_snprintf(buf, len, "rt-%d", ((int) source) - 1);
- } else {
- if (s)
- g_strlcpy(buf, s, len);
- else
- g_snprintf(buf, len, "(%d)", source);
- }
- return buf;
-}
-
-/**
- * nmp_utils_sysctl_open_netdir:
- * @ifindex: the ifindex for which to open "/sys/class/net/%s"
- * @ifname_guess: (allow-none): optional argument, if present used as initial
- * guess as the current name for @ifindex. If guessed right,
- * it saves an additional if_indextoname() call.
- * @out_ifname: (allow-none): if present, must be at least IFNAMSIZ
- * characters. On success, this will contain the actual ifname
- * found while opening the directory.
- *
- * Returns: a negative value on failure, on success returns the open fd
- * to the "/sys/class/net/%s" directory for @ifindex.
- */
-int
-nmp_utils_sysctl_open_netdir(int ifindex, const char *ifname_guess, char *out_ifname)
-{
-#define SYS_CLASS_NET "/sys/class/net/"
- const char *ifname = ifname_guess;
- char ifname_buf_last_try[IFNAMSIZ];
- char ifname_buf[IFNAMSIZ];
- guint try_count = 0;
- char sysdir[NM_STRLEN(SYS_CLASS_NET) + IFNAMSIZ] = SYS_CLASS_NET;
- char fd_buf[256];
- ssize_t nn;
-
- g_return_val_if_fail(ifindex >= 0, -1);
-
- ifname_buf_last_try[0] = '\0';
-
- for (try_count = 0; try_count < 10; try_count++, ifname = NULL) {
- nm_auto_close int fd_dir = -1;
- nm_auto_close int fd_ifindex = -1;
-
- if (!ifname) {
- ifname = nmp_utils_if_indextoname(ifindex, ifname_buf);
- if (!ifname)
- return -1;
- }
-
- nm_assert(nm_utils_ifname_valid_kernel(ifname, NULL));
-
- if (g_strlcpy(&sysdir[NM_STRLEN(SYS_CLASS_NET)], ifname, IFNAMSIZ) >= IFNAMSIZ)
- g_return_val_if_reached(-1);
-
- /* we only retry, if the name changed since previous attempt.
- * Hence, it is extremely unlikely that this loop runes until the
- * end of the @try_count. */
- if (nm_streq(ifname, ifname_buf_last_try))
- return -1;
- strcpy(ifname_buf_last_try, ifname);
-
- fd_dir = open(sysdir, O_DIRECTORY | O_CLOEXEC);
- if (fd_dir < 0)
- continue;
-
- fd_ifindex = openat(fd_dir, "ifindex", O_CLOEXEC);
- if (fd_ifindex < 0)
- continue;
-
- nn = nm_utils_fd_read_loop(fd_ifindex, fd_buf, sizeof(fd_buf) - 2, FALSE);
- if (nn <= 0)
- continue;
- fd_buf[nn] = '\0';
-
- if (ifindex != (int) _nm_utils_ascii_str_to_int64(fd_buf, 10, 1, G_MAXINT, -1))
- continue;
-
- if (out_ifname)
- strcpy(out_ifname, ifname);
-
- return nm_steal_fd(&fd_dir);
- }
-
- return -1;
-}
diff --git a/shared/nm-platform/nm-platform-utils.h b/shared/nm-platform/nm-platform-utils.h
deleted file mode 100644
index d74723eb9f..0000000000
--- a/shared/nm-platform/nm-platform-utils.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- */
-
-#ifndef __NM_PLATFORM_UTILS_H__
-#define __NM_PLATFORM_UTILS_H__
-
-#include "nm-base/nm-base.h"
-#include "nm-platform/nmp-base.h"
-
-/*****************************************************************************/
-
-const char *nmp_utils_ethtool_get_driver(int ifindex);
-gboolean nmp_utils_ethtool_supports_carrier_detect(int ifindex);
-gboolean nmp_utils_ethtool_supports_vlans(int ifindex);
-int nmp_utils_ethtool_get_peer_ifindex(int ifindex);
-gboolean nmp_utils_ethtool_get_wake_on_lan(int ifindex);
-gboolean nmp_utils_ethtool_set_wake_on_lan(int ifindex,
- _NMSettingWiredWakeOnLan wol,
- const char * wol_password);
-
-const char *nm_platform_link_duplex_type_to_string(NMPlatformLinkDuplexType duplex);
-
-gboolean nmp_utils_ethtool_get_link_settings(int ifindex,
- gboolean * out_autoneg,
- guint32 * out_speed,
- NMPlatformLinkDuplexType *out_duplex);
-gboolean nmp_utils_ethtool_set_link_settings(int ifindex,
- gboolean autoneg,
- guint32 speed,
- NMPlatformLinkDuplexType duplex);
-
-gboolean nmp_utils_ethtool_get_permanent_address(int ifindex, guint8 *buf, size_t *length);
-
-gboolean nmp_utils_ethtool_get_driver_info(int ifindex, NMPUtilsEthtoolDriverInfo *data);
-
-NMEthtoolFeatureStates *nmp_utils_ethtool_get_features(int ifindex);
-
-gboolean nmp_utils_ethtool_set_features(
- int ifindex,
- const NMEthtoolFeatureStates *features,
- const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
- gboolean do_set /* or reset */);
-
-gboolean nmp_utils_ethtool_get_coalesce(int ifindex, NMEthtoolCoalesceState *coalesce);
-
-gboolean nmp_utils_ethtool_set_coalesce(int ifindex, const NMEthtoolCoalesceState *coalesce);
-
-gboolean nmp_utils_ethtool_get_ring(int ifindex, NMEthtoolRingState *ring);
-
-gboolean nmp_utils_ethtool_set_ring(int ifindex, const NMEthtoolRingState *ring);
-
-/*****************************************************************************/
-
-gboolean nmp_utils_mii_supports_carrier_detect(int ifindex);
-
-struct udev_device;
-
-const char *nmp_utils_udev_get_driver(struct udev_device *udevice);
-
-NMIPConfigSource nmp_utils_ip_config_source_from_rtprot(guint8 rtprot) _nm_const;
-guint8 nmp_utils_ip_config_source_coerce_to_rtprot(NMIPConfigSource source) _nm_const;
-NMIPConfigSource nmp_utils_ip_config_source_coerce_from_rtprot(NMIPConfigSource source) _nm_const;
-NMIPConfigSource nmp_utils_ip_config_source_round_trip_rtprot(NMIPConfigSource source) _nm_const;
-const char *nmp_utils_ip_config_source_to_string(NMIPConfigSource source, char *buf, gsize len);
-
-const char *nmp_utils_if_indextoname(int ifindex, char *out_ifname /*IFNAMSIZ*/);
-int nmp_utils_if_nametoindex(const char *ifname);
-
-int nmp_utils_sysctl_open_netdir(int ifindex, const char *ifname_guess, char *out_ifname);
-
-#endif /* __NM_PLATFORM_UTILS_H__ */
diff --git a/shared/nm-platform/nmp-base.h b/shared/nm-platform/nmp-base.h
deleted file mode 100644
index 210c26d6bb..0000000000
--- a/shared/nm-platform/nmp-base.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#ifndef __NMP_FWD_H__
-#define __NMP_FWD_H__
-
-#include "nm-base/nm-base.h"
-
-/*****************************************************************************/
-
-typedef enum {
- NM_PLATFORM_LINK_DUPLEX_UNKNOWN,
- NM_PLATFORM_LINK_DUPLEX_HALF,
- NM_PLATFORM_LINK_DUPLEX_FULL,
-} NMPlatformLinkDuplexType;
-
-/*****************************************************************************/
-
-typedef struct {
- /* We don't want to include <linux/ethtool.h> in header files,
- * thus create a ABI compatible version of struct ethtool_drvinfo.*/
- guint32 _private_cmd;
- char driver[32];
- char version[32];
- char fw_version[32];
- char _private_bus_info[32];
- char _private_erom_version[32];
- char _private_reserved2[12];
- guint32 _private_n_priv_flags;
- guint32 _private_n_stats;
- guint32 _private_testinfo_len;
- guint32 _private_eedump_len;
- guint32 _private_regdump_len;
-} NMPUtilsEthtoolDriverInfo;
-
-typedef struct {
- NMEthtoolID ethtool_id;
-
- guint8 n_kernel_names;
-
- /* one NMEthtoolID refers to one or more kernel_names. The reason for supporting this complexity
- * (where one NMSettingEthtool option refers to multiple kernel features) is to follow what
- * ethtool does, where "tx" is an alias for multiple features. */
- const char *const *kernel_names;
-} NMEthtoolFeatureInfo;
-
-typedef struct {
- const NMEthtoolFeatureInfo *info;
-
- guint idx_ss_features;
-
- /* one NMEthtoolFeatureInfo references one or more kernel_names. This is the index
- * of the matching info->kernel_names */
- guint8 idx_kernel_name;
-
- bool available : 1;
- bool requested : 1;
- bool active : 1;
- bool never_changed : 1;
-} NMEthtoolFeatureState;
-
-typedef struct {
- guint n_states;
-
- guint n_ss_features;
-
- /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */
- const NMEthtoolFeatureState *const *states_indexed[_NM_ETHTOOL_ID_FEATURE_NUM];
-
- /* the same content, here as a list of n_states entries. */
- const NMEthtoolFeatureState states_list[];
-} NMEthtoolFeatureStates;
-
-/*****************************************************************************/
-
-typedef struct {
- guint32
- s[_NM_ETHTOOL_ID_COALESCE_NUM /* indexed by (NMEthtoolID - _NM_ETHTOOL_ID_COALESCE_FIRST) */
- ];
-} NMEthtoolCoalesceState;
-
-/*****************************************************************************/
-
-typedef struct {
- guint32 rx_pending;
- guint32 rx_mini_pending;
- guint32 rx_jumbo_pending;
- guint32 tx_pending;
-} NMEthtoolRingState;
-
-/*****************************************************************************/
-
-typedef struct _NMPNetns NMPNetns;
-
-#endif /* __NMP_FWD_H__ */
diff --git a/shared/nm-platform/nmp-netns.c b/shared/nm-platform/nmp-netns.c
deleted file mode 100644
index f97339a756..0000000000
--- a/shared/nm-platform/nmp-netns.c
+++ /dev/null
@@ -1,767 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#include "nm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nmp-netns.h"
-
-#include <fcntl.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <pthread.h>
-
-#include "nm-log-core/nm-logging.h"
-
-/*****************************************************************************/
-
-/* NOTE: NMPNetns and all code used here must be thread-safe! */
-
-/* we may not call logging functions from the main-thread alone. Hence, we
- * require locking from nm-logging. Indicate that by setting NM_THREAD_SAFE_ON_MAIN_THREAD
- * to zero. */
-#undef NM_THREAD_SAFE_ON_MAIN_THREAD
-#define NM_THREAD_SAFE_ON_MAIN_THREAD 0
-
-/*****************************************************************************/
-
-#define PROC_SELF_NS_MNT "/proc/self/ns/mnt"
-#define PROC_SELF_NS_NET "/proc/self/ns/net"
-
-#define _CLONE_NS_ALL ((int) (CLONE_NEWNS | CLONE_NEWNET))
-#define _CLONE_NS_ALL_V CLONE_NEWNS, CLONE_NEWNET
-
-static NM_UTILS_FLAGS2STR_DEFINE(_clone_ns_to_str,
- int,
- NM_UTILS_FLAGS2STR(CLONE_NEWNS, "mnt"),
- NM_UTILS_FLAGS2STR(CLONE_NEWNET, "net"), );
-
-static const char *
-__ns_types_to_str(int ns_types, int ns_types_already_set, char *buf, gsize len)
-{
- const char *b = buf;
- char bb[200];
-
- nm_utils_strbuf_append_c(&buf, &len, '[');
- if (ns_types & ~ns_types_already_set) {
- nm_utils_strbuf_append_str(
- &buf,
- &len,
- _clone_ns_to_str(ns_types & ~ns_types_already_set, bb, sizeof(bb)));
- }
- if (ns_types & ns_types_already_set) {
- if (ns_types & ~ns_types_already_set)
- nm_utils_strbuf_append_c(&buf, &len, '/');
- nm_utils_strbuf_append_str(
- &buf,
- &len,
- _clone_ns_to_str(ns_types & ns_types_already_set, bb, sizeof(bb)));
- }
- nm_utils_strbuf_append_c(&buf, &len, ']');
- return b;
-}
-#define _ns_types_to_str(ns_types, ns_types_already_set, buf) \
- __ns_types_to_str(ns_types, ns_types_already_set, buf, sizeof(buf))
-
-/*****************************************************************************/
-
-#define _NMLOG_DOMAIN LOGD_PLATFORM
-#define _NMLOG_PREFIX_NAME "netns"
-#define _NMLOG(level, netns, ...) \
- G_STMT_START \
- { \
- NMLogLevel _level = (level); \
- \
- if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \
- NMPNetns *_netns = (netns); \
- char _sbuf[20]; \
- \
- _nm_log(_level, \
- _NMLOG_DOMAIN, \
- 0, \
- NULL, \
- NULL, \
- "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- _NMLOG_PREFIX_NAME, \
- (_netns ? nm_sprintf_buf(_sbuf, "[%p]", _netns) \
- : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } \
- G_STMT_END
-
-/*****************************************************************************/
-
-NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_FD_NET, PROP_FD_MNT, );
-
-typedef struct {
- int fd_net;
- int fd_mnt;
-} NMPNetnsPrivate;
-
-struct _NMPNetns {
- GObject parent;
- NMPNetnsPrivate _priv;
-};
-
-struct _NMPNetnsClass {
- GObjectClass parent;
-};
-
-G_DEFINE_TYPE(NMPNetns, nmp_netns, G_TYPE_OBJECT);
-
-#define NMP_NETNS_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMPNetns, NMP_IS_NETNS)
-
-/*****************************************************************************/
-
-typedef struct {
- NMPNetns *netns;
- int count;
- int ns_types;
-} NetnsInfo;
-
-static void _stack_push(GArray *netns_stack, NMPNetns *netns, int ns_types);
-static NMPNetns *_netns_new(GError **error);
-
-/*****************************************************************************/
-
-static NMPNetns *
-_netns_get(NetnsInfo *info)
-{
- nm_assert(!info || NMP_IS_NETNS(info->netns));
- return info ? info->netns : NULL;
-}
-
-/*****************************************************************************/
-
-static _nm_thread_local GArray *_netns_stack = NULL;
-
-static void
-_netns_stack_clear_cb(gpointer data)
-{
- NetnsInfo *info = data;
-
- nm_assert(NMP_IS_NETNS(info->netns));
- g_object_unref(info->netns);
-}
-
-static GArray *
-_netns_stack_get_impl(void)
-{
- gs_unref_object NMPNetns *netns = NULL;
- gs_free_error GError *error = NULL;
- pthread_key_t key;
- GArray * s;
-
- s = g_array_new(FALSE, FALSE, sizeof(NetnsInfo));
- g_array_set_clear_func(s, _netns_stack_clear_cb);
- _netns_stack = s;
-
- /* register a destructor function to cleanup the array. If we fail
- * to do so, we will leak NMPNetns instances (and their file descriptor) when the
- * thread exits. */
- if (pthread_key_create(&key, (void (*)(void *)) g_array_unref) != 0)
- _LOGE(NULL, "failure to initialize thread-local storage");
- else if (pthread_setspecific(key, s) != 0)
- _LOGE(NULL, "failure to set thread-local storage");
-
- /* at the bottom of the stack we must try to create a netns instance
- * that we never pop. It's the base to which we need to return. */
- netns = _netns_new(&error);
-
- if (!netns) {
- _LOGD(NULL, "failed to create initial netns: %s", error->message);
- return s;
- }
-
- /* we leak this instance inside the stack. */
- _stack_push(s, netns, _CLONE_NS_ALL);
-
- return s;
-}
-
-#define _netns_stack_get() \
- ({ \
- GArray *_s = _netns_stack; \
- \
- if (G_UNLIKELY(!_s)) \
- _s = _netns_stack_get_impl(); \
- _s; \
- })
-
-/*****************************************************************************/
-
-static NMPNetns *
-_stack_current_netns(GArray *netns_stack, int ns_types)
-{
- guint j;
-
- nm_assert(netns_stack && netns_stack->len > 0);
-
- /* we search the stack top-down to find the netns that has
- * all @ns_types set. */
- for (j = netns_stack->len; ns_types && j >= 1;) {
- NetnsInfo *info;
-
- info = &g_array_index(netns_stack, NetnsInfo, --j);
-
- if (NM_FLAGS_ALL(info->ns_types, ns_types))
- return info->netns;
- }
-
- g_return_val_if_reached(NULL);
-}
-
-static int
-_stack_current_ns_types(GArray *netns_stack, NMPNetns *netns, int ns_types)
-{
- const int ns_types_check[] = {_CLONE_NS_ALL_V};
- guint i, j;
- int res = 0;
-
- nm_assert(netns);
- nm_assert(netns_stack && netns_stack->len > 0);
-
- /* we search the stack top-down to check which of @ns_types
- * are already set to @netns. */
- for (j = netns_stack->len; ns_types && j >= 1;) {
- NetnsInfo *info;
-
- info = &g_array_index(netns_stack, NetnsInfo, --j);
- if (info->netns != netns) {
- ns_types = NM_FLAGS_UNSET(ns_types, info->ns_types);
- continue;
- }
-
- 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])) {
- res = NM_FLAGS_SET(res, ns_types_check[i]);
- ns_types = NM_FLAGS_UNSET(ns_types, ns_types_check[i]);
- }
- }
- }
-
- return res;
-}
-
-static NetnsInfo *
-_stack_peek(GArray *netns_stack)
-{
- if (netns_stack->len > 0)
- return &g_array_index(netns_stack, NetnsInfo, (netns_stack->len - 1));
- return NULL;
-}
-
-static NetnsInfo *
-_stack_bottom(GArray *netns_stack)
-{
- if (netns_stack->len > 0)
- return &g_array_index(netns_stack, NetnsInfo, 0);
- return NULL;
-}
-
-static void
-_stack_push(GArray *netns_stack, NMPNetns *netns, int ns_types)
-{
- NetnsInfo *info;
-
- nm_assert(netns_stack);
- nm_assert(NMP_IS_NETNS(netns));
- nm_assert(NM_FLAGS_ANY(ns_types, _CLONE_NS_ALL));
- nm_assert(!NM_FLAGS_ANY(ns_types, ~_CLONE_NS_ALL));
-
- g_array_set_size(netns_stack, netns_stack->len + 1);
-
- info = &g_array_index(netns_stack, NetnsInfo, (netns_stack->len - 1));
- *info = (NetnsInfo){
- .netns = g_object_ref(netns),
- .ns_types = ns_types,
- .count = 1,
- };
-}
-
-static void
-_stack_pop(GArray *netns_stack)
-{
- NetnsInfo *info;
-
- nm_assert(netns_stack);
- nm_assert(netns_stack->len > 1);
-
- info = &g_array_index(netns_stack, NetnsInfo, (netns_stack->len - 1));
-
- nm_assert(NMP_IS_NETNS(info->netns));
- nm_assert(info->count == 1);
-
- g_array_set_size(netns_stack, netns_stack->len - 1);
-}
-
-static guint
-_stack_size(GArray *netns_stack)
-{
- nm_assert(netns_stack);
-
- return netns_stack->len;
-}
-
-/*****************************************************************************/
-
-static NMPNetns *
-_netns_new(GError **error)
-{
- NMPNetns *self;
- int fd_net, fd_mnt;
- int errsv;
-
- fd_net = open(PROC_SELF_NS_NET, O_RDONLY | O_CLOEXEC);
- if (fd_net == -1) {
- errsv = errno;
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_UNKNOWN,
- "Failed opening netns: %s",
- nm_strerror_native(errsv));
- errno = errsv;
- return NULL;
- }
-
- fd_mnt = open(PROC_SELF_NS_MNT, O_RDONLY | O_CLOEXEC);
- if (fd_mnt == -1) {
- errsv = errno;
- g_set_error(error,
- NM_UTILS_ERROR,
- NM_UTILS_ERROR_UNKNOWN,
- "Failed opening mntns: %s",
- nm_strerror_native(errsv));
- nm_close(fd_net);
- errno = errsv;
- return NULL;
- }
-
- self = g_object_new(NMP_TYPE_NETNS, NMP_NETNS_FD_NET, fd_net, NMP_NETNS_FD_MNT, fd_mnt, NULL);
-
- _LOGD(self, "new netns (net:%d, mnt:%d)", fd_net, fd_mnt);
-
- return self;
-}
-
-static int
-_setns(NMPNetns *self, int type)
-{
- char buf[100];
- int fd;
- NMPNetnsPrivate *priv = NMP_NETNS_GET_PRIVATE(self);
-
- nm_assert(NM_IN_SET(type, _CLONE_NS_ALL_V));
-
- fd = (type == CLONE_NEWNET) ? priv->fd_net : priv->fd_mnt;
-
- _LOGt(self, "set netns(%s, %d)", _ns_types_to_str(type, 0, buf), fd);
-
- return setns(fd, type);
-}
-
-static gboolean
-_netns_switch_push(GArray *netns_stack, NMPNetns *self, int ns_types)
-{
- int errsv;
-
- if (NM_FLAGS_HAS(ns_types, CLONE_NEWNET)
- && !_stack_current_ns_types(netns_stack, self, CLONE_NEWNET)
- && _setns(self, CLONE_NEWNET) != 0) {
- errsv = errno;
- _LOGE(self, "failed to switch netns: %s", nm_strerror_native(errsv));
- return FALSE;
- }
- if (NM_FLAGS_HAS(ns_types, CLONE_NEWNS)
- && !_stack_current_ns_types(netns_stack, self, CLONE_NEWNS)
- && _setns(self, CLONE_NEWNS) != 0) {
- errsv = errno;
- _LOGE(self, "failed to switch mntns: %s", nm_strerror_native(errsv));
-
- /* try to fix the mess by returning to the previous netns. */
- if (NM_FLAGS_HAS(ns_types, CLONE_NEWNET)
- && !_stack_current_ns_types(netns_stack, self, CLONE_NEWNET)) {
- self = _stack_current_netns(netns_stack, CLONE_NEWNET);
- if (self && _setns(self, CLONE_NEWNET) != 0) {
- errsv = errno;
- _LOGE(self, "failed to restore netns: %s", nm_strerror_native(errsv));
- }
- }
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gboolean
-_netns_switch_pop(GArray *netns_stack, NMPNetns *self, int ns_types)
-{
- int errsv;
- NMPNetns *current;
- int success = TRUE;
-
- if (NM_FLAGS_HAS(ns_types, CLONE_NEWNET)
- && (!self || !_stack_current_ns_types(netns_stack, self, CLONE_NEWNET))) {
- current = _stack_current_netns(netns_stack, CLONE_NEWNET);
- if (!current) {
- g_warn_if_reached();
- success = FALSE;
- } else if (_setns(current, CLONE_NEWNET) != 0) {
- errsv = errno;
- _LOGE(self, "failed to switch netns: %s", nm_strerror_native(errsv));
- success = FALSE;
- }
- }
- if (NM_FLAGS_HAS(ns_types, CLONE_NEWNS)
- && (!self || !_stack_current_ns_types(netns_stack, self, CLONE_NEWNS))) {
- current = _stack_current_netns(netns_stack, CLONE_NEWNS);
- if (!current) {
- g_warn_if_reached();
- success = FALSE;
- } else if (_setns(current, CLONE_NEWNS) != 0) {
- errsv = errno;
- _LOGE(self, "failed to switch mntns: %s", nm_strerror_native(errsv));
- success = FALSE;
- }
- }
-
- return success;
-}
-
-/*****************************************************************************/
-
-int
-nmp_netns_get_fd_net(NMPNetns *self)
-{
- g_return_val_if_fail(NMP_IS_NETNS(self), 0);
-
- return NMP_NETNS_GET_PRIVATE(self)->fd_net;
-}
-
-int
-nmp_netns_get_fd_mnt(NMPNetns *self)
-{
- g_return_val_if_fail(NMP_IS_NETNS(self), 0);
-
- return NMP_NETNS_GET_PRIVATE(self)->fd_mnt;
-}
-
-/*****************************************************************************/
-
-static gboolean
-_nmp_netns_push_type(NMPNetns *self, int ns_types)
-{
- GArray * netns_stack = _netns_stack_get();
- NetnsInfo *info;
- char sbuf[100];
-
- info = _stack_peek(netns_stack);
- g_return_val_if_fail(info, FALSE);
-
- if (info->netns == self && info->ns_types == ns_types) {
- info->count++;
- _LOGt(self,
- "push#%u* %s (increase count to %d)",
- _stack_size(netns_stack) - 1,
- _ns_types_to_str(ns_types, ns_types, sbuf),
- info->count);
- return TRUE;
- }
-
- _LOGD(self,
- "push#%u %s",
- _stack_size(netns_stack),
- _ns_types_to_str(ns_types, _stack_current_ns_types(netns_stack, self, ns_types), sbuf));
-
- if (!_netns_switch_push(netns_stack, self, ns_types))
- return FALSE;
-
- _stack_push(netns_stack, self, ns_types);
- return TRUE;
-}
-
-gboolean
-nmp_netns_push(NMPNetns *self)
-{
- g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
-
- return _nmp_netns_push_type(self, _CLONE_NS_ALL);
-}
-
-gboolean
-nmp_netns_push_type(NMPNetns *self, int ns_types)
-{
- g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
- g_return_val_if_fail(!NM_FLAGS_ANY(ns_types, ~_CLONE_NS_ALL), FALSE);
-
- return _nmp_netns_push_type(self, ns_types == 0 ? _CLONE_NS_ALL : ns_types);
-}
-
-NMPNetns *
-nmp_netns_new(void)
-{
- GArray * netns_stack = _netns_stack_get();
- NMPNetns * self;
- int errsv;
- GError * error = NULL;
- unsigned long mountflags = 0;
-
- if (!_stack_peek(netns_stack)) {
- /* there are no netns instances. We cannot create a new one
- * (because after unshare we couldn't return to the original one). */
- errno = ENOTSUP;
- return NULL;
- }
-
- if (unshare(_CLONE_NS_ALL) != 0) {
- errsv = errno;
- _LOGE(NULL, "failed to create new net and mnt namespace: %s", nm_strerror_native(errsv));
- return NULL;
- }
-
- if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL) != 0) {
- errsv = errno;
- _LOGE(NULL, "failed mount --make-rslave: %s", nm_strerror_native(errsv));
- goto err_out;
- }
-
- if (umount2("/sys", MNT_DETACH) != 0) {
- errsv = errno;
- _LOGE(NULL, "failed umount /sys: %s", nm_strerror_native(errsv));
- goto err_out;
- }
-
- if (access("/sys", W_OK) == -1)
- mountflags = MS_RDONLY;
-
- if (mount("sysfs", "/sys", "sysfs", mountflags, NULL) != 0) {
- errsv = errno;
- _LOGE(NULL, "failed mount /sys: %s", nm_strerror_native(errsv));
- goto err_out;
- }
-
- self = _netns_new(&error);
- if (!self) {
- errsv = errno;
- _LOGE(NULL, "failed to create netns after unshare: %s", error->message);
- g_clear_error(&error);
- goto err_out;
- }
-
- _stack_push(netns_stack, self, _CLONE_NS_ALL);
-
- return self;
-err_out:
- _netns_switch_pop(netns_stack, NULL, _CLONE_NS_ALL);
- errno = errsv;
- return NULL;
-}
-
-gboolean
-nmp_netns_pop(NMPNetns *self)
-{
- GArray * netns_stack = _netns_stack_get();
- NetnsInfo *info;
- int ns_types;
-
- g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
-
- info = _stack_peek(netns_stack);
-
- g_return_val_if_fail(info, FALSE);
- g_return_val_if_fail(info->netns == self, FALSE);
-
- if (info->count > 1) {
- info->count--;
- _LOGt(self, "pop#%u* (decrease count to %d)", _stack_size(netns_stack) - 1, info->count);
- return TRUE;
- }
- g_return_val_if_fail(info->count == 1, FALSE);
-
- /* cannot pop the original netns. */
- g_return_val_if_fail(_stack_size(netns_stack) > 1, FALSE);
-
- _LOGD(self, "pop#%u", _stack_size(netns_stack) - 1);
-
- ns_types = info->ns_types;
-
- _stack_pop(netns_stack);
-
- return _netns_switch_pop(netns_stack, self, ns_types);
-}
-
-NMPNetns *
-nmp_netns_get_current(void)
-{
- return _netns_get(_stack_peek(_netns_stack_get()));
-}
-
-NMPNetns *
-nmp_netns_get_initial(void)
-{
- return _netns_get(_stack_bottom(_netns_stack_get()));
-}
-
-gboolean
-nmp_netns_is_initial(void)
-{
- GArray *netns_stack = _netns_stack_get();
-
- return (_netns_get(_stack_peek(netns_stack)) == _netns_get(_stack_bottom(netns_stack)));
-}
-
-/*****************************************************************************/
-
-gboolean
-nmp_netns_bind_to_path(NMPNetns *self, const char *filename, int *out_fd)
-{
- gs_free char * dirname = NULL;
- int errsv;
- int fd;
- nm_auto_pop_netns NMPNetns *netns_pop = NULL;
-
- g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
- g_return_val_if_fail(filename && filename[0] == '/', FALSE);
-
- if (!nmp_netns_push_type(self, CLONE_NEWNET))
- return FALSE;
- netns_pop = self;
-
- dirname = g_path_get_dirname(filename);
- if (mkdir(dirname, 0) != 0) {
- errsv = errno;
- if (errsv != EEXIST) {
- _LOGE(self,
- "bind: failed to create directory %s: %s",
- dirname,
- nm_strerror_native(errsv));
- return FALSE;
- }
- }
-
- if ((fd = creat(filename, S_IRUSR | S_IRGRP | S_IROTH)) == -1) {
- errsv = errno;
- _LOGE(self, "bind: failed to create %s: %s", filename, nm_strerror_native(errsv));
- return FALSE;
- }
- nm_close(fd);
-
- if (mount(PROC_SELF_NS_NET, filename, "none", MS_BIND, NULL) != 0) {
- errsv = errno;
- _LOGE(self,
- "bind: failed to mount %s to %s: %s",
- PROC_SELF_NS_NET,
- filename,
- nm_strerror_native(errsv));
- unlink(filename);
- return FALSE;
- }
-
- if (out_fd) {
- if ((fd = open(filename, O_RDONLY | O_CLOEXEC)) == -1) {
- errsv = errno;
- _LOGE(self, "bind: failed to open %s: %s", filename, nm_strerror_native(errsv));
- umount2(filename, MNT_DETACH);
- unlink(filename);
- return FALSE;
- }
- *out_fd = fd;
- }
-
- return TRUE;
-}
-
-gboolean
-nmp_netns_bind_to_path_destroy(NMPNetns *self, const char *filename)
-{
- int errsv;
-
- g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
- g_return_val_if_fail(filename && filename[0] == '/', FALSE);
-
- if (umount2(filename, MNT_DETACH) != 0) {
- errsv = errno;
- _LOGE(self, "bind: failed to unmount2 %s: %s", filename, nm_strerror_native(errsv));
- return FALSE;
- }
- if (unlink(filename) != 0) {
- errsv = errno;
- _LOGE(self, "bind: failed to unlink %s: %s", filename, nm_strerror_native(errsv));
- return FALSE;
- }
- return TRUE;
-}
-
-/*****************************************************************************/
-
-static void
-set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- NMPNetns * self = NMP_NETNS(object);
- NMPNetnsPrivate *priv = NMP_NETNS_GET_PRIVATE(self);
-
- switch (prop_id) {
- case PROP_FD_NET:
- /* construct-only */
- priv->fd_net = g_value_get_int(value);
- g_return_if_fail(priv->fd_net > 0);
- break;
- case PROP_FD_MNT:
- /* construct-only */
- priv->fd_mnt = g_value_get_int(value);
- g_return_if_fail(priv->fd_mnt > 0);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
-}
-
-static void
-nmp_netns_init(NMPNetns *self)
-{}
-
-static void
-dispose(GObject *object)
-{
- NMPNetns * self = NMP_NETNS(object);
- NMPNetnsPrivate *priv = NMP_NETNS_GET_PRIVATE(self);
-
- nm_close(priv->fd_net);
- priv->fd_net = -1;
-
- nm_close(priv->fd_mnt);
- priv->fd_mnt = -1;
-
- G_OBJECT_CLASS(nmp_netns_parent_class)->dispose(object);
-}
-
-static void
-nmp_netns_class_init(NMPNetnsClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS(klass);
-
- object_class->set_property = set_property;
- object_class->dispose = dispose;
-
- obj_properties[PROP_FD_NET] =
- g_param_spec_int(NMP_NETNS_FD_NET,
- "",
- "",
- 0,
- G_MAXINT,
- 0,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- obj_properties[PROP_FD_MNT] =
- g_param_spec_int(NMP_NETNS_FD_MNT,
- "",
- "",
- 0,
- G_MAXINT,
- 0,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
- g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-}
diff --git a/shared/nm-platform/nmp-netns.h b/shared/nm-platform/nmp-netns.h
deleted file mode 100644
index b18bd03e76..0000000000
--- a/shared/nm-platform/nmp-netns.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2016 Red Hat, Inc.
- */
-
-#ifndef __NMP_NETNS_UTILS_H__
-#define __NMP_NETNS_UTILS_H__
-
-#include "nmp-base.h"
-
-/*****************************************************************************/
-
-#define NMP_TYPE_NETNS (nmp_netns_get_type())
-#define NMP_NETNS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NMP_TYPE_NETNS, NMPNetns))
-#define NMP_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NMP_TYPE_NETNS, NMPNetnsClass))
-#define NMP_IS_NETNS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMP_TYPE_NETNS))
-#define NMP_IS_NETNS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NMP_TYPE_NETNS))
-#define NMP_NETNS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NMP_TYPE_NETNS, NMPNetnsClass))
-
-#define NMP_NETNS_FD_NET "fd-net"
-#define NMP_NETNS_FD_MNT "fd-mnt"
-
-typedef struct _NMPNetns NMPNetns;
-typedef struct _NMPNetnsClass NMPNetnsClass;
-
-GType nmp_netns_get_type(void);
-
-NMPNetns *nmp_netns_new(void);
-
-gboolean nmp_netns_push(NMPNetns *self);
-gboolean nmp_netns_push_type(NMPNetns *self, int ns_types);
-gboolean nmp_netns_pop(NMPNetns *self);
-
-NMPNetns *nmp_netns_get_current(void);
-NMPNetns *nmp_netns_get_initial(void);
-gboolean nmp_netns_is_initial(void);
-
-int nmp_netns_get_fd_net(NMPNetns *self);
-int nmp_netns_get_fd_mnt(NMPNetns *self);
-
-static inline void
-_nm_auto_pop_netns(NMPNetns **p)
-{
- if (*p) {
- int errsv = errno;
-
- nmp_netns_pop(*p);
- errno = errsv;
- }
-}
-#define nm_auto_pop_netns nm_auto(_nm_auto_pop_netns)
-
-gboolean nmp_netns_bind_to_path(NMPNetns *self, const char *filename, int *out_fd);
-gboolean nmp_netns_bind_to_path_destroy(NMPNetns *self, const char *filename);
-
-#endif /* __NMP_NETNS_UTILS_H__ */
diff --git a/shared/nm-platform/tests/meson.build b/shared/nm-platform/tests/meson.build
deleted file mode 100644
index dd9c3f58ee..0000000000
--- a/shared/nm-platform/tests/meson.build
+++ /dev/null
@@ -1,17 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-exe = executable(
- 'test-nm-platform',
- 'test-nm-platform.c',
- dependencies: [
- libnm_log_core_dep,
- libnm_platform_dep,
- ],
-)
-
-test(
- 'shared/nm-glib-aux/test-nm-platform',
- test_script,
- args: test_args + [exe.full_path()],
- timeout: default_test_timeout,
-)
diff --git a/shared/nm-platform/tests/test-nm-platform.c b/shared/nm-platform/tests/test-nm-platform.c
deleted file mode 100644
index a3e9ff13ba..0000000000
--- a/shared/nm-platform/tests/test-nm-platform.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-glib-aux/nm-default-glib-i18n-prog.h"
-
-#include "nm-log-core/nm-logging.h"
-#include "nm-platform/nm-netlink.h"
-#include "nm-platform/nmp-netns.h"
-
-#include "nm-utils/nm-test-utils.h"
-
-/*****************************************************************************/
-
-void
-_nm_logging_clear_platform_logging_cache(void)
-{
- /* this symbols is required by nm-log-core library. */
-}
-
-/*****************************************************************************/
-
-static void
-test_use_symbols(void)
-{
- static void (*const SYMBOLS[])(void) = {
- (void (*)(void)) nl_nlmsghdr_to_str,
- (void (*)(void)) nlmsg_hdr,
- (void (*)(void)) nlmsg_reserve,
- (void (*)(void)) nla_reserve,
- (void (*)(void)) nlmsg_alloc_size,
- (void (*)(void)) nlmsg_alloc,
- (void (*)(void)) nlmsg_alloc_convert,
- (void (*)(void)) nlmsg_alloc_simple,
- (void (*)(void)) nlmsg_free,
- (void (*)(void)) nlmsg_append,
- (void (*)(void)) nlmsg_parse,
- (void (*)(void)) nlmsg_put,
- (void (*)(void)) nla_strlcpy,
- (void (*)(void)) nla_memcpy,
- (void (*)(void)) nla_put,
- (void (*)(void)) nla_find,
- (void (*)(void)) nla_nest_cancel,
- (void (*)(void)) nla_nest_start,
- (void (*)(void)) nla_nest_end,
- (void (*)(void)) nla_parse,
- (void (*)(void)) nlmsg_get_proto,
- (void (*)(void)) nlmsg_set_proto,
- (void (*)(void)) nlmsg_set_src,
- (void (*)(void)) nlmsg_get_creds,
- (void (*)(void)) nlmsg_set_creds,
- (void (*)(void)) genlmsg_put,
- (void (*)(void)) genlmsg_data,
- (void (*)(void)) genlmsg_user_hdr,
- (void (*)(void)) genlmsg_hdr,
- (void (*)(void)) genlmsg_user_data,
- (void (*)(void)) genlmsg_attrdata,
- (void (*)(void)) genlmsg_len,
- (void (*)(void)) genlmsg_attrlen,
- (void (*)(void)) genlmsg_valid_hdr,
- (void (*)(void)) genlmsg_parse,
- (void (*)(void)) genl_ctrl_resolve,
- (void (*)(void)) nl_socket_alloc,
- (void (*)(void)) nl_socket_free,
- (void (*)(void)) nl_socket_get_fd,
- (void (*)(void)) nl_socket_get_local_port,
- (void (*)(void)) nl_socket_get_msg_buf_size,
- (void (*)(void)) nl_socket_set_passcred,
- (void (*)(void)) nl_socket_set_msg_buf_size,
- (void (*)(void)) nlmsg_get_dst,
- (void (*)(void)) nl_socket_set_nonblocking,
- (void (*)(void)) nl_socket_set_buffer_size,
- (void (*)(void)) nl_socket_add_memberships,
- (void (*)(void)) nl_socket_set_ext_ack,
- (void (*)(void)) nl_socket_disable_msg_peek,
- (void (*)(void)) nl_connect,
- (void (*)(void)) nl_wait_for_ack,
- (void (*)(void)) nl_recvmsgs,
- (void (*)(void)) nl_sendmsg,
- (void (*)(void)) nl_send_iovec,
- (void (*)(void)) nl_complete_msg,
- (void (*)(void)) nl_send,
- (void (*)(void)) nl_send_auto,
- (void (*)(void)) nl_recv,
-
- (void (*)(void)) nmp_netns_bind_to_path,
- (void (*)(void)) nmp_netns_bind_to_path_destroy,
- (void (*)(void)) nmp_netns_get_current,
- (void (*)(void)) nmp_netns_get_fd_mnt,
- (void (*)(void)) nmp_netns_get_fd_net,
- (void (*)(void)) nmp_netns_get_initial,
- (void (*)(void)) nmp_netns_is_initial,
- (void (*)(void)) nmp_netns_new,
- (void (*)(void)) nmp_netns_pop,
- (void (*)(void)) nmp_netns_push,
- (void (*)(void)) nmp_netns_push_type,
-
- NULL,
- };
-
- /* The only (not very exciting) purpose of this test is to see that
- * we can use various symbols and don't get a linker error. */
- assert(G_N_ELEMENTS(SYMBOLS) == NM_PTRARRAY_LEN(SYMBOLS) + 1);
-}
-
-/*****************************************************************************/
-
-NMTST_DEFINE();
-
-int
-main(int argc, char **argv)
-{
- nmtst_init(&argc, &argv, TRUE);
-
- g_test_add_func("/nm-platform/test_use_symbols", test_use_symbols);
-
- return g_test_run();
-}