^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include "netlink.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) struct linkinfo_req_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) struct ethnl_req_info base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) struct linkinfo_reply_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct ethnl_reply_data base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct ethtool_link_ksettings ksettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) struct ethtool_link_settings *lsettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define LINKINFO_REPDATA(__reply_base) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) container_of(__reply_base, struct linkinfo_reply_data, base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) const struct nla_policy ethnl_linkinfo_get_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) [ETHTOOL_A_LINKINFO_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static int linkinfo_prepare_data(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct ethnl_reply_data *reply_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct linkinfo_reply_data *data = LINKINFO_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct net_device *dev = reply_base->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) data->lsettings = &data->ksettings.base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ret = __ethtool_get_link_ksettings(dev, &data->ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (ret < 0 && info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) GENL_SET_ERR_MSG(info, "failed to retrieve link settings");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static int linkinfo_reply_size(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return nla_total_size(sizeof(u8)) /* LINKINFO_PORT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) + nla_total_size(sizeof(u8)) /* LINKINFO_PHYADDR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) + nla_total_size(sizeof(u8)) /* LINKINFO_TP_MDIX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) + nla_total_size(sizeof(u8)) /* LINKINFO_TP_MDIX_CTRL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) + nla_total_size(sizeof(u8)) /* LINKINFO_TRANSCEIVER */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) + 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static int linkinfo_fill_reply(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) const struct linkinfo_reply_data *data = LINKINFO_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (nla_put_u8(skb, ETHTOOL_A_LINKINFO_PORT, data->lsettings->port) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) nla_put_u8(skb, ETHTOOL_A_LINKINFO_PHYADDR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) data->lsettings->phy_address) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) nla_put_u8(skb, ETHTOOL_A_LINKINFO_TP_MDIX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) data->lsettings->eth_tp_mdix) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) nla_put_u8(skb, ETHTOOL_A_LINKINFO_TP_MDIX_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) data->lsettings->eth_tp_mdix_ctrl) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) nla_put_u8(skb, ETHTOOL_A_LINKINFO_TRANSCEIVER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) data->lsettings->transceiver))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) const struct ethnl_request_ops ethnl_linkinfo_request_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .request_cmd = ETHTOOL_MSG_LINKINFO_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .reply_cmd = ETHTOOL_MSG_LINKINFO_GET_REPLY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .hdr_attr = ETHTOOL_A_LINKINFO_HEADER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .req_info_size = sizeof(struct linkinfo_req_info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .reply_data_size = sizeof(struct linkinfo_reply_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .prepare_data = linkinfo_prepare_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .reply_size = linkinfo_reply_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) .fill_reply = linkinfo_fill_reply,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* LINKINFO_SET */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) const struct nla_policy ethnl_linkinfo_set_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) [ETHTOOL_A_LINKINFO_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) [ETHTOOL_A_LINKINFO_PORT] = { .type = NLA_U8 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) [ETHTOOL_A_LINKINFO_PHYADDR] = { .type = NLA_U8 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .type = NLA_U8 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct ethtool_link_ksettings ksettings = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct ethtool_link_settings *lsettings;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct ethnl_req_info req_info = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct nlattr **tb = info->attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) bool mod = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) ret = ethnl_parse_header_dev_get(&req_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) tb[ETHTOOL_A_LINKINFO_HEADER],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) genl_info_net(info), info->extack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) dev = req_info.dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) ret = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (!dev->ethtool_ops->get_link_ksettings ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) !dev->ethtool_ops->set_link_ksettings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) goto out_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) goto out_rtnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ret = __ethtool_get_link_ksettings(dev, &ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) GENL_SET_ERR_MSG(info, "failed to retrieve link settings");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) lsettings = &ksettings.base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ethnl_update_u8(&lsettings->port, tb[ETHTOOL_A_LINKINFO_PORT], &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) ethnl_update_u8(&lsettings->phy_address, tb[ETHTOOL_A_LINKINFO_PHYADDR],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) ethnl_update_u8(&lsettings->eth_tp_mdix_ctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) tb[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL], &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (!mod)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ret = dev->ethtool_ops->set_link_ksettings(dev, &ksettings);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) GENL_SET_ERR_MSG(info, "link settings update failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) ethtool_notify(dev, ETHTOOL_MSG_LINKINFO_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) out_ops:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) out_rtnl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) out_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) dev_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }