1 // SPDX-License-Identifier: GPL-2.0-only
6 struct linkinfo_req_info
{
7 struct ethnl_req_info base
;
10 struct linkinfo_reply_data
{
11 struct ethnl_reply_data base
;
12 struct ethtool_link_ksettings ksettings
;
13 struct ethtool_link_settings
*lsettings
;
16 #define LINKINFO_REPDATA(__reply_base) \
17 container_of(__reply_base, struct linkinfo_reply_data, base)
19 static const struct nla_policy
20 linkinfo_get_policy
[ETHTOOL_A_LINKINFO_MAX
+ 1] = {
21 [ETHTOOL_A_LINKINFO_UNSPEC
] = { .type
= NLA_REJECT
},
22 [ETHTOOL_A_LINKINFO_HEADER
] = { .type
= NLA_NESTED
},
23 [ETHTOOL_A_LINKINFO_PORT
] = { .type
= NLA_REJECT
},
24 [ETHTOOL_A_LINKINFO_PHYADDR
] = { .type
= NLA_REJECT
},
25 [ETHTOOL_A_LINKINFO_TP_MDIX
] = { .type
= NLA_REJECT
},
26 [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL
] = { .type
= NLA_REJECT
},
27 [ETHTOOL_A_LINKINFO_TRANSCEIVER
] = { .type
= NLA_REJECT
},
30 static int linkinfo_prepare_data(const struct ethnl_req_info
*req_base
,
31 struct ethnl_reply_data
*reply_base
,
32 struct genl_info
*info
)
34 struct linkinfo_reply_data
*data
= LINKINFO_REPDATA(reply_base
);
35 struct net_device
*dev
= reply_base
->dev
;
38 data
->lsettings
= &data
->ksettings
.base
;
40 ret
= ethnl_ops_begin(dev
);
43 ret
= __ethtool_get_link_ksettings(dev
, &data
->ksettings
);
45 GENL_SET_ERR_MSG(info
, "failed to retrieve link settings");
46 ethnl_ops_complete(dev
);
51 static int linkinfo_reply_size(const struct ethnl_req_info
*req_base
,
52 const struct ethnl_reply_data
*reply_base
)
54 return nla_total_size(sizeof(u8
)) /* LINKINFO_PORT */
55 + nla_total_size(sizeof(u8
)) /* LINKINFO_PHYADDR */
56 + nla_total_size(sizeof(u8
)) /* LINKINFO_TP_MDIX */
57 + nla_total_size(sizeof(u8
)) /* LINKINFO_TP_MDIX_CTRL */
58 + nla_total_size(sizeof(u8
)) /* LINKINFO_TRANSCEIVER */
62 static int linkinfo_fill_reply(struct sk_buff
*skb
,
63 const struct ethnl_req_info
*req_base
,
64 const struct ethnl_reply_data
*reply_base
)
66 const struct linkinfo_reply_data
*data
= LINKINFO_REPDATA(reply_base
);
68 if (nla_put_u8(skb
, ETHTOOL_A_LINKINFO_PORT
, data
->lsettings
->port
) ||
69 nla_put_u8(skb
, ETHTOOL_A_LINKINFO_PHYADDR
,
70 data
->lsettings
->phy_address
) ||
71 nla_put_u8(skb
, ETHTOOL_A_LINKINFO_TP_MDIX
,
72 data
->lsettings
->eth_tp_mdix
) ||
73 nla_put_u8(skb
, ETHTOOL_A_LINKINFO_TP_MDIX_CTRL
,
74 data
->lsettings
->eth_tp_mdix_ctrl
) ||
75 nla_put_u8(skb
, ETHTOOL_A_LINKINFO_TRANSCEIVER
,
76 data
->lsettings
->transceiver
))
82 const struct ethnl_request_ops ethnl_linkinfo_request_ops
= {
83 .request_cmd
= ETHTOOL_MSG_LINKINFO_GET
,
84 .reply_cmd
= ETHTOOL_MSG_LINKINFO_GET_REPLY
,
85 .hdr_attr
= ETHTOOL_A_LINKINFO_HEADER
,
86 .max_attr
= ETHTOOL_A_LINKINFO_MAX
,
87 .req_info_size
= sizeof(struct linkinfo_req_info
),
88 .reply_data_size
= sizeof(struct linkinfo_reply_data
),
89 .request_policy
= linkinfo_get_policy
,
91 .prepare_data
= linkinfo_prepare_data
,
92 .reply_size
= linkinfo_reply_size
,
93 .fill_reply
= linkinfo_fill_reply
,
98 static const struct nla_policy
99 linkinfo_set_policy
[ETHTOOL_A_LINKINFO_MAX
+ 1] = {
100 [ETHTOOL_A_LINKINFO_UNSPEC
] = { .type
= NLA_REJECT
},
101 [ETHTOOL_A_LINKINFO_HEADER
] = { .type
= NLA_NESTED
},
102 [ETHTOOL_A_LINKINFO_PORT
] = { .type
= NLA_U8
},
103 [ETHTOOL_A_LINKINFO_PHYADDR
] = { .type
= NLA_U8
},
104 [ETHTOOL_A_LINKINFO_TP_MDIX
] = { .type
= NLA_REJECT
},
105 [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL
] = { .type
= NLA_U8
},
106 [ETHTOOL_A_LINKINFO_TRANSCEIVER
] = { .type
= NLA_REJECT
},
109 int ethnl_set_linkinfo(struct sk_buff
*skb
, struct genl_info
*info
)
111 struct nlattr
*tb
[ETHTOOL_A_LINKINFO_MAX
+ 1];
112 struct ethtool_link_ksettings ksettings
= {};
113 struct ethtool_link_settings
*lsettings
;
114 struct ethnl_req_info req_info
= {};
115 struct net_device
*dev
;
119 ret
= nlmsg_parse(info
->nlhdr
, GENL_HDRLEN
, tb
,
120 ETHTOOL_A_LINKINFO_MAX
, linkinfo_set_policy
,
124 ret
= ethnl_parse_header_dev_get(&req_info
,
125 tb
[ETHTOOL_A_LINKINFO_HEADER
],
126 genl_info_net(info
), info
->extack
,
132 if (!dev
->ethtool_ops
->get_link_ksettings
||
133 !dev
->ethtool_ops
->set_link_ksettings
)
137 ret
= ethnl_ops_begin(dev
);
141 ret
= __ethtool_get_link_ksettings(dev
, &ksettings
);
143 GENL_SET_ERR_MSG(info
, "failed to retrieve link settings");
146 lsettings
= &ksettings
.base
;
148 ethnl_update_u8(&lsettings
->port
, tb
[ETHTOOL_A_LINKINFO_PORT
], &mod
);
149 ethnl_update_u8(&lsettings
->phy_address
, tb
[ETHTOOL_A_LINKINFO_PHYADDR
],
151 ethnl_update_u8(&lsettings
->eth_tp_mdix_ctrl
,
152 tb
[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL
], &mod
);
157 ret
= dev
->ethtool_ops
->set_link_ksettings(dev
, &ksettings
);
159 GENL_SET_ERR_MSG(info
, "link settings update failed");
161 ethtool_notify(dev
, ETHTOOL_MSG_LINKINFO_NTF
, NULL
);
164 ethnl_ops_complete(dev
);