summaryrefslogtreecommitdiff
path: root/net/ethtool/mm.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ethtool/mm.c')
-rw-r--r--net/ethtool/mm.c82
1 files changed, 31 insertions, 51 deletions
diff --git a/net/ethtool/mm.c b/net/ethtool/mm.c
index 3e8acdb806fd..7e51f7633001 100644
--- a/net/ethtool/mm.c
+++ b/net/ethtool/mm.c
@@ -146,18 +146,6 @@ static int mm_fill_reply(struct sk_buff *skb,
return 0;
}
-const struct ethnl_request_ops ethnl_mm_request_ops = {
- .request_cmd = ETHTOOL_MSG_MM_GET,
- .reply_cmd = ETHTOOL_MSG_MM_GET_REPLY,
- .hdr_attr = ETHTOOL_A_MM_HEADER,
- .req_info_size = sizeof(struct mm_req_info),
- .reply_data_size = sizeof(struct mm_reply_data),
-
- .prepare_data = mm_prepare_data,
- .reply_size = mm_reply_size,
- .fill_reply = mm_fill_reply,
-};
-
const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1] = {
[ETHTOOL_A_MM_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
[ETHTOOL_A_MM_VERIFY_ENABLED] = NLA_POLICY_MAX(NLA_U8, 1),
@@ -184,40 +172,28 @@ static void mm_state_to_cfg(const struct ethtool_mm_state *state,
cfg->tx_min_frag_size = state->tx_min_frag_size;
}
-int ethnl_set_mm(struct sk_buff *skb, struct genl_info *info)
+static int
+ethnl_set_mm_validate(struct ethnl_req_info *req_info, struct genl_info *info)
+{
+ const struct ethtool_ops *ops = req_info->dev->ethtool_ops;
+
+ return ops->get_mm && ops->set_mm ? 1 : -EOPNOTSUPP;
+}
+
+static int ethnl_set_mm(struct ethnl_req_info *req_info, struct genl_info *info)
{
struct netlink_ext_ack *extack = info->extack;
- struct ethnl_req_info req_info = {};
+ struct net_device *dev = req_info->dev;
struct ethtool_mm_state state = {};
struct nlattr **tb = info->attrs;
struct ethtool_mm_cfg cfg = {};
- const struct ethtool_ops *ops;
- struct net_device *dev;
bool mod = false;
int ret;
- ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_MM_HEADER],
- genl_info_net(info), extack, true);
+ ret = dev->ethtool_ops->get_mm(dev, &state);
if (ret)
return ret;
- dev = req_info.dev;
- ops = dev->ethtool_ops;
-
- if (!ops->get_mm || !ops->set_mm) {
- ret = -EOPNOTSUPP;
- goto out_dev_put;
- }
-
- rtnl_lock();
- ret = ethnl_ops_begin(dev);
- if (ret < 0)
- goto out_rtnl_unlock;
-
- ret = ops->get_mm(dev, &state);
- if (ret)
- goto out_complete;
-
mm_state_to_cfg(&state, &cfg);
ethnl_update_bool(&cfg.verify_enabled, tb[ETHTOOL_A_MM_VERIFY_ENABLED],
@@ -225,34 +201,38 @@ int ethnl_set_mm(struct sk_buff *skb, struct genl_info *info)
ethnl_update_u32(&cfg.verify_time, tb[ETHTOOL_A_MM_VERIFY_TIME], &mod);
ethnl_update_bool(&cfg.tx_enabled, tb[ETHTOOL_A_MM_TX_ENABLED], &mod);
ethnl_update_bool(&cfg.pmac_enabled, tb[ETHTOOL_A_MM_PMAC_ENABLED],
- &mod);
+ &mod);
ethnl_update_u32(&cfg.tx_min_frag_size,
tb[ETHTOOL_A_MM_TX_MIN_FRAG_SIZE], &mod);
if (!mod)
- goto out_complete;
+ return 0;
if (cfg.verify_time > state.max_verify_time) {
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_MM_VERIFY_TIME],
"verifyTime exceeds device maximum");
- ret = -ERANGE;
- goto out_complete;
+ return -ERANGE;
}
- ret = ops->set_mm(dev, &cfg, extack);
- if (ret)
- goto out_complete;
+ ret = dev->ethtool_ops->set_mm(dev, &cfg, extack);
+ return ret < 0 ? ret : 1;
+}
+
+const struct ethnl_request_ops ethnl_mm_request_ops = {
+ .request_cmd = ETHTOOL_MSG_MM_GET,
+ .reply_cmd = ETHTOOL_MSG_MM_GET_REPLY,
+ .hdr_attr = ETHTOOL_A_MM_HEADER,
+ .req_info_size = sizeof(struct mm_req_info),
+ .reply_data_size = sizeof(struct mm_reply_data),
- ethtool_notify(dev, ETHTOOL_MSG_MM_NTF, NULL);
+ .prepare_data = mm_prepare_data,
+ .reply_size = mm_reply_size,
+ .fill_reply = mm_fill_reply,
-out_complete:
- ethnl_ops_complete(dev);
-out_rtnl_unlock:
- rtnl_unlock();
-out_dev_put:
- ethnl_parse_header_dev_put(&req_info);
- return ret;
-}
+ .set_validate = ethnl_set_mm_validate,
+ .set = ethnl_set_mm,
+ .set_ntf_cmd = ETHTOOL_MSG_MM_NTF,
+};
/* Returns whether a given device supports the MAC merge layer
* (has an eMAC and a pMAC). Must be called under rtnl_lock() and