xref: /openbmc/linux/net/ethtool/cabletest.c (revision 11ca3c42)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <linux/phy.h>
4 #include "netlink.h"
5 #include "common.h"
6 
7 /* CABLE_TEST_ACT */
8 
9 static const struct nla_policy
10 cable_test_act_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = {
11 	[ETHTOOL_A_CABLE_TEST_UNSPEC]		= { .type = NLA_REJECT },
12 	[ETHTOOL_A_CABLE_TEST_HEADER]		= { .type = NLA_NESTED },
13 };
14 
15 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info)
16 {
17 	struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1];
18 	struct ethnl_req_info req_info = {};
19 	struct net_device *dev;
20 	int ret;
21 
22 	ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
23 			  ETHTOOL_A_CABLE_TEST_MAX,
24 			  cable_test_act_policy, info->extack);
25 	if (ret < 0)
26 		return ret;
27 
28 	ret = ethnl_parse_header_dev_get(&req_info,
29 					 tb[ETHTOOL_A_CABLE_TEST_HEADER],
30 					 genl_info_net(info), info->extack,
31 					 true);
32 	if (ret < 0)
33 		return ret;
34 
35 	dev = req_info.dev;
36 	if (!dev->phydev) {
37 		ret = -EOPNOTSUPP;
38 		goto out_dev_put;
39 	}
40 
41 	rtnl_lock();
42 	ret = ethnl_ops_begin(dev);
43 	if (ret < 0)
44 		goto out_rtnl;
45 
46 	ret = phy_start_cable_test(dev->phydev, info->extack);
47 
48 	ethnl_ops_complete(dev);
49 out_rtnl:
50 	rtnl_unlock();
51 out_dev_put:
52 	dev_put(dev);
53 	return ret;
54 }
55