57 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			57 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| #include <linux/kernel.h>
 | |
| #include <net/netlink.h>
 | |
| #include <linux/drbd_genl_api.h>
 | |
| #include "drbd_nla.h"
 | |
| 
 | |
| static int drbd_nla_check_mandatory(int maxtype, struct nlattr *nla)
 | |
| {
 | |
| 	struct nlattr *head = nla_data(nla);
 | |
| 	int len = nla_len(nla);
 | |
| 	int rem;
 | |
| 
 | |
| 	/*
 | |
| 	 * validate_nla (called from nla_parse_nested) ignores attributes
 | |
| 	 * beyond maxtype, and does not understand the DRBD_GENLA_F_MANDATORY flag.
 | |
| 	 * In order to have it validate attributes with the DRBD_GENLA_F_MANDATORY
 | |
| 	 * flag set also, check and remove that flag before calling
 | |
| 	 * nla_parse_nested.
 | |
| 	 */
 | |
| 
 | |
| 	nla_for_each_attr(nla, head, len, rem) {
 | |
| 		if (nla->nla_type & DRBD_GENLA_F_MANDATORY) {
 | |
| 			nla->nla_type &= ~DRBD_GENLA_F_MANDATORY;
 | |
| 			if (nla_type(nla) > maxtype)
 | |
| 				return -EOPNOTSUPP;
 | |
| 		}
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int drbd_nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
 | |
| 			  const struct nla_policy *policy)
 | |
| {
 | |
| 	int err;
 | |
| 
 | |
| 	err = drbd_nla_check_mandatory(maxtype, nla);
 | |
| 	if (!err)
 | |
| 		err = nla_parse_nested_deprecated(tb, maxtype, nla, policy,
 | |
| 						  NULL);
 | |
| 
 | |
| 	return err;
 | |
| }
 | |
| 
 | |
| struct nlattr *drbd_nla_find_nested(int maxtype, struct nlattr *nla, int attrtype)
 | |
| {
 | |
| 	int err;
 | |
| 	/*
 | |
| 	 * If any nested attribute has the DRBD_GENLA_F_MANDATORY flag set and
 | |
| 	 * we don't know about that attribute, reject all the nested
 | |
| 	 * attributes.
 | |
| 	 */
 | |
| 	err = drbd_nla_check_mandatory(maxtype, nla);
 | |
| 	if (err)
 | |
| 		return ERR_PTR(err);
 | |
| 	return nla_find_nested(nla, attrtype);
 | |
| }
 |