[PATCH 3/4] libnftnl: set: Implement new buffer of TLV objects.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



These functions allow create a buffer (nftnl_attrbuf) of TLV objects
(nftnl_attr). It is inspired in libmnl/src/attr.c.

Signed-off-by: Carlos Falgueras García <carlosfg@xxxxxxxxxx>
---
 include/libnftnl/set.h | 133 ++++++++++++++++++++
 include/set.h          |  39 ++++++
 src/libnftnl.map       |  47 +++++++
 src/set.c              | 327 +++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 536 insertions(+), 10 deletions(-)

diff --git a/include/libnftnl/set.h b/include/libnftnl/set.h
index 7a5a512..ec15603 100644
--- a/include/libnftnl/set.h
+++ b/include/libnftnl/set.h
@@ -278,4 +278,137 @@ void nft_set_elems_iter_destroy(struct nft_set_elems_iter *iter);
 int nft_set_elems_nlmsg_build_payload_iter(struct nlmsghdr *nlh,
 					   struct nft_set_elems_iter *iter);
 
+/*
+ * nftnl attributes API
+ */
+struct nftnl_attr;
+struct nftnl_attrbuf;
+
+/* nftnl_attrbuf */
+struct nftnl_attrbuf *nftnl_attrbuf_alloc(size_t size);
+void nftnl_attrbuf_delete(struct nftnl_attrbuf *attrbuf);
+void nftnl_attrbuf_free(struct nftnl_attrbuf *attrbuf);
+void nftnl_attrbuf_printf(const struct nftnl_attrbuf *attrbuf);
+size_t nftnl_attrbuf_len(const struct nftnl_attrbuf *attrbuf);
+size_t nftnl_attrbuf_size(const struct nftnl_attrbuf *attrbuf);
+void *nftnl_attrbuf_data(const struct nftnl_attrbuf *attrbuf);
+
+/* TLV attribute getters */
+uint16_t nftnl_attr_get_type(const struct nftnl_attr *attr);
+uint16_t nftnl_attr_get_len(const struct nftnl_attr *attr);
+void *nftnl_attr_get_value(const struct nftnl_attr *attr);
+uint32_t nftnl_attr_get_size(const struct nftnl_attr *attr);
+
+/* TLV attribute putters */
+struct nftnl_attr *nftnl_attr_put(struct nftnl_attrbuf *attrbuf,
+				  uint16_t type, size_t len, const void *data);
+struct nftnl_attr *nftnl_attr_put_check(struct nftnl_attrbuf *attrbuf,
+					size_t bufsize, uint16_t type,
+					size_t len, const void *data);
+
+/* TLV attribute nesting */
+struct nftnl_attr *nftnl_attr_nest_start(struct nftnl_attrbuf *attrbuf,
+					 uint16_t type);
+struct nftnl_attr *nftnl_attr_nest_start_check(struct nftnl_attrbuf *attrbuf,
+					       size_t bufsize, uint16_t type);
+void nftnl_attr_nest_end(struct nftnl_attrbuf *attrbuf,
+			 struct nftnl_attr *start);
+void nftnl_attr_nest_cancel(struct nftnl_attrbuf *attrbuf,
+			    struct nftnl_attr *start);
+
+/* TLV validation */
+enum nftnl_attr_data_type {
+	NFTNL_ATTR_TYPE_UNSPEC,
+	NFTNL_ATTR_TYPE_U8,
+	NFTNL_ATTR_TYPE_U16,
+	NFTNL_ATTR_TYPE_U32,
+	NFTNL_ATTR_TYPE_U64,
+	NFTNL_ATTR_TYPE_STRING,
+	NFTNL_ATTR_TYPE_FLAG,
+	NFTNL_ATTR_TYPE_MSECS,
+	NFTNL_ATTR_TYPE_NESTED,
+	NFTNL_ATTR_TYPE_NESTED_COMPAT,
+	NFTNL_ATTR_TYPE_NUL_STRING,
+	NFTNL_ATTR_TYPE_BINARY,
+	__NFTNL_ATTR_TYPE_MAX,
+};
+#define NFTNL_ATTR_TYPE_MAX (__NFTNL_ATTR_TYPE_MAX - 1)
+
+int nftnl_attr_type_valid(const struct nftnl_attr *attr);
+int nftnl_attr_validate(const struct nftnl_attr *attr);
+int nftnl_attr_validate2(const struct nftnl_attr *attr, size_t exp_len);
+
+/* TLV iterators */
+struct nftnl_attr *nftnl_attr_next(const struct nftnl_attr *attr);
+
+#define nftnl_attr_for_each(attr, attrbuf)                  \
+	for ((attr) = (struct nftnl_attr *)(attrbuf)->data; \
+	     (char *)(attrbuf)->tail > (char *)(attr);      \
+	     (attr) = nftnl_attr_next(attr))
+
+#define nftnl_attr_for_each_nested(attr, nest)                          \
+	for ((attr) = (struct nftnl_attr *)nftnl_attr_get_value(nest);  \
+	     (char *)(attr) - (char *)(nest) < nftnl_attr_get_len(nest);\
+	     (attr) = nftnl_attr_next(attr))
+
+#define nftnl_attr_for_each_payload(attr, payload, payload_len) \
+	for ((attr) = (struct nftnl_attr *)(payload);           \
+	     (char *)(attr) - (char *)(payload) < (payload_len);\
+	     (attr) = nftnl_attr_next(attr))
+
+int nftnl_attr_payload_snprint(const void *payload, size_t payload_len,
+			       char *buf, int bsize);
+/*
+ * Compact
+ */
+struct nft_attr;
+struct nft_attrbuf;
+
+struct nft_attrbuf *nft_attrbuf_alloc(size_t size);
+void nft_attrbuf_delete(struct nft_attrbuf *attrbuf);
+void nft_attrbuf_free(struct nft_attrbuf *attrbuf);
+void nft_attrbuf_printf(const struct nft_attrbuf *attrbuf);
+size_t nft_attrbuf_len(const struct nft_attrbuf *attrbuf);
+size_t nft_attrbuf_size(const struct nft_attrbuf *attrbuf);
+void *nft_attrbuf_data(const struct nft_attrbuf *attrbuf);
+
+/* TLV attribute getters */
+uint16_t nft_attr_get_type(const struct nft_attr *attr);
+uint16_t nft_attr_get_len(const struct nft_attr *attr);
+void *nft_attr_get_value(const struct nft_attr *attr);
+uint16_t nft_attr_get_size(const struct nft_attr *attr);
+
+/* TLV attribute putters */
+struct nft_attr *nft_attr_put(struct nft_attrbuf *attrbuf,
+			      uint16_t type, size_t len, const void *data);
+struct nft_attr *nft_attr_put_check(struct nft_attrbuf *attrbuf,
+				    size_t bufsize, uint16_t type,
+				    size_t len, const void *data);
+
+/* TLV attribute nesting */
+struct nft_attr *nft_attr_nest_start(struct nft_attrbuf *attrbuf,
+				     uint16_t type);
+struct nft_attr *nft_attr_nest_start_check(struct nft_attrbuf *attrbuf,
+					   size_t bufsize, uint16_t type);
+void nft_attr_nest_end(struct nft_attrbuf *attrbuf,
+		       struct nft_attr *start);
+void nft_attr_nest_cancel(struct nft_attrbuf *attrbuf,
+			  struct nft_attr *start);
+
+/* TLV validation */
+int nft_attr_type_valid(const struct nft_attr *attr);
+int nft_attr_validate(const struct nft_attr *attr);
+int nft_attr_validate2(const struct nft_attr *attr, size_t exp_len);
+
+/* TLV iterators */
+struct nft_attr *nft_attr_next(const struct nft_attr *attr);
+
+#define nft_attr_for_each(attr, attrbuf) nftnl_attr_for_each(attr, attrbuf)
+
+#define nft_attr_for_each_nested(attr, nest) \
+	nftnl_attr_for_each_nested(attr, attrbuf)
+
+int nft_attr_payload_snprint(const void *payload, size_t payload_len,
+			     char *buf, int bsize);
+
 #endif /* _LIBNFTNL_SET_H_ */
