about summary refs log tree commit diff
path: root/src/platform/nm-netlink.h
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-03-26 23:25:23 +0100
committerMichael Biebl <biebl@debian.org>2019-03-26 23:25:23 +0100
commit9a6dcbf895f9da01768e64b73cec88c16157d91e (patch)
treea359958930d731e9f1b59344642e10754419fe84 /src/platform/nm-netlink.h
parent964ae8cc391520440cf5aa13e2b9cc34850ea6c2 (diff)
New upstream version 1.16.0 upstream/1.16.0
Diffstat (limited to 'src/platform/nm-netlink.h')
-rw-r--r--src/platform/nm-netlink.h326
1 files changed, 211 insertions, 115 deletions
diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h
index d5df7ab9..094a3c6f 100644
--- a/src/platform/nm-netlink.h
+++ b/src/platform/nm-netlink.h
@@ -25,21 +25,9 @@
 #include <linux/rtnetlink.h>
 #include <linux/genetlink.h>
 
+#include "nm-utils/unaligned.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
@@ -51,50 +39,6 @@
 #define NLM_F_ACK_TLVS                  0x200
 #endif
 
-static inline int
-nl_errno (int nlerr)
-{
-	/* Normalizes an netlink error to be positive. Various API returns negative
-	 * error codes, and this function converts the negative value to its
-	 * positive.
-	 *
-	 * It's very similar to nm_errno(), but not exactly. The difference is that
-	 * nm_errno() is for plain errno, while nl_errno() is for netlink error numbers.
-	 * Yes, netlink error number are ~almost~ the same as errno, except that a particular
-	 * range (_NLE_BASE, _NLE_BASE_END) is reserved. The difference between the two
-	 * functions is only how G_MININT is mapped.
-	 *
-	 * See also nl_syserr2nlerr() below. */
-	return nlerr >= 0
-	       ? nlerr
-	       : ((nlerr == G_MININT) ? NLE_BUG : -nlerr);
-}
-
-static inline int
-nl_syserr2nlerr (int errsv)
-{
-	/* this maps a native errno to a (always non-negative) netlink error number.
-	 *
-	 * Note that netlink error numbers are embedded into the range of regular
-	 * errno. The only difference is, that netlink error numbers reserve a
-	 * range (_NLE_BASE, _NLE_BASE_END) for their own purpose.
-	 *
-	 * That means, converting an errno to netlink error number means in
-	 * most cases just returning itself (negative values are normalized
-	 * to be positive). Only values G_MININT and [_NLE_BASE, _NLE_BASE_END]
-	 * are coerced to the special value NLE_NATIVE_ERRNO, as they cannot
-	 * otherwise be represented in netlink error number domain. */
-	if (errsv == G_MININT)
-		return NLE_NATIVE_ERRNO;
-	if (errsv < 0)
-		errsv = -errsv;
-	return (errsv >= _NLE_BASE && errsv < _NLE_BASE_END)
-	       ? NLE_NATIVE_ERRNO
-	       : errsv;
-}
-
-const char *nl_geterror (int nlerr);
-
 /*****************************************************************************/
 
 /* Basic attribute data types */
@@ -145,8 +89,26 @@ struct nla_policy {
 
 /*****************************************************************************/
 
+/* static asserts that @tb and @policy are suitable arguments to nla_parse(). */
+#define _nl_static_assert_tb(tb, policy) \
+	G_STMT_START { \
+		\
+		G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (tb) > 0); \
+		\
+		/* we allow @policy to be either NULL or a C array. */ \
+		G_STATIC_ASSERT_EXPR (   sizeof (policy) == sizeof (NULL) \
+		                      || G_N_ELEMENTS (tb) == (sizeof (policy) / sizeof (struct nla_policy))); \
+		\
+		/* For above check to work, we don't support policy being an array with same size as
+		 * sizeof(NULL), otherwise, the compile time check breaks down. */ \
+		G_STATIC_ASSERT_EXPR (sizeof (NULL) != G_N_ELEMENTS (tb) * sizeof (struct nla_policy)); \
+		\
+	} G_STMT_END
+
+/*****************************************************************************/
+
 static inline int
-nla_attr_size(int payload)
+nla_attr_size (int payload)
 {
 	nm_assert (payload >= 0);
 
@@ -162,7 +124,7 @@ nla_total_size (int payload)
 static inline int
 nla_padlen (int payload)
 {
-	return nla_total_size(payload) - nla_attr_size(payload);
+	return nla_total_size (payload) - nla_attr_size (payload);
 }
 
 struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen);
