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>
11 #include "libbpf_internal.h"
12 #include <linux/rtnetlink.h>
16 /* make sure libbpf doesn't use kernel-only integer typedefs */
17 #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
19 static uint16_t nla_attr_minlen
[LIBBPF_NLA_TYPE_MAX
+1] = {
20 [LIBBPF_NLA_U8
] = sizeof(uint8_t),
21 [LIBBPF_NLA_U16
] = sizeof(uint16_t),
22 [LIBBPF_NLA_U32
] = sizeof(uint32_t),
23 [LIBBPF_NLA_U64
] = sizeof(uint64_t),
24 [LIBBPF_NLA_STRING
] = 1,
25 [LIBBPF_NLA_FLAG
] = 0,
28 static struct nlattr
*nla_next(const struct nlattr
*nla
, int *remaining
)
30 int totlen
= NLA_ALIGN(nla
->nla_len
);
33 return (struct nlattr
*) ((char *) nla
+ totlen
);
36 static int nla_ok(const struct nlattr
*nla
, int remaining
)
38 return remaining
>= sizeof(*nla
) &&
39 nla
->nla_len
>= sizeof(*nla
) &&
40 nla
->nla_len
<= remaining
;
43 static int nla_type(const struct nlattr
*nla
)
45 return nla
->nla_type
& NLA_TYPE_MASK
;
48 static int validate_nla(struct nlattr
*nla
, int maxtype
,
49 struct libbpf_nla_policy
*policy
)
51 struct libbpf_nla_policy
*pt
;
52 unsigned int minlen
= 0;
53 int type
= nla_type(nla
);
55 if (type
< 0 || type
> maxtype
)
60 if (pt
->type
> LIBBPF_NLA_TYPE_MAX
)
65 else if (pt
->type
!= LIBBPF_NLA_UNSPEC
)
66 minlen
= nla_attr_minlen
[pt
->type
];
68 if (libbpf_nla_len(nla
) < minlen
)
71 if (pt
->maxlen
&& libbpf_nla_len(nla
) > pt
->maxlen
)
74 if (pt
->type
== LIBBPF_NLA_STRING
) {
75 char *data
= libbpf_nla_data(nla
);
77 if (data
[libbpf_nla_len(nla
) - 1] != '\0')
84 static inline int nlmsg_len(const struct nlmsghdr
*nlh
)
86 return nlh
->nlmsg_len
- NLMSG_HDRLEN
;
90 * Create attribute index based on a stream of attributes.
91 * @arg tb Index array to be filled (maxtype+1 elements).
92 * @arg maxtype Maximum attribute type expected and accepted.
93 * @arg head Head of attribute stream.
94 * @arg len Length of attribute stream.
95 * @arg policy Attribute validation policy.
97 * Iterates over the stream of attributes and stores a pointer to each
98 * attribute in the index array using the attribute type as index to
99 * the array. Attribute with a type greater than the maximum type
100 * specified will be silently ignored in order to maintain backwards
101 * compatibility. If \a policy is not NULL, the attribute will be
102 * validated using the specified policy.
105 * @return 0 on success or a negative error code.
107 int libbpf_nla_parse(struct nlattr
*tb
[], int maxtype
, struct nlattr
*head
,
108 int len
, struct libbpf_nla_policy
*policy
)
113 memset(tb
, 0, sizeof(struct nlattr
*) * (maxtype
+ 1));
115 libbpf_nla_for_each_attr(nla
, head
, len
, rem
) {
116 int type
= nla_type(nla
);
122 err
= validate_nla(nla
, maxtype
, policy
);
128 pr_warn("Attribute of type %#x found multiple times in message, "
129 "previous attribute is being ignored.\n", type
);
140 * Create attribute index based on nested attribute
141 * @arg tb Index array to be filled (maxtype+1 elements).
142 * @arg maxtype Maximum attribute type expected and accepted.
143 * @arg nla Nested Attribute.
144 * @arg policy Attribute validation policy.
146 * Feeds the stream of attributes nested into the specified attribute
147 * to libbpf_nla_parse().
149 * @see libbpf_nla_parse
150 * @return 0 on success or a negative error code.
152 int libbpf_nla_parse_nested(struct nlattr
*tb
[], int maxtype
,
154 struct libbpf_nla_policy
*policy
)
156 return libbpf_nla_parse(tb
, maxtype
, libbpf_nla_data(nla
),
157 libbpf_nla_len(nla
), policy
);
160 /* dump netlink extended ack error message */
161 int libbpf_nla_dump_errormsg(struct nlmsghdr
*nlh
)
163 struct libbpf_nla_policy extack_policy
[NLMSGERR_ATTR_MAX
+ 1] = {
164 [NLMSGERR_ATTR_MSG
] = { .type
= LIBBPF_NLA_STRING
},
165 [NLMSGERR_ATTR_OFFS
] = { .type
= LIBBPF_NLA_U32
},
167 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1], *attr
;
168 struct nlmsgerr
*err
;
172 /* no TLVs, nothing to do here */
173 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
176 err
= (struct nlmsgerr
*)NLMSG_DATA(nlh
);
179 /* if NLM_F_CAPPED is set then the inner err msg was capped */
180 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
181 hlen
+= nlmsg_len(&err
->msg
);
183 attr
= (struct nlattr
*) ((void *) err
+ hlen
);
184 alen
= nlh
->nlmsg_len
- hlen
;
186 if (libbpf_nla_parse(tb
, NLMSGERR_ATTR_MAX
, attr
, alen
,
187 extack_policy
) != 0) {
188 pr_warn("Failed to parse extended error attributes\n");
192 if (tb
[NLMSGERR_ATTR_MSG
])
193 errmsg
= (char *) libbpf_nla_data(tb
[NLMSGERR_ATTR_MSG
]);
195 pr_warn("Kernel error message: %s\n", errmsg
);