libmnl  1.0.4
attr.c
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 
38 EXPORT_SYMBOL(mnl_attr_get_type);
39 uint16_t mnl_attr_get_type(const struct nlattr *attr)
40 {
41  return attr->nla_type & NLA_TYPE_MASK;
42 }
43 
51 EXPORT_SYMBOL(mnl_attr_get_len);
52 uint16_t mnl_attr_get_len(const struct nlattr *attr)
53 {
54  return attr->nla_len;
55 }
56 
63 EXPORT_SYMBOL(mnl_attr_get_payload_len);
64 uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
65 {
66  return attr->nla_len - MNL_ATTR_HDRLEN;
67 }
68 
75 EXPORT_SYMBOL(mnl_attr_get_payload);
76 void *mnl_attr_get_payload(const struct nlattr *attr)
77 {
78  return (void *)attr + MNL_ATTR_HDRLEN;
79 }
80 
97 EXPORT_SYMBOL(mnl_attr_ok);
98 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 
113 EXPORT_SYMBOL(mnl_attr_next);
114 struct nlattr *mnl_attr_next(const struct nlattr *attr)
115 {
116  return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len));
117 }
118 
133 EXPORT_SYMBOL(mnl_attr_type_valid);
134 int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
135 {
136  if (mnl_attr_get_type(attr) > max) {
137  errno = EOPNOTSUPP;
138  return -1;
139  }
140  return 1;
141 }
142 
143 static int __mnl_attr_validate(const struct nlattr *attr,
144  enum mnl_attr_data_type type, size_t exp_len)
145 {
146  uint16_t attr_len = mnl_attr_get_payload_len(attr);
147  const char *attr_data = mnl_attr_get_payload(attr);
148 
149  if (attr_len < exp_len) {
150  errno = ERANGE;
151  return -1;
152  }
153  switch(type) {
154  case MNL_TYPE_FLAG:
155  if (attr_len > 0) {
156  errno = ERANGE;
157  return -1;
158  }
159  break;
160  case MNL_TYPE_NUL_STRING:
161  if (attr_len == 0) {
162  errno = ERANGE;
163  return -1;
164  }
165  if (attr_data[attr_len-1] != '\0') {
166  errno = EINVAL;
167  return -1;
168  }
169  break;
170  case MNL_TYPE_STRING:
171  if (attr_len == 0) {
172  errno = ERANGE;
173  return -1;
174  }
175  break;
176  case MNL_TYPE_NESTED:
177  /* empty nested attributes are OK. */
178  if (attr_len == 0)
179  break;
180  /* if not empty, they must contain one header, eg. flag */
181  if (attr_len < MNL_ATTR_HDRLEN) {
182  errno = ERANGE;
183  return -1;
184  }
185  break;
186  default:
187  /* make gcc happy. */
188  break;
189  }
190  if (exp_len && attr_len > exp_len) {
191  errno = ERANGE;
192  return -1;
193  }
194  return 0;
195 }
196 
197 static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = {
198  [MNL_TYPE_U8] = sizeof(uint8_t),
199  [MNL_TYPE_U16] = sizeof(uint16_t),
200  [MNL_TYPE_U32] = sizeof(uint32_t),
201  [MNL_TYPE_U64] = sizeof(uint64_t),
202  [MNL_TYPE_MSECS] = sizeof(uint64_t),
203 };
204 
214 EXPORT_SYMBOL(mnl_attr_validate);
215 int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
216 {
217  int exp_len;
218 
219  if (type >= MNL_TYPE_MAX) {
220  errno = EINVAL;
221  return -1;
222  }
223  exp_len = mnl_attr_data_type_len[type];
224  return __mnl_attr_validate(attr, type, exp_len);
225 }
226 
237 EXPORT_SYMBOL(mnl_attr_validate2);
238 int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type,
239  size_t exp_len)
240 {
241  if (type >= MNL_TYPE_MAX) {
242  errno = EINVAL;
243  return -1;
244  }
245  return __mnl_attr_validate(attr, type, exp_len);
246 }
247 
263 EXPORT_SYMBOL(mnl_attr_parse);
264 int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset,
265  mnl_attr_cb_t cb, void *data)
266 {
267  int ret = MNL_CB_OK;
268  const struct nlattr *attr;
269 
270  mnl_attr_for_each(attr, nlh, offset)
271  if ((ret = cb(attr, data)) <= MNL_CB_STOP)
272  return ret;
273  return ret;
274 }
275 
290 EXPORT_SYMBOL(mnl_attr_parse_nested);
291 int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb,
292  void *data)
293 {
294  int ret = MNL_CB_OK;
295  const struct nlattr *attr;
296 
297  mnl_attr_for_each_nested(attr, nested)
298  if ((ret = cb(attr, data)) <= MNL_CB_STOP)
299  return ret;
300  return ret;
301 }
302 
322 EXPORT_SYMBOL(mnl_attr_parse_payload);
323 int mnl_attr_parse_payload(const void *payload, size_t payload_len,
324  mnl_attr_cb_t cb, void *data)
325 {
326  int ret = MNL_CB_OK;
327  const struct nlattr *attr;
328 
329  mnl_attr_for_each_payload(payload, payload_len)
330  if ((ret = cb(attr, data)) <= MNL_CB_STOP)
331  return ret;
332  return ret;
333 }
334 
341 EXPORT_SYMBOL(mnl_attr_get_u8);
342 uint8_t mnl_attr_get_u8(const struct nlattr *attr)
343 {
344  return *((uint8_t *)mnl_attr_get_payload(attr));
345 }
346 
353 EXPORT_SYMBOL(mnl_attr_get_u16);
354 uint16_t mnl_attr_get_u16(const struct nlattr *attr)
355 {
356  return *((uint16_t *)mnl_attr_get_payload(attr));
357 }
358 
365 EXPORT_SYMBOL(mnl_attr_get_u32);
366 uint32_t mnl_attr_get_u32(const struct nlattr *attr)
367 {
368  return *((uint32_t *)mnl_attr_get_payload(attr));
369 }
370 
379 EXPORT_SYMBOL(mnl_attr_get_u64);
380 uint64_t mnl_attr_get_u64(const struct nlattr *attr)
381 {
382  uint64_t tmp;
383  memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp));
384  return tmp;
385 }
386 
393 EXPORT_SYMBOL(mnl_attr_get_str);
394 const char *mnl_attr_get_str(const struct nlattr *attr)
395 {
396  return mnl_attr_get_payload(attr);
397 }
398 
409 EXPORT_SYMBOL(mnl_attr_put);
410 void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len,
411  const void *data)
412 {
413  struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
414  uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
415 
416  attr->nla_type = type;
417  attr->nla_len = payload_len;
418  memcpy(mnl_attr_get_payload(attr), data, len);
419  nlh->nlmsg_len += MNL_ALIGN(payload_len);
420 }
421 
431 EXPORT_SYMBOL(mnl_attr_put_u8);
432 void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data)
433 {
434  mnl_attr_put(nlh, type, sizeof(uint8_t), &data);
435 }
436 
446 EXPORT_SYMBOL(mnl_attr_put_u16);
447 void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data)
448 {
449  mnl_attr_put(nlh, type, sizeof(uint16_t), &data);
450 }
451 
461 EXPORT_SYMBOL(mnl_attr_put_u32);
462 void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data)
463 {
464  mnl_attr_put(nlh, type, sizeof(uint32_t), &data);
465 }
466 
476 EXPORT_SYMBOL(mnl_attr_put_u64);
477 void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data)
478 {
479  mnl_attr_put(nlh, type, sizeof(uint64_t), &data);
480 }
481 
491 EXPORT_SYMBOL(mnl_attr_put_str);
492 void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data)
493 {
494  mnl_attr_put(nlh, type, strlen(data), data);
495 }
496 
509 EXPORT_SYMBOL(mnl_attr_put_strz);
510 void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data)
511 {
512  mnl_attr_put(nlh, type, strlen(data)+1, data);
513 }
514 
524 EXPORT_SYMBOL(mnl_attr_nest_start);
525 struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type)
526 {
527  struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh);
528 
529  /* set start->nla_len in mnl_attr_nest_end() */
530  start->nla_type = NLA_F_NESTED | type;
531  nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr));
532 
533  return start;
534 }
535 
550 EXPORT_SYMBOL(mnl_attr_put_check);
551 bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
552  uint16_t type, size_t len, const void *data)
553 {
554  if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
555  return false;
556  mnl_attr_put(nlh, type, len, data);
557  return true;
558 }
559 
573 EXPORT_SYMBOL(mnl_attr_put_u8_check);
574 bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
575  uint16_t type, uint8_t data)
576 {
577  return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
578 }
579 
595 EXPORT_SYMBOL(mnl_attr_put_u16_check);
596 bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
597  uint16_t type, uint16_t data)
598 {
599  return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
600 }
601 
617 EXPORT_SYMBOL(mnl_attr_put_u32_check);
618 bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
619  uint16_t type, uint32_t data)
620 {
621  return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
622 }
623 
639 EXPORT_SYMBOL(mnl_attr_put_u64_check);
640 bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen,
641  uint16_t type, uint64_t data)
642 {
643  return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data);
644 }
645 
661 EXPORT_SYMBOL(mnl_attr_put_str_check);
662 bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen,
663  uint16_t type, const char *data)
664 {
665  return mnl_attr_put_check(nlh, buflen, type, strlen(data), data);
666 }
667 
684 EXPORT_SYMBOL(mnl_attr_put_strz_check);
685 bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen,
686  uint16_t type, const char *data)
687 {
688  return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data);
689 }
690 
701 EXPORT_SYMBOL(mnl_attr_nest_start_check);
702 struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen,
703  uint16_t type)
704 {
705  if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
706  return NULL;
707  return mnl_attr_nest_start(nlh, type);
708 }
709 
717 EXPORT_SYMBOL(mnl_attr_nest_end);
718 void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start)
719 {
720  start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
721 }
722 
730 EXPORT_SYMBOL(mnl_attr_nest_cancel);
731 void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start)
732 {
733  nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
734 }
735