11bc38b8fSAlexei Starovoitov /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2bbf48c18SEric Leblond
3bbf48c18SEric Leblond /*
4bbf48c18SEric Leblond * NETLINK Netlink attributes
5bbf48c18SEric Leblond *
6bbf48c18SEric Leblond * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
7bbf48c18SEric Leblond */
8bbf48c18SEric Leblond
9eff81908SAndrey Ignatov #ifndef __LIBBPF_NLATTR_H
10eff81908SAndrey Ignatov #define __LIBBPF_NLATTR_H
11bbf48c18SEric Leblond
12bbf48c18SEric Leblond #include <stdint.h>
138bbb77b7SKumar Kartikeya Dwivedi #include <string.h>
148bbb77b7SKumar Kartikeya Dwivedi #include <errno.h>
15bbf48c18SEric Leblond #include <linux/netlink.h>
160ae64fb6SKumar Kartikeya Dwivedi #include <linux/rtnetlink.h>
17*04d58f1bSLorenzo Bianconi #include <linux/genetlink.h>
188bbb77b7SKumar Kartikeya Dwivedi
19bbf48c18SEric Leblond /* avoid multiple definition of netlink features */
20bbf48c18SEric Leblond #define __LINUX_NETLINK_H
21bbf48c18SEric Leblond
22bbf48c18SEric Leblond /**
23bbf48c18SEric Leblond * Standard attribute types to specify validation policy
24bbf48c18SEric Leblond */
25bbf48c18SEric Leblond enum {
26f04bc8a4SAndrey Ignatov LIBBPF_NLA_UNSPEC, /**< Unspecified type, binary data chunk */
27f04bc8a4SAndrey Ignatov LIBBPF_NLA_U8, /**< 8 bit integer */
28f04bc8a4SAndrey Ignatov LIBBPF_NLA_U16, /**< 16 bit integer */
29f04bc8a4SAndrey Ignatov LIBBPF_NLA_U32, /**< 32 bit integer */
30f04bc8a4SAndrey Ignatov LIBBPF_NLA_U64, /**< 64 bit integer */
31f04bc8a4SAndrey Ignatov LIBBPF_NLA_STRING, /**< NUL terminated character string */
32f04bc8a4SAndrey Ignatov LIBBPF_NLA_FLAG, /**< Flag */
33f04bc8a4SAndrey Ignatov LIBBPF_NLA_MSECS, /**< Micro seconds (64bit) */
34f04bc8a4SAndrey Ignatov LIBBPF_NLA_NESTED, /**< Nested attributes */
35f04bc8a4SAndrey Ignatov __LIBBPF_NLA_TYPE_MAX,
36bbf48c18SEric Leblond };
37bbf48c18SEric Leblond
38f04bc8a4SAndrey Ignatov #define LIBBPF_NLA_TYPE_MAX (__LIBBPF_NLA_TYPE_MAX - 1)
39bbf48c18SEric Leblond
40bbf48c18SEric Leblond /**
41bbf48c18SEric Leblond * @ingroup attr
42bbf48c18SEric Leblond * Attribute validation policy.
43bbf48c18SEric Leblond *
44bbf48c18SEric Leblond * See section @core_doc{core_attr_parse,Attribute Parsing} for more details.
45bbf48c18SEric Leblond */
46f04bc8a4SAndrey Ignatov struct libbpf_nla_policy {
47f04bc8a4SAndrey Ignatov /** Type of attribute or LIBBPF_NLA_UNSPEC */
48bbf48c18SEric Leblond uint16_t type;
49bbf48c18SEric Leblond
50bbf48c18SEric Leblond /** Minimal length of payload required */
51bbf48c18SEric Leblond uint16_t minlen;
52bbf48c18SEric Leblond
53bbf48c18SEric Leblond /** Maximal length of payload allowed */
54bbf48c18SEric Leblond uint16_t maxlen;
55bbf48c18SEric Leblond };
56bbf48c18SEric Leblond
570ae64fb6SKumar Kartikeya Dwivedi struct libbpf_nla_req {
580ae64fb6SKumar Kartikeya Dwivedi struct nlmsghdr nh;
590ae64fb6SKumar Kartikeya Dwivedi union {
600ae64fb6SKumar Kartikeya Dwivedi struct ifinfomsg ifinfo;
610ae64fb6SKumar Kartikeya Dwivedi struct tcmsg tc;
62*04d58f1bSLorenzo Bianconi struct genlmsghdr gnl;
630ae64fb6SKumar Kartikeya Dwivedi };
640ae64fb6SKumar Kartikeya Dwivedi char buf[128];
650ae64fb6SKumar Kartikeya Dwivedi };
660ae64fb6SKumar Kartikeya Dwivedi
67bbf48c18SEric Leblond /**
68bbf48c18SEric Leblond * @ingroup attr
69bbf48c18SEric Leblond * Iterate over a stream of attributes
70bbf48c18SEric Leblond * @arg pos loop counter, set to current attribute
71bbf48c18SEric Leblond * @arg head head of attribute stream
72bbf48c18SEric Leblond * @arg len length of attribute stream
73bbf48c18SEric Leblond * @arg rem initialized to len, holds bytes currently remaining in stream
74bbf48c18SEric Leblond */
75f04bc8a4SAndrey Ignatov #define libbpf_nla_for_each_attr(pos, head, len, rem) \
76bbf48c18SEric Leblond for (pos = head, rem = len; \
77bbf48c18SEric Leblond nla_ok(pos, rem); \
78bbf48c18SEric Leblond pos = nla_next(pos, &(rem)))
79bbf48c18SEric Leblond
8036f1678dSYonghong Song /**
81f04bc8a4SAndrey Ignatov * libbpf_nla_data - head of payload
8236f1678dSYonghong Song * @nla: netlink attribute
8336f1678dSYonghong Song */
libbpf_nla_data(const struct nlattr * nla)84f04bc8a4SAndrey Ignatov static inline void *libbpf_nla_data(const struct nlattr *nla)
8536f1678dSYonghong Song {
86ee62a5c6SKumar Kartikeya Dwivedi return (void *)nla + NLA_HDRLEN;
8736f1678dSYonghong Song }
8836f1678dSYonghong Song
libbpf_nla_getattr_u8(const struct nlattr * nla)89f04bc8a4SAndrey Ignatov static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla)
9036f1678dSYonghong Song {
91f04bc8a4SAndrey Ignatov return *(uint8_t *)libbpf_nla_data(nla);
9236f1678dSYonghong Song }
9336f1678dSYonghong Song
libbpf_nla_getattr_u16(const struct nlattr * nla)94*04d58f1bSLorenzo Bianconi static inline uint16_t libbpf_nla_getattr_u16(const struct nlattr *nla)
95*04d58f1bSLorenzo Bianconi {
96*04d58f1bSLorenzo Bianconi return *(uint16_t *)libbpf_nla_data(nla);
97*04d58f1bSLorenzo Bianconi }
98*04d58f1bSLorenzo Bianconi
libbpf_nla_getattr_u32(const struct nlattr * nla)99f04bc8a4SAndrey Ignatov static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla)
10036f1678dSYonghong Song {
101f04bc8a4SAndrey Ignatov return *(uint32_t *)libbpf_nla_data(nla);
10236f1678dSYonghong Song }
10336f1678dSYonghong Song
libbpf_nla_getattr_u64(const struct nlattr * nla)104*04d58f1bSLorenzo Bianconi static inline uint64_t libbpf_nla_getattr_u64(const struct nlattr *nla)
105*04d58f1bSLorenzo Bianconi {
106*04d58f1bSLorenzo Bianconi return *(uint64_t *)libbpf_nla_data(nla);
107*04d58f1bSLorenzo Bianconi }
108*04d58f1bSLorenzo Bianconi
libbpf_nla_getattr_str(const struct nlattr * nla)109f04bc8a4SAndrey Ignatov static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla)
11036f1678dSYonghong Song {
111f04bc8a4SAndrey Ignatov return (const char *)libbpf_nla_data(nla);
11236f1678dSYonghong Song }
11336f1678dSYonghong Song
11436f1678dSYonghong Song /**
115f04bc8a4SAndrey Ignatov * libbpf_nla_len - length of payload
11636f1678dSYonghong Song * @nla: netlink attribute
11736f1678dSYonghong Song */
libbpf_nla_len(const struct nlattr * nla)118f04bc8a4SAndrey Ignatov static inline int libbpf_nla_len(const struct nlattr *nla)
11936f1678dSYonghong Song {
12036f1678dSYonghong Song return nla->nla_len - NLA_HDRLEN;
12136f1678dSYonghong Song }
12236f1678dSYonghong Song
123f04bc8a4SAndrey Ignatov int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
124f04bc8a4SAndrey Ignatov int len, struct libbpf_nla_policy *policy);
125f04bc8a4SAndrey Ignatov int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
126f04bc8a4SAndrey Ignatov struct nlattr *nla,
127f04bc8a4SAndrey Ignatov struct libbpf_nla_policy *policy);
12836f1678dSYonghong Song
129f04bc8a4SAndrey Ignatov int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh);
130bbf48c18SEric Leblond
nla_data(struct nlattr * nla)1318bbb77b7SKumar Kartikeya Dwivedi static inline struct nlattr *nla_data(struct nlattr *nla)
1328bbb77b7SKumar Kartikeya Dwivedi {
133ee62a5c6SKumar Kartikeya Dwivedi return (struct nlattr *)((void *)nla + NLA_HDRLEN);
1348bbb77b7SKumar Kartikeya Dwivedi }
1358bbb77b7SKumar Kartikeya Dwivedi
req_tail(struct libbpf_nla_req * req)1360ae64fb6SKumar Kartikeya Dwivedi static inline struct nlattr *req_tail(struct libbpf_nla_req *req)
1378bbb77b7SKumar Kartikeya Dwivedi {
138ee62a5c6SKumar Kartikeya Dwivedi return (struct nlattr *)((void *)req + NLMSG_ALIGN(req->nh.nlmsg_len));
1398bbb77b7SKumar Kartikeya Dwivedi }
1408bbb77b7SKumar Kartikeya Dwivedi
nlattr_add(struct libbpf_nla_req * req,int type,const void * data,int len)1410ae64fb6SKumar Kartikeya Dwivedi static inline int nlattr_add(struct libbpf_nla_req *req, int type,
1428bbb77b7SKumar Kartikeya Dwivedi const void *data, int len)
1438bbb77b7SKumar Kartikeya Dwivedi {
1448bbb77b7SKumar Kartikeya Dwivedi struct nlattr *nla;
1458bbb77b7SKumar Kartikeya Dwivedi
1460ae64fb6SKumar Kartikeya Dwivedi if (NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > sizeof(*req))
1478bbb77b7SKumar Kartikeya Dwivedi return -EMSGSIZE;
1488bbb77b7SKumar Kartikeya Dwivedi if (!!data != !!len)
1498bbb77b7SKumar Kartikeya Dwivedi return -EINVAL;
1508bbb77b7SKumar Kartikeya Dwivedi
1510ae64fb6SKumar Kartikeya Dwivedi nla = req_tail(req);
1528bbb77b7SKumar Kartikeya Dwivedi nla->nla_type = type;
1538bbb77b7SKumar Kartikeya Dwivedi nla->nla_len = NLA_HDRLEN + len;
1548bbb77b7SKumar Kartikeya Dwivedi if (data)
1558bbb77b7SKumar Kartikeya Dwivedi memcpy(nla_data(nla), data, len);
1560ae64fb6SKumar Kartikeya Dwivedi req->nh.nlmsg_len = NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(nla->nla_len);
1578bbb77b7SKumar Kartikeya Dwivedi return 0;
1588bbb77b7SKumar Kartikeya Dwivedi }
1598bbb77b7SKumar Kartikeya Dwivedi
nlattr_begin_nested(struct libbpf_nla_req * req,int type)1600ae64fb6SKumar Kartikeya Dwivedi static inline struct nlattr *nlattr_begin_nested(struct libbpf_nla_req *req, int type)
1618bbb77b7SKumar Kartikeya Dwivedi {
1628bbb77b7SKumar Kartikeya Dwivedi struct nlattr *tail;
1638bbb77b7SKumar Kartikeya Dwivedi
1640ae64fb6SKumar Kartikeya Dwivedi tail = req_tail(req);
1650ae64fb6SKumar Kartikeya Dwivedi if (nlattr_add(req, type | NLA_F_NESTED, NULL, 0))
1668bbb77b7SKumar Kartikeya Dwivedi return NULL;
1678bbb77b7SKumar Kartikeya Dwivedi return tail;
1688bbb77b7SKumar Kartikeya Dwivedi }
1698bbb77b7SKumar Kartikeya Dwivedi
nlattr_end_nested(struct libbpf_nla_req * req,struct nlattr * tail)1700ae64fb6SKumar Kartikeya Dwivedi static inline void nlattr_end_nested(struct libbpf_nla_req *req,
1710ae64fb6SKumar Kartikeya Dwivedi struct nlattr *tail)
1728bbb77b7SKumar Kartikeya Dwivedi {
173ee62a5c6SKumar Kartikeya Dwivedi tail->nla_len = (void *)req_tail(req) - (void *)tail;
1748bbb77b7SKumar Kartikeya Dwivedi }
1758bbb77b7SKumar Kartikeya Dwivedi
176eff81908SAndrey Ignatov #endif /* __LIBBPF_NLATTR_H */
177