diff options
Diffstat (limited to 'net/ethtool/cabletest.c')
-rw-r--r-- | net/ethtool/cabletest.c | 78 |
1 files changed, 49 insertions, 29 deletions
diff --git a/net/ethtool/cabletest.c b/net/ethtool/cabletest.c index 06a151165c31..0364b8fb577b 100644 --- a/net/ethtool/cabletest.c +++ b/net/ethtool/cabletest.c @@ -2,6 +2,7 @@ #include <linux/phy.h> #include <linux/ethtool_netlink.h> +#include <net/netdev_lock.h> #include "netlink.h" #include "common.h" @@ -13,7 +14,7 @@ const struct nla_policy ethnl_cable_test_act_policy[] = { [ETHTOOL_A_CABLE_TEST_HEADER] = - NLA_POLICY_NESTED(ethnl_header_policy), + NLA_POLICY_NESTED(ethnl_header_policy_phy), }; static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd) @@ -58,6 +59,7 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) struct ethnl_req_info req_info = {}; const struct ethtool_phy_ops *ops; struct nlattr **tb = info->attrs; + struct phy_device *phydev; struct net_device *dev; int ret; @@ -69,33 +71,37 @@ int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) return ret; dev = req_info.dev; - if (!dev->phydev) { + + rtnl_lock(); + netdev_lock_ops(dev); + phydev = ethnl_req_get_phydev(&req_info, tb, + ETHTOOL_A_CABLE_TEST_HEADER, + info->extack); + if (IS_ERR_OR_NULL(phydev)) { ret = -EOPNOTSUPP; - goto out_dev_put; + goto out_unlock; } - rtnl_lock(); ops = ethtool_phy_ops; if (!ops || !ops->start_cable_test) { ret = -EOPNOTSUPP; - goto out_rtnl; + goto out_unlock; } ret = ethnl_ops_begin(dev); if (ret < 0) - goto out_rtnl; + goto out_unlock; - ret = ops->start_cable_test(dev->phydev, info->extack); + ret = ops->start_cable_test(phydev, info->extack); ethnl_ops_complete(dev); if (!ret) - ethnl_cable_test_started(dev->phydev, - ETHTOOL_MSG_CABLE_TEST_NTF); + ethnl_cable_test_started(phydev, ETHTOOL_MSG_CABLE_TEST_NTF); -out_rtnl: +out_unlock: + netdev_unlock_ops(dev); rtnl_unlock(); -out_dev_put: ethnl_parse_header_dev_put(&req_info); return ret; } @@ -160,7 +166,8 @@ void ethnl_cable_test_finished(struct phy_device *phydev) } EXPORT_SYMBOL_GPL(ethnl_cable_test_finished); -int ethnl_cable_test_result(struct phy_device *phydev, u8 pair, u8 result) +int ethnl_cable_test_result_with_src(struct phy_device *phydev, u8 pair, + u8 result, u32 src) { struct nlattr *nest; int ret = -EMSGSIZE; @@ -173,6 +180,10 @@ int ethnl_cable_test_result(struct phy_device *phydev, u8 pair, u8 result) goto err; if (nla_put_u8(phydev->skb, ETHTOOL_A_CABLE_RESULT_CODE, result)) goto err; + if (src != ETHTOOL_A_CABLE_INF_SRC_UNSPEC) { + if (nla_put_u32(phydev->skb, ETHTOOL_A_CABLE_RESULT_SRC, src)) + goto err; + } nla_nest_end(phydev->skb, nest); return 0; @@ -181,9 +192,10 @@ err: nla_nest_cancel(phydev->skb, nest); return ret; } -EXPORT_SYMBOL_GPL(ethnl_cable_test_result); +EXPORT_SYMBOL_GPL(ethnl_cable_test_result_with_src); -int ethnl_cable_test_fault_length(struct phy_device *phydev, u8 pair, u32 cm) +int ethnl_cable_test_fault_length_with_src(struct phy_device *phydev, u8 pair, + u32 cm, u32 src) { struct nlattr *nest; int ret = -EMSGSIZE; @@ -197,6 +209,11 @@ int ethnl_cable_test_fault_length(struct phy_device *phydev, u8 pair, u32 cm) goto err; if (nla_put_u32(phydev->skb, ETHTOOL_A_CABLE_FAULT_LENGTH_CM, cm)) goto err; + if (src != ETHTOOL_A_CABLE_INF_SRC_UNSPEC) { + if (nla_put_u32(phydev->skb, ETHTOOL_A_CABLE_FAULT_LENGTH_SRC, + src)) + goto err; + } nla_nest_end(phydev->skb, nest); return 0; @@ -205,11 +222,7 @@ err: nla_nest_cancel(phydev->skb, nest); return ret; } -EXPORT_SYMBOL_GPL(ethnl_cable_test_fault_length); - -struct cable_test_tdr_req_info { - struct ethnl_req_info base; -}; +EXPORT_SYMBOL_GPL(ethnl_cable_test_fault_length_with_src); static const struct nla_policy cable_test_tdr_act_cfg_policy[] = { [ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST] = { .type = NLA_U32 }, @@ -220,7 +233,7 @@ static const struct nla_policy cable_test_tdr_act_cfg_policy[] = { const struct nla_policy ethnl_cable_test_tdr_act_policy[] = { [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = - NLA_POLICY_NESTED(ethnl_header_policy), + NLA_POLICY_NESTED(ethnl_header_policy_phy), [ETHTOOL_A_CABLE_TEST_TDR_CFG] = { .type = NLA_NESTED }, }; @@ -309,6 +322,7 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info) struct ethnl_req_info req_info = {}; const struct ethtool_phy_ops *ops; struct nlattr **tb = info->attrs; + struct phy_device *phydev; struct phy_tdr_config cfg; struct net_device *dev; int ret; @@ -321,10 +335,6 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info) return ret; dev = req_info.dev; - if (!dev->phydev) { - ret = -EOPNOTSUPP; - goto out_dev_put; - } ret = ethnl_act_cable_test_tdr_cfg(tb[ETHTOOL_A_CABLE_TEST_TDR_CFG], info, &cfg); @@ -332,25 +342,35 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info) goto out_dev_put; rtnl_lock(); + netdev_lock_ops(dev); + phydev = ethnl_req_get_phydev(&req_info, tb, + ETHTOOL_A_CABLE_TEST_TDR_HEADER, + info->extack); + if (IS_ERR_OR_NULL(phydev)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } + ops = ethtool_phy_ops; if (!ops || !ops->start_cable_test_tdr) { ret = -EOPNOTSUPP; - goto out_rtnl; + goto out_unlock; } ret = ethnl_ops_begin(dev); if (ret < 0) - goto out_rtnl; + goto out_unlock; - ret = ops->start_cable_test_tdr(dev->phydev, info->extack, &cfg); + ret = ops->start_cable_test_tdr(phydev, info->extack, &cfg); ethnl_ops_complete(dev); if (!ret) - ethnl_cable_test_started(dev->phydev, + ethnl_cable_test_started(phydev, ETHTOOL_MSG_CABLE_TEST_TDR_NTF); -out_rtnl: +out_unlock: + netdev_unlock_ops(dev); rtnl_unlock(); out_dev_put: ethnl_parse_header_dev_put(&req_info); |