162306a36Sopenharmony_ci/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci * NETLINK      Netlink attributes
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#ifndef __LIBBPF_NLATTR_H
1062306a36Sopenharmony_ci#define __LIBBPF_NLATTR_H
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <stdint.h>
1362306a36Sopenharmony_ci#include <string.h>
1462306a36Sopenharmony_ci#include <errno.h>
1562306a36Sopenharmony_ci#include <linux/netlink.h>
1662306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1762306a36Sopenharmony_ci#include <linux/genetlink.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* avoid multiple definition of netlink features */
2062306a36Sopenharmony_ci#define __LINUX_NETLINK_H
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/**
2362306a36Sopenharmony_ci * Standard attribute types to specify validation policy
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_cienum {
2662306a36Sopenharmony_ci	LIBBPF_NLA_UNSPEC,	/**< Unspecified type, binary data chunk */
2762306a36Sopenharmony_ci	LIBBPF_NLA_U8,		/**< 8 bit integer */
2862306a36Sopenharmony_ci	LIBBPF_NLA_U16,		/**< 16 bit integer */
2962306a36Sopenharmony_ci	LIBBPF_NLA_U32,		/**< 32 bit integer */
3062306a36Sopenharmony_ci	LIBBPF_NLA_U64,		/**< 64 bit integer */
3162306a36Sopenharmony_ci	LIBBPF_NLA_STRING,	/**< NUL terminated character string */
3262306a36Sopenharmony_ci	LIBBPF_NLA_FLAG,	/**< Flag */
3362306a36Sopenharmony_ci	LIBBPF_NLA_MSECS,	/**< Micro seconds (64bit) */
3462306a36Sopenharmony_ci	LIBBPF_NLA_NESTED,	/**< Nested attributes */
3562306a36Sopenharmony_ci	__LIBBPF_NLA_TYPE_MAX,
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define LIBBPF_NLA_TYPE_MAX (__LIBBPF_NLA_TYPE_MAX - 1)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/**
4162306a36Sopenharmony_ci * @ingroup attr
4262306a36Sopenharmony_ci * Attribute validation policy.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_cistruct libbpf_nla_policy {
4762306a36Sopenharmony_ci	/** Type of attribute or LIBBPF_NLA_UNSPEC */
4862306a36Sopenharmony_ci	uint16_t	type;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/** Minimal length of payload required */
5162306a36Sopenharmony_ci	uint16_t	minlen;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	/** Maximal length of payload allowed */
5462306a36Sopenharmony_ci	uint16_t	maxlen;
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct libbpf_nla_req {
5862306a36Sopenharmony_ci	struct nlmsghdr nh;
5962306a36Sopenharmony_ci	union {
6062306a36Sopenharmony_ci		struct ifinfomsg ifinfo;
6162306a36Sopenharmony_ci		struct tcmsg tc;
6262306a36Sopenharmony_ci		struct genlmsghdr gnl;
6362306a36Sopenharmony_ci	};
6462306a36Sopenharmony_ci	char buf[128];
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci/**
6862306a36Sopenharmony_ci * @ingroup attr
6962306a36Sopenharmony_ci * Iterate over a stream of attributes
7062306a36Sopenharmony_ci * @arg pos	loop counter, set to current attribute
7162306a36Sopenharmony_ci * @arg head	head of attribute stream
7262306a36Sopenharmony_ci * @arg len	length of attribute stream
7362306a36Sopenharmony_ci * @arg rem	initialized to len, holds bytes currently remaining in stream
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_ci#define libbpf_nla_for_each_attr(pos, head, len, rem) \
7662306a36Sopenharmony_ci	for (pos = head, rem = len; \
7762306a36Sopenharmony_ci	     nla_ok(pos, rem); \
7862306a36Sopenharmony_ci	     pos = nla_next(pos, &(rem)))
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/**
8162306a36Sopenharmony_ci * libbpf_nla_data - head of payload
8262306a36Sopenharmony_ci * @nla: netlink attribute
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_cistatic inline void *libbpf_nla_data(const struct nlattr *nla)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	return (void *)nla + NLA_HDRLEN;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	return *(uint8_t *)libbpf_nla_data(nla);
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic inline uint16_t libbpf_nla_getattr_u16(const struct nlattr *nla)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	return *(uint16_t *)libbpf_nla_data(nla);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	return *(uint32_t *)libbpf_nla_data(nla);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic inline uint64_t libbpf_nla_getattr_u64(const struct nlattr *nla)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	return *(uint64_t *)libbpf_nla_data(nla);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic inline const char *libbpf_nla_getattr_str(const struct nlattr *nla)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	return (const char *)libbpf_nla_data(nla);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/**
11562306a36Sopenharmony_ci * libbpf_nla_len - length of payload
11662306a36Sopenharmony_ci * @nla: netlink attribute
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_cistatic inline int libbpf_nla_len(const struct nlattr *nla)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	return nla->nla_len - NLA_HDRLEN;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciint libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
12462306a36Sopenharmony_ci		     int len, struct libbpf_nla_policy *policy);
12562306a36Sopenharmony_ciint libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
12662306a36Sopenharmony_ci			    struct nlattr *nla,
12762306a36Sopenharmony_ci			    struct libbpf_nla_policy *policy);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ciint libbpf_nla_dump_errormsg(struct nlmsghdr *nlh);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic inline struct nlattr *nla_data(struct nlattr *nla)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	return (struct nlattr *)((void *)nla + NLA_HDRLEN);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic inline struct nlattr *req_tail(struct libbpf_nla_req *req)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	return (struct nlattr *)((void *)req + NLMSG_ALIGN(req->nh.nlmsg_len));
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic inline int nlattr_add(struct libbpf_nla_req *req, int type,
14262306a36Sopenharmony_ci			     const void *data, int len)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct nlattr *nla;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > sizeof(*req))
14762306a36Sopenharmony_ci		return -EMSGSIZE;
14862306a36Sopenharmony_ci	if (!!data != !!len)
14962306a36Sopenharmony_ci		return -EINVAL;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	nla = req_tail(req);
15262306a36Sopenharmony_ci	nla->nla_type = type;
15362306a36Sopenharmony_ci	nla->nla_len = NLA_HDRLEN + len;
15462306a36Sopenharmony_ci	if (data)
15562306a36Sopenharmony_ci		memcpy(nla_data(nla), data, len);
15662306a36Sopenharmony_ci	req->nh.nlmsg_len = NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(nla->nla_len);
15762306a36Sopenharmony_ci	return 0;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic inline struct nlattr *nlattr_begin_nested(struct libbpf_nla_req *req, int type)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct nlattr *tail;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	tail = req_tail(req);
16562306a36Sopenharmony_ci	if (nlattr_add(req, type | NLA_F_NESTED, NULL, 0))
16662306a36Sopenharmony_ci		return NULL;
16762306a36Sopenharmony_ci	return tail;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic inline void nlattr_end_nested(struct libbpf_nla_req *req,
17162306a36Sopenharmony_ci				     struct nlattr *tail)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	tail->nla_len = (void *)req_tail(req) - (void *)tail;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci#endif /* __LIBBPF_NLATTR_H */
177