1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
4 * NETLINK Netlink attributes
6 * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
12 #include <linux/rtnetlink.h>
14 #include "libbpf_internal.h"
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,
25 static struct nlattr
*nla_next(const struct nlattr
*nla
, int *remaining
)
27 int totlen
= NLA_ALIGN(nla
->nla_len
);
30 return (struct nlattr
*)((void *)nla
+ totlen
);
33 static int nla_ok(const struct nlattr
*nla
, int remaining
)
35 return remaining
>= (int)sizeof(*nla
) &&
36 nla
->nla_len
>= sizeof(*nla
) &&
37 nla
->nla_len
<= remaining
;
40 static int nla_type(const struct nlattr
*nla
)
42 return nla
->nla_type
& NLA_TYPE_MASK
;
45 static int validate_nla(struct nlattr
*nla
, int maxtype
,
46 struct libbpf_nla_policy
*policy
)
48 struct libbpf_nla_policy
*pt
;
49 unsigned int minlen
= 0;
50 int type
= nla_type(nla
);
52 if (type
< 0 || type
> maxtype
)
57 if (pt
->type
> LIBBPF_NLA_TYPE_MAX
)
62 else if (pt
->type
!= LIBBPF_NLA_UNSPEC
)
63 minlen
= nla_attr_minlen
[pt
->type
];
65 if (libbpf_nla_len(nla
) < minlen
)
68 if (pt
->maxlen
&& libbpf_nla_len(nla
) > pt
->maxlen
)
71 if (pt
->type
== LIBBPF_NLA_STRING
) {
72 char *data
= libbpf_nla_data(nla
);
74 if (data
[libbpf_nla_len(nla
) - 1] != '\0')
81 static inline int nlmsg_len(const struct nlmsghdr
*nlh
)
83 return nlh
->nlmsg_len
- NLMSG_HDRLEN
;
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.
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.
102 * @return 0 on success or a negative error code.
104 int libbpf_nla_parse(struct nlattr
*tb
[], int maxtype
, struct nlattr
*head
,
105 int len
, struct libbpf_nla_policy
*policy
)
110 memset(tb
, 0, sizeof(struct nlattr
*) * (maxtype
+ 1));
112 libbpf_nla_for_each_attr(nla
, head
, len
, rem
) {
113 int type
= nla_type(nla
);
119 err
= validate_nla(nla
, maxtype
, policy
);
125 pr_warn("Attribute of type %#x found multiple times in message, "
126 "previous attribute is being ignored.\n", type
);
137 * Create attribute index based on nested attribute
138 * @arg tb Index array to be filled (maxtype+1 elements).
139 * @arg maxtype Maximum attribute type expected and accepted.
140 * @arg nla Nested Attribute.
141 * @arg policy Attribute validation policy.
143 * Feeds the stream of attributes nested into the specified attribute
144 * to libbpf_nla_parse().
146 * @see libbpf_nla_parse
147 * @return 0 on success or a negative error code.
149 int libbpf_nla_parse_nested(struct nlattr
*tb
[], int maxtype
,
151 struct libbpf_nla_policy
*policy
)
153 return libbpf_nla_parse(tb
, maxtype
, libbpf_nla_data(nla
),
154 libbpf_nla_len(nla
), policy
);
157 /* dump netlink extended ack error message */
158 int libbpf_nla_dump_errormsg(struct nlmsghdr
*nlh
)
160 struct libbpf_nla_policy extack_policy
[NLMSGERR_ATTR_MAX
+ 1] = {
161 [NLMSGERR_ATTR_MSG
] = { .type
= LIBBPF_NLA_STRING
},
162 [NLMSGERR_ATTR_OFFS
] = { .type
= LIBBPF_NLA_U32
},
164 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1], *attr
;
165 struct nlmsgerr
*err
;
169 /* no TLVs, nothing to do here */
170 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
173 err
= (struct nlmsgerr
*)NLMSG_DATA(nlh
);
176 /* if NLM_F_CAPPED is set then the inner err msg was capped */
177 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
178 hlen
+= nlmsg_len(&err
->msg
);
180 attr
= (struct nlattr
*) ((void *) err
+ hlen
);
181 alen
= (void *)nlh
+ nlh
->nlmsg_len
- (void *)attr
;
183 if (libbpf_nla_parse(tb
, NLMSGERR_ATTR_MAX
, attr
, alen
,
184 extack_policy
) != 0) {
185 pr_warn("Failed to parse extended error attributes\n");
189 if (tb
[NLMSGERR_ATTR_MSG
])
190 errmsg
= (char *) libbpf_nla_data(tb
[NLMSGERR_ATTR_MSG
]);
192 pr_warn("Kernel error message: %s\n", errmsg
);