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