Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/lib/bpf/nlattr.c
26282 views
1
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2
3
/*
4
* NETLINK Netlink attributes
5
*
6
* Copyright (c) 2003-2013 Thomas Graf <[email protected]>
7
*/
8
9
#include <errno.h>
10
#include <string.h>
11
#include <stdio.h>
12
#include <linux/rtnetlink.h>
13
#include "nlattr.h"
14
#include "libbpf_internal.h"
15
16
static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = {
17
[LIBBPF_NLA_U8] = sizeof(uint8_t),
18
[LIBBPF_NLA_U16] = sizeof(uint16_t),
19
[LIBBPF_NLA_U32] = sizeof(uint32_t),
20
[LIBBPF_NLA_U64] = sizeof(uint64_t),
21
[LIBBPF_NLA_STRING] = 1,
22
[LIBBPF_NLA_FLAG] = 0,
23
};
24
25
static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
26
{
27
int totlen = NLA_ALIGN(nla->nla_len);
28
29
*remaining -= totlen;
30
return (struct nlattr *)((void *)nla + totlen);
31
}
32
33
static int nla_ok(const struct nlattr *nla, int remaining)
34
{
35
return remaining >= (int)sizeof(*nla) &&
36
nla->nla_len >= sizeof(*nla) &&
37
nla->nla_len <= remaining;
38
}
39
40
static int nla_type(const struct nlattr *nla)
41
{
42
return nla->nla_type & NLA_TYPE_MASK;
43
}
44
45
static int validate_nla(struct nlattr *nla, int maxtype,
46
struct libbpf_nla_policy *policy)
47
{
48
struct libbpf_nla_policy *pt;
49
unsigned int minlen = 0;
50
int type = nla_type(nla);
51
52
if (type < 0 || type > maxtype)
53
return 0;
54
55
pt = &policy[type];
56
57
if (pt->type > LIBBPF_NLA_TYPE_MAX)
58
return 0;
59
60
if (pt->minlen)
61
minlen = pt->minlen;
62
else if (pt->type != LIBBPF_NLA_UNSPEC)
63
minlen = nla_attr_minlen[pt->type];
64
65
if (libbpf_nla_len(nla) < minlen)
66
return -EINVAL;
67
68
if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen)
69
return -EINVAL;
70
71
if (pt->type == LIBBPF_NLA_STRING) {
72
char *data = libbpf_nla_data(nla);
73
74
if (data[libbpf_nla_len(nla) - 1] != '\0')
75
return -EINVAL;
76
}
77
78
return 0;
79
}
80
81
static inline int nlmsg_len(const struct nlmsghdr *nlh)
82
{
83
return nlh->nlmsg_len - NLMSG_HDRLEN;
84
}
85
86
/**
87
* Create attribute index based on a stream of attributes.
88
* @arg tb Index array to be filled (maxtype+1 elements).
89
* @arg maxtype Maximum attribute type expected and accepted.
90
* @arg head Head of attribute stream.
91
* @arg len Length of attribute stream.
92
* @arg policy Attribute validation policy.
93
*
94
* Iterates over the stream of attributes and stores a pointer to each
95
* attribute in the index array using the attribute type as index to
96
* the array. Attribute with a type greater than the maximum type
97
* specified will be silently ignored in order to maintain backwards
98
* compatibility. If \a policy is not NULL, the attribute will be
99
* validated using the specified policy.
100
*
101
* @see nla_validate
102
* @return 0 on success or a negative error code.
103
*/
104
int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
105
int len, struct libbpf_nla_policy *policy)
106
{
107
struct nlattr *nla;
108
int rem, err;
109
110
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
111
112
libbpf_nla_for_each_attr(nla, head, len, rem) {
113
int type = nla_type(nla);
114
115
if (type > maxtype)
116
continue;
117
118
if (policy) {
119
err = validate_nla(nla, maxtype, policy);
120
if (err < 0)
121
return err;
122
}
123
124
if (tb[type]) {
125
pr_warn("Attribute of type %#x found multiple times in message, "
126
"previous attribute is being ignored.\n", type);
127
}
128
129
tb[type] = nla;
130
}
131
132
return 0;
133
}
134
135
/**
136
* Create attribute index based on nested attribute
137
* @arg tb Index array to be filled (maxtype+1 elements).
138
* @arg maxtype Maximum attribute type expected and accepted.
139
* @arg nla Nested Attribute.
140
* @arg policy Attribute validation policy.
141
*
142
* Feeds the stream of attributes nested into the specified attribute
143
* to libbpf_nla_parse().
144
*
145
* @see libbpf_nla_parse
146
* @return 0 on success or a negative error code.
147
*/
148
int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
149
struct nlattr *nla,
150
struct libbpf_nla_policy *policy)
151
{
152
return libbpf_nla_parse(tb, maxtype, libbpf_nla_data(nla),
153
libbpf_nla_len(nla), policy);
154
}
155
156
/* dump netlink extended ack error message */
157
int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
158
{
159
struct libbpf_nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
160
[NLMSGERR_ATTR_MSG] = { .type = LIBBPF_NLA_STRING },
161
[NLMSGERR_ATTR_OFFS] = { .type = LIBBPF_NLA_U32 },
162
};
163
struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;
164
struct nlmsgerr *err;
165
char *errmsg = NULL;
166
int hlen, alen;
167
168
/* no TLVs, nothing to do here */
169
if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
170
return 0;
171
172
err = (struct nlmsgerr *)NLMSG_DATA(nlh);
173
hlen = sizeof(*err);
174
175
/* if NLM_F_CAPPED is set then the inner err msg was capped */
176
if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
177
hlen += nlmsg_len(&err->msg);
178
179
attr = (struct nlattr *) ((void *) err + hlen);
180
alen = (void *)nlh + nlh->nlmsg_len - (void *)attr;
181
182
if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
183
extack_policy) != 0) {
184
pr_warn("Failed to parse extended error attributes\n");
185
return 0;
186
}
187
188
if (tb[NLMSGERR_ATTR_MSG])
189
errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);
190
191
pr_warn("Kernel error message: %s\n", errmsg);
192
193
return 0;
194
}
195
196