Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
0002 
0003 /*
0004  * NETLINK      Netlink attributes
0005  *
0006  * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
0007  */
0008 
0009 #include <errno.h>
0010 #include <string.h>
0011 #include <stdio.h>
0012 #include <linux/rtnetlink.h>
0013 #include "nlattr.h"
0014 #include "libbpf_internal.h"
0015 
0016 static uint16_t nla_attr_minlen[LIBBPF_NLA_TYPE_MAX+1] = {
0017     [LIBBPF_NLA_U8]     = sizeof(uint8_t),
0018     [LIBBPF_NLA_U16]    = sizeof(uint16_t),
0019     [LIBBPF_NLA_U32]    = sizeof(uint32_t),
0020     [LIBBPF_NLA_U64]    = sizeof(uint64_t),
0021     [LIBBPF_NLA_STRING] = 1,
0022     [LIBBPF_NLA_FLAG]   = 0,
0023 };
0024 
0025 static struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
0026 {
0027     int totlen = NLA_ALIGN(nla->nla_len);
0028 
0029     *remaining -= totlen;
0030     return (struct nlattr *)((void *)nla + totlen);
0031 }
0032 
0033 static int nla_ok(const struct nlattr *nla, int remaining)
0034 {
0035     return remaining >= sizeof(*nla) &&
0036            nla->nla_len >= sizeof(*nla) &&
0037            nla->nla_len <= remaining;
0038 }
0039 
0040 static int nla_type(const struct nlattr *nla)
0041 {
0042     return nla->nla_type & NLA_TYPE_MASK;
0043 }
0044 
0045 static int validate_nla(struct nlattr *nla, int maxtype,
0046             struct libbpf_nla_policy *policy)
0047 {
0048     struct libbpf_nla_policy *pt;
0049     unsigned int minlen = 0;
0050     int type = nla_type(nla);
0051 
0052     if (type < 0 || type > maxtype)
0053         return 0;
0054 
0055     pt = &policy[type];
0056 
0057     if (pt->type > LIBBPF_NLA_TYPE_MAX)
0058         return 0;
0059 
0060     if (pt->minlen)
0061         minlen = pt->minlen;
0062     else if (pt->type != LIBBPF_NLA_UNSPEC)
0063         minlen = nla_attr_minlen[pt->type];
0064 
0065     if (libbpf_nla_len(nla) < minlen)
0066         return -1;
0067 
0068     if (pt->maxlen && libbpf_nla_len(nla) > pt->maxlen)
0069         return -1;
0070 
0071     if (pt->type == LIBBPF_NLA_STRING) {
0072         char *data = libbpf_nla_data(nla);
0073 
0074         if (data[libbpf_nla_len(nla) - 1] != '\0')
0075             return -1;
0076     }
0077 
0078     return 0;
0079 }
0080 
0081 static inline int nlmsg_len(const struct nlmsghdr *nlh)
0082 {
0083     return nlh->nlmsg_len - NLMSG_HDRLEN;
0084 }
0085 
0086 /**
0087  * Create attribute index based on a stream of attributes.
0088  * @arg tb      Index array to be filled (maxtype+1 elements).
0089  * @arg maxtype     Maximum attribute type expected and accepted.
0090  * @arg head        Head of attribute stream.
0091  * @arg len     Length of attribute stream.
0092  * @arg policy      Attribute validation policy.
0093  *
0094  * Iterates over the stream of attributes and stores a pointer to each
0095  * attribute in the index array using the attribute type as index to
0096  * the array. Attribute with a type greater than the maximum type
0097  * specified will be silently ignored in order to maintain backwards
0098  * compatibility. If \a policy is not NULL, the attribute will be
0099  * validated using the specified policy.
0100  *
0101  * @see nla_validate
0102  * @return 0 on success or a negative error code.
0103  */
0104 int libbpf_nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
0105              int len, struct libbpf_nla_policy *policy)
0106 {
0107     struct nlattr *nla;
0108     int rem, err;
0109 
0110     memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
0111 
0112     libbpf_nla_for_each_attr(nla, head, len, rem) {
0113         int type = nla_type(nla);
0114 
0115         if (type > maxtype)
0116             continue;
0117 
0118         if (policy) {
0119             err = validate_nla(nla, maxtype, policy);
0120             if (err < 0)
0121                 goto errout;
0122         }
0123 
0124         if (tb[type])
0125             pr_warn("Attribute of type %#x found multiple times in message, "
0126                 "previous attribute is being ignored.\n", type);
0127 
0128         tb[type] = nla;
0129     }
0130 
0131     err = 0;
0132 errout:
0133     return err;
0134 }
0135 
0136 /**
0137  * Create attribute index based on nested attribute
0138  * @arg tb              Index array to be filled (maxtype+1 elements).
0139  * @arg maxtype         Maximum attribute type expected and accepted.
0140  * @arg nla             Nested Attribute.
0141  * @arg policy          Attribute validation policy.
0142  *
0143  * Feeds the stream of attributes nested into the specified attribute
0144  * to libbpf_nla_parse().
0145  *
0146  * @see libbpf_nla_parse
0147  * @return 0 on success or a negative error code.
0148  */
0149 int libbpf_nla_parse_nested(struct nlattr *tb[], int maxtype,
0150                 struct nlattr *nla,
0151                 struct libbpf_nla_policy *policy)
0152 {
0153     return libbpf_nla_parse(tb, maxtype, libbpf_nla_data(nla),
0154                 libbpf_nla_len(nla), policy);
0155 }
0156 
0157 /* dump netlink extended ack error message */
0158 int libbpf_nla_dump_errormsg(struct nlmsghdr *nlh)
0159 {
0160     struct libbpf_nla_policy extack_policy[NLMSGERR_ATTR_MAX + 1] = {
0161         [NLMSGERR_ATTR_MSG] = { .type = LIBBPF_NLA_STRING },
0162         [NLMSGERR_ATTR_OFFS]    = { .type = LIBBPF_NLA_U32 },
0163     };
0164     struct nlattr *tb[NLMSGERR_ATTR_MAX + 1], *attr;
0165     struct nlmsgerr *err;
0166     char *errmsg = NULL;
0167     int hlen, alen;
0168 
0169     /* no TLVs, nothing to do here */
0170     if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
0171         return 0;
0172 
0173     err = (struct nlmsgerr *)NLMSG_DATA(nlh);
0174     hlen = sizeof(*err);
0175 
0176     /* if NLM_F_CAPPED is set then the inner err msg was capped */
0177     if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
0178         hlen += nlmsg_len(&err->msg);
0179 
0180     attr = (struct nlattr *) ((void *) err + hlen);
0181     alen = nlh->nlmsg_len - hlen;
0182 
0183     if (libbpf_nla_parse(tb, NLMSGERR_ATTR_MAX, attr, alen,
0184                  extack_policy) != 0) {
0185         pr_warn("Failed to parse extended error attributes\n");
0186         return 0;
0187     }
0188 
0189     if (tb[NLMSGERR_ATTR_MSG])
0190         errmsg = (char *) libbpf_nla_data(tb[NLMSGERR_ATTR_MSG]);
0191 
0192     pr_warn("Kernel error message: %s\n", errmsg);
0193 
0194     return 0;
0195 }