1 | // SPDX-License-Identifier: GPL-2.0-only |
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) |
38 | err = nla_parse_nested_deprecated(tb, maxtype, nla, policy, |
39 | NULL); |
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(error: err); |
55 | return nla_find_nested(nla, attrtype); |
56 | } |
57 | |