111ca3c42SAndrew Lunn // SPDX-License-Identifier: GPL-2.0-only 211ca3c42SAndrew Lunn 311ca3c42SAndrew Lunn #include <linux/phy.h> 411ca3c42SAndrew Lunn #include "netlink.h" 511ca3c42SAndrew Lunn #include "common.h" 611ca3c42SAndrew Lunn 711ca3c42SAndrew Lunn /* CABLE_TEST_ACT */ 811ca3c42SAndrew Lunn 911ca3c42SAndrew Lunn static const struct nla_policy 1011ca3c42SAndrew Lunn cable_test_act_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { 1111ca3c42SAndrew Lunn [ETHTOOL_A_CABLE_TEST_UNSPEC] = { .type = NLA_REJECT }, 1211ca3c42SAndrew Lunn [ETHTOOL_A_CABLE_TEST_HEADER] = { .type = NLA_NESTED }, 1311ca3c42SAndrew Lunn }; 1411ca3c42SAndrew Lunn 1511ca3c42SAndrew Lunn int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) 1611ca3c42SAndrew Lunn { 1711ca3c42SAndrew Lunn struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1]; 1811ca3c42SAndrew Lunn struct ethnl_req_info req_info = {}; 1911ca3c42SAndrew Lunn struct net_device *dev; 2011ca3c42SAndrew Lunn int ret; 2111ca3c42SAndrew Lunn 2211ca3c42SAndrew Lunn ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 2311ca3c42SAndrew Lunn ETHTOOL_A_CABLE_TEST_MAX, 2411ca3c42SAndrew Lunn cable_test_act_policy, info->extack); 2511ca3c42SAndrew Lunn if (ret < 0) 2611ca3c42SAndrew Lunn return ret; 2711ca3c42SAndrew Lunn 2811ca3c42SAndrew Lunn ret = ethnl_parse_header_dev_get(&req_info, 2911ca3c42SAndrew Lunn tb[ETHTOOL_A_CABLE_TEST_HEADER], 3011ca3c42SAndrew Lunn genl_info_net(info), info->extack, 3111ca3c42SAndrew Lunn true); 3211ca3c42SAndrew Lunn if (ret < 0) 3311ca3c42SAndrew Lunn return ret; 3411ca3c42SAndrew Lunn 3511ca3c42SAndrew Lunn dev = req_info.dev; 3611ca3c42SAndrew Lunn if (!dev->phydev) { 3711ca3c42SAndrew Lunn ret = -EOPNOTSUPP; 3811ca3c42SAndrew Lunn goto out_dev_put; 3911ca3c42SAndrew Lunn } 4011ca3c42SAndrew Lunn 4111ca3c42SAndrew Lunn rtnl_lock(); 4211ca3c42SAndrew Lunn ret = ethnl_ops_begin(dev); 4311ca3c42SAndrew Lunn if (ret < 0) 4411ca3c42SAndrew Lunn goto out_rtnl; 4511ca3c42SAndrew Lunn 4611ca3c42SAndrew Lunn ret = phy_start_cable_test(dev->phydev, info->extack); 4711ca3c42SAndrew Lunn 4811ca3c42SAndrew Lunn ethnl_ops_complete(dev); 4911ca3c42SAndrew Lunn out_rtnl: 5011ca3c42SAndrew Lunn rtnl_unlock(); 5111ca3c42SAndrew Lunn out_dev_put: 5211ca3c42SAndrew Lunn dev_put(dev); 5311ca3c42SAndrew Lunn return ret; 5411ca3c42SAndrew Lunn } 55