Andrew Lunn | 11ca3c42 | 2020-05-10 21:12:33 +0200 | [diff] [blame^] | 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 | } |