0001
0002
0003
0004
0005
0006
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
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
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
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
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
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
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
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 }