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(err); 55 return nla_find_nested(nla, attrtype); 56 } 57