diff options
Diffstat (limited to 'net/core/lwtunnel.c')
| -rw-r--r-- | net/core/lwtunnel.c | 38 | 
1 files changed, 30 insertions, 8 deletions
| diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c index cfae3d5fe11f..d9cb3532f1dd 100644 --- a/net/core/lwtunnel.c +++ b/net/core/lwtunnel.c @@ -103,37 +103,53 @@ EXPORT_SYMBOL(lwtunnel_encap_del_ops);  int lwtunnel_build_state(u16 encap_type,  			 struct nlattr *encap, unsigned int family, -			 const void *cfg, struct lwtunnel_state **lws) +			 const void *cfg, struct lwtunnel_state **lws, +			 struct netlink_ext_ack *extack)  {  	const struct lwtunnel_encap_ops *ops; +	bool found = false;  	int ret = -EINVAL;  	if (encap_type == LWTUNNEL_ENCAP_NONE || -	    encap_type > LWTUNNEL_ENCAP_MAX) +	    encap_type > LWTUNNEL_ENCAP_MAX) { +		NL_SET_ERR_MSG_ATTR(extack, encap, +				    "Unknown LWT encapsulation type");  		return ret; +	}  	ret = -EOPNOTSUPP;  	rcu_read_lock();  	ops = rcu_dereference(lwtun_encaps[encap_type]);  	if (likely(ops && ops->build_state && try_module_get(ops->owner))) { -		ret = ops->build_state(encap, family, cfg, lws); +		found = true; +		ret = ops->build_state(encap, family, cfg, lws, extack);  		if (ret)  			module_put(ops->owner);  	}  	rcu_read_unlock(); +	/* don't rely on -EOPNOTSUPP to detect match as build_state +	 * handlers could return it +	 */ +	if (!found) { +		NL_SET_ERR_MSG_ATTR(extack, encap, +				    "LWT encapsulation type not supported"); +	} +  	return ret;  }  EXPORT_SYMBOL(lwtunnel_build_state); -int lwtunnel_valid_encap_type(u16 encap_type) +int lwtunnel_valid_encap_type(u16 encap_type, struct netlink_ext_ack *extack)  {  	const struct lwtunnel_encap_ops *ops;  	int ret = -EINVAL;  	if (encap_type == LWTUNNEL_ENCAP_NONE || -	    encap_type > LWTUNNEL_ENCAP_MAX) +	    encap_type > LWTUNNEL_ENCAP_MAX) { +		NL_SET_ERR_MSG(extack, "Unknown lwt encapsulation type");  		return ret; +	}  	rcu_read_lock();  	ops = rcu_dereference(lwtun_encaps[encap_type]); @@ -153,11 +169,16 @@ int lwtunnel_valid_encap_type(u16 encap_type)  		}  	}  #endif -	return ops ? 0 : -EOPNOTSUPP; +	ret = ops ? 0 : -EOPNOTSUPP; +	if (ret < 0) +		NL_SET_ERR_MSG(extack, "lwt encapsulation type not supported"); + +	return ret;  }  EXPORT_SYMBOL(lwtunnel_valid_encap_type); -int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining) +int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining, +				   struct netlink_ext_ack *extack)  {  	struct rtnexthop *rtnh = (struct rtnexthop *)attr;  	struct nlattr *nla_entype; @@ -174,7 +195,8 @@ int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining)  			if (nla_entype) {  				encap_type = nla_get_u16(nla_entype); -				if (lwtunnel_valid_encap_type(encap_type) != 0) +				if (lwtunnel_valid_encap_type(encap_type, +							      extack) != 0)  					return -EOPNOTSUPP;  			}  		} |