Commit f265d799 authored by Michal Kubecek's avatar Michal Kubecek Committed by David S. Miller

ethtool: set device private flags with PRIVFLAGS_SET request

Implement PRIVFLAGS_SET netlink request to set private flags of a network
device. These are traditionally set with ETHTOOL_SPFLAGS ioctl request.
Signed-off-by: default avatarMichal Kubecek <mkubecek@suse.cz>
Reviewed-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e16c3386
...@@ -192,6 +192,7 @@ Userspace to kernel: ...@@ -192,6 +192,7 @@ Userspace to kernel:
``ETHTOOL_MSG_FEATURES_GET`` get device features ``ETHTOOL_MSG_FEATURES_GET`` get device features
``ETHTOOL_MSG_FEATURES_SET`` set device features ``ETHTOOL_MSG_FEATURES_SET`` set device features
``ETHTOOL_MSG_PRIVFLAGS_GET`` get private flags ``ETHTOOL_MSG_PRIVFLAGS_GET`` get private flags
``ETHTOOL_MSG_PRIVFLAGS_SET`` set private flags
===================================== ================================ ===================================== ================================
Kernel to userspace: Kernel to userspace:
...@@ -211,6 +212,7 @@ Kernel to userspace: ...@@ -211,6 +212,7 @@ Kernel to userspace:
``ETHTOOL_MSG_FEATURES_SET_REPLY`` optional reply to FEATURES_SET ``ETHTOOL_MSG_FEATURES_SET_REPLY`` optional reply to FEATURES_SET
``ETHTOOL_MSG_FEATURES_NTF`` netdev features notification ``ETHTOOL_MSG_FEATURES_NTF`` netdev features notification
``ETHTOOL_MSG_PRIVFLAGS_GET_REPLY`` private flags ``ETHTOOL_MSG_PRIVFLAGS_GET_REPLY`` private flags
``ETHTOOL_MSG_PRIVFLAGS_NTF`` private flags
===================================== ================================= ===================================== =================================
``GET`` requests are sent by userspace applications to retrieve device ``GET`` requests are sent by userspace applications to retrieve device
...@@ -626,6 +628,23 @@ response uses all private flags supported by the device as mask so that client ...@@ -626,6 +628,23 @@ response uses all private flags supported by the device as mask so that client
gets the full information without having to fetch the string set with names. gets the full information without having to fetch the string set with names.
PRIVFLAGS_SET
=============
Sets or modifies values of device private flags like ``ETHTOOL_SPFLAGS``
ioctl request.
Request contents:
==================================== ====== ==========================
``ETHTOOL_A_PRIVFLAGS_HEADER`` nested request header
``ETHTOOL_A_PRIVFLAGS_FLAGS`` bitset private flags
==================================== ====== ==========================
``ETHTOOL_A_PRIVFLAGS_FLAGS`` can either set the whole set of private flags or
modify only values of some of them.
Request translation Request translation
=================== ===================
...@@ -676,7 +695,7 @@ have their netlink replacement yet. ...@@ -676,7 +695,7 @@ have their netlink replacement yet.
``ETHTOOL_GFLAGS`` ``ETHTOOL_MSG_FEATURES_GET`` ``ETHTOOL_GFLAGS`` ``ETHTOOL_MSG_FEATURES_GET``
``ETHTOOL_SFLAGS`` ``ETHTOOL_MSG_FEATURES_SET`` ``ETHTOOL_SFLAGS`` ``ETHTOOL_MSG_FEATURES_SET``
``ETHTOOL_GPFLAGS`` ``ETHTOOL_MSG_PRIVFLAGS_GET`` ``ETHTOOL_GPFLAGS`` ``ETHTOOL_MSG_PRIVFLAGS_GET``
``ETHTOOL_SPFLAGS`` n/a ``ETHTOOL_SPFLAGS`` ``ETHTOOL_MSG_PRIVFLAGS_SET``
``ETHTOOL_GRXFH`` n/a ``ETHTOOL_GRXFH`` n/a
``ETHTOOL_SRXFH`` n/a ``ETHTOOL_SRXFH`` n/a
``ETHTOOL_GGRO`` ``ETHTOOL_MSG_FEATURES_GET`` ``ETHTOOL_GGRO`` ``ETHTOOL_MSG_FEATURES_GET``
......
...@@ -27,6 +27,7 @@ enum { ...@@ -27,6 +27,7 @@ enum {
ETHTOOL_MSG_FEATURES_GET, ETHTOOL_MSG_FEATURES_GET,
ETHTOOL_MSG_FEATURES_SET, ETHTOOL_MSG_FEATURES_SET,
ETHTOOL_MSG_PRIVFLAGS_GET, ETHTOOL_MSG_PRIVFLAGS_GET,
ETHTOOL_MSG_PRIVFLAGS_SET,
/* add new constants above here */ /* add new constants above here */
__ETHTOOL_MSG_USER_CNT, __ETHTOOL_MSG_USER_CNT,
......
...@@ -741,6 +741,11 @@ static const struct genl_ops ethtool_genl_ops[] = { ...@@ -741,6 +741,11 @@ static const struct genl_ops ethtool_genl_ops[] = {
.dumpit = ethnl_default_dumpit, .dumpit = ethnl_default_dumpit,
.done = ethnl_default_done, .done = ethnl_default_done,
}, },
{
.cmd = ETHTOOL_MSG_PRIVFLAGS_SET,
.flags = GENL_UNS_ADMIN_PERM,
.doit = ethnl_set_privflags,
},
}; };
static const struct genl_multicast_group ethtool_nl_mcgrps[] = { static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
......
...@@ -345,5 +345,6 @@ int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); ...@@ -345,5 +345,6 @@ int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info); int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_wol(struct sk_buff *skb, struct genl_info *info); int ethnl_set_wol(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info);
#endif /* _NET_ETHTOOL_NETLINK_H */ #endif /* _NET_ETHTOOL_NETLINK_H */
...@@ -134,3 +134,73 @@ const struct ethnl_request_ops ethnl_privflags_request_ops = { ...@@ -134,3 +134,73 @@ const struct ethnl_request_ops ethnl_privflags_request_ops = {
.fill_reply = privflags_fill_reply, .fill_reply = privflags_fill_reply,
.cleanup_data = privflags_cleanup_data, .cleanup_data = privflags_cleanup_data,
}; };
/* PRIVFLAGS_SET */
static const struct nla_policy
privflags_set_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = {
[ETHTOOL_A_PRIVFLAGS_UNSPEC] = { .type = NLA_REJECT },
[ETHTOOL_A_PRIVFLAGS_HEADER] = { .type = NLA_NESTED },
[ETHTOOL_A_PRIVFLAGS_FLAGS] = { .type = NLA_NESTED },
};
int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *tb[ETHTOOL_A_PRIVFLAGS_MAX + 1];
const char (*names)[ETH_GSTRING_LEN] = NULL;
struct ethnl_req_info req_info = {};
const struct ethtool_ops *ops;
struct net_device *dev;
unsigned int nflags;
bool mod = false;
bool compact;
u32 flags;
int ret;
ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
ETHTOOL_A_PRIVFLAGS_MAX, privflags_set_policy,
info->extack);
if (ret < 0)
return ret;
if (!tb[ETHTOOL_A_PRIVFLAGS_FLAGS])
return -EINVAL;
ret = ethnl_bitset_is_compact(tb[ETHTOOL_A_PRIVFLAGS_FLAGS], &compact);
if (ret < 0)
return ret;
ret = ethnl_parse_header_dev_get(&req_info,
tb[ETHTOOL_A_PRIVFLAGS_HEADER],
genl_info_net(info), info->extack,
true);
if (ret < 0)
return ret;
dev = req_info.dev;
ops = dev->ethtool_ops;
if (!ops->get_priv_flags || !ops->set_priv_flags ||
!ops->get_sset_count || !ops->get_strings)
return -EOPNOTSUPP;
rtnl_lock();
ret = ethnl_ops_begin(dev);
if (ret < 0)
goto out_rtnl;
ret = ethnl_get_priv_flags_info(dev, &nflags, compact ? NULL : &names);
if (ret < 0)
goto out_ops;
flags = ops->get_priv_flags(dev);
ret = ethnl_update_bitset32(&flags, nflags,
tb[ETHTOOL_A_PRIVFLAGS_FLAGS], names,
info->extack, &mod);
if (ret < 0 || !mod)
goto out_free;
ret = ops->set_priv_flags(dev, flags);
out_free:
kfree(names);
out_ops:
ethnl_ops_complete(dev);
out_rtnl:
rtnl_unlock();
dev_put(dev);
return ret;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment