blob: aeb6672a46d0692f9a020b0fce0be84707a0c904 [file] [log] [blame]
Andrew Lunn11ca3c422020-05-10 21:12:33 +02001// 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
9static const struct nla_policy
10cable_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
15int 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);
49out_rtnl:
50 rtnl_unlock();
51out_dev_put:
52 dev_put(dev);
53 return ret;
54}