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