summary refs log tree commit diff
path: root/src/platform/nm-netlink.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/nm-netlink.h')
-rw-r--r--src/platform/nm-netlink.h511
1 files changed, 511 insertions, 0 deletions
diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h
new file mode 100644
index 00000000..c0dc09c4
--- /dev/null
+++ b/src/platform/nm-netlink.h
@@ -0,0 +1,511 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* nm-platform.c - Handle runtime kernel networking configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ */
+
+#ifndef __NM_NETLINK_H__
+#define __NM_NETLINK_H__
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/genetlink.h>
+
+/*****************************************************************************/
+#define _NLE_BASE               100000
+#define NLE_UNSPEC              (_NLE_BASE +  0)
+#define NLE_BUG                 (_NLE_BASE +  1)
+#define NLE_NATIVE_ERRNO        (_NLE_BASE +  2)
+#define NLE_SEQ_MISMATCH        (_NLE_BASE +  3)
+#define NLE_MSG_TRUNC           (_NLE_BASE +  4)
+#define NLE_MSG_TOOSHORT        (_NLE_BASE +  5)
+#define NLE_DUMP_INTR           (_NLE_BASE +  6)
+#define NLE_ATTRSIZE            (_NLE_BASE +  7)
+#define NLE_BAD_SOCK            (_NLE_BASE +  8)
+#define NLE_NOADDR              (_NLE_BASE +  9)
+#define NLE_MSG_OVERFLOW        (_NLE_BASE + 10)
+
+#define _NLE_BASE_END           (_NLE_BASE + 11)
+
+#define NLMSGERR_ATTR_UNUSED            0
+#define NLMSGERR_ATTR_MSG               1
+#define NLMSGERR_ATTR_OFFS              2
+#define NLMSGERR_ATTR_COOKIE            3
+#define NLMSGERR_ATTR_MAX               3
+
+#ifndef NLM_F_ACK_TLVS
+#define NLM_F_ACK_TLVS                  0x200
+#endif
+
+static inline int
+nl_errno (int err)
+{
+	/* the error codes from our netlink implementation are plain errno
+	 * extended with our own error in a particular range starting from
+	 * _NLE_BASE.
+	 *
+	 * However, often we encode errors as negative values. This function
+	 * normalizes the error and returns its positive value. */
+	return err >= 0
+	       ? err
+	       : ((err == G_MININT) ? NLE_BUG : -errno);
+}
+
+static inline int
+nl_syserr2nlerr (int err)
+{
+	if (err == G_MININT)
+		return NLE_NATIVE_ERRNO;
+	if (err < 0)
+		err = -err;
+	return (err >= _NLE_BASE && err < _NLE_BASE_END)
+	       ? NLE_NATIVE_ERRNO
+	       : err;
+}
+
+const char *nl_geterror (int err);
+
+/*****************************************************************************/
+
+/* Basic attribute data types */
+enum {
+	NLA_UNSPEC,     /* Unspecified type, binary data chunk */
+	NLA_U8,         /* 8 bit integer */
+	NLA_U16,        /* 16 bit integer */
+	NLA_U32,        /* 32 bit integer */
+	NLA_U64,        /* 64 bit integer */
+	NLA_STRING,     /* NUL terminated character string */
+	NLA_FLAG,       /* Flag */
+	NLA_MSECS,      /* Micro seconds (64bit) */
+	NLA_NESTED,     /* Nested attributes */
+	NLA_NESTED_COMPAT,
+	NLA_NUL_STRING,
+	NLA_BINARY,
+	NLA_S8,
+	NLA_S16,
+	NLA_S32,
+	NLA_S64,
+	__NLA_TYPE_MAX,
+};
+
+#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
+
+struct nl_msg;
+
+/*****************************************************************************/
+
+const char *nl_nlmsgtype2str (int type, char *buf, size_t size);
+
+const char *nl_nlmsg_flags2str (int flags, char *buf, size_t len);
+
+const char *nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len);
+
+/*****************************************************************************/
+
+struct nla_policy {
+	/* Type of attribute or NLA_UNSPEC */
+	uint16_t type;
+
+	/* Minimal length of payload required */
+	uint16_t minlen;
+
+	/* Maximal length of payload allowed */
+	uint16_t maxlen;
+};
+
+/*****************************************************************************/
+
+static inline int
+nla_attr_size(int payload)
+{
+	nm_assert (payload >= 0);
+
+	return NLA_HDRLEN + payload;
+}
+
+static inline int
+nla_total_size (int payload)
+{
+	return NLA_ALIGN (nla_attr_size (payload));
+}
+
+static inline int
+nla_padlen (int payload)
+{
+	return nla_total_size(payload) - nla_attr_size(payload);
+}
+
+struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen);
+
+static inline int
+nla_len (const struct nlattr *nla)
+{
+	return nla->nla_len - NLA_HDRLEN;
+}
+
+static inline int
+nla_type (const struct nlattr *nla)
+{
+	return nla->nla_type & NLA_TYPE_MASK;
+}
+
+static inline void *
+nla_data (const struct nlattr *nla)
+{
+	nm_assert (nla);
+	return (char *) nla + NLA_HDRLEN;
+}
+
+static inline uint8_t
+nla_get_u8 (const struct nlattr *nla)
+{
+	return *(const uint8_t *) nla_data (nla);
+}
+
+static inline uint8_t
+nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_val)
+{
+	nm_assert (tb);
+	nm_assert (attr >= 0);
+
+	return tb[attr] ? nla_get_u8 (tb[attr]) : default_val;
+}
+
+static inline uint16_t
+nla_get_u16 (const struct nlattr *nla)
+{
+	return *(const uint16_t *) nla_data (nla);
+}
+
+static inline uint32_t
+nla_get_u32(const struct nlattr *nla)
+{
+	return *(const uint32_t *) nla_data (nla);
+}
+
+uint64_t nla_get_u64 (const struct nlattr *nla);
+
+static inline char *
+nla_get_string (const struct nlattr *nla)
+{
+	return (char *) nla_data (nla);
+}
+
+size_t nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize);
+
+int nla_memcpy (void *dest, const struct nlattr *src, int count);
+
+int nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data);
+
+static inline int
+nla_put_string (struct nl_msg *msg, int attrtype, const char *str)
+{
+	return nla_put(msg, attrtype, strlen(str) + 1, str);
+}
+
+#define NLA_PUT(msg, attrtype, attrlen, data) \
+	do { \
+		if (nla_put(msg, attrtype, attrlen, data) < 0) \
+			goto nla_put_failure; \
+	} while(0)
+
+#define NLA_PUT_TYPE(msg, type, attrtype, value) \
+	do { \
+		type __tmp = value; \
+		NLA_PUT(msg, attrtype, sizeof(type), &__tmp); \
+	} while(0)
+
+#define NLA_PUT_U8(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
+
+#define NLA_PUT_U16(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
+
+#define NLA_PUT_U32(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
+
+#define NLA_PUT_U64(msg, attrtype, value) \
+	NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
+
+#define NLA_PUT_STRING(msg, attrtype, value) \
+	NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value)
+
+struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype);
+
+static inline int
+nla_ok (const struct nlattr *nla, int remaining)
+{
+	return remaining >= sizeof(*nla) &&
+	       nla->nla_len >= sizeof(*nla) &&
+	       nla->nla_len <= remaining;
+}
+
+static inline struct nlattr *
+nla_next(const struct nlattr *nla, int *remaining)
+{
+	int totlen = NLA_ALIGN(nla->nla_len);
+
+	*remaining -= totlen;
+	return (struct nlattr *) ((char *) nla + totlen);
+}
+
+#define nla_for_each_attr(pos, head, len, rem) \
+	for (pos = head, rem = len; \
+	     nla_ok(pos, rem); \
+	     pos = nla_next(pos, &(rem)))
+
+#define nla_for_each_nested(pos, nla, rem) \
+	for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); \
+	     nla_ok(pos, rem); \
+	     pos = nla_next(pos, &(rem)))
+
+void nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr);
+struct nlattr *nla_nest_start (struct nl_msg *msg, int attrtype);
+int nla_nest_end (struct nl_msg *msg, struct nlattr *start);
+
+int nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
+               const struct nla_policy *policy);
+
+static inline int
+nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla,
+                  const struct nla_policy *policy)
+{
+	return nla_parse (tb, maxtype, nla_data(nla), nla_len(nla), policy);
+}
+
+/*****************************************************************************/
+
+struct nl_msg *nlmsg_alloc (void);
+
+struct nl_msg *nlmsg_alloc_size (size_t max);
+
+struct nl_msg *nlmsg_alloc_inherit (struct nlmsghdr *hdr);
+
+struct nl_msg *nlmsg_alloc_convert (struct nlmsghdr *hdr);
+
+struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags);
+
+void *nlmsg_reserve (struct nl_msg *n, size_t len, int pad);
+
+int nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad);
+
+void nlmsg_free (struct nl_msg *msg);
+
+static inline int
+nlmsg_size (int payload)
+{
+	nm_assert (payload >= 0 && payload < G_MAXINT - NLMSG_HDRLEN - 4);
+	return NLMSG_HDRLEN + payload;
+}
+
+static inline int
+nlmsg_total_size (int payload)
+{
+	return NLMSG_ALIGN (nlmsg_size (payload));
+}
+
+static inline int
+nlmsg_ok (const struct nlmsghdr *nlh, int remaining)
+{
+	return (remaining >= (int)sizeof(struct nlmsghdr) &&
+	       nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
+	       nlh->nlmsg_len <= remaining);
+}
+
+static inline struct nlmsghdr *
+nlmsg_next (struct nlmsghdr *nlh, int *remaining)
+{
+	int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
+
+	*remaining -= totlen;
+
+	return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
+}
+
+int nlmsg_get_proto (struct nl_msg *msg);
+void nlmsg_set_proto (struct nl_msg *msg, int protocol);
+
+void nlmsg_set_src (struct nl_msg *msg, struct sockaddr_nl *addr);
+
+struct ucred *nlmsg_get_creds (struct nl_msg *msg);
+void nlmsg_set_creds (struct nl_msg *msg, struct ucred *creds);
+
+static inline void
+_nm_auto_nl_msg_cleanup (struct nl_msg **ptr)
+{
+	nlmsg_free (*ptr);
+}
+#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
+
+static inline void *
+nlmsg_data (const struct nlmsghdr *nlh)
+{
+	return (unsigned char *) nlh + NLMSG_HDRLEN;
+}
+
+static inline void *
+nlmsg_tail (const struct nlmsghdr *nlh)
+{
+	return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
+}
+
+struct nlmsghdr *nlmsg_hdr (struct nl_msg *n);
+
+static inline int
+nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
+{
+	if (nlh->nlmsg_len < nlmsg_size (hdrlen))
+		return 0;
+
+	return 1;
+}
+
+static inline int
+nlmsg_datalen (const struct nlmsghdr *nlh)
+{
+	return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+static inline int
+nlmsg_attrlen (const struct nlmsghdr *nlh, int hdrlen)
+{
+	return NM_MAX ((int) (nlmsg_datalen (nlh) - NLMSG_ALIGN (hdrlen)), 0);
+}
+
+static inline struct nlattr *
+nlmsg_attrdata (const struct nlmsghdr *nlh, int hdrlen)
+{
+	unsigned char *data = nlmsg_data(nlh);
+	return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
+}
+
+static inline struct nlattr *
+nlmsg_find_attr (struct nlmsghdr *nlh, int hdrlen, int attrtype)
+{
+	return nla_find (nlmsg_attrdata (nlh, hdrlen),
+	                 nlmsg_attrlen (nlh, hdrlen),
+	                 attrtype);
+}
+
+int nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+                 int maxtype, const struct nla_policy *policy);
+
+struct nlmsghdr *nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq,
+                            int type, int payload, int flags);
+
+/*****************************************************************************/
+
+#define NL_AUTO_PORT 0
+#define NL_AUTO_SEQ  0
+
+struct nl_sock;
+
+struct nl_sock *nl_socket_alloc (void);
+
+void nl_socket_free (struct nl_sock *sk);
+
+int nl_socket_get_fd (const struct nl_sock *sk);
+
+struct sockaddr_nl *nlmsg_get_dst (struct nl_msg *msg);
+
+size_t nl_socket_get_msg_buf_size (struct nl_sock *sk);
+int nl_socket_set_msg_buf_size (struct nl_sock *sk, size_t bufsize);
+
+int nl_socket_set_buffer_size (struct nl_sock *sk, int rxbuf, int txbuf);
+
+int nl_socket_set_passcred (struct nl_sock *sk, int state);
+
+int nl_socket_set_nonblocking (const struct nl_sock *sk);
+
+void nl_socket_disable_msg_peek (struct nl_sock *sk);
+
+uint32_t nl_socket_get_local_port (const struct nl_sock *sk);
+
+int nl_socket_add_memberships (struct nl_sock *sk, int group, ...);
+
+int nl_connect (struct nl_sock *sk, int protocol);
+
+int nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla,
+             unsigned char **buf, struct ucred **creds);
+
+int nl_send (struct nl_sock *sk, struct nl_msg *msg);
+
+int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg);
+
+/*****************************************************************************/
+
+enum nl_cb_action {
+	/* Proceed with wathever would come next */
+	NL_OK,
+	/* Skip this message */
+	NL_SKIP,
+	/* Stop parsing altogether and discard remaining messages */
+	NL_STOP,
+};
+
+typedef int (*nl_recvmsg_msg_cb_t) (struct nl_msg *msg, void *arg);
+
+typedef int (*nl_recvmsg_err_cb_t) (struct sockaddr_nl *nla,
+                                    struct nlmsgerr *nlerr, void *arg);
+
+struct nl_cb {
+	nl_recvmsg_msg_cb_t     valid_cb;
+	void *                  valid_arg;
+
+	nl_recvmsg_msg_cb_t     finish_cb;
+	void *                  finish_arg;
+
+	nl_recvmsg_msg_cb_t     ack_cb;
+	void *                  ack_arg;
+
+	nl_recvmsg_err_cb_t     err_cb;
+	void *                  err_arg;
+};
+
+int nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr);
+
+int nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen);
+
+void nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg);
+
+int nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb);
+
+int nl_wait_for_ack (struct nl_sock *sk,
+                     const struct nl_cb *cb);
+
+int nl_socket_set_ext_ack (struct nl_sock *sk, gboolean enable);
+
+/*****************************************************************************/
+
+void *genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
+                   int hdrlen, int flags, uint8_t cmd, uint8_t version);
+void *genlmsg_data (const struct genlmsghdr *gnlh);
+void *genlmsg_user_hdr (const struct genlmsghdr *gnlh);
+struct genlmsghdr *genlmsg_hdr (struct nlmsghdr *nlh);
+void *genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen);
+struct nlattr *genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen);
+int genlmsg_len (const struct genlmsghdr *gnlh);
+int genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen);
+int genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen);
+int genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+                   int maxtype, const struct nla_policy *policy);
+
+int genl_ctrl_resolve (struct nl_sock *sk, const char *name);
+
+/*****************************************************************************/
+
+#endif /* __NM_NETLINK_H__ */