@@ -170,32 +132,56 @@ struct nlattr *nla_reserve (struct nl_msg *msg, int attrtype, int attrlen);
 static inline int
 nla_len (const struct nlattr *nla)
 {
-	return nla->nla_len - NLA_HDRLEN;
+	nm_assert (nla);
+	nm_assert (nla->nla_len >= NLA_HDRLEN);
+
+	return ((int) nla->nla_len) - NLA_HDRLEN;
 }
 
 static inline int
 nla_type (const struct nlattr *nla)
 {
+	nm_assert (nla_len (nla) >= 0);
+
 	return nla->nla_type & NLA_TYPE_MASK;
 }
 
 static inline void *
 nla_data (const struct nlattr *nla)
 {
-	nm_assert (nla);
-	return (char *) nla + NLA_HDRLEN;
+	nm_assert (nla_len (nla) >= 0);
+
+	return &(((char *) nla)[NLA_HDRLEN]);
 }
 
+#define nla_data_as(type, nla) \
+	({ \
+		const struct nlattr *_nla = (nla); \
+		\
+		nm_assert (nla_len (_nla) >= sizeof (type)); \
+		\
+		/* note that casting the pointer is undefined behavior in C, if
+		 * the data has wrong alignment. Netlink data is aligned to 4 bytes,
+		 * that means, if the alignment is larger than 4, this is invalid. */ \
+		G_STATIC_ASSERT_EXPR (_nm_alignof (type) <= NLA_ALIGNTO); \
+		\
+		(type *) nla_data (_nla); \
+	})
+
 static inline uint8_t
 nla_get_u8 (const struct nlattr *nla)
 {
-	return *(const uint8_t *) nla_data (nla);
+	nm_assert (nla_len (nla) >= sizeof (uint8_t));
+
+	return *((const uint8_t *) nla_data (nla));
 }
 
-static inline uint8_t
+static inline int8_t
 nla_get_s8 (const struct nlattr *nla)
 {
-	return *(const int8_t *) nla_data (nla);
+	nm_assert (nla_len (nla) >= sizeof (int8_t));
+
+	return *((const int8_t *) nla_data (nla));
 }
 
 static inline uint8_t
@@ -210,91 +196,150 @@ nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_va
 static inline uint16_t
 nla_get_u16 (const struct nlattr *nla)
 {
-	return *(const uint16_t *) nla_data (nla);
+	nm_assert (nla_len (nla) >= sizeof (uint16_t));
+
+	return *((const uint16_t *) nla_data (nla));
 }
 
 static inline uint32_t
-nla_get_u32(const struct nlattr *nla)
+nla_get_u32 (const struct nlattr *nla)
 {
-	return *(const uint32_t *) nla_data (nla);
+	nm_assert (nla_len (nla) >= sizeof (uint32_t));
+
+	return *((const uint32_t *) nla_data (nla));
 }
 
 static inline int32_t
-nla_get_s32(const struct nlattr *nla)
+nla_get_s32 (const struct nlattr *nla)
 {
-	return *(const int32_t *) nla_data (nla);
+	nm_assert (nla_len (nla) >= sizeof (int32_t));
+
+	return *((const int32_t *) nla_data (nla));
 }
 
-uint64_t nla_get_u64 (const struct nlattr *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);
 
-int nla_memcpy (void *dest, const struct nlattr *src, int count);
+size_t nla_memcpy (void *dst, const struct nlattr *nla, size_t dstsize);
+
+#define nla_memcpy_checked_size(dst, nla, dstsize) \
+	G_STMT_START { \
+		void *const _dst = (dst); \
+		const struct nlattr *const _nla = (nla); \
+		const size_t _dstsize = (dstsize); \
+		size_t _srcsize; \
+		\
+		/* assert that, if @nla is given, that it has the exact expected
+		 * size. This implies that the caller previously verified the length
+		 * of the attribute (via minlen/maxlen at nla_parse()). */ \
+		\
+		if (_nla) { \
+			_srcsize = nla_memcpy (_dst, _nla, _dstsize); \
+			nm_assert (_srcsize == _dstsize); \
+		} \
+	} G_STMT_END
 
 int nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data);
 
 static inline int
 nla_put_string (struct nl_msg *msg, int attrtype, const char *str)
 {
-	return nla_put(msg, attrtype, strlen(str) + 1, str);
+	nm_assert (str);
+
+	return nla_put (msg, attrtype, strlen (str) + 1, str);
+}
+
+static inline int
+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) \
-	do { \
-		if (nla_put(msg, attrtype, attrlen, data) < 0) \
+	G_STMT_START { \
+		if (nla_put (msg, attrtype, attrlen, data) < 0) \
 			goto nla_put_failure; \
-	} while(0)
+	} G_STMT_END
 
 #define NLA_PUT_TYPE(msg, type, attrtype, value) \
