[PATCH net-next 12/14] devlink: Throw extack messages on param value validation error

Saeed Mahameed
2025-02-28T02:13:34Z

From: Saeed Mahameed <saeedm@nvidia.com>

Centralize devlink param value data validation in one function and
fill corresponding extack error messages on validation error.

Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
---
net/devlink/param.c | 76 +++++++++++++++++++++++++++++++++++----------
1 file changed, 60 insertions(+), 16 deletions(-)

diff --git a/net/devlink/param.c b/net/devlink/param.c
index 03c65ccf2acf..1922ca5b9cbc 100644
--- a/net/devlink/param.c
+++ b/net/devlink/param.c
@@ -458,45 +458,89 @@ devlink_param_type_get_from_info(struct genl_info *info,
return 0;
}

+static int
+devlink_param_value_validate(struct genl_info *info,
+ enum devlink_param_type type)
+{
+ struct netlink_ext_ack *extack = info->extack;
+ struct nlattr *param_data;
+ int len = 0;
+
+ if (type != DEVLINK_PARAM_TYPE_BOOL &&
+ GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_DATA))
+ return -EINVAL;
+
+ param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
+
+ if (param_data)
+ len = nla_len(param_data);
+
+ switch (type) {
+ case DEVLINK_PARAM_TYPE_U8:
+ if (len == sizeof(u8))
+ return 0;
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Expected uint8, got %d bytes", len);
+ break;
+ case DEVLINK_PARAM_TYPE_U16:
+ if (len == sizeof(u16))
+ return 0;
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Expected uint16, got %d bytes", len);
+ break;
+ case DEVLINK_PARAM_TYPE_U32:
+ if (len == sizeof(u32))
+ return 0;
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Expected uint32, got %d bytes", len);
+ break;
+ case DEVLINK_PARAM_TYPE_STRING:
+ len = strnlen(nla_data(param_data), nla_len(param_data));
+
+ if (len < nla_len(param_data) &&
+ len < __DEVLINK_PARAM_MAX_STRING_VALUE)
+ return 0;
+ NL_SET_ERR_MSG_MOD(extack, "String too long");
+ break;
+ case DEVLINK_PARAM_TYPE_BOOL:
+ if (!len)
+ return 0;
+ NL_SET_ERR_MSG_MOD(extack, "Expected flag, got data");
+ break;
+ default:
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Not supported value type %d", type);
+ break;
+ }
+ return -EINVAL;
+}
+
static int
devlink_param_value_get_from_info(const struct devlink_param *param,
struct genl_info *info,
union devlink_param_value *value)
{
struct nlattr *param_data;
- int len;
-
- param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];

- if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
+ if (devlink_param_value_validate(info, param->type))
return -EINVAL;

+ param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
+
switch (param->type) {
case DEVLINK_PARAM_TYPE_U8:
- if (nla_len(param_data) != sizeof(u8))
- return -EINVAL;
value->vu8 = nla_get_u8(param_data);
break;
case DEVLINK_PARAM_TYPE_U16:
- if (nla_len(param_data) != sizeof(u16))
- return -EINVAL;
value->vu16 = nla_get_u16(param_data);
break;
case DEVLINK_PARAM_TYPE_U32:
- if (nla_len(param_data) != sizeof(u32))
- return -EINVAL;
value->vu32 = nla_get_u32(param_data);
break;
case DEVLINK_PARAM_TYPE_STRING:
- len = strnlen(nla_data(param_data), nla_len(param_data));
- if (len == nla_len(param_data) ||
- len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
- return -EINVAL;
strcpy(value->vstr, nla_data(param_data));
break;
case DEVLINK_PARAM_TYPE_BOOL:
- if (param_data && nla_len(param_data))
- return -EINVAL;
value->vbool = nla_get_flag(param_data);
break;
}
--
2.48.1