Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ /* * NETLINK Netlink attributes * * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> */ #ifndef __LIBBPF_NLATTR_H #define __LIBBPF_NLATTR_H #include <stdint.h> #include <string.h> #include <errno.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <linux/genetlink.h> /* avoid multiple definition of netlink features */ #define __LINUX_NETLINK_H /** * Standard attribute types to specify validation policy */ enum { LIBBPF_NLA_UNSPEC, /**< Unspecified type, binary data chunk */ LIBBPF_NLA_U8, /**< 8 bit integer */ LIBBPF_NLA_U16, /**< 16 bit integer */ LIBBPF_NLA_U32, /**< 32 bit integer */ LIBBPF_NLA_U64, /**< 64 bit integer */ LIBBPF_NLA_STRING, /**< NUL terminated character string */ LIBBPF_NLA_FLAG, /**< Flag */ LIBBPF_NLA_MSECS, /**< Micro seconds (64bit) */ LIBBPF_NLA_NESTED, /**< Nested attributes */ __LIBBPF_NLA_TYPE_MAX, }; #define LIBBPF_NLA_TYPE_MAX (__LIBBPF_NLA_TYPE_MAX - 1) /** * @ingroup attr * Attribute validation policy. * * See section @core_doc{core_attr_parse,Attribute Parsing} for more details. */ struct libbpf_nla_policy { /** Type of attribute or LIBBPF_NLA_UNSPEC */ uint16_t type; /** Minimal length of payload required */ uint16_t minlen; /** Maximal length of payload allowed */ uint16_t maxlen; }; struct libbpf_nla_req { struct nlmsghdr nh; union { struct ifinfomsg ifinfo; struct tcmsg tc; struct genlmsghdr gnl; }; char buf[128]; }; /** * @ingroup attr * Iterate over a stream of attributes * @arg pos loop counter, set to current attribute * @arg head head of attribute stream * @arg len length of attribute stream * @arg rem initialized to len, holds bytes currently remaining in stream */ #define libbpf_nla_for_each_attr(pos, head, len, rem) \ for (pos = head, rem = len; \ nla_ok(pos, rem); \ pos = nla_next(pos, &(rem))) /** * libbpf_nla_data - head of payload * @nla: netlink attribute */ static inline void *libbpf_nla_data(const struct nlattr *nla) { return (void *)nla + NLA_HDRLEN; } static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla) { return *(uint8_t *)libbpf_nla_data(nla); } static inline uint16_t libbpf_nla_getattr_u16(const struct nlattr *nla) { return *(uint16_t *)libbpf_nla_data(nla); } static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla) { return *(uint32_t *)libbpf_nla_data(nla); } static inline uint64_t libbpf_nla_getattr_u64(const struct nlattr *nla) { return *(uint64_t *)libbpf_nla_data(nla); } static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla) { return (const char *)libbpf_nla_data(nla); } /** * libbpf_nla_len - length of payload * @nla: netlink attribute */ static inline int libbpf_nla_len(const struct nlattr *nla) { return nla->nla_len - NLA_HDRLEN; } int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, struct libbpf_nla_policy *policy); int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, struct libbpf_nla_policy *policy); int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh); static inline struct nlattr *nla_data(struct nlattr *nla) { return (struct nlattr *)((void *)nla + NLA_HDRLEN); } static inline struct nlattr *req_tail(struct libbpf_nla_req *req) { return (struct nlattr *)((void *)req + NLMSG_ALIGN(req->nh.nlmsg_len)); } static inline int nlattr_add(struct libbpf_nla_req *req, int type, const void *data, int len) { struct nlattr *nla; if (NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(NLA_HDRLEN + len) > sizeof(*req)) return -EMSGSIZE; if (!!data != !!len) return -EINVAL; nla = req_tail(req); nla->nla_type = type; nla->nla_len = NLA_HDRLEN + len; if (data) memcpy(nla_data(nla), data, len); req->nh.nlmsg_len = NLMSG_ALIGN(req->nh.nlmsg_len) + NLA_ALIGN(nla->nla_len); return 0; } static inline struct nlattr *nlattr_begin_nested(struct libbpf_nla_req *req, int type) { struct nlattr *tail; tail = req_tail(req); if (nlattr_add(req, type | NLA_F_NESTED, NULL, 0)) return NULL; return tail; } static inline void nlattr_end_nested(struct libbpf_nla_req *req, struct nlattr *tail) { tail->nla_len = (void *)req_tail(req) - (void *)tail; } #endif /* __LIBBPF_NLATTR_H */ |