1 // SPDX-License-Identifier: LGPL-2.1
4 * NETLINK Netlink attributes
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation version 2.1
11 * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
16 #include <linux/rtnetlink.h>
20 static uint16_t nla_attr_minlen
[NLA_TYPE_MAX
+1] = {
21 [NLA_U8
] = sizeof(uint8_t),
22 [NLA_U16
] = sizeof(uint16_t),
23 [NLA_U32
] = sizeof(uint32_t),
24 [NLA_U64
] = sizeof(uint64_t),
29 static int nla_len(const struct nlattr
*nla
)
31 return nla
->nla_len
- NLA_HDRLEN
;
34 static struct nlattr
*nla_next(const struct nlattr
*nla
, int *remaining
)
36 int totlen
= NLA_ALIGN(nla
->nla_len
);
39 return (struct nlattr
*) ((char *) nla
+ totlen
);
42 static int nla_ok(const struct nlattr
*nla
, int remaining
)
44 return remaining
>= sizeof(*nla
) &&
45 nla
->nla_len
>= sizeof(*nla
) &&
46 nla
->nla_len
<= remaining
;
49 static void *nla_data(const struct nlattr
*nla
)
51 return (char *) nla
+ NLA_HDRLEN
;
54 static int nla_type(const struct nlattr
*nla
)
56 return nla
->nla_type
& NLA_TYPE_MASK
;
59 static int validate_nla(struct nlattr
*nla
, int maxtype
,
60 struct nla_policy
*policy
)
62 struct nla_policy
*pt
;
63 unsigned int minlen
= 0;
64 int type
= nla_type(nla
);
66 if (type
< 0 || type
> maxtype
)
71 if (pt
->type
> NLA_TYPE_MAX
)
76 else if (pt
->type
!= NLA_UNSPEC
)
77 minlen
= nla_attr_minlen
[pt
->type
];
79 if (nla_len(nla
) < minlen
)
82 if (pt
->maxlen
&& nla_len(nla
) > pt
->maxlen
)
85 if (pt
->type
== NLA_STRING
) {
86 char *data
= nla_data(nla
);
87 if (data
[nla_len(nla
) - 1] != '\0')
94 static inline int nlmsg_len(const struct nlmsghdr
*nlh
)
96 return nlh
->nlmsg_len
- NLMSG_HDRLEN
;
100 * Create attribute index based on a stream of attributes.
101 * @arg tb Index array to be filled (maxtype+1 elements).
102 * @arg maxtype Maximum attribute type expected and accepted.
103 * @arg head Head of attribute stream.
104 * @arg len Length of attribute stream.
105 * @arg policy Attribute validation policy.
107 * Iterates over the stream of attributes and stores a pointer to each
108 * attribute in the index array using the attribute type as index to
109 * the array. Attribute with a type greater than the maximum type
110 * specified will be silently ignored in order to maintain backwards
111 * compatibility. If \a policy is not NULL, the attribute will be
112 * validated using the specified policy.
115 * @return 0 on success or a negative error code.
117 static int nla_parse(struct nlattr
*tb
[], int maxtype
, struct nlattr
*head
, int len
,
118 struct nla_policy
*policy
)
123 memset(tb
, 0, sizeof(struct nlattr
*) * (maxtype
+ 1));
125 nla_for_each_attr(nla
, head
, len
, rem
) {
126 int type
= nla_type(nla
);
132 err
= validate_nla(nla
, maxtype
, policy
);
138 fprintf(stderr
, "Attribute of type %#x found multiple times in message, "
139 "previous attribute is being ignored.\n", type
);
149 /* dump netlink extended ack error message */
150 int nla_dump_errormsg(struct nlmsghdr
*nlh
)
152 struct nla_policy extack_policy
[NLMSGERR_ATTR_MAX
+ 1] = {
153 [NLMSGERR_ATTR_MSG
] = { .type
= NLA_STRING
},
154 [NLMSGERR_ATTR_OFFS
] = { .type
= NLA_U32
},
156 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1], *attr
;
157 struct nlmsgerr
*err
;
161 /* no TLVs, nothing to do here */
162 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
165 err
= (struct nlmsgerr
*)NLMSG_DATA(nlh
);
168 /* if NLM_F_CAPPED is set then the inner err msg was capped */
169 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
170 hlen
+= nlmsg_len(&err
->msg
);
172 attr
= (struct nlattr
*) ((void *) err
+ hlen
);
173 alen
= nlh
->nlmsg_len
- hlen
;
175 if (nla_parse(tb
, NLMSGERR_ATTR_MAX
, attr
, alen
, extack_policy
) != 0) {
177 "Failed to parse extended error attributes\n");
181 if (tb
[NLMSGERR_ATTR_MSG
])
182 errmsg
= (char *) nla_data(tb
[NLMSGERR_ATTR_MSG
]);
184 fprintf(stderr
, "Kernel error message: %s\n", errmsg
);