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