about summary refs log tree commit diff
path: root/shared/nm-platform/nm-netlink.h
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2021-02-11 18:11:46 +0100
committerMichael Biebl <biebl@debian.org>2021-02-11 18:11:46 +0100
commit80ec1decc49c72efec2a8b87c06245c92c0ab807 (patch)
treee3b229aa94e8dcf0590f2317664176e7b8f7607b /shared/nm-platform/nm-netlink.h
parent65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (diff)
New upstream version 1.29.90 upstream/1.29.90
Diffstat (limited to 'shared/nm-platform/nm-netlink.h')
-rw-r--r--shared/nm-platform/nm-netlink.h616
1 files changed, 616 insertions, 0 deletions
diff --git a/shared/nm-platform/nm-netlink.h b/shared/nm-platform/nm-netlink.h
new file mode 100644
index 00000000..8de42531
--- /dev/null
+++ b/shared/nm-platform/nm-netlink.h
@@ -0,0 +1,616 @@
+/* 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__ */