1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) 2008-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
5*4882a593Smuzhiyun * it under the terms of the GNU Lesser General Public License as published
6*4882a593Smuzhiyun * by the Free Software Foundation; either version 2.1 of the License, or
7*4882a593Smuzhiyun * (at your option) any later version.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun #include <limits.h> /* for INT_MAX */
10*4882a593Smuzhiyun #include <string.h>
11*4882a593Smuzhiyun #include <errno.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include "libmnl.h"
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun /**
16*4882a593Smuzhiyun * \defgroup attr Netlink attribute helpers
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * Netlink Type-Length-Value (TLV) attribute:
19*4882a593Smuzhiyun * \verbatim
20*4882a593Smuzhiyun |<-- 2 bytes -->|<-- 2 bytes -->|<-- variable -->|
21*4882a593Smuzhiyun -------------------------------------------------
22*4882a593Smuzhiyun | length | type | value |
23*4882a593Smuzhiyun -------------------------------------------------
24*4882a593Smuzhiyun |<--------- header ------------>|<-- payload --->|
25*4882a593Smuzhiyun \endverbatim
26*4882a593Smuzhiyun * The payload of the Netlink message contains sequences of attributes that are
27*4882a593Smuzhiyun * expressed in TLV format.
28*4882a593Smuzhiyun *
29*4882a593Smuzhiyun * @{
30*4882a593Smuzhiyun */
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /**
33*4882a593Smuzhiyun * mnl_attr_get_type - get type of netlink attribute
34*4882a593Smuzhiyun * \param attr pointer to netlink attribute
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * This function returns the attribute type.
37*4882a593Smuzhiyun */
mnl_attr_get_type(const struct nlattr * attr)38*4882a593Smuzhiyun uint16_t mnl_attr_get_type(const struct nlattr *attr)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun return attr->nla_type & NLA_TYPE_MASK;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun /**
44*4882a593Smuzhiyun * mnl_attr_get_len - get length of netlink attribute
45*4882a593Smuzhiyun * \param attr pointer to netlink attribute
46*4882a593Smuzhiyun *
47*4882a593Smuzhiyun * This function returns the attribute length that is the attribute header
48*4882a593Smuzhiyun * plus the attribute payload.
49*4882a593Smuzhiyun */
mnl_attr_get_len(const struct nlattr * attr)50*4882a593Smuzhiyun uint16_t mnl_attr_get_len(const struct nlattr *attr)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun return attr->nla_len;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /**
56*4882a593Smuzhiyun * mnl_attr_get_payload_len - get the attribute payload-value length
57*4882a593Smuzhiyun * \param attr pointer to netlink attribute
58*4882a593Smuzhiyun *
59*4882a593Smuzhiyun * This function returns the attribute payload-value length.
60*4882a593Smuzhiyun */
mnl_attr_get_payload_len(const struct nlattr * attr)61*4882a593Smuzhiyun uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun return attr->nla_len - MNL_ATTR_HDRLEN;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /**
67*4882a593Smuzhiyun * mnl_attr_get_payload - get pointer to the attribute payload
68*4882a593Smuzhiyun * \param attr pointer to netlink attribute
69*4882a593Smuzhiyun *
70*4882a593Smuzhiyun * This function return a pointer to the attribute payload.
71*4882a593Smuzhiyun */
mnl_attr_get_payload(const struct nlattr * attr)72*4882a593Smuzhiyun void *mnl_attr_get_payload(const struct nlattr *attr)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun return (void *)attr + MNL_ATTR_HDRLEN;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /**
78*4882a593Smuzhiyun * mnl_attr_ok - check if there is room for an attribute in a buffer
79*4882a593Smuzhiyun * \param attr attribute that we want to check if there is room for
80*4882a593Smuzhiyun * \param len remaining bytes in a buffer that contains the attribute
81*4882a593Smuzhiyun *
82*4882a593Smuzhiyun * This function is used to check that a buffer, which is supposed to contain
83*4882a593Smuzhiyun * an attribute, has enough room for the attribute that it stores, i.e. this
84*4882a593Smuzhiyun * function can be used to verify that an attribute is neither malformed nor
85*4882a593Smuzhiyun * truncated.
86*4882a593Smuzhiyun *
87*4882a593Smuzhiyun * This function does not set errno in case of error since it is intended
88*4882a593Smuzhiyun * for iterations. Thus, it returns true on success and false on error.
89*4882a593Smuzhiyun *
90*4882a593Smuzhiyun * The len parameter may be negative in the case of malformed messages during
91*4882a593Smuzhiyun * attribute iteration, that is why we use a signed integer.
92*4882a593Smuzhiyun */
mnl_attr_ok(const struct nlattr * attr,int len)93*4882a593Smuzhiyun bool mnl_attr_ok(const struct nlattr *attr, int len)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun return len >= (int)sizeof(struct nlattr) &&
96*4882a593Smuzhiyun attr->nla_len >= sizeof(struct nlattr) &&
97*4882a593Smuzhiyun (int)attr->nla_len <= len;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /**
101*4882a593Smuzhiyun * mnl_attr_next - get the next attribute in the payload of a netlink message
102*4882a593Smuzhiyun * \param attr pointer to the current attribute
103*4882a593Smuzhiyun *
104*4882a593Smuzhiyun * This function returns a pointer to the next attribute after the one passed
105*4882a593Smuzhiyun * as parameter. You have to use mnl_attr_ok() to ensure that the next
106*4882a593Smuzhiyun * attribute is valid.
107*4882a593Smuzhiyun */
mnl_attr_next(const struct nlattr * attr)108*4882a593Smuzhiyun struct nlattr *mnl_attr_next(const struct nlattr *attr)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len));
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /**
114*4882a593Smuzhiyun * mnl_attr_type_valid - check if the attribute type is valid
115*4882a593Smuzhiyun * \param attr pointer to attribute to be checked
116*4882a593Smuzhiyun * \param max maximum attribute type
117*4882a593Smuzhiyun *
118*4882a593Smuzhiyun * This function allows to check if the attribute type is higher than the
119*4882a593Smuzhiyun * maximum supported type. If the attribute type is invalid, this function
120*4882a593Smuzhiyun * returns -1 and errno is explicitly set. On success, this function returns 1.
121*4882a593Smuzhiyun *
122*4882a593Smuzhiyun * Strict attribute checking in user-space is not a good idea since you may
123*4882a593Smuzhiyun * run an old application with a newer kernel that supports new attributes.
124*4882a593Smuzhiyun * This leads to backward compatibility breakages in user-space. Better check
125*4882a593Smuzhiyun * if you support an attribute, if not, skip it.
126*4882a593Smuzhiyun */
mnl_attr_type_valid(const struct nlattr * attr,uint16_t max)127*4882a593Smuzhiyun int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun if (mnl_attr_get_type(attr) > max) {
130*4882a593Smuzhiyun errno = EOPNOTSUPP;
131*4882a593Smuzhiyun return -1;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun return 1;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
__mnl_attr_validate(const struct nlattr * attr,enum mnl_attr_data_type type,size_t exp_len)136*4882a593Smuzhiyun static int __mnl_attr_validate(const struct nlattr *attr,
137*4882a593Smuzhiyun enum mnl_attr_data_type type, size_t exp_len)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun uint16_t attr_len = mnl_attr_get_payload_len(attr);
140*4882a593Smuzhiyun const char *attr_data = mnl_attr_get_payload(attr);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun if (attr_len < exp_len) {
143*4882a593Smuzhiyun errno = ERANGE;
144*4882a593Smuzhiyun return -1;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun switch(type) {
147*4882a593Smuzhiyun case MNL_TYPE_FLAG:
148*4882a593Smuzhiyun if (attr_len > 0) {
149*4882a593Smuzhiyun errno = ERANGE;
150*4882a593Smuzhiyun return -1;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun break;
153*4882a593Smuzhiyun case MNL_TYPE_NUL_STRING:
154*4882a593Smuzhiyun if (attr_len == 0) {
155*4882a593Smuzhiyun errno = ERANGE;
156*4882a593Smuzhiyun return -1;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun if (attr_data[attr_len-1] != '\0') {
159*4882a593Smuzhiyun errno = EINVAL;
160*4882a593Smuzhiyun return -1;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun break;
163*4882a593Smuzhiyun case MNL_TYPE_STRING:
164*4882a593Smuzhiyun if (attr_len == 0) {
165*4882a593Smuzhiyun errno = ERANGE;
166*4882a593Smuzhiyun return -1;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun break;
169*4882a593Smuzhiyun case MNL_TYPE_NESTED:
170*4882a593Smuzhiyun /* empty nested attributes are OK. */
171*4882a593Smuzhiyun if (attr_len == 0)
172*4882a593Smuzhiyun break;
173*4882a593Smuzhiyun /* if not empty, they must contain one header, eg. flag */
174*4882a593Smuzhiyun if (attr_len < MNL_ATTR_HDRLEN) {
175*4882a593Smuzhiyun errno = ERANGE;
176*4882a593Smuzhiyun return -1;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun break;
179*4882a593Smuzhiyun default:
180*4882a593Smuzhiyun /* make gcc happy. */
181*4882a593Smuzhiyun break;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun if (exp_len && attr_len > exp_len) {
184*4882a593Smuzhiyun errno = ERANGE;
185*4882a593Smuzhiyun return -1;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun return 0;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = {
191*4882a593Smuzhiyun [MNL_TYPE_U8] = sizeof(uint8_t),
192*4882a593Smuzhiyun [MNL_TYPE_U16] = sizeof(uint16_t),
193*4882a593Smuzhiyun [MNL_TYPE_U32] = sizeof(uint32_t),
194*4882a593Smuzhiyun [MNL_TYPE_U64] = sizeof(uint64_t),
195*4882a593Smuzhiyun [MNL_TYPE_MSECS] = sizeof(uint64_t),
196*4882a593Smuzhiyun };
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /**
199*4882a593Smuzhiyun * mnl_attr_validate - validate netlink attribute (simplified version)
200*4882a593Smuzhiyun * \param attr pointer to netlink attribute that we want to validate
201*4882a593Smuzhiyun * \param type data type (see enum mnl_attr_data_type)
202*4882a593Smuzhiyun *
203*4882a593Smuzhiyun * The validation is based on the data type. Specifically, it checks that
204*4882a593Smuzhiyun * integers (u8, u16, u32 and u64) have enough room for them. This function
205*4882a593Smuzhiyun * returns -1 in case of error, and errno is explicitly set.
206*4882a593Smuzhiyun */
mnl_attr_validate(const struct nlattr * attr,enum mnl_attr_data_type type)207*4882a593Smuzhiyun int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun int exp_len;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (type >= MNL_TYPE_MAX) {
212*4882a593Smuzhiyun errno = EINVAL;
213*4882a593Smuzhiyun return -1;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun exp_len = mnl_attr_data_type_len[type];
216*4882a593Smuzhiyun return __mnl_attr_validate(attr, type, exp_len);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /**
220*4882a593Smuzhiyun * mnl_attr_validate2 - validate netlink attribute (extended version)
221*4882a593Smuzhiyun * \param attr pointer to netlink attribute that we want to validate
222*4882a593Smuzhiyun * \param type attribute type (see enum mnl_attr_data_type)
223*4882a593Smuzhiyun * \param exp_len expected attribute data size
224*4882a593Smuzhiyun *
225*4882a593Smuzhiyun * This function allows to perform a more accurate validation for attributes
226*4882a593Smuzhiyun * whose size is variable. If the size of the attribute is not what we expect,
227*4882a593Smuzhiyun * this functions returns -1 and errno is explicitly set.
228*4882a593Smuzhiyun */
mnl_attr_validate2(const struct nlattr * attr,enum mnl_attr_data_type type,size_t exp_len)229*4882a593Smuzhiyun int mnl_attr_validate2(const struct nlattr *attr,
230*4882a593Smuzhiyun enum mnl_attr_data_type type,
231*4882a593Smuzhiyun size_t exp_len)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun if (type >= MNL_TYPE_MAX) {
234*4882a593Smuzhiyun errno = EINVAL;
235*4882a593Smuzhiyun return -1;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun return __mnl_attr_validate(attr, type, exp_len);
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /**
241*4882a593Smuzhiyun * mnl_attr_parse - parse attributes
242*4882a593Smuzhiyun * \param nlh pointer to netlink message
243*4882a593Smuzhiyun * \param offset offset to start parsing from (if payload is after any header)
244*4882a593Smuzhiyun * \param cb callback function that is called for each attribute
245*4882a593Smuzhiyun * \param data pointer to data that is passed to the callback function
246*4882a593Smuzhiyun *
247*4882a593Smuzhiyun * This function allows to iterate over the sequence of attributes that compose
248*4882a593Smuzhiyun * the Netlink message. You can then put the attribute in an array as it
249*4882a593Smuzhiyun * usually happens at this stage or you can use any other data structure (such
250*4882a593Smuzhiyun * as lists or trees).
251*4882a593Smuzhiyun *
252*4882a593Smuzhiyun * This function propagates the return value of the callback, which can be
253*4882a593Smuzhiyun * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
254*4882a593Smuzhiyun */
mnl_attr_parse(const struct nlmsghdr * nlh,unsigned int offset,mnl_attr_cb_t cb,void * data)255*4882a593Smuzhiyun int mnl_attr_parse(const struct nlmsghdr *nlh,
256*4882a593Smuzhiyun unsigned int offset, mnl_attr_cb_t cb,
257*4882a593Smuzhiyun void *data)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun int ret = MNL_CB_OK;
260*4882a593Smuzhiyun const struct nlattr *attr;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun mnl_attr_for_each(attr, nlh, offset)
263*4882a593Smuzhiyun if ((ret = cb(attr, data)) <= MNL_CB_STOP)
264*4882a593Smuzhiyun return ret;
265*4882a593Smuzhiyun return ret;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /**
269*4882a593Smuzhiyun * mnl_attr_parse_nested - parse attributes inside a nest
270*4882a593Smuzhiyun * \param nested pointer to netlink attribute that contains a nest
271*4882a593Smuzhiyun * \param cb callback function that is called for each attribute in the nest
272*4882a593Smuzhiyun * \param data pointer to data passed to the callback function
273*4882a593Smuzhiyun *
274*4882a593Smuzhiyun * This function allows to iterate over the sequence of attributes that compose
275*4882a593Smuzhiyun * the Netlink message. You can then put the attribute in an array as it
276*4882a593Smuzhiyun * usually happens at this stage or you can use any other data structure (such
277*4882a593Smuzhiyun * as lists or trees).
278*4882a593Smuzhiyun *
279*4882a593Smuzhiyun * This function propagates the return value of the callback, which can be
280*4882a593Smuzhiyun * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
281*4882a593Smuzhiyun */
mnl_attr_parse_nested(const struct nlattr * nested,mnl_attr_cb_t cb,void * data)282*4882a593Smuzhiyun int mnl_attr_parse_nested(const struct nlattr *nested,
283*4882a593Smuzhiyun mnl_attr_cb_t cb, void *data)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun int ret = MNL_CB_OK;
286*4882a593Smuzhiyun const struct nlattr *attr;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun mnl_attr_for_each_nested(attr, nested)
289*4882a593Smuzhiyun if ((ret = cb(attr, data)) <= MNL_CB_STOP)
290*4882a593Smuzhiyun return ret;
291*4882a593Smuzhiyun return ret;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /**
295*4882a593Smuzhiyun * mnl_attr_parse_payload - parse attributes in payload of Netlink message
296*4882a593Smuzhiyun * \param payload pointer to payload of the Netlink message
297*4882a593Smuzhiyun * \param payload_len payload length that contains the attributes
298*4882a593Smuzhiyun * \param cb callback function that is called for each attribute
299*4882a593Smuzhiyun * \param data pointer to data that is passed to the callback function
300*4882a593Smuzhiyun *
301*4882a593Smuzhiyun * This function takes a pointer to the area that contains the attributes,
302*4882a593Smuzhiyun * commonly known as the payload of the Netlink message. Thus, you have to
303*4882a593Smuzhiyun * pass a pointer to the Netlink message payload, instead of the entire
304*4882a593Smuzhiyun * message.
305*4882a593Smuzhiyun *
306*4882a593Smuzhiyun * This function allows you to iterate over the sequence of attributes that are
307*4882a593Smuzhiyun * located at some payload offset. You can then put the attributes in one array
308*4882a593Smuzhiyun * as usual, or you can use any other data structure (such as lists or trees).
309*4882a593Smuzhiyun *
310*4882a593Smuzhiyun * This function propagates the return value of the callback, which can be
311*4882a593Smuzhiyun * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
312*4882a593Smuzhiyun */
mnl_attr_parse_payload(const void * payload,size_t payload_len,mnl_attr_cb_t cb,void * data)313*4882a593Smuzhiyun int mnl_attr_parse_payload(const void *payload,
314*4882a593Smuzhiyun size_t payload_len,
315*4882a593Smuzhiyun mnl_attr_cb_t cb, void *data)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun int ret = MNL_CB_OK;
318*4882a593Smuzhiyun const struct nlattr *attr;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun mnl_attr_for_each_payload(payload, payload_len)
321*4882a593Smuzhiyun if ((ret = cb(attr, data)) <= MNL_CB_STOP)
322*4882a593Smuzhiyun return ret;
323*4882a593Smuzhiyun return ret;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun /**
327*4882a593Smuzhiyun * mnl_attr_get_u8 - returns 8-bit unsigned integer attribute payload
328*4882a593Smuzhiyun * \param attr pointer to netlink attribute
329*4882a593Smuzhiyun *
330*4882a593Smuzhiyun * This function returns the 8-bit value of the attribute payload.
331*4882a593Smuzhiyun */
mnl_attr_get_u8(const struct nlattr * attr)332*4882a593Smuzhiyun uint8_t mnl_attr_get_u8(const struct nlattr *attr)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun return *((uint8_t *)mnl_attr_get_payload(attr));
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /**
338*4882a593Smuzhiyun * mnl_attr_get_u16 - returns 16-bit unsigned integer attribute payload
339*4882a593Smuzhiyun * \param attr pointer to netlink attribute
340*4882a593Smuzhiyun *
341*4882a593Smuzhiyun * This function returns the 16-bit value of the attribute payload.
342*4882a593Smuzhiyun */
mnl_attr_get_u16(const struct nlattr * attr)343*4882a593Smuzhiyun uint16_t mnl_attr_get_u16(const struct nlattr *attr)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun return *((uint16_t *)mnl_attr_get_payload(attr));
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun /**
349*4882a593Smuzhiyun * mnl_attr_get_u32 - returns 32-bit unsigned integer attribute payload
350*4882a593Smuzhiyun * \param attr pointer to netlink attribute
351*4882a593Smuzhiyun *
352*4882a593Smuzhiyun * This function returns the 32-bit value of the attribute payload.
353*4882a593Smuzhiyun */
mnl_attr_get_u32(const struct nlattr * attr)354*4882a593Smuzhiyun uint32_t mnl_attr_get_u32(const struct nlattr *attr)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun return *((uint32_t *)mnl_attr_get_payload(attr));
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun /**
360*4882a593Smuzhiyun * mnl_attr_get_u64 - returns 64-bit unsigned integer attribute.
361*4882a593Smuzhiyun * \param attr pointer to netlink attribute
362*4882a593Smuzhiyun *
363*4882a593Smuzhiyun * This function returns the 64-bit value of the attribute payload. This
364*4882a593Smuzhiyun * function is align-safe, since accessing 64-bit Netlink attributes is a
365*4882a593Smuzhiyun * common source of alignment issues.
366*4882a593Smuzhiyun */
mnl_attr_get_u64(const struct nlattr * attr)367*4882a593Smuzhiyun uint64_t mnl_attr_get_u64(const struct nlattr *attr)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun uint64_t tmp;
370*4882a593Smuzhiyun memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp));
371*4882a593Smuzhiyun return tmp;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /**
375*4882a593Smuzhiyun * mnl_attr_get_str - returns pointer to string attribute.
376*4882a593Smuzhiyun * \param attr pointer to netlink attribute
377*4882a593Smuzhiyun *
378*4882a593Smuzhiyun * This function returns the payload of string attribute value.
379*4882a593Smuzhiyun */
mnl_attr_get_str(const struct nlattr * attr)380*4882a593Smuzhiyun const char *mnl_attr_get_str(const struct nlattr *attr)
381*4882a593Smuzhiyun {
382*4882a593Smuzhiyun return mnl_attr_get_payload(attr);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun /**
386*4882a593Smuzhiyun * mnl_attr_put - add an attribute to netlink message
387*4882a593Smuzhiyun * \param nlh pointer to the netlink message
388*4882a593Smuzhiyun * \param type netlink attribute type that you want to add
389*4882a593Smuzhiyun * \param len netlink attribute payload length
390*4882a593Smuzhiyun * \param data pointer to the data that will be stored by the new attribute
391*4882a593Smuzhiyun *
392*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
393*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
394*4882a593Smuzhiyun */
mnl_attr_put(struct nlmsghdr * nlh,uint16_t type,size_t len,const void * data)395*4882a593Smuzhiyun void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type,
396*4882a593Smuzhiyun size_t len, const void *data)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
399*4882a593Smuzhiyun uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
400*4882a593Smuzhiyun int pad;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun attr->nla_type = type;
403*4882a593Smuzhiyun attr->nla_len = payload_len;
404*4882a593Smuzhiyun memcpy(mnl_attr_get_payload(attr), data, len);
405*4882a593Smuzhiyun pad = MNL_ALIGN(len) - len;
406*4882a593Smuzhiyun if (pad > 0)
407*4882a593Smuzhiyun memset(mnl_attr_get_payload(attr) + len, 0, pad);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun nlh->nlmsg_len += MNL_ALIGN(payload_len);
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /**
413*4882a593Smuzhiyun * mnl_attr_put_u8 - add 8-bit unsigned integer attribute to netlink message
414*4882a593Smuzhiyun * \param nlh pointer to the netlink message
415*4882a593Smuzhiyun * \param type netlink attribute type
416*4882a593Smuzhiyun * \param data 8-bit unsigned integer data that is stored by the new attribute
417*4882a593Smuzhiyun *
418*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
419*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
420*4882a593Smuzhiyun */
mnl_attr_put_u8(struct nlmsghdr * nlh,uint16_t type,uint8_t data)421*4882a593Smuzhiyun void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type,
422*4882a593Smuzhiyun uint8_t data)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun mnl_attr_put(nlh, type, sizeof(uint8_t), &data);
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun /**
428*4882a593Smuzhiyun * mnl_attr_put_u16 - add 16-bit unsigned integer attribute to netlink message
429*4882a593Smuzhiyun * \param nlh pointer to the netlink message
430*4882a593Smuzhiyun * \param type netlink attribute type
431*4882a593Smuzhiyun * \param data 16-bit unsigned integer data that is stored by the new attribute
432*4882a593Smuzhiyun *
433*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
434*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
435*4882a593Smuzhiyun */
mnl_attr_put_u16(struct nlmsghdr * nlh,uint16_t type,uint16_t data)436*4882a593Smuzhiyun void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type,
437*4882a593Smuzhiyun uint16_t data)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun mnl_attr_put(nlh, type, sizeof(uint16_t), &data);
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /**
443*4882a593Smuzhiyun * mnl_attr_put_u32 - add 32-bit unsigned integer attribute to netlink message
444*4882a593Smuzhiyun * \param nlh pointer to the netlink message
445*4882a593Smuzhiyun * \param type netlink attribute type
446*4882a593Smuzhiyun * \param data 32-bit unsigned integer data that is stored by the new attribute
447*4882a593Smuzhiyun *
448*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
449*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
450*4882a593Smuzhiyun */
mnl_attr_put_u32(struct nlmsghdr * nlh,uint16_t type,uint32_t data)451*4882a593Smuzhiyun void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type,
452*4882a593Smuzhiyun uint32_t data)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun mnl_attr_put(nlh, type, sizeof(uint32_t), &data);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun /**
458*4882a593Smuzhiyun * mnl_attr_put_u64 - add 64-bit unsigned integer attribute to netlink message
459*4882a593Smuzhiyun * \param nlh pointer to the netlink message
460*4882a593Smuzhiyun * \param type netlink attribute type
461*4882a593Smuzhiyun * \param data 64-bit unsigned integer data that is stored by the new attribute
462*4882a593Smuzhiyun *
463*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
464*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
465*4882a593Smuzhiyun */
mnl_attr_put_u64(struct nlmsghdr * nlh,uint16_t type,uint64_t data)466*4882a593Smuzhiyun void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type,
467*4882a593Smuzhiyun uint64_t data)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun mnl_attr_put(nlh, type, sizeof(uint64_t), &data);
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun /**
473*4882a593Smuzhiyun * mnl_attr_put_str - add string attribute to netlink message
474*4882a593Smuzhiyun * \param nlh pointer to the netlink message
475*4882a593Smuzhiyun * \param type netlink attribute type
476*4882a593Smuzhiyun * \param data pointer to string data that is stored by the new attribute
477*4882a593Smuzhiyun *
478*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
479*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
480*4882a593Smuzhiyun */
mnl_attr_put_str(struct nlmsghdr * nlh,uint16_t type,const char * data)481*4882a593Smuzhiyun void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type,
482*4882a593Smuzhiyun const char *data)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun mnl_attr_put(nlh, type, strlen(data), data);
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun /**
488*4882a593Smuzhiyun * mnl_attr_put_strz - add string attribute to netlink message
489*4882a593Smuzhiyun * \param nlh pointer to the netlink message
490*4882a593Smuzhiyun * \param type netlink attribute type
491*4882a593Smuzhiyun * \param data pointer to string data that is stored by the new attribute
492*4882a593Smuzhiyun *
493*4882a593Smuzhiyun * This function is similar to mnl_attr_put_str, but it includes the
494*4882a593Smuzhiyun * NUL/zero ('\0') terminator at the end of the string.
495*4882a593Smuzhiyun *
496*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
497*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
498*4882a593Smuzhiyun */
mnl_attr_put_strz(struct nlmsghdr * nlh,uint16_t type,const char * data)499*4882a593Smuzhiyun void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type,
500*4882a593Smuzhiyun const char *data)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun mnl_attr_put(nlh, type, strlen(data)+1, data);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun /**
506*4882a593Smuzhiyun * mnl_attr_nest_start - start an attribute nest
507*4882a593Smuzhiyun * \param nlh pointer to the netlink message
508*4882a593Smuzhiyun * \param type netlink attribute type
509*4882a593Smuzhiyun *
510*4882a593Smuzhiyun * This function adds the attribute header that identifies the beginning of
511*4882a593Smuzhiyun * an attribute nest. This function always returns a valid pointer to the
512*4882a593Smuzhiyun * beginning of the nest.
513*4882a593Smuzhiyun */
mnl_attr_nest_start(struct nlmsghdr * nlh,uint16_t type)514*4882a593Smuzhiyun struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh,
515*4882a593Smuzhiyun uint16_t type)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /* set start->nla_len in mnl_attr_nest_end() */
520*4882a593Smuzhiyun start->nla_type = NLA_F_NESTED | type;
521*4882a593Smuzhiyun nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr));
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun return start;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /**
527*4882a593Smuzhiyun * mnl_attr_put_check - add an attribute to netlink message
528*4882a593Smuzhiyun * \param nlh pointer to the netlink message
529*4882a593Smuzhiyun * \param buflen size of buffer which stores the message
530*4882a593Smuzhiyun * \param type netlink attribute type that you want to add
531*4882a593Smuzhiyun * \param len netlink attribute payload length
532*4882a593Smuzhiyun * \param data pointer to the data that will be stored by the new attribute
533*4882a593Smuzhiyun *
534*4882a593Smuzhiyun * This function first checks that the data can be added to the message
535*4882a593Smuzhiyun * (fits into the buffer) and then updates the length field of the Netlink
536*4882a593Smuzhiyun * message (nlmsg_len) by adding the size (header + payload) of the new
537*4882a593Smuzhiyun * attribute. The function returns true if the attribute could be added
538*4882a593Smuzhiyun * to the message, otherwise false is returned.
539*4882a593Smuzhiyun */
mnl_attr_put_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,size_t len,const void * data)540*4882a593Smuzhiyun bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
541*4882a593Smuzhiyun uint16_t type, size_t len,
542*4882a593Smuzhiyun const void *data)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
545*4882a593Smuzhiyun return false;
546*4882a593Smuzhiyun mnl_attr_put(nlh, type, len, data);
547*4882a593Smuzhiyun return true;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun /**
551*4882a593Smuzhiyun * mnl_attr_put_u8_check - add 8-bit unsigned int attribute to netlink message
552*4882a593Smuzhiyun * \param nlh pointer to the netlink message
553*4882a593Smuzhiyun * \param buflen size of buffer which stores the message
554*4882a593Smuzhiyun * \param type netlink attribute type
555*4882a593Smuzhiyun * \param data 8-bit unsigned integer data that is stored by the new attribute
556*4882a593Smuzhiyun *
557*4882a593Smuzhiyun * This function first checks that the data can be added to the message
558*4882a593Smuzhiyun * (fits into the buffer) and then updates the length field of the Netlink
559*4882a593Smuzhiyun * message (nlmsg_len) by adding the size (header + payload) of the new
560*4882a593Smuzhiyun * attribute. The function returns true if the attribute could be added
561*4882a593Smuzhiyun * to the message, otherwise false is returned.
562*4882a593Smuzhiyun */
mnl_attr_put_u8_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,uint8_t data)563*4882a593Smuzhiyun bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
564*4882a593Smuzhiyun uint16_t type, uint8_t data)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /**
570*4882a593Smuzhiyun * mnl_attr_put_u16_check - add 16-bit unsigned int attribute to netlink message
571*4882a593Smuzhiyun * \param nlh pointer to the netlink message
572*4882a593Smuzhiyun * \param buflen size of buffer which stores the message
573*4882a593Smuzhiyun * \param type netlink attribute type
574*4882a593Smuzhiyun * \param data 16-bit unsigned integer data that is stored by the new attribute
575*4882a593Smuzhiyun *
576*4882a593Smuzhiyun * This function first checks that the data can be added to the message
577*4882a593Smuzhiyun * (fits into the buffer) and then updates the length field of the Netlink
578*4882a593Smuzhiyun * message (nlmsg_len) by adding the size (header + payload) of the new
579*4882a593Smuzhiyun * attribute. The function returns true if the attribute could be added
580*4882a593Smuzhiyun * to the message, otherwise false is returned.
581*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
582*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
583*4882a593Smuzhiyun */
mnl_attr_put_u16_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,uint16_t data)584*4882a593Smuzhiyun bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
585*4882a593Smuzhiyun uint16_t type, uint16_t data)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun /**
591*4882a593Smuzhiyun * mnl_attr_put_u32_check - add 32-bit unsigned int attribute to netlink message
592*4882a593Smuzhiyun * \param nlh pointer to the netlink message
593*4882a593Smuzhiyun * \param buflen size of buffer which stores the message
594*4882a593Smuzhiyun * \param type netlink attribute type
595*4882a593Smuzhiyun * \param data 32-bit unsigned integer data that is stored by the new attribute
596*4882a593Smuzhiyun *
597*4882a593Smuzhiyun * This function first checks that the data can be added to the message
598*4882a593Smuzhiyun * (fits into the buffer) and then updates the length field of the Netlink
599*4882a593Smuzhiyun * message (nlmsg_len) by adding the size (header + payload) of the new
600*4882a593Smuzhiyun * attribute. The function returns true if the attribute could be added
601*4882a593Smuzhiyun * to the message, otherwise false is returned.
602*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
603*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
604*4882a593Smuzhiyun */
mnl_attr_put_u32_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,uint32_t data)605*4882a593Smuzhiyun bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
606*4882a593Smuzhiyun uint16_t type, uint32_t data)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun /**
612*4882a593Smuzhiyun * mnl_attr_put_u64_check - add 64-bit unsigned int attribute to netlink message
613*4882a593Smuzhiyun * \param nlh pointer to the netlink message
614*4882a593Smuzhiyun * \param buflen size of buffer which stores the message
615*4882a593Smuzhiyun * \param type netlink attribute type
616*4882a593Smuzhiyun * \param data 64-bit unsigned integer data that is stored by the new attribute
617*4882a593Smuzhiyun *
618*4882a593Smuzhiyun * This function first checks that the data can be added to the message
619*4882a593Smuzhiyun * (fits into the buffer) and then updates the length field of the Netlink
620*4882a593Smuzhiyun * message (nlmsg_len) by adding the size (header + payload) of the new
621*4882a593Smuzhiyun * attribute. The function returns true if the attribute could be added
622*4882a593Smuzhiyun * to the message, otherwise false is returned.
623*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
624*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
625*4882a593Smuzhiyun */
mnl_attr_put_u64_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,uint64_t data)626*4882a593Smuzhiyun bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen,
627*4882a593Smuzhiyun uint16_t type, uint64_t data)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun /**
633*4882a593Smuzhiyun * mnl_attr_put_str_check - add string attribute to netlink message
634*4882a593Smuzhiyun * \param nlh pointer to the netlink message
635*4882a593Smuzhiyun * \param buflen size of buffer which stores the message
636*4882a593Smuzhiyun * \param type netlink attribute type
637*4882a593Smuzhiyun * \param data pointer to string data that is stored by the new attribute
638*4882a593Smuzhiyun *
639*4882a593Smuzhiyun * This function first checks that the data can be added to the message
640*4882a593Smuzhiyun * (fits into the buffer) and then updates the length field of the Netlink
641*4882a593Smuzhiyun * message (nlmsg_len) by adding the size (header + payload) of the new
642*4882a593Smuzhiyun * attribute. The function returns true if the attribute could be added
643*4882a593Smuzhiyun * to the message, otherwise false is returned.
644*4882a593Smuzhiyun * This function updates the length field of the Netlink message (nlmsg_len)
645*4882a593Smuzhiyun * by adding the size (header + payload) of the new attribute.
646*4882a593Smuzhiyun */
mnl_attr_put_str_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,const char * data)647*4882a593Smuzhiyun bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen,
648*4882a593Smuzhiyun uint16_t type, const char *data)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun return mnl_attr_put_check(nlh, buflen, type, strlen(data), data);
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun /**
654*4882a593Smuzhiyun * mnl_attr_put_strz_check - add string attribute to netlink message
655*4882a593Smuzhiyun * \param nlh pointer to the netlink message
656*4882a593Smuzhiyun * \param buflen size of buffer which stores the message
657*4882a593Smuzhiyun * \param type netlink attribute type
658*4882a593Smuzhiyun * \param data pointer to string data that is stored by the new attribute
659*4882a593Smuzhiyun *
660*4882a593Smuzhiyun * This function is similar to mnl_attr_put_str, but it includes the
661*4882a593Smuzhiyun * NUL/zero ('\0') terminator at the end of the string.
662*4882a593Smuzhiyun *
663*4882a593Smuzhiyun * This function first checks that the data can be added to the message
664*4882a593Smuzhiyun * (fits into the buffer) and then updates the length field of the Netlink
665*4882a593Smuzhiyun * message (nlmsg_len) by adding the size (header + payload) of the new
666*4882a593Smuzhiyun * attribute. The function returns true if the attribute could be added
667*4882a593Smuzhiyun * to the message, otherwise false is returned.
668*4882a593Smuzhiyun */
mnl_attr_put_strz_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,const char * data)669*4882a593Smuzhiyun bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen,
670*4882a593Smuzhiyun uint16_t type, const char *data)
671*4882a593Smuzhiyun {
672*4882a593Smuzhiyun return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data);
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun /**
676*4882a593Smuzhiyun * mnl_attr_nest_start_check - start an attribute nest
677*4882a593Smuzhiyun * \param buflen size of buffer which stores the message
678*4882a593Smuzhiyun * \param nlh pointer to the netlink message
679*4882a593Smuzhiyun * \param type netlink attribute type
680*4882a593Smuzhiyun *
681*4882a593Smuzhiyun * This function adds the attribute header that identifies the beginning of
682*4882a593Smuzhiyun * an attribute nest. If the nested attribute cannot be added then NULL,
683*4882a593Smuzhiyun * otherwise valid pointer to the beginning of the nest is returned.
684*4882a593Smuzhiyun */
mnl_attr_nest_start_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type)685*4882a593Smuzhiyun struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh,
686*4882a593Smuzhiyun size_t buflen,
687*4882a593Smuzhiyun uint16_t type)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
690*4882a593Smuzhiyun return NULL;
691*4882a593Smuzhiyun return mnl_attr_nest_start(nlh, type);
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun /**
695*4882a593Smuzhiyun * mnl_attr_nest_end - end an attribute nest
696*4882a593Smuzhiyun * \param nlh pointer to the netlink message
697*4882a593Smuzhiyun * \param start pointer to the attribute nest returned by mnl_attr_nest_start()
698*4882a593Smuzhiyun *
699*4882a593Smuzhiyun * This function updates the attribute header that identifies the nest.
700*4882a593Smuzhiyun */
mnl_attr_nest_end(struct nlmsghdr * nlh,struct nlattr * start)701*4882a593Smuzhiyun void mnl_attr_nest_end(struct nlmsghdr *nlh,
702*4882a593Smuzhiyun struct nlattr *start)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun /**
708*4882a593Smuzhiyun * mnl_attr_nest_cancel - cancel an attribute nest
709*4882a593Smuzhiyun * \param nlh pointer to the netlink message
710*4882a593Smuzhiyun * \param start pointer to the attribute nest returned by mnl_attr_nest_start()
711*4882a593Smuzhiyun *
712*4882a593Smuzhiyun * This function updates the attribute header that identifies the nest.
713*4882a593Smuzhiyun */
mnl_attr_nest_cancel(struct nlmsghdr * nlh,struct nlattr * start)714*4882a593Smuzhiyun void mnl_attr_nest_cancel(struct nlmsghdr *nlh,
715*4882a593Smuzhiyun struct nlattr *start)
716*4882a593Smuzhiyun {
717*4882a593Smuzhiyun nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun /**
721*4882a593Smuzhiyun * @}
722*4882a593Smuzhiyun */
723