diff --git a/include/set.h b/include/set.h
index 85bd389..2b5ce98 100644
--- a/include/set.h
+++ b/include/set.h
@@ -35,4 +35,43 @@ struct nftnl_expr;
 int nftnl_set_lookup_id(struct nftnl_expr *e, struct nftnl_set_list *set_list,
 		      uint32_t *set_id);
 
+/*
+ * TLV structures:
+ * nftnl_attr
+ *  <-- sizeof(nftnl_attr) -->             <-- nftnl_attr->len -->
+ * +--------------------------+- - - - - -+- - - - -  -- - - - - -+- - - - - +
+ * |          Header          |  Pading   |       Payload         |  Pading  |
+ * |         (4 bytes)        | (4 bytes) |                       |          |
+ * +--------------------------+- - - - - -+- - - - - - - - - - - -+- - - - - +
+ *  <------------------------ nftnl_attr_get_size() ------------------------>
+ *
+ *
+ * nftnl_attr->type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type                |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+
+struct nftnl_attr {
+	uint16_t type;
+	uint16_t len;
+	unsigned char value[] __aligned(__alignof__(uint64_t));
+};
+
+#define NFTNLA_F_NESTED		(1 << 15)
+#define NFTNLA_F_NET_BYTEORDER	(1 << 14)
+#define NFTNLA_TYPE_MASK	~(NFTNLA_F_NESTED | NFTNLA_F_NET_BYTEORDER)
+
+#define NFTNL_ALIGNTO		8
+#define NFTNL_ALIGN(len)	(((len)+NFTNL_ALIGNTO-1) & ~(NFTNL_ALIGNTO-1))
+
+struct nftnl_attrbuf {
+	struct nftnl_attr *tail;
+	unsigned char data[] __aligned(__alignof__(uint64_t);
+};
+
 #endif
diff --git a/src/libnftnl.map b/src/libnftnl.map
index 2e193b7..80f7ff5 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -136,6 +136,29 @@ global:
   nft_set_snprintf;
   nft_set_fprintf;
 
+  nft_attrbuf_alloc;
+  nft_attrbuf_delete;
+  nft_attrbuf_free;
+  nft_attrbuf_printf;
+  nft_attrbuf_len;
+  nft_attrbuf_size;
+  nft_attrbuf_data;
+  nft_attr_get_type;
+  nft_attr_get_len;
+  nft_attr_get_value;
+  nft_attr_get_size;
+  nft_attr_put;
+  nft_attr_put_check;
+  nft_attr_nest_start;
+  nft_attr_nest_start_check;
+  nft_attr_nest_end;
+  nft_attr_nest_cancel;
+  nft_attr_type_valid;
+  nft_attr_validate;
+  nft_attr_validate2;
+  nft_attr_next;
+  nft_attr_payload_snprint;
+
   nft_set_list_alloc;
   nft_set_list_free;
   nft_set_list_add;
@@ -336,6 +359,30 @@ global:
   nftnl_set_snprintf;
   nftnl_set_fprintf;
 
+  nftnl_attrbuf_alloc;
+  nftnl_attrbuf_delete;
+  nftnl_attrbuf_free;
+  nftnl_attrbuf_printf;
+  nftnl_attrbuf_len;
+  nftnl_attrbuf_size;
+  nftnl_attrbuf_data;
+  nftnl_attr_get_type;
+  nftnl_attr_get_len;
+  nftnl_attr_get_value;
+  nftnl_attr_get_size;
+  nftnl_attr_put;
+  nftnl_attr_put_check;
+  nftnl_attr_nest_start;
+  nftnl_attr_nest_start_check;
+  nftnl_attr_nest_end;
+  nftnl_attr_nest_cancel;
+  nftnl_attr_type_valid;
+  nftnl_attr_validate;
+  nftnl_attr_validate2;
+  nftnl_attr_next;
+  nftnl_attr_payload_snprint;
+
+
   nftnl_set_list_alloc;
   nftnl_set_list_free;
   nftnl_set_list_add;
diff --git a/src/set.c b/src/set.c
index 315bced..b9031e1 100644
--- a/src/set.c
+++ b/src/set.c
@@ -28,6 +28,12 @@
 #include <libnftnl/set.h>
 #include <libnftnl/expr.h>
 
+#define ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, attr_len) ( \
+	(bufsize) >= \
+		NFTNL_ALIGN(attr_len) + \
+		sizeof(struct nftnl_attr) + \
+		nftnl_attrbuf_len(attrbuf))
+
 struct nftnl_set *nftnl_set_alloc(void)
 {
 	struct nftnl_set *s;
@@ -804,7 +810,6 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
 				  uint32_t type, uint32_t flags)
 {
 	int len = size, offset = 0, ret;
-	int i;
 	struct nftnl_set_elem *elem;
 
 	ret = snprintf(buf, len, "{\"set\":{");
@@ -861,18 +866,14 @@ static int nftnl_set_snprintf_json(char *buf, size_t size, struct nftnl_set *s,
 			       s->user.len);
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
-		ret = snprintf(buf + offset, len, ",\"userdata\":\"");
+		ret = snprintf(buf + offset, len, ",\"userdata\":[");
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
-		char *c = s->user.data;
-
-		for (i = 0; i < s->user.len; i++) {
-			ret = snprintf(buf + offset, len, "%c",
-				       isprint(c[i]) ? c[i] : ' ');
-			SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
-		}
+		ret = nftnl_attr_payload_snprint(s->user.data, s->user.len,
+						 buf + offset, len);
+		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 
-		ret = snprintf(buf + offset, len, "\"");
+		ret = snprintf(buf + offset, len, "]");
 		SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
 	}
 
@@ -1270,3 +1271,309 @@ int nftnl_set_lookup_id(struct nftnl_expr *e,
 	*set_id = nftnl_set_get_u32(s, NFTNL_SET_ID);
 	return 1;
 }
+
+/* TLV */
+struct nftnl_attrbuf *nftnl_attrbuf_alloc(size_t size)
+{
+	struct nftnl_attrbuf *attrbuf;
+
+	attrbuf =
+		(struct nftnl_attrbuf *)malloc(sizeof(struct nftnl_attrbuf) +
+					       size
+					      );
+	attrbuf->tail = (struct nftnl_attr *)attrbuf->data;
+
+	return attrbuf;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_alloc, nft_attrbuf_alloc);
+
+void nftnl_attrbuf_delete(struct nftnl_attrbuf *attrbuf)
+{
+	attrbuf->tail = (struct nftnl_attr *)attrbuf->data;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_delete, nft_attrbuf_delete);
+
+void nftnl_attrbuf_free(struct nftnl_attrbuf *attrbuf)
+{
+	nftnl_attrbuf_delete(attrbuf);
+	free((void *)attrbuf);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_free, nft_attrbuf_free);
+
+size_t nftnl_attrbuf_len(const struct nftnl_attrbuf *attrbuf)
+{
+	return (size_t)((char *)attrbuf->tail - (char *)attrbuf->data);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_len, nft_attrbuf_len);
+
+size_t nftnl_attrbuf_size(const struct nftnl_attrbuf *attrbuf)
+{
+	return (size_t)((char *)attrbuf->tail - (char *)attrbuf);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_size, nft_attrbuf_size);
+
+void *nftnl_attrbuf_data(const struct nftnl_attrbuf *attrbuf)
+{
+	return (void *)attrbuf->data;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attrbuf_data, nft_attrbuf_data);
+
+uint16_t nftnl_attr_get_type(const struct nftnl_attr *attr)
+{
+	return attr->type;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_type, nft_attr_get_type);
+
+uint16_t nftnl_attr_get_len(const struct nftnl_attr *attr)
+{
+	return attr->len;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_len, nft_attr_get_len);
+
+void *nftnl_attr_get_value(const struct nftnl_attr *attr)
+{
+	return (void *)attr->value;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_value, nft_attr_get_value);
+
+uint32_t nftnl_attr_get_size(const struct nftnl_attr *attr)
+{
+	return (char *)nftnl_attr_next(attr) - (char *)attr;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_get_size, nft_attr_get_size);
+
+struct nftnl_attr *nftnl_attr_put(struct nftnl_attrbuf *attrbuf,
+				  uint16_t type, size_t len, const void *data)
+{
+	struct nftnl_attr *attr = attrbuf->tail;
+
+	attr->len  = len;
+	attr->type = type;
+	memcpy(attr->value, data, len);
+
+	attrbuf->tail = nftnl_attr_next(attr);
+
+	return attr;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_put, nft_attr_put);
+
+struct nftnl_attr *nftnl_attr_put_check(struct nftnl_attrbuf *attrbuf,
+					size_t bufsize, uint16_t type,
+					size_t len, const void *data)
+{
+	if (!ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, len))
+		return NULL;
+	return nftnl_attr_put(attrbuf, type, len, data);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_put_check, nft_attr_put_check);
+
+struct nftnl_attr *nftnl_attr_nest_start(struct nftnl_attrbuf *attrbuf,
+					 uint16_t type)
+{
+	struct nftnl_attr *start;
+
+	start = attrbuf->tail;
+	start->len = 0;
+	start->type = NFTNLA_F_NESTED | type;
+
+	attrbuf->tail = nftnl_attr_next(attrbuf->tail);
+
+	return start;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_start, nft_attr_nest_start);
+
+struct nftnl_attr *nftnl_attr_nest_start_check(struct nftnl_attrbuf *attrbuf,
+					       size_t bufsize, uint16_t type)
+{
+	if (!ATTRBUF_ENOUGH_SIZE(attrbuf, bufsize, 0))
+		return NULL;
+	return nftnl_attr_nest_start(attrbuf, type);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_start_check, nft_attr_nest_start_check);
+
+void nftnl_attr_nest_end(struct nftnl_attrbuf *attrbuf,
+			 struct nftnl_attr *start)
+{
+	start->len = (char *)attrbuf->tail - (char *)start->value;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_end, nft_attr_nest_end);
+
+int nftnl_attr_type_valid(const struct nftnl_attr *attr)
+{
+	if (nftnl_attr_get_type(attr) > NFTNL_ATTR_TYPE_MAX) {
+		errno = EINVAL;
+		return -1;
+	}
+	return 1;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_type_valid, nft_attr_type_valid);
+
+static const size_t nftnl_attr_data_type_len[MNL_TYPE_MAX] = {
+	[NFTNL_ATTR_TYPE_U8]	= sizeof(uint8_t),
+	[NFTNL_ATTR_TYPE_U16]	= sizeof(uint16_t),
+	[NFTNL_ATTR_TYPE_U32]	= sizeof(uint32_t),
+	[NFTNL_ATTR_TYPE_U64]	= sizeof(uint64_t),
+	[NFTNL_ATTR_TYPE_MSECS]	= sizeof(uint64_t),
+};
+
+int nftnl_attr_validate(const struct nftnl_attr *attr)
+{
+	int exp_len;
+
+	exp_len = nftnl_attr_data_type_len[nftnl_attr_get_type(attr)];
+	return nftnl_attr_validate2(attr, exp_len);
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_validate, nft_attr_validate);
+
+int nftnl_attr_validate2(const struct nftnl_attr *attr, size_t exp_len)
+{
+	uint16_t type = nftnl_attr_get_type(attr);
+	uint16_t len = nftnl_attr_get_len(attr);
+	const char *val = nftnl_attr_get_value(attr);
+
+	if (len != exp_len) {
+		errno = ERANGE;
+		return -1;
+	}
+
+	switch (type) {
+	case MNL_TYPE_FLAG:
+		if (len > 0) {
+			errno = ERANGE;
+			return -1;
+		}
+		break;
+	case MNL_TYPE_NUL_STRING:
+		if (len == 0) {
+			errno = ERANGE;
+			return -1;
+		}
+		if (val[len-1] != '\0') {
+			errno = EINVAL;
+			return -1;
+		}
+		break;
+	case MNL_TYPE_STRING:
+		if (len == 0) {
+			errno = ERANGE;
+			return -1;
+		}
+		break;
+	case MNL_TYPE_NESTED:
+		/*
+		 * Empty nested attributes are OK. If not empty,
+		 * they must contain one header
+		 */
+		if (len > 0 && len < sizeof(struct nftnl_attr)) {
+			errno = ERANGE;
+			return -1;
+		}
+		break;
+	default:
+		if (!nftnl_attr_type_valid(attr))
+			return -1;
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_validate2, nft_attr_validate2);
+
+void nftnl_attr_nest_cancel(struct nftnl_attrbuf *attrbuf,
+			    struct nftnl_attr *start)
+{
+	attrbuf->tail = start;
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_nest_cancel, nft_attr_nest_cancel);
+
+struct nftnl_attr *nftnl_attr_next(const struct nftnl_attr *attr)
+{
+	return (struct nftnl_attr *)&attr->value[NFTNL_ALIGN(attr->len)];
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_next, nft_attr_next);
+
+static int __attr_snprint(const struct nftnl_attr *attr,
+			char *buf, size_t bsize)
+{
+	int i;
+	int written, blen, boffset;
+	uint16_t alen;
+	char *aval;
+	struct nftnl_attr *pattr;
+
+	written = 0;
+	boffset = 0;
+	blen = bsize;
+	alen = nftnl_attr_get_len(attr);
+	aval = (char *)nftnl_attr_get_value(attr);
+
+
+	/* type */
+	written = snprintf(buf + boffset, blen, "{\"type\":%u,",
+			   nftnl_attr_get_type(attr));
+	SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+	/* len */
+	written = snprintf(buf + boffset, blen, "\"len\":%u,", alen);
+	SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+	/* value as string */
+	written = snprintf(buf + boffset, blen, "\"val\":");
+	SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+	if (attr->type & NFTNLA_F_NESTED) {
+		written = snprintf(buf + boffset, blen, "[");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+		nftnl_attr_for_each_nested(pattr, attr) {
+			written = __attr_snprint(pattr, buf + boffset, blen);
+			SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+			written = snprintf(buf + boffset, blen, ",");
+			SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+		}
+		boffset--; /* delete last comma */
+
+		written = snprintf(buf + boffset, blen, "]");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+	} else {
+		written = snprintf(buf + boffset, blen, "\"");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+		for (i = 0; i < alen; i++) {
+			written = snprintf(buf + boffset, blen, "%c",
+					   isprint(aval[i]) ? aval[i] : ' ');
+			SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+		}
+
+		written = snprintf(buf + boffset, blen, "\"");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+	}
+
+	written = snprintf(buf + boffset, blen, "}");
+	SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+	return boffset;
+}
+
+int nftnl_attr_payload_snprint(const void *payload, size_t payload_len,
+			       char *buf, int bsize)
+{
+	struct nftnl_attr *attr;
+	int written, blen, boffset;
+
+	written = 0;
+	boffset = 0;
+	blen = bsize;
+
+	nftnl_attr_for_each_payload(attr, payload, payload_len) {
+		written = __attr_snprint(attr, buf + boffset, blen);
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+
+		written = snprintf(buf + boffset, blen, ",");
+		SNPRINTF_BUFFER_SIZE(written, bsize, blen, boffset);
+	}
+
+	return boffset-1; /* delete last comma */
+}
+EXPORT_SYMBOL_ALIAS(nftnl_attr_payload_snprint, nft_attr_payload_snprint);
-- 
2.6.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux