root/tools/lib/bpf/nlattr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nla_next
  2. nla_ok
  3. nla_type
  4. validate_nla
  5. nlmsg_len
  6. libbpf_nla_parse
  7. libbpf_nla_parse_nested
  8. libbpf_nla_dump_errormsg

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

/* [<][>][^][v][top][bottom][index][help] */