1 // SPDX-License-Identifier: GPL-2.0-only
7 struct features_req_info
{
8 struct ethnl_req_info base
;
11 struct features_reply_data
{
12 struct ethnl_reply_data base
;
13 u32 hw
[ETHTOOL_DEV_FEATURE_WORDS
];
14 u32 wanted
[ETHTOOL_DEV_FEATURE_WORDS
];
15 u32 active
[ETHTOOL_DEV_FEATURE_WORDS
];
16 u32 nochange
[ETHTOOL_DEV_FEATURE_WORDS
];
17 u32 all
[ETHTOOL_DEV_FEATURE_WORDS
];
20 #define FEATURES_REPDATA(__reply_base) \
21 container_of(__reply_base, struct features_reply_data, base)
23 static const struct nla_policy
24 features_get_policy
[ETHTOOL_A_FEATURES_MAX
+ 1] = {
25 [ETHTOOL_A_FEATURES_UNSPEC
] = { .type
= NLA_REJECT
},
26 [ETHTOOL_A_FEATURES_HEADER
] = { .type
= NLA_NESTED
},
27 [ETHTOOL_A_FEATURES_HW
] = { .type
= NLA_REJECT
},
28 [ETHTOOL_A_FEATURES_WANTED
] = { .type
= NLA_REJECT
},
29 [ETHTOOL_A_FEATURES_ACTIVE
] = { .type
= NLA_REJECT
},
30 [ETHTOOL_A_FEATURES_NOCHANGE
] = { .type
= NLA_REJECT
},
33 static void ethnl_features_to_bitmap32(u32
*dest
, netdev_features_t src
)
37 for (i
= 0; i
< ETHTOOL_DEV_FEATURE_WORDS
; i
++)
38 dest
[i
] = src
>> (32 * i
);
41 static int features_prepare_data(const struct ethnl_req_info
*req_base
,
42 struct ethnl_reply_data
*reply_base
,
43 struct genl_info
*info
)
45 struct features_reply_data
*data
= FEATURES_REPDATA(reply_base
);
46 struct net_device
*dev
= reply_base
->dev
;
47 netdev_features_t all_features
;
49 ethnl_features_to_bitmap32(data
->hw
, dev
->hw_features
);
50 ethnl_features_to_bitmap32(data
->wanted
, dev
->wanted_features
);
51 ethnl_features_to_bitmap32(data
->active
, dev
->features
);
52 ethnl_features_to_bitmap32(data
->nochange
, NETIF_F_NEVER_CHANGE
);
53 all_features
= GENMASK_ULL(NETDEV_FEATURE_COUNT
- 1, 0);
54 ethnl_features_to_bitmap32(data
->all
, all_features
);
59 static int features_reply_size(const struct ethnl_req_info
*req_base
,
60 const struct ethnl_reply_data
*reply_base
)
62 const struct features_reply_data
*data
= FEATURES_REPDATA(reply_base
);
63 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
67 ret
= ethnl_bitset32_size(data
->hw
, data
->all
, NETDEV_FEATURE_COUNT
,
68 netdev_features_strings
, compact
);
72 ret
= ethnl_bitset32_size(data
->wanted
, NULL
, NETDEV_FEATURE_COUNT
,
73 netdev_features_strings
, compact
);
77 ret
= ethnl_bitset32_size(data
->active
, NULL
, NETDEV_FEATURE_COUNT
,
78 netdev_features_strings
, compact
);
82 ret
= ethnl_bitset32_size(data
->nochange
, NULL
, NETDEV_FEATURE_COUNT
,
83 netdev_features_strings
, compact
);
91 static int features_fill_reply(struct sk_buff
*skb
,
92 const struct ethnl_req_info
*req_base
,
93 const struct ethnl_reply_data
*reply_base
)
95 const struct features_reply_data
*data
= FEATURES_REPDATA(reply_base
);
96 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
99 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_FEATURES_HW
, data
->hw
,
100 data
->all
, NETDEV_FEATURE_COUNT
,
101 netdev_features_strings
, compact
);
104 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_FEATURES_WANTED
, data
->wanted
,
105 NULL
, NETDEV_FEATURE_COUNT
,
106 netdev_features_strings
, compact
);
109 ret
= ethnl_put_bitset32(skb
, ETHTOOL_A_FEATURES_ACTIVE
, data
->active
,
110 NULL
, NETDEV_FEATURE_COUNT
,
111 netdev_features_strings
, compact
);
114 return ethnl_put_bitset32(skb
, ETHTOOL_A_FEATURES_NOCHANGE
,
115 data
->nochange
, NULL
, NETDEV_FEATURE_COUNT
,
116 netdev_features_strings
, compact
);
119 const struct ethnl_request_ops ethnl_features_request_ops
= {
120 .request_cmd
= ETHTOOL_MSG_FEATURES_GET
,
121 .reply_cmd
= ETHTOOL_MSG_FEATURES_GET_REPLY
,
122 .hdr_attr
= ETHTOOL_A_FEATURES_HEADER
,
123 .max_attr
= ETHTOOL_A_FEATURES_MAX
,
124 .req_info_size
= sizeof(struct features_req_info
),
125 .reply_data_size
= sizeof(struct features_reply_data
),
126 .request_policy
= features_get_policy
,
128 .prepare_data
= features_prepare_data
,
129 .reply_size
= features_reply_size
,
130 .fill_reply
= features_fill_reply
,
135 static const struct nla_policy
136 features_set_policy
[ETHTOOL_A_FEATURES_MAX
+ 1] = {
137 [ETHTOOL_A_FEATURES_UNSPEC
] = { .type
= NLA_REJECT
},
138 [ETHTOOL_A_FEATURES_HEADER
] = { .type
= NLA_NESTED
},
139 [ETHTOOL_A_FEATURES_HW
] = { .type
= NLA_REJECT
},
140 [ETHTOOL_A_FEATURES_WANTED
] = { .type
= NLA_NESTED
},
141 [ETHTOOL_A_FEATURES_ACTIVE
] = { .type
= NLA_REJECT
},
142 [ETHTOOL_A_FEATURES_NOCHANGE
] = { .type
= NLA_REJECT
},
145 static void ethnl_features_to_bitmap(unsigned long *dest
, netdev_features_t val
)
147 const unsigned int words
= BITS_TO_LONGS(NETDEV_FEATURE_COUNT
);
150 bitmap_zero(dest
, NETDEV_FEATURE_COUNT
);
151 for (i
= 0; i
< words
; i
++)
152 dest
[i
] = (unsigned long)(val
>> (i
* BITS_PER_LONG
));
155 static netdev_features_t
ethnl_bitmap_to_features(unsigned long *src
)
157 const unsigned int nft_bits
= sizeof(netdev_features_t
) * BITS_PER_BYTE
;
158 const unsigned int words
= BITS_TO_LONGS(NETDEV_FEATURE_COUNT
);
159 netdev_features_t ret
= 0;
162 for (i
= 0; i
< words
; i
++)
163 ret
|= (netdev_features_t
)(src
[i
]) << (i
* BITS_PER_LONG
);
164 ret
&= ~(netdev_features_t
)0 >> (nft_bits
- NETDEV_FEATURE_COUNT
);
168 static int features_send_reply(struct net_device
*dev
, struct genl_info
*info
,
169 const unsigned long *wanted
,
170 const unsigned long *wanted_mask
,
171 const unsigned long *active
,
172 const unsigned long *active_mask
, bool compact
)
174 struct sk_buff
*rskb
;
179 reply_len
= ethnl_reply_header_size();
180 ret
= ethnl_bitset_size(wanted
, wanted_mask
, NETDEV_FEATURE_COUNT
,
181 netdev_features_strings
, compact
);
185 ret
= ethnl_bitset_size(active
, active_mask
, NETDEV_FEATURE_COUNT
,
186 netdev_features_strings
, compact
);
192 rskb
= ethnl_reply_init(reply_len
, dev
, ETHTOOL_MSG_FEATURES_SET_REPLY
,
193 ETHTOOL_A_FEATURES_HEADER
, info
,
198 ret
= ethnl_put_bitset(rskb
, ETHTOOL_A_FEATURES_WANTED
, wanted
,
199 wanted_mask
, NETDEV_FEATURE_COUNT
,
200 netdev_features_strings
, compact
);
202 goto nla_put_failure
;
203 ret
= ethnl_put_bitset(rskb
, ETHTOOL_A_FEATURES_ACTIVE
, active
,
204 active_mask
, NETDEV_FEATURE_COUNT
,
205 netdev_features_strings
, compact
);
207 goto nla_put_failure
;
209 genlmsg_end(rskb
, reply_payload
);
210 ret
= genlmsg_reply(rskb
, info
);
215 WARN_ONCE(1, "calculated message payload length (%d) not sufficient\n",
218 GENL_SET_ERR_MSG(info
, "failed to send reply message");
222 int ethnl_set_features(struct sk_buff
*skb
, struct genl_info
*info
)
224 DECLARE_BITMAP(wanted_diff_mask
, NETDEV_FEATURE_COUNT
);
225 DECLARE_BITMAP(active_diff_mask
, NETDEV_FEATURE_COUNT
);
226 DECLARE_BITMAP(old_active
, NETDEV_FEATURE_COUNT
);
227 DECLARE_BITMAP(new_active
, NETDEV_FEATURE_COUNT
);
228 DECLARE_BITMAP(req_wanted
, NETDEV_FEATURE_COUNT
);
229 DECLARE_BITMAP(req_mask
, NETDEV_FEATURE_COUNT
);
230 struct nlattr
*tb
[ETHTOOL_A_FEATURES_MAX
+ 1];
231 struct ethnl_req_info req_info
= {};
232 struct net_device
*dev
;
236 ret
= nlmsg_parse(info
->nlhdr
, GENL_HDRLEN
, tb
,
237 ETHTOOL_A_FEATURES_MAX
, features_set_policy
,
241 if (!tb
[ETHTOOL_A_FEATURES_WANTED
])
243 ret
= ethnl_parse_header_dev_get(&req_info
,
244 tb
[ETHTOOL_A_FEATURES_HEADER
],
245 genl_info_net(info
), info
->extack
,
252 ethnl_features_to_bitmap(old_active
, dev
->features
);
253 ret
= ethnl_parse_bitset(req_wanted
, req_mask
, NETDEV_FEATURE_COUNT
,
254 tb
[ETHTOOL_A_FEATURES_WANTED
],
255 netdev_features_strings
, info
->extack
);
258 if (ethnl_bitmap_to_features(req_mask
) & ~NETIF_F_ETHTOOL_BITS
) {
259 GENL_SET_ERR_MSG(info
, "attempt to change non-ethtool features");
264 /* set req_wanted bits not in req_mask from old_active */
265 bitmap_and(req_wanted
, req_wanted
, req_mask
, NETDEV_FEATURE_COUNT
);
266 bitmap_andnot(new_active
, old_active
, req_mask
, NETDEV_FEATURE_COUNT
);
267 bitmap_or(req_wanted
, new_active
, req_wanted
, NETDEV_FEATURE_COUNT
);
268 if (bitmap_equal(req_wanted
, old_active
, NETDEV_FEATURE_COUNT
)) {
273 dev
->wanted_features
= ethnl_bitmap_to_features(req_wanted
);
274 __netdev_update_features(dev
);
275 ethnl_features_to_bitmap(new_active
, dev
->features
);
276 mod
= !bitmap_equal(old_active
, new_active
, NETDEV_FEATURE_COUNT
);
279 if (!(req_info
.flags
& ETHTOOL_FLAG_OMIT_REPLY
)) {
280 bool compact
= req_info
.flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
282 bitmap_xor(wanted_diff_mask
, req_wanted
, new_active
,
283 NETDEV_FEATURE_COUNT
);
284 bitmap_xor(active_diff_mask
, old_active
, new_active
,
285 NETDEV_FEATURE_COUNT
);
286 bitmap_and(wanted_diff_mask
, wanted_diff_mask
, req_mask
,
287 NETDEV_FEATURE_COUNT
);
288 bitmap_and(req_wanted
, req_wanted
, wanted_diff_mask
,
289 NETDEV_FEATURE_COUNT
);
290 bitmap_and(new_active
, new_active
, active_diff_mask
,
291 NETDEV_FEATURE_COUNT
);
293 ret
= features_send_reply(dev
, info
, req_wanted
,
294 wanted_diff_mask
, new_active
,
295 active_diff_mask
, compact
);
298 ethtool_notify(dev
, ETHTOOL_MSG_FEATURES_NTF
, NULL
);