xref: /aosp_15_r20/external/ethtool/libmnl/src/attr.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 /*
2  * (C) 2008-2012 by Pablo Neira Ayuso <[email protected]>
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_str - get pointer to string attribute
394  * \param attr pointer to netlink attribute
395  *
396  * \return string pointer of the attribute payload
397  */
mnl_attr_get_str(const struct nlattr * attr)398 EXPORT_SYMBOL const char *mnl_attr_get_str(const struct nlattr *attr)
399 {
400 	return mnl_attr_get_payload(attr);
401 }
402 
403 /**
404  * mnl_attr_put - add an attribute to netlink message
405  * \param nlh pointer to the netlink message
406  * \param type netlink attribute type that you want to add
407  * \param len netlink attribute payload length
408  * \param data pointer to the data that will be stored by the new attribute
409  *
410  * This function updates the length field of the Netlink message (nlmsg_len)
411  * by adding the size (header + payload) of the new attribute.
412  */
mnl_attr_put(struct nlmsghdr * nlh,uint16_t type,size_t len,const void * data)413 EXPORT_SYMBOL void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type,
414 				size_t len, const void *data)
415 {
416 	struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
417 	uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
418 	int pad;
419 
420 	attr->nla_type = type;
421 	attr->nla_len = payload_len;
422 	memcpy(mnl_attr_get_payload(attr), data, len);
423 	pad = MNL_ALIGN(len) - len;
424 	if (pad > 0)
425 		memset(mnl_attr_get_payload(attr) + len, 0, pad);
426 
427 	nlh->nlmsg_len += MNL_ALIGN(payload_len);
428 }
429 
430 /**
431  * mnl_attr_put_u8 - add 8-bit unsigned integer attribute to netlink message
432  * \param nlh pointer to the netlink message
433  * \param type netlink attribute type
434  * \param data 8-bit unsigned integer data that is stored by the new attribute
435  *
436  * This function updates the length field of the Netlink message (nlmsg_len)
437  * by adding the size (header + payload) of the new attribute.
438  */
mnl_attr_put_u8(struct nlmsghdr * nlh,uint16_t type,uint8_t data)439 EXPORT_SYMBOL void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type,
440 				   uint8_t data)
441 {
442 	mnl_attr_put(nlh, type, sizeof(uint8_t), &data);
443 }
444 
445 /**
446  * mnl_attr_put_u16 - add 16-bit unsigned integer attribute to netlink message
447  * \param nlh pointer to the netlink message
448  * \param type netlink attribute type
449  * \param data 16-bit unsigned integer data that is stored by the new attribute
450  *
451  * This function updates the length field of the Netlink message (nlmsg_len)
452  * by adding the size (header + payload) of the new attribute.
453  */
mnl_attr_put_u16(struct nlmsghdr * nlh,uint16_t type,uint16_t data)454 EXPORT_SYMBOL void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type,
455 				    uint16_t data)
456 {
457 	mnl_attr_put(nlh, type, sizeof(uint16_t), &data);
458 }
459 
460 /**
461  * mnl_attr_put_u32 - add 32-bit unsigned integer attribute to netlink message
462  * \param nlh pointer to the netlink message
463  * \param type netlink attribute type
464  * \param data 32-bit unsigned integer data that is stored by the new attribute
465  *
466  * This function updates the length field of the Netlink message (nlmsg_len)
467  * by adding the size (header + payload) of the new attribute.
468  */
mnl_attr_put_u32(struct nlmsghdr * nlh,uint16_t type,uint32_t data)469 EXPORT_SYMBOL void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type,
470 				    uint32_t data)
471 {
472 	mnl_attr_put(nlh, type, sizeof(uint32_t), &data);
473 }
474 
475 /**
476  * mnl_attr_put_u64 - add 64-bit unsigned integer attribute to netlink message
477  * \param nlh pointer to the netlink message
478  * \param type netlink attribute type
479  * \param data 64-bit unsigned integer data that is stored by the new attribute
480  *
481  * This function updates the length field of the Netlink message (nlmsg_len)
482  * by adding the size (header + payload) of the new attribute.
483  */
mnl_attr_put_u64(struct nlmsghdr * nlh,uint16_t type,uint64_t data)484 EXPORT_SYMBOL void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type,
485 				    uint64_t data)
486 {
487 	mnl_attr_put(nlh, type, sizeof(uint64_t), &data);
488 }
489 
490 /**
491  * mnl_attr_put_str - add string attribute to netlink message
492  * \param nlh  pointer to the netlink message
493  * \param type netlink attribute type
494  * \param data pointer to string data that is stored by the new attribute
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_str(struct nlmsghdr * nlh,uint16_t type,const char * data)499 EXPORT_SYMBOL void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type,
500 				    const char *data)
501 {
502 	mnl_attr_put(nlh, type, strlen(data), data);
503 }
504 
505 /**
506  * mnl_attr_put_strz - add string attribute to netlink message
507  * \param nlh pointer to the netlink message
508  * \param type netlink attribute type
509  * \param data pointer to string data that is stored by the new attribute
510  *
511  * This function is similar to mnl_attr_put_str, but it includes the
512  * NUL/zero ('\0') terminator at the end of the string.
513  *
514  * This function updates the length field of the Netlink message (nlmsg_len)
515  * by adding the size (header + payload) of the new attribute.
516  */
mnl_attr_put_strz(struct nlmsghdr * nlh,uint16_t type,const char * data)517 EXPORT_SYMBOL void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type,
518 				     const char *data)
519 {
520 	mnl_attr_put(nlh, type, strlen(data)+1, data);
521 }
522 
523 /**
524  * mnl_attr_nest_start - start an attribute nest
525  * \param nlh pointer to the netlink message
526  * \param type netlink attribute type
527  *
528  * This function adds the attribute header that identifies the beginning of
529  * an attribute nest.
530  *
531  * \return valid pointer to the beginning of the nest
532  */
mnl_attr_nest_start(struct nlmsghdr * nlh,uint16_t type)533 EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh,
534 						 uint16_t type)
535 {
536 	struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh);
537 
538 	/* set start->nla_len in mnl_attr_nest_end() */
539 	start->nla_type = NLA_F_NESTED | type;
540 	nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr));
541 
542 	return start;
543 }
544 
545 /**
546  * mnl_attr_put_check - add an attribute to netlink message
547  * \param nlh pointer to the netlink message
548  * \param buflen size of buffer which stores the message
549  * \param type netlink attribute type that you want to add
550  * \param len netlink attribute payload length
551  * \param data pointer to the data that will be stored by the new attribute
552  *
553  * This function first checks that the data can be added to the message
554  * (fits into the buffer) and then updates the length field of the Netlink
555  * message (nlmsg_len) by adding the size (header + payload) of the new
556  * attribute.
557  *
558  * \return true if the attribute could be added, false otherwise
559  */
mnl_attr_put_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,size_t len,const void * data)560 EXPORT_SYMBOL bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
561 				      uint16_t type, size_t len,
562 				      const void *data)
563 {
564 	if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
565 		return false;
566 	mnl_attr_put(nlh, type, len, data);
567 	return true;
568 }
569 
570 /**
571  * mnl_attr_put_u8_check - add 8-bit unsigned int attribute to netlink message
572  * \param nlh pointer to the netlink message
573  * \param buflen size of buffer which stores the message
574  * \param type netlink attribute type
575  * \param data 8-bit unsigned integer data that is stored by the new attribute
576  *
577  * This function first checks that the data can be added to the message
578  * (fits into the buffer) and then updates the length field of the Netlink
579  * message (nlmsg_len) by adding the size (header + payload) of the new
580  * attribute.
581  *
582  * \return true if the attribute could be added, false otherwise
583  */
mnl_attr_put_u8_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,uint8_t data)584 EXPORT_SYMBOL bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
585 					 uint16_t type, uint8_t data)
586 {
587 	return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
588 }
589 
590 /**
591  * mnl_attr_put_u16_check - add 16-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 16-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.
601  *
602  * \return true if the attribute could be added, false otherwise
603  */
mnl_attr_put_u16_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,uint16_t data)604 EXPORT_SYMBOL bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
605 					  uint16_t type, uint16_t data)
606 {
607 	return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
608 }
609 
610 /**
611  * mnl_attr_put_u32_check - add 32-bit unsigned int attribute to netlink message
612  * \param nlh pointer to the netlink message
613  * \param buflen size of buffer which stores the message
614  * \param type netlink attribute type
615  * \param data 32-bit unsigned integer data that is stored by the new attribute
616  *
617  * This function first checks that the data can be added to the message
618  * (fits into the buffer) and then updates the length field of the Netlink
619  * message (nlmsg_len) by adding the size (header + payload) of the new
620  * attribute.
621  *
622  * \return true if the attribute could be added, false otherwise
623  */
mnl_attr_put_u32_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,uint32_t data)624 EXPORT_SYMBOL bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
625 					  uint16_t type, uint32_t data)
626 {
627 	return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
628 }
629 
630 /**
631  * mnl_attr_put_u64_check - add 64-bit unsigned int attribute to netlink message
632  * \param nlh pointer to the netlink message
633  * \param buflen size of buffer which stores the message
634  * \param type netlink attribute type
635  * \param data 64-bit unsigned integer data that is stored by the new attribute
636  *
637  * This function first checks that the data can be added to the message
638  * (fits into the buffer) and then updates the length field of the Netlink
639  * message (nlmsg_len) by adding the size (header + payload) of the new
640  * attribute.
641  *
642  * \return true if the attribute could be added, false otherwise
643  */
mnl_attr_put_u64_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,uint64_t data)644 EXPORT_SYMBOL bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen,
645 					  uint16_t type, uint64_t data)
646 {
647 	return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data);
648 }
649 
650 /**
651  * mnl_attr_put_str_check - add string attribute to netlink message
652  * \param nlh  pointer to the netlink message
653  * \param buflen size of buffer which stores the message
654  * \param type netlink attribute type
655  * \param data pointer to string data that is stored by the new attribute
656  *
657  * This function first checks that the data can be added to the message
658  * (fits into the buffer) and then updates the length field of the Netlink
659  * message (nlmsg_len) by adding the size (header + payload) of the new
660  * attribute.
661  *
662  * \return true if the attribute could be added, false otherwise
663  */
mnl_attr_put_str_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,const char * data)664 EXPORT_SYMBOL bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen,
665 					  uint16_t type, const char *data)
666 {
667 	return mnl_attr_put_check(nlh, buflen, type, strlen(data), data);
668 }
669 
670 /**
671  * mnl_attr_put_strz_check - add string attribute to netlink message
672  * \param nlh pointer to the netlink message
673  * \param buflen size of buffer which stores the message
674  * \param type netlink attribute type
675  * \param data pointer to string data that is stored by the new attribute
676  *
677  * This function is similar to mnl_attr_put_str, but it includes the
678  * NUL/zero ('\0') terminator at the end of the string.
679  *
680  * This function first checks that the data can be added to the message
681  * (fits into the buffer) and then updates the length field of the Netlink
682  * message (nlmsg_len) by adding the size (header + payload) of the new
683  * attribute.
684  *
685  * \return true if the attribute could be added, false otherwise
686  */
mnl_attr_put_strz_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type,const char * data)687 EXPORT_SYMBOL bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen,
688 					   uint16_t type, const char *data)
689 {
690 	return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data);
691 }
692 
693 /**
694  * mnl_attr_nest_start_check - start an attribute nest
695  * \param buflen size of buffer which stores the message
696  * \param nlh pointer to the netlink message
697  * \param type netlink attribute type
698  *
699  * This function adds the attribute header that identifies the beginning of
700  * an attribute nest.
701  *
702  * \return NULL if the attribute cannot be added, otherwise a pointer to the
703  * beginning of the nest
704  */
mnl_attr_nest_start_check(struct nlmsghdr * nlh,size_t buflen,uint16_t type)705 EXPORT_SYMBOL struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh,
706 						       size_t buflen,
707 						       uint16_t type)
708 {
709 	if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
710 		return NULL;
711 	return mnl_attr_nest_start(nlh, type);
712 }
713 
714 /**
715  * mnl_attr_nest_end - end an attribute nest
716  * \param nlh pointer to the netlink message
717  * \param start pointer to the attribute nest returned by mnl_attr_nest_start()
718  *
719  * This function updates the attribute header that identifies the nest.
720  */
mnl_attr_nest_end(struct nlmsghdr * nlh,struct nlattr * start)721 EXPORT_SYMBOL void mnl_attr_nest_end(struct nlmsghdr *nlh,
722 				     struct nlattr *start)
723 {
724 	start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
725 }
726 
727 /**
728  * mnl_attr_nest_cancel - cancel an attribute nest
729  * \param nlh pointer to the netlink message
730  * \param start pointer to the attribute nest returned by mnl_attr_nest_start()
731  *
732  * This function updates the attribute header that identifies the nest.
733  */
mnl_attr_nest_cancel(struct nlmsghdr * nlh,struct nlattr * start)734 EXPORT_SYMBOL void mnl_attr_nest_cancel(struct nlmsghdr *nlh,
735 					struct nlattr *start)
736 {
737 	nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
738 }
739 
740 /**
741  * @}
742  */
743