cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

linkinfo.c (4410B)


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