Commit | Line | Data |
---|---|---|
93c68cc4 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
01b39b50 AG |
2 | #include <linux/kernel.h> |
3 | #include <net/netlink.h> | |
4 | #include <linux/drbd_genl_api.h> | |
5 | #include "drbd_nla.h" | |
6 | ||
7 | static int drbd_nla_check_mandatory(int maxtype, struct nlattr *nla) | |
8 | { | |
9 | struct nlattr *head = nla_data(nla); | |
10 | int len = nla_len(nla); | |
11 | int rem; | |
12 | ||
13 | /* | |
14 | * validate_nla (called from nla_parse_nested) ignores attributes | |
15 | * beyond maxtype, and does not understand the DRBD_GENLA_F_MANDATORY flag. | |
16 | * In order to have it validate attributes with the DRBD_GENLA_F_MANDATORY | |
17 | * flag set also, check and remove that flag before calling | |
18 | * nla_parse_nested. | |
19 | */ | |
20 | ||
21 | nla_for_each_attr(nla, head, len, rem) { | |
22 | if (nla->nla_type & DRBD_GENLA_F_MANDATORY) { | |
23 | nla->nla_type &= ~DRBD_GENLA_F_MANDATORY; | |
24 | if (nla_type(nla) > maxtype) | |
25 | return -EOPNOTSUPP; | |
26 | } | |
27 | } | |
28 | return 0; | |
29 | } | |
30 | ||
31 | int drbd_nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, | |
32 | const struct nla_policy *policy) | |
33 | { | |
34 | int err; | |
35 | ||
36 | err = drbd_nla_check_mandatory(maxtype, nla); | |
37 | if (!err) | |
8cb08174 JB |
38 | err = nla_parse_nested_deprecated(tb, maxtype, nla, policy, |
39 | NULL); | |
01b39b50 AG |
40 | |
41 | return err; | |
42 | } | |
43 | ||
44 | struct nlattr *drbd_nla_find_nested(int maxtype, struct nlattr *nla, int attrtype) | |
45 | { | |
46 | int err; | |
47 | /* | |
48 | * If any nested attribute has the DRBD_GENLA_F_MANDATORY flag set and | |
49 | * we don't know about that attribute, reject all the nested | |
50 | * attributes. | |
51 | */ | |
52 | err = drbd_nla_check_mandatory(maxtype, nla); | |
53 | if (err) | |
54 | return ERR_PTR(err); | |
55 | return nla_find_nested(nla, attrtype); | |
56 | } |