1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/ethtool.h>
12 const char (*strings
)[ETH_GSTRING_LEN
];
15 static const struct strset_info info_template
[] = {
22 [ETH_SS_PRIV_FLAGS
] = {
27 .count
= ARRAY_SIZE(netdev_features_strings
),
28 .strings
= netdev_features_strings
,
30 [ETH_SS_RSS_HASH_FUNCS
] = {
32 .count
= ARRAY_SIZE(rss_hash_func_strings
),
33 .strings
= rss_hash_func_strings
,
37 .count
= ARRAY_SIZE(tunable_strings
),
38 .strings
= tunable_strings
,
40 [ETH_SS_PHY_STATS
] = {
43 [ETH_SS_PHY_TUNABLES
] = {
45 .count
= ARRAY_SIZE(phy_tunable_strings
),
46 .strings
= phy_tunable_strings
,
48 [ETH_SS_LINK_MODES
] = {
50 .count
= __ETHTOOL_LINK_MODE_MASK_NBITS
,
51 .strings
= link_mode_names
,
53 [ETH_SS_MSG_CLASSES
] = {
55 .count
= NETIF_MSG_CLASS_COUNT
,
56 .strings
= netif_msg_class_names
,
58 [ETH_SS_WOL_MODES
] = {
60 .count
= WOL_MODE_COUNT
,
61 .strings
= wol_mode_names
,
63 [ETH_SS_SOF_TIMESTAMPING
] = {
65 .count
= __SOF_TIMESTAMPING_CNT
,
66 .strings
= sof_timestamping_names
,
68 [ETH_SS_TS_TX_TYPES
] = {
70 .count
= __HWTSTAMP_TX_CNT
,
71 .strings
= ts_tx_type_names
,
73 [ETH_SS_TS_RX_FILTERS
] = {
75 .count
= __HWTSTAMP_FILTER_CNT
,
76 .strings
= ts_rx_filter_names
,
78 [ETH_SS_UDP_TUNNEL_TYPES
] = {
80 .count
= __ETHTOOL_UDP_TUNNEL_TYPE_CNT
,
81 .strings
= udp_tunnel_type_names
,
85 struct strset_req_info
{
86 struct ethnl_req_info base
;
91 #define STRSET_REQINFO(__req_base) \
92 container_of(__req_base, struct strset_req_info, base)
94 struct strset_reply_data
{
95 struct ethnl_reply_data base
;
96 struct strset_info sets
[ETH_SS_COUNT
];
99 #define STRSET_REPDATA(__reply_base) \
100 container_of(__reply_base, struct strset_reply_data, base)
102 const struct nla_policy ethnl_strset_get_policy
[] = {
103 [ETHTOOL_A_STRSET_HEADER
] =
104 NLA_POLICY_NESTED(ethnl_header_policy
),
105 [ETHTOOL_A_STRSET_STRINGSETS
] = { .type
= NLA_NESTED
},
106 [ETHTOOL_A_STRSET_COUNTS_ONLY
] = { .type
= NLA_FLAG
},
109 static const struct nla_policy get_stringset_policy
[] = {
110 [ETHTOOL_A_STRINGSET_ID
] = { .type
= NLA_U32
},
114 * strset_include() - test if a string set should be included in reply
115 * @info: parsed client request
116 * @data: pointer to request data structure
117 * @id: id of string set to check (ETH_SS_* constants)
119 static bool strset_include(const struct strset_req_info
*info
,
120 const struct strset_reply_data
*data
, u32 id
)
124 BUILD_BUG_ON(ETH_SS_COUNT
>= BITS_PER_BYTE
* sizeof(info
->req_ids
));
127 return info
->req_ids
& (1U << id
);
128 per_dev
= data
->sets
[id
].per_dev
;
129 if (!per_dev
&& !data
->sets
[id
].strings
)
132 return data
->base
.dev
? per_dev
: !per_dev
;
135 static int strset_get_id(const struct nlattr
*nest
, u32
*val
,
136 struct netlink_ext_ack
*extack
)
138 struct nlattr
*tb
[ARRAY_SIZE(get_stringset_policy
)];
141 ret
= nla_parse_nested(tb
, ARRAY_SIZE(get_stringset_policy
) - 1, nest
,
142 get_stringset_policy
, extack
);
145 if (!tb
[ETHTOOL_A_STRINGSET_ID
])
148 *val
= nla_get_u32(tb
[ETHTOOL_A_STRINGSET_ID
]);
152 static const struct nla_policy strset_stringsets_policy
[] = {
153 [ETHTOOL_A_STRINGSETS_STRINGSET
] = { .type
= NLA_NESTED
},
156 static int strset_parse_request(struct ethnl_req_info
*req_base
,
158 struct netlink_ext_ack
*extack
)
160 struct strset_req_info
*req_info
= STRSET_REQINFO(req_base
);
161 struct nlattr
*nest
= tb
[ETHTOOL_A_STRSET_STRINGSETS
];
167 ret
= nla_validate_nested(nest
,
168 ARRAY_SIZE(strset_stringsets_policy
) - 1,
169 strset_stringsets_policy
, extack
);
173 req_info
->counts_only
= tb
[ETHTOOL_A_STRSET_COUNTS_ONLY
];
174 nla_for_each_nested(attr
, nest
, rem
) {
177 if (WARN_ONCE(nla_type(attr
) != ETHTOOL_A_STRINGSETS_STRINGSET
,
178 "unexpected attrtype %u in ETHTOOL_A_STRSET_STRINGSETS\n",
182 ret
= strset_get_id(attr
, &id
, extack
);
185 if (id
>= ETH_SS_COUNT
) {
186 NL_SET_ERR_MSG_ATTR(extack
, attr
,
187 "unknown string set id");
191 req_info
->req_ids
|= (1U << id
);
197 static void strset_cleanup_data(struct ethnl_reply_data
*reply_base
)
199 struct strset_reply_data
*data
= STRSET_REPDATA(reply_base
);
202 for (i
= 0; i
< ETH_SS_COUNT
; i
++)
203 if (data
->sets
[i
].free_strings
) {
204 kfree(data
->sets
[i
].strings
);
205 data
->sets
[i
].strings
= NULL
;
206 data
->sets
[i
].free_strings
= false;
210 static int strset_prepare_set(struct strset_info
*info
, struct net_device
*dev
,
211 unsigned int id
, bool counts_only
)
213 const struct ethtool_phy_ops
*phy_ops
= ethtool_phy_ops
;
214 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
218 if (id
== ETH_SS_PHY_STATS
&& dev
->phydev
&&
219 !ops
->get_ethtool_phy_stats
&& phy_ops
&&
220 phy_ops
->get_sset_count
)
221 ret
= phy_ops
->get_sset_count(dev
->phydev
);
222 else if (ops
->get_sset_count
&& ops
->get_strings
)
223 ret
= ops
->get_sset_count(dev
, id
);
233 strings
= kcalloc(count
, ETH_GSTRING_LEN
, GFP_KERNEL
);
236 if (id
== ETH_SS_PHY_STATS
&& dev
->phydev
&&
237 !ops
->get_ethtool_phy_stats
&& phy_ops
&&
238 phy_ops
->get_strings
)
239 phy_ops
->get_strings(dev
->phydev
, strings
);
241 ops
->get_strings(dev
, id
, strings
);
242 info
->strings
= strings
;
243 info
->free_strings
= true;
250 static int strset_prepare_data(const struct ethnl_req_info
*req_base
,
251 struct ethnl_reply_data
*reply_base
,
252 struct genl_info
*info
)
254 const struct strset_req_info
*req_info
= STRSET_REQINFO(req_base
);
255 struct strset_reply_data
*data
= STRSET_REPDATA(reply_base
);
256 struct net_device
*dev
= reply_base
->dev
;
260 BUILD_BUG_ON(ARRAY_SIZE(info_template
) != ETH_SS_COUNT
);
261 memcpy(&data
->sets
, &info_template
, sizeof(data
->sets
));
264 for (i
= 0; i
< ETH_SS_COUNT
; i
++) {
265 if ((req_info
->req_ids
& (1U << i
)) &&
266 data
->sets
[i
].per_dev
) {
268 GENL_SET_ERR_MSG(info
, "requested per device strings without dev");
275 ret
= ethnl_ops_begin(dev
);
278 for (i
= 0; i
< ETH_SS_COUNT
; i
++) {
279 if (!strset_include(req_info
, data
, i
) ||
280 !data
->sets
[i
].per_dev
)
283 ret
= strset_prepare_set(&data
->sets
[i
], dev
, i
,
284 req_info
->counts_only
);
288 ethnl_ops_complete(dev
);
292 ethnl_ops_complete(dev
);
294 strset_cleanup_data(reply_base
);
298 /* calculate size of ETHTOOL_A_STRSET_STRINGSET nest for one string set */
299 static int strset_set_size(const struct strset_info
*info
, bool counts_only
)
301 unsigned int len
= 0;
304 if (info
->count
== 0)
307 return nla_total_size(2 * nla_total_size(sizeof(u32
)));
309 for (i
= 0; i
< info
->count
; i
++) {
310 const char *str
= info
->strings
[i
];
312 /* ETHTOOL_A_STRING_INDEX, ETHTOOL_A_STRING_VALUE, nest */
313 len
+= nla_total_size(nla_total_size(sizeof(u32
)) +
314 ethnl_strz_size(str
));
316 /* ETHTOOL_A_STRINGSET_ID, ETHTOOL_A_STRINGSET_COUNT */
317 len
= 2 * nla_total_size(sizeof(u32
)) + nla_total_size(len
);
319 return nla_total_size(len
);
322 static int strset_reply_size(const struct ethnl_req_info
*req_base
,
323 const struct ethnl_reply_data
*reply_base
)
325 const struct strset_req_info
*req_info
= STRSET_REQINFO(req_base
);
326 const struct strset_reply_data
*data
= STRSET_REPDATA(reply_base
);
331 for (i
= 0; i
< ETH_SS_COUNT
; i
++) {
332 const struct strset_info
*set_info
= &data
->sets
[i
];
334 if (!strset_include(req_info
, data
, i
))
337 ret
= strset_set_size(set_info
, req_info
->counts_only
);
346 /* fill one string into reply */
347 static int strset_fill_string(struct sk_buff
*skb
,
348 const struct strset_info
*set_info
, u32 idx
)
350 struct nlattr
*string_attr
;
353 value
= set_info
->strings
[idx
];
355 string_attr
= nla_nest_start(skb
, ETHTOOL_A_STRINGS_STRING
);
358 if (nla_put_u32(skb
, ETHTOOL_A_STRING_INDEX
, idx
) ||
359 ethnl_put_strz(skb
, ETHTOOL_A_STRING_VALUE
, value
))
360 goto nla_put_failure
;
361 nla_nest_end(skb
, string_attr
);
365 nla_nest_cancel(skb
, string_attr
);
369 /* fill one string set into reply */
370 static int strset_fill_set(struct sk_buff
*skb
,
371 const struct strset_info
*set_info
, u32 id
,
374 struct nlattr
*stringset_attr
;
375 struct nlattr
*strings_attr
;
378 if (!set_info
->per_dev
&& !set_info
->strings
)
380 if (set_info
->count
== 0)
382 stringset_attr
= nla_nest_start(skb
, ETHTOOL_A_STRINGSETS_STRINGSET
);
386 if (nla_put_u32(skb
, ETHTOOL_A_STRINGSET_ID
, id
) ||
387 nla_put_u32(skb
, ETHTOOL_A_STRINGSET_COUNT
, set_info
->count
))
388 goto nla_put_failure
;
391 strings_attr
= nla_nest_start(skb
, ETHTOOL_A_STRINGSET_STRINGS
);
393 goto nla_put_failure
;
394 for (i
= 0; i
< set_info
->count
; i
++) {
395 if (strset_fill_string(skb
, set_info
, i
) < 0)
396 goto nla_put_failure
;
398 nla_nest_end(skb
, strings_attr
);
401 nla_nest_end(skb
, stringset_attr
);
405 nla_nest_cancel(skb
, stringset_attr
);
409 static int strset_fill_reply(struct sk_buff
*skb
,
410 const struct ethnl_req_info
*req_base
,
411 const struct ethnl_reply_data
*reply_base
)
413 const struct strset_req_info
*req_info
= STRSET_REQINFO(req_base
);
414 const struct strset_reply_data
*data
= STRSET_REPDATA(reply_base
);
419 nest
= nla_nest_start(skb
, ETHTOOL_A_STRSET_STRINGSETS
);
423 for (i
= 0; i
< ETH_SS_COUNT
; i
++) {
424 if (strset_include(req_info
, data
, i
)) {
425 ret
= strset_fill_set(skb
, &data
->sets
[i
], i
,
426 req_info
->counts_only
);
428 goto nla_put_failure
;
432 nla_nest_end(skb
, nest
);
436 nla_nest_cancel(skb
, nest
);
440 const struct ethnl_request_ops ethnl_strset_request_ops
= {
441 .request_cmd
= ETHTOOL_MSG_STRSET_GET
,
442 .reply_cmd
= ETHTOOL_MSG_STRSET_GET_REPLY
,
443 .hdr_attr
= ETHTOOL_A_STRSET_HEADER
,
444 .req_info_size
= sizeof(struct strset_req_info
),
445 .reply_data_size
= sizeof(struct strset_reply_data
),
446 .allow_nodev_do
= true,
448 .parse_request
= strset_parse_request
,
449 .prepare_data
= strset_prepare_data
,
450 .reply_size
= strset_reply_size
,
451 .fill_reply
= strset_fill_reply
,
452 .cleanup_data
= strset_cleanup_data
,