-	do { \
+	G_STMT_START { \
 		type __nla_tmp = value; \
-		NLA_PUT(msg, attrtype, sizeof(type), &__nla_tmp); \
-	} while(0)
+		NLA_PUT (msg, attrtype, sizeof (type), &__nla_tmp); \
+	} G_STMT_END
 
 #define NLA_PUT_U8(msg, attrtype, value) \
-	NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
+	NLA_PUT_TYPE (msg, uint8_t, attrtype, value)
 
 #define NLA_PUT_S8(msg, attrtype, value) \
-	NLA_PUT_TYPE(msg, int8_t, attrtype, value)
+	NLA_PUT_TYPE (msg, int8_t, attrtype, value)
 
 #define NLA_PUT_U16(msg, attrtype, value) \
-	NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
+	NLA_PUT_TYPE (msg, uint16_t, attrtype, value)
 
 #define NLA_PUT_U32(msg, attrtype, value) \
-	NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
+	NLA_PUT_TYPE (msg, uint32_t, attrtype, value)
 
 #define NLA_PUT_S32(msg, attrtype, value) \
-	NLA_PUT_TYPE(msg, int32_t, attrtype, value)
+	NLA_PUT_TYPE (msg, int32_t, attrtype, value)
 
 #define NLA_PUT_U64(msg, attrtype, value) \
-	NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
+	NLA_PUT_TYPE (msg, uint64_t, attrtype, value)
 
 #define NLA_PUT_STRING(msg, attrtype, value) \
-	NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value)
+	NLA_PUT (msg, attrtype, (int) strlen (value) + 1, value)
 
 #define NLA_PUT_FLAG(msg, attrtype) \
-	NLA_PUT(msg, attrtype, 0, NULL)
+	NLA_PUT (msg, attrtype, 0, NULL)
 
 struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype);
 
 static inline int
 nla_ok (const struct nlattr *nla, int remaining)
 {
-	return remaining >= (int) sizeof(*nla) &&
-	       nla->nla_len >= sizeof(*nla) &&
+	return remaining >= (int) sizeof (*nla) &&
+	       nla->nla_len >= sizeof (*nla) &&
 	       nla->nla_len <= remaining;
 }
 
 static inline struct nlattr *
-nla_next(const struct nlattr *nla, int *remaining)
+nla_next (const struct nlattr *nla, int *remaining)
 {
-	int totlen = NLA_ALIGN(nla->nla_len);
+	int totlen = NLA_ALIGN (nla->nla_len);
 
 	*remaining -= totlen;
 	return (struct nlattr *) ((char *) nla + totlen);
@@ -302,28 +347,47 @@ nla_next(const struct nlattr *nla, int *remaining)
 
 #define nla_for_each_attr(pos, head, len, rem) \
 	for (pos = head, rem = len; \
-	     nla_ok(pos, rem); \
-	     pos = nla_next(pos, &(rem)))
+	     nla_ok (pos, rem); \
+	     pos = nla_next (pos, &(rem)))
 
 #define nla_for_each_nested(pos, nla, rem) \
-	for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); \
-	     nla_ok(pos, rem); \
-	     pos = nla_next(pos, &(rem)))
+	for (pos = (struct nlattr *) nla_data (nla), rem = nla_len (nla); \
+	     nla_ok (pos, rem); \
+	     pos = nla_next (pos, &(rem)))
 
 void nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr);
 struct nlattr *nla_nest_start (struct nl_msg *msg, int attrtype);
 int nla_nest_end (struct nl_msg *msg, struct nlattr *start);
 
-int nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
+int nla_parse (struct nlattr *tb[],
+               int maxtype,
+               struct nlattr *head,
+               int len,
                const struct nla_policy *policy);
 
+#define nla_parse_arr(tb, head, len, policy) \
+	({ \
+		_nl_static_assert_tb ((tb), (policy)); \
+		\
+		nla_parse ((tb), G_N_ELEMENTS (tb) - 1, (head), (len), (policy)); \
+	})
+
 static inline int
-nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla,
+nla_parse_nested (struct nlattr *tb[],
+                  int maxtype,
+                  struct nlattr *nla,
                   const struct nla_policy *policy)
 {
-	return nla_parse (tb, maxtype, nla_data(nla), nla_len(nla), policy);
+	return nla_parse (tb, maxtype, nla_data (nla), nla_len (nla), policy);
 }
 
+#define nla_parse_nested_arr(tb, nla, policy) \
+	({ \
+		_nl_static_assert_tb ((tb), (policy)); \
+		\
+		nla_parse_nested ((tb), G_N_ELEMENTS (tb) - 1, (nla), (policy)); \
+	})
+
 /*****************************************************************************/
 
 struct nl_msg *nlmsg_alloc (void);
