diff options
Diffstat (limited to 'net/ethtool')
| -rw-r--r-- | net/ethtool/netlink.h | 28 | ||||
| -rw-r--r-- | net/ethtool/rss.c | 14 |
2 files changed, 36 insertions, 6 deletions
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index fd2198e45d2b..733fb3c3a63a 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -116,6 +116,34 @@ static inline void ethnl_update_u8(u8 *dst, const struct nlattr *attr, } /** + * ethnl_update_u8_u32() - update u8 value from an NLA_U32 attribute + * @dst: value to update + * @attr: netlink attribute with new value or null + * @mod: pointer to bool for modification tracking + * + * Some attributes are NLA_U32 on the wire but are stored in a u8. Read the + * full 32-bit value from NLA_U32 netlink attribute @attr and narrow it into + * the u8 pointed to by @dst; do nothing if @attr is null. + * Bool pointed to by @mod is set to true if this function changed the value + * of *dst, otherwise it is left as is. + */ +static inline void ethnl_update_u8_u32(u8 *dst, const struct nlattr *attr, + bool *mod) +{ + u32 val; + + if (!attr) + return; + val = nla_get_u32(attr); + DEBUG_NET_WARN_ON_ONCE(val > U8_MAX); + if (*dst == val) + return; + + *dst = val; + *mod = true; +} + +/** * ethnl_update_bool32() - update u32 used as bool from NLA_U8 attribute * @dst: value to update * @attr: netlink attribute with new value or null diff --git a/net/ethtool/rss.c b/net/ethtool/rss.c index 53792f53f922..ca6ed152c2be 100644 --- a/net/ethtool/rss.c +++ b/net/ethtool/rss.c @@ -574,7 +574,7 @@ static const struct nla_policy ethnl_rss_flows_policy[] = { const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1] = { [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32, }, - [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1), + [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_RANGE(NLA_U32, 1, U8_MAX), [ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, }, [ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1), [ETHTOOL_A_RSS_INPUT_XFRM] = @@ -855,7 +855,7 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info) indir_mod = !!tb[ETHTOOL_A_RSS_INDIR]; rxfh.hfunc = data.hfunc; - ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod); + ethnl_update_u8_u32(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod); if (rxfh.hfunc == data.hfunc) rxfh.hfunc = ETH_RSS_HASH_NO_CHANGE; @@ -864,7 +864,8 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info) goto exit_free_indir; rxfh.input_xfrm = data.input_xfrm; - ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod); + ethnl_update_u8_u32(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], + &mod); xfrm_sym = rxfh.input_xfrm || data.input_xfrm; if (rxfh.input_xfrm == data.input_xfrm) rxfh.input_xfrm = RXH_XFRM_NO_CHANGE; @@ -938,7 +939,7 @@ const struct ethnl_request_ops ethnl_rss_request_ops = { const struct nla_policy ethnl_rss_create_policy[ETHTOOL_A_RSS_INPUT_XFRM + 1] = { [ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1), - [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1), + [ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_RANGE(NLA_U32, 1, U8_MAX), [ETHTOOL_A_RSS_INDIR] = NLA_POLICY_MIN(NLA_BINARY, 1), [ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1), [ETHTOOL_A_RSS_INPUT_XFRM] = @@ -1054,14 +1055,15 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info) goto exit_clean_data; indir_user_size = ret; - ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod); + ethnl_update_u8_u32(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod); ret = rss_set_prep_hkey(dev, info, &data, &rxfh, &mod); if (ret) goto exit_free_indir; rxfh.input_xfrm = RXH_XFRM_NO_CHANGE; - ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod); + ethnl_update_u8_u32(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], + &mod); ctx = ethtool_rxfh_ctx_alloc(ops, data.indir_size, data.hkey_size); if (!ctx) { |
