nlattr.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
  2. /*
  3. * NETLINK Netlink attributes
  4. *
  5. * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
  6. */
  7. #include <errno.h>
  8. #include "nlattr.h"
  9. #include <linux/rtnetlink.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = {
  13. [LIBBPF_NLA_U8] = sizeof(uint8_t),
  14. [LIBBPF_NLA_U16] = sizeof(uint16_t),
  15. [LIBBPF_NLA_U32] = sizeof(uint32_t),
  16. [LIBBPF_NLA_U64] = sizeof(uint64_t),
  17. [LIBBPF_NLA_STRING] = 1,
  18. [LIBBPF_NLA_FLAG] = 0,
  19. };
  20. static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
  21. {
  22. int totlen = NLA_ALIGN(nla->nla_len);
  23. *remaining -= totlen;
  24. return (struct nlattr *) ((char *) nla + totlen);
  25. }
  26. static int nla_ok(const struct nlattr *nla, int remaining)
  27. {
  28. return remaining >= sizeof(*nla) &&
  29. nla->nla_len >= sizeof(*nla) &&
  30. nla->nla_len <= remaining;
  31. }
  32. static int nla_type(const struct nlattr *nla)
  33. {
  34. return nla->nla_type & NLA_TYPE_MASK;
  35. }
  36. static int validate_nla(struct nlattr *nla, int maxtype,
  37. struct libbpf_nla_policy *policy)
  38. {
  39. struct libbpf_nla_policy *pt;
  40. unsigned int minlen = 0;
  41. int type = nla_type(nla);
  42. if (type < 0 || type > maxtype)
  43. return 0;
  44. pt = &policy[type];
  45. if (pt->type > LIBBPF_NLA_TYPE_MAX)
  46. return 0;
  47. if (pt->minlen)
  48. minlen = pt->minlen;
  49. else if (pt->type != LIBBPF_NLA_UNSPEC)
  50. minlen = nla_attr_minlen[pt->type];
  51. if (libbpf_nla_len(nla) < minlen)
  52. return -1;
  53. if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen)
  54. return -1;
  55. if (pt->type == LIBBPF_NLA_STRING) {
  56. char *data = libbpf_nla_data(nla);
  57. if (data[libbpf_nla_len(nla) - 1] != '\0')
  58. return -1;
  59. }
  60. return 0;
  61. }
  62. static inline int nlmsg_len(const struct nlmsghdr *nlh)
  63. {
  64. return nlh->nlmsg_len - NLMSG_HDRLEN;
  65. }
  66. /**
  67. * Create attribute index based on a stream of attributes.
  68. * @arg tb Index array to be filled (maxtype+1 elements).
  69. * @arg maxtype Maximum attribute type expected and accepted.
  70. * @arg head Head of attribute stream.
  71. * @arg len Length of attribute stream.
  72. * @arg policy Attribute validation policy.
  73. *
  74. * Iterates over the stream of attributes and stores a pointer to each
  75. * attribute in the index array using the attribute type as index to
  76. * the array. Attribute with a type greater than the maximum type
  77. * specified will be silently ignored in order to maintain backwards
  78. * compatibility. If \a policy is not NULL, the attribute will be
  79. * validated using the specified policy.
  80. *
  81. * @see nla_validate
  82. * @return 0 on success or a negative error code.
  83. */
  84. int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
  85. int len, struct libbpf_nla_policy *policy)
  86. {
  87. struct nlattr *nla;
  88. int rem, err;
  89. memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
  90. libbpf_nla_for_each_attr(nla, head, len, rem) {
  91. int type = nla_type(nla);
  92. if (type > maxtype)
  93. continue;
  94. if (policy) {
  95. err = validate_nla(nla, maxtype, policy);
  96. if (err < 0)
  97. goto errout;
  98. }
  99. if (tb[type])
  100. fprintf(stderr, "Attribute of type %#x found multiple times in message, "
  101. "previous attribute is being ignored.\n", type);
  102. tb[type] = nla;
  103. }
  104. err = 0;
  105. errout:
  106. return err;
  107. }
  108. /**
  109. * Create attribute index based on nested attribute
  110. * @arg tb Index array to be filled (maxtype+1 elements).
  111. * @arg maxtype Maximum attribute type expected and accepted.
  112. * @arg nla Nested Attribute.
  113. * @arg policy Attribute validation policy.
  114. *
  115. * Feeds the stream of attributes nested into the specified attribute
  116. * to libbpf_nla_parse().
  117. *
  118. * @see libbpf_nla_parse
  119. * @return 0 on success or a negative error code.
  120. */
  121. int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
  122. struct nlattr *nla,
  123. struct libbpf_nla_policy *policy)
  124. {
  125. return libbpf_nla_parse(tb, maxtype, libbpf_nla_data(nla),
  126. libbpf_nla_len(nla), policy);
  127. }
  128. /* dump netlink extended ack error message */
  129. int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
  130. {
  131. struct libbpf_nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
  132. [NLMSGERR_ATTR_MSG] = { .type = LIBBPF_NLA_STRING },
  133. [NLMSGERR_ATTR_OFFS] = { .type = LIBBPF_NLA_U32 },
  134. };
  135. struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;
  136. struct nlmsgerr *err;
  137. char *errmsg = NULL;
  138. int hlen, alen;
  139. /* no TLVs, nothing to do here */
  140. if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
  141. return 0;
  142. err = (struct nlmsgerr *)NLMSG_DATA(nlh);
  143. hlen = sizeof(*err);
  144. /* if NLM_F_CAPPED is set then the inner err msg was capped */
  145. if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
  146. hlen += nlmsg_len(&err->msg);
  147. attr = (struct nlattr *) ((void *) err + hlen);
  148. alen = nlh->nlmsg_len - hlen;
  149. if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
  150. extack_policy) != 0) {
  151. fprintf(stderr,
  152. "Failed to parse extended error attributes\n");
  153. return 0;
  154. }
  155. if (tb[NLMSGERR_ATTR_MSG])
  156. errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);
  157. fprintf(stderr, "Kernel error message: %s\n", errmsg);
  158. return 0;
  159. }