@@ -336,7 +400,13 @@ struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags);
 
 void *nlmsg_reserve (struct nl_msg *n, size_t len, int pad);
 
-int nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad);
+int nlmsg_append (struct nl_msg *n,
+                  const void *data,
+                  size_t len,
+                  int pad);
+
+#define nlmsg_append_struct(n, data) \
+	nlmsg_append (n, (data), sizeof (*(data)), NLMSG_ALIGNTO)
 
 void nlmsg_free (struct nl_msg *msg);
 
@@ -356,15 +426,15 @@ nlmsg_total_size (int payload)
 static inline int
 nlmsg_ok (const struct nlmsghdr *nlh, int remaining)
 {
-	return (remaining >= (int)sizeof(struct nlmsghdr) &&
-	       nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
+	return (remaining >= (int) sizeof (struct nlmsghdr) &&
+	       nlh->nlmsg_len >= sizeof (struct nlmsghdr) &&
 	       nlh->nlmsg_len <= remaining);
 }
 
 static inline struct nlmsghdr *
 nlmsg_next (struct nlmsghdr *nlh, int *remaining)
 {
-	int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
+	int totlen = NLMSG_ALIGN (nlh->nlmsg_len);
 
 	*remaining -= totlen;
 
@@ -384,7 +454,7 @@ _nm_auto_nl_msg_cleanup (struct nl_msg **ptr)
 {
 	nlmsg_free (*ptr);
 }
-#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
+#define nm_auto_nlmsg nm_auto (_nm_auto_nl_msg_cleanup)
 
 static inline void *
 nlmsg_data (const struct nlmsghdr *nlh)
@@ -395,13 +465,13 @@ nlmsg_data (const struct nlmsghdr *nlh)
 static inline void *
 nlmsg_tail (const struct nlmsghdr *nlh)
 {
-	return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
+	return (unsigned char *) nlh + NLMSG_ALIGN (nlh->nlmsg_len);
 }
 
 struct nlmsghdr *nlmsg_hdr (struct nl_msg *n);
 
 static inline int
-nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
+nlmsg_valid_hdr (const struct nlmsghdr *nlh, int hdrlen)
 {
 	if (nlh->nlmsg_len < nlmsg_size (hdrlen))
 		return 0;
@@ -424,8 +494,8 @@ nlmsg_attrlen (const struct nlmsghdr *nlh, int hdrlen)
 static inline struct nlattr *
 nlmsg_attrdata (const struct nlmsghdr *nlh, int hdrlen)
 {
-	unsigned char *data = nlmsg_data(nlh);
-	return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
+	unsigned char *data = nlmsg_data (nlh);
+	return (struct nlattr *) (data + NLMSG_ALIGN (hdrlen));
 }
 
 static inline struct nlattr *
@@ -436,8 +506,19 @@ nlmsg_find_attr (struct nlmsghdr *nlh, int hdrlen, int attrtype)
 	                 attrtype);
 }
 
-int nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
-                 int maxtype, const struct nla_policy *policy);
+int nlmsg_parse (struct nlmsghdr *nlh,
+                 int hdrlen,
+                 struct nlattr *tb[],
+                 int maxtype,
+                 const struct nla_policy *policy);
+
+#define nlmsg_parse_arr(nlh, hdrlen, tb, policy) \
+	({ \
+		_nl_static_assert_tb ((tb), (policy)); \
+		G_STATIC_ASSERT_EXPR ((hdrlen) >= 0); \
+		\
+		nlmsg_parse ((nlh), (hdrlen), (tb), G_N_ELEMENTS (tb) - 1, (policy)); \
+	})
 
 struct nlmsghdr *nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq,
                             int type, int payload, int flags);
@@ -474,8 +555,11 @@ 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_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);
 
@@ -536,8 +620,20 @@ struct nlattr *genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen);
 int genlmsg_len (const struct genlmsghdr *gnlh);
 int genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen);
 int genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen);
-int genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
-                   int maxtype, const struct nla_policy *policy);
+
+int genlmsg_parse (struct nlmsghdr *nlh,
+                   int hdrlen,
+                   struct nlattr *tb[],
+                   int maxtype,
+                   const struct nla_policy *policy);
+
+#define genlmsg_parse_arr(nlh, hdrlen, tb, policy) \
+	({ \
+		_nl_static_assert_tb ((tb), (policy)); \
+		G_STATIC_ASSERT_EXPR ((hdrlen) >= 0); \
+		\
+		genlmsg_parse ((nlh), (hdrlen), (tb), G_N_ELEMENTS (tb) - 1, (policy)); \
+	})
 
 int genl_ctrl_resolve (struct nl_sock *sk, const char *name);