Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include "netlink.h"
  4#include "common.h"
  5#include "bitset.h"
  6
  7struct features_req_info {
  8	struct ethnl_req_info	base;
  9};
 10
 11struct 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];
 18};
 19
 20#define FEATURES_REPDATA(__reply_base) \
 21	container_of(__reply_base, struct features_reply_data, base)
 22
 23const struct nla_policy ethnl_features_get_policy[] = {
 24	[ETHTOOL_A_FEATURES_HEADER]	=
 25		NLA_POLICY_NESTED(ethnl_header_policy),
 26};
 27
 28static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t src)
 29{
 30	unsigned int i;
 31
 32	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++)
 33		dest[i] = src >> (32 * i);
 34}
 35
 36static int features_prepare_data(const struct ethnl_req_info *req_base,
 37				 struct ethnl_reply_data *reply_base,
 38				 const struct genl_info *info)
 39{
 40	struct features_reply_data *data = FEATURES_REPDATA(reply_base);
 41	struct net_device *dev = reply_base->dev;
 42	netdev_features_t all_features;
 43
 44	ethnl_features_to_bitmap32(data->hw, dev->hw_features);
 45	ethnl_features_to_bitmap32(data->wanted, dev->wanted_features);
 46	ethnl_features_to_bitmap32(data->active, dev->features);
 47	ethnl_features_to_bitmap32(data->nochange, NETIF_F_NEVER_CHANGE);
 48	all_features = GENMASK_ULL(NETDEV_FEATURE_COUNT - 1, 0);
 49	ethnl_features_to_bitmap32(data->all, all_features);
 50
 51	return 0;
 52}
 53
 54static int features_reply_size(const struct ethnl_req_info *req_base,
 55			       const struct ethnl_reply_data *reply_base)
 56{
 57	const struct features_reply_data *data = FEATURES_REPDATA(reply_base);
 58	bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
 59	unsigned int len = 0;
 60	int ret;
 61
 62	ret = ethnl_bitset32_size(data->hw, data->all, NETDEV_FEATURE_COUNT,
 63				  netdev_features_strings, compact);
 64	if (ret < 0)
 65		return ret;
 66	len += ret;
 67	ret = ethnl_bitset32_size(data->wanted, NULL, NETDEV_FEATURE_COUNT,
 68				  netdev_features_strings, compact);
 69	if (ret < 0)
 70		return ret;
 71	len += ret;
 72	ret = ethnl_bitset32_size(data->active, NULL, NETDEV_FEATURE_COUNT,
 73				  netdev_features_strings, compact);
 74	if (ret < 0)
 75		return ret;
 76	len += ret;
 77	ret = ethnl_bitset32_size(data->nochange, NULL, NETDEV_FEATURE_COUNT,
 78				  netdev_features_strings, compact);
 79	if (ret < 0)
 80		return ret;
 81	len += ret;
 82
 83	return len;
 84}
 85
 86static int features_fill_reply(struct sk_buff *skb,
 87			       const struct ethnl_req_info *req_base,
 88			       const struct ethnl_reply_data *reply_base)
 89{
 90	const struct features_reply_data *data = FEATURES_REPDATA(reply_base);
 91	bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
 92	int ret;
 93
 94	ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_HW, data->hw,
 95				 data->all, NETDEV_FEATURE_COUNT,
 96				 netdev_features_strings, compact);
 97	if (ret < 0)
 98		return ret;
 99	ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_WANTED, data->wanted,
100				 NULL, NETDEV_FEATURE_COUNT,
101				 netdev_features_strings, compact);
102	if (ret < 0)
103		return ret;
104	ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_ACTIVE, data->active,
105				 NULL, NETDEV_FEATURE_COUNT,
106				 netdev_features_strings, compact);
107	if (ret < 0)
108		return ret;
109	return ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_NOCHANGE,
110				  data->nochange, NULL, NETDEV_FEATURE_COUNT,
111				  netdev_features_strings, compact);
112}
113
114const struct ethnl_request_ops ethnl_features_request_ops = {
115	.request_cmd		= ETHTOOL_MSG_FEATURES_GET,
116	.reply_cmd		= ETHTOOL_MSG_FEATURES_GET_REPLY,
117	.hdr_attr		= ETHTOOL_A_FEATURES_HEADER,
118	.req_info_size		= sizeof(struct features_req_info),
119	.reply_data_size	= sizeof(struct features_reply_data),
120
121	.prepare_data		= features_prepare_data,
122	.reply_size		= features_reply_size,
123	.fill_reply		= features_fill_reply,
124};
125
126/* FEATURES_SET */
127
128const struct nla_policy ethnl_features_set_policy[] = {
129	[ETHTOOL_A_FEATURES_HEADER]	=
130		NLA_POLICY_NESTED(ethnl_header_policy),
131	[ETHTOOL_A_FEATURES_WANTED]	= { .type = NLA_NESTED },
132};
133
134static void ethnl_features_to_bitmap(unsigned long *dest, netdev_features_t val)
135{
136	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
137	unsigned int i;
138
139	for (i = 0; i < words; i++)
140		dest[i] = (unsigned long)(val >> (i * BITS_PER_LONG));
141}
142
143static netdev_features_t ethnl_bitmap_to_features(unsigned long *src)
144{
145	const unsigned int nft_bits = sizeof(netdev_features_t) * BITS_PER_BYTE;
146	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
147	netdev_features_t ret = 0;
148	unsigned int i;
149
150	for (i = 0; i < words; i++)
151		ret |= (netdev_features_t)(src[i]) << (i * BITS_PER_LONG);
152	ret &= ~(netdev_features_t)0 >> (nft_bits - NETDEV_FEATURE_COUNT);
153	return ret;
154}
155
156static int features_send_reply(struct net_device *dev, struct genl_info *info,
157			       const unsigned long *wanted,
158			       const unsigned long *wanted_mask,
159			       const unsigned long *active,
160			       const unsigned long *active_mask, bool compact)
161{
162	struct sk_buff *rskb;
163	void *reply_payload;
164	int reply_len = 0;
165	int ret;
166
167	reply_len = ethnl_reply_header_size();
168	ret = ethnl_bitset_size(wanted, wanted_mask, NETDEV_FEATURE_COUNT,
169				netdev_features_strings, compact);
170	if (ret < 0)
171		goto err;
172	reply_len += ret;
173	ret = ethnl_bitset_size(active, active_mask, NETDEV_FEATURE_COUNT,
174				netdev_features_strings, compact);
175	if (ret < 0)
176		goto err;
177	reply_len += ret;
178
179	ret = -ENOMEM;
180	rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_FEATURES_SET_REPLY,
181				ETHTOOL_A_FEATURES_HEADER, info,
182				&reply_payload);
183	if (!rskb)
184		goto err;
185
186	ret = ethnl_put_bitset(rskb, ETHTOOL_A_FEATURES_WANTED, wanted,
187			       wanted_mask, NETDEV_FEATURE_COUNT,
188			       netdev_features_strings, compact);
189	if (ret < 0)
190		goto nla_put_failure;
191	ret = ethnl_put_bitset(rskb, ETHTOOL_A_FEATURES_ACTIVE, active,
192			       active_mask, NETDEV_FEATURE_COUNT,
193			       netdev_features_strings, compact);
194	if (ret < 0)
195		goto nla_put_failure;
196
197	genlmsg_end(rskb, reply_payload);
198	ret = genlmsg_reply(rskb, info);
199	return ret;
200
201nla_put_failure:
202	nlmsg_free(rskb);
203	WARN_ONCE(1, "calculated message payload length (%d) not sufficient\n",
204		  reply_len);
205err:
206	GENL_SET_ERR_MSG(info, "failed to send reply message");
207	return ret;
208}
209
210int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
211{
212	DECLARE_BITMAP(wanted_diff_mask, NETDEV_FEATURE_COUNT);
213	DECLARE_BITMAP(active_diff_mask, NETDEV_FEATURE_COUNT);
214	DECLARE_BITMAP(old_active, NETDEV_FEATURE_COUNT);
215	DECLARE_BITMAP(old_wanted, NETDEV_FEATURE_COUNT);
216	DECLARE_BITMAP(new_active, NETDEV_FEATURE_COUNT);
217	DECLARE_BITMAP(new_wanted, NETDEV_FEATURE_COUNT);
218	DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT);
219	DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT);
220	struct ethnl_req_info req_info = {};
221	struct nlattr **tb = info->attrs;
222	struct net_device *dev;
223	bool mod;
224	int ret;
225
226	if (!tb[ETHTOOL_A_FEATURES_WANTED])
227		return -EINVAL;
228	ret = ethnl_parse_header_dev_get(&req_info,
229					 tb[ETHTOOL_A_FEATURES_HEADER],
230					 genl_info_net(info), info->extack,
231					 true);
232	if (ret < 0)
233		return ret;
234	dev = req_info.dev;
235
236	rtnl_lock();
237	ret = ethnl_ops_begin(dev);
238	if (ret < 0)
239		goto out_rtnl;
240	ethnl_features_to_bitmap(old_active, dev->features);
241	ethnl_features_to_bitmap(old_wanted, dev->wanted_features);
242	ret = ethnl_parse_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
243				 tb[ETHTOOL_A_FEATURES_WANTED],
244				 netdev_features_strings, info->extack);
245	if (ret < 0)
246		goto out_ops;
247	if (ethnl_bitmap_to_features(req_mask) & ~NETIF_F_ETHTOOL_BITS) {
248		GENL_SET_ERR_MSG(info, "attempt to change non-ethtool features");
249		ret = -EINVAL;
250		goto out_ops;
251	}
252
253	/* set req_wanted bits not in req_mask from old_wanted */
254	bitmap_and(req_wanted, req_wanted, req_mask, NETDEV_FEATURE_COUNT);
255	bitmap_andnot(new_wanted, old_wanted, req_mask, NETDEV_FEATURE_COUNT);
256	bitmap_or(req_wanted, new_wanted, req_wanted, NETDEV_FEATURE_COUNT);
257	if (!bitmap_equal(req_wanted, old_wanted, NETDEV_FEATURE_COUNT)) {
258		dev->wanted_features &= ~dev->hw_features;
259		dev->wanted_features |= ethnl_bitmap_to_features(req_wanted) & dev->hw_features;
260		__netdev_update_features(dev);
261	}
262	ethnl_features_to_bitmap(new_active, dev->features);
263	mod = !bitmap_equal(old_active, new_active, NETDEV_FEATURE_COUNT);
264
265	ret = 0;
266	if (!(req_info.flags & ETHTOOL_FLAG_OMIT_REPLY)) {
267		bool compact = req_info.flags & ETHTOOL_FLAG_COMPACT_BITSETS;
268
269		bitmap_xor(wanted_diff_mask, req_wanted, new_active,
270			   NETDEV_FEATURE_COUNT);
271		bitmap_xor(active_diff_mask, old_active, new_active,
272			   NETDEV_FEATURE_COUNT);
273		bitmap_and(wanted_diff_mask, wanted_diff_mask, req_mask,
274			   NETDEV_FEATURE_COUNT);
275		bitmap_and(req_wanted, req_wanted, wanted_diff_mask,
276			   NETDEV_FEATURE_COUNT);
277		bitmap_and(new_active, new_active, active_diff_mask,
278			   NETDEV_FEATURE_COUNT);
279
280		ret = features_send_reply(dev, info, req_wanted,
281					  wanted_diff_mask, new_active,
282					  active_diff_mask, compact);
283	}
284	if (mod)
285		netdev_features_change(dev);
286
287out_ops:
288	ethnl_ops_complete(dev);
289out_rtnl:
290	rtnl_unlock();
291	ethnl_parse_header_dev_put(&req_info);
292	return ret;
293}
v6.8
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include "netlink.h"
  4#include "common.h"
  5#include "bitset.h"
  6
  7struct features_req_info {
  8	struct ethnl_req_info	base;
  9};
 10
 11struct 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];
 18};
 19
 20#define FEATURES_REPDATA(__reply_base) \
 21	container_of(__reply_base, struct features_reply_data, base)
 22
 23const struct nla_policy ethnl_features_get_policy[] = {
 24	[ETHTOOL_A_FEATURES_HEADER]	=
 25		NLA_POLICY_NESTED(ethnl_header_policy),
 26};
 27
 28static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t src)
 29{
 30	unsigned int i;
 31
 32	for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++)
 33		dest[i] = src >> (32 * i);
 34}
 35
 36static int features_prepare_data(const struct ethnl_req_info *req_base,
 37				 struct ethnl_reply_data *reply_base,
 38				 const struct genl_info *info)
 39{
 40	struct features_reply_data *data = FEATURES_REPDATA(reply_base);
 41	struct net_device *dev = reply_base->dev;
 42	netdev_features_t all_features;
 43
 44	ethnl_features_to_bitmap32(data->hw, dev->hw_features);
 45	ethnl_features_to_bitmap32(data->wanted, dev->wanted_features);
 46	ethnl_features_to_bitmap32(data->active, dev->features);
 47	ethnl_features_to_bitmap32(data->nochange, NETIF_F_NEVER_CHANGE);
 48	all_features = GENMASK_ULL(NETDEV_FEATURE_COUNT - 1, 0);
 49	ethnl_features_to_bitmap32(data->all, all_features);
 50
 51	return 0;
 52}
 53
 54static int features_reply_size(const struct ethnl_req_info *req_base,
 55			       const struct ethnl_reply_data *reply_base)
 56{
 57	const struct features_reply_data *data = FEATURES_REPDATA(reply_base);
 58	bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
 59	unsigned int len = 0;
 60	int ret;
 61
 62	ret = ethnl_bitset32_size(data->hw, data->all, NETDEV_FEATURE_COUNT,
 63				  netdev_features_strings, compact);
 64	if (ret < 0)
 65		return ret;
 66	len += ret;
 67	ret = ethnl_bitset32_size(data->wanted, NULL, NETDEV_FEATURE_COUNT,
 68				  netdev_features_strings, compact);
 69	if (ret < 0)
 70		return ret;
 71	len += ret;
 72	ret = ethnl_bitset32_size(data->active, NULL, NETDEV_FEATURE_COUNT,
 73				  netdev_features_strings, compact);
 74	if (ret < 0)
 75		return ret;
 76	len += ret;
 77	ret = ethnl_bitset32_size(data->nochange, NULL, NETDEV_FEATURE_COUNT,
 78				  netdev_features_strings, compact);
 79	if (ret < 0)
 80		return ret;
 81	len += ret;
 82
 83	return len;
 84}
 85
 86static int features_fill_reply(struct sk_buff *skb,
 87			       const struct ethnl_req_info *req_base,
 88			       const struct ethnl_reply_data *reply_base)
 89{
 90	const struct features_reply_data *data = FEATURES_REPDATA(reply_base);
 91	bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
 92	int ret;
 93
 94	ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_HW, data->hw,
 95				 data->all, NETDEV_FEATURE_COUNT,
 96				 netdev_features_strings, compact);
 97	if (ret < 0)
 98		return ret;
 99	ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_WANTED, data->wanted,
100				 NULL, NETDEV_FEATURE_COUNT,
101				 netdev_features_strings, compact);
102	if (ret < 0)
103		return ret;
104	ret = ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_ACTIVE, data->active,
105				 NULL, NETDEV_FEATURE_COUNT,
106				 netdev_features_strings, compact);
107	if (ret < 0)
108		return ret;
109	return ethnl_put_bitset32(skb, ETHTOOL_A_FEATURES_NOCHANGE,
110				  data->nochange, NULL, NETDEV_FEATURE_COUNT,
111				  netdev_features_strings, compact);
112}
113
114const struct ethnl_request_ops ethnl_features_request_ops = {
115	.request_cmd		= ETHTOOL_MSG_FEATURES_GET,
116	.reply_cmd		= ETHTOOL_MSG_FEATURES_GET_REPLY,
117	.hdr_attr		= ETHTOOL_A_FEATURES_HEADER,
118	.req_info_size		= sizeof(struct features_req_info),
119	.reply_data_size	= sizeof(struct features_reply_data),
120
121	.prepare_data		= features_prepare_data,
122	.reply_size		= features_reply_size,
123	.fill_reply		= features_fill_reply,
124};
125
126/* FEATURES_SET */
127
128const struct nla_policy ethnl_features_set_policy[] = {
129	[ETHTOOL_A_FEATURES_HEADER]	=
130		NLA_POLICY_NESTED(ethnl_header_policy),
131	[ETHTOOL_A_FEATURES_WANTED]	= { .type = NLA_NESTED },
132};
133
134static void ethnl_features_to_bitmap(unsigned long *dest, netdev_features_t val)
135{
136	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
137	unsigned int i;
138
139	for (i = 0; i < words; i++)
140		dest[i] = (unsigned long)(val >> (i * BITS_PER_LONG));
141}
142
143static netdev_features_t ethnl_bitmap_to_features(unsigned long *src)
144{
145	const unsigned int nft_bits = sizeof(netdev_features_t) * BITS_PER_BYTE;
146	const unsigned int words = BITS_TO_LONGS(NETDEV_FEATURE_COUNT);
147	netdev_features_t ret = 0;
148	unsigned int i;
149
150	for (i = 0; i < words; i++)
151		ret |= (netdev_features_t)(src[i]) << (i * BITS_PER_LONG);
152	ret &= ~(netdev_features_t)0 >> (nft_bits - NETDEV_FEATURE_COUNT);
153	return ret;
154}
155
156static int features_send_reply(struct net_device *dev, struct genl_info *info,
157			       const unsigned long *wanted,
158			       const unsigned long *wanted_mask,
159			       const unsigned long *active,
160			       const unsigned long *active_mask, bool compact)
161{
162	struct sk_buff *rskb;
163	void *reply_payload;
164	int reply_len = 0;
165	int ret;
166
167	reply_len = ethnl_reply_header_size();
168	ret = ethnl_bitset_size(wanted, wanted_mask, NETDEV_FEATURE_COUNT,
169				netdev_features_strings, compact);
170	if (ret < 0)
171		goto err;
172	reply_len += ret;
173	ret = ethnl_bitset_size(active, active_mask, NETDEV_FEATURE_COUNT,
174				netdev_features_strings, compact);
175	if (ret < 0)
176		goto err;
177	reply_len += ret;
178
179	ret = -ENOMEM;
180	rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_FEATURES_SET_REPLY,
181				ETHTOOL_A_FEATURES_HEADER, info,
182				&reply_payload);
183	if (!rskb)
184		goto err;
185
186	ret = ethnl_put_bitset(rskb, ETHTOOL_A_FEATURES_WANTED, wanted,
187			       wanted_mask, NETDEV_FEATURE_COUNT,
188			       netdev_features_strings, compact);
189	if (ret < 0)
190		goto nla_put_failure;
191	ret = ethnl_put_bitset(rskb, ETHTOOL_A_FEATURES_ACTIVE, active,
192			       active_mask, NETDEV_FEATURE_COUNT,
193			       netdev_features_strings, compact);
194	if (ret < 0)
195		goto nla_put_failure;
196
197	genlmsg_end(rskb, reply_payload);
198	ret = genlmsg_reply(rskb, info);
199	return ret;
200
201nla_put_failure:
202	nlmsg_free(rskb);
203	WARN_ONCE(1, "calculated message payload length (%d) not sufficient\n",
204		  reply_len);
205err:
206	GENL_SET_ERR_MSG(info, "failed to send reply message");
207	return ret;
208}
209
210int ethnl_set_features(struct sk_buff *skb, struct genl_info *info)
211{
212	DECLARE_BITMAP(wanted_diff_mask, NETDEV_FEATURE_COUNT);
213	DECLARE_BITMAP(active_diff_mask, NETDEV_FEATURE_COUNT);
214	DECLARE_BITMAP(old_active, NETDEV_FEATURE_COUNT);
215	DECLARE_BITMAP(old_wanted, NETDEV_FEATURE_COUNT);
216	DECLARE_BITMAP(new_active, NETDEV_FEATURE_COUNT);
217	DECLARE_BITMAP(new_wanted, NETDEV_FEATURE_COUNT);
218	DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT);
219	DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT);
220	struct ethnl_req_info req_info = {};
221	struct nlattr **tb = info->attrs;
222	struct net_device *dev;
223	bool mod;
224	int ret;
225
226	if (!tb[ETHTOOL_A_FEATURES_WANTED])
227		return -EINVAL;
228	ret = ethnl_parse_header_dev_get(&req_info,
229					 tb[ETHTOOL_A_FEATURES_HEADER],
230					 genl_info_net(info), info->extack,
231					 true);
232	if (ret < 0)
233		return ret;
234	dev = req_info.dev;
235
236	rtnl_lock();
237	ret = ethnl_ops_begin(dev);
238	if (ret < 0)
239		goto out_rtnl;
240	ethnl_features_to_bitmap(old_active, dev->features);
241	ethnl_features_to_bitmap(old_wanted, dev->wanted_features);
242	ret = ethnl_parse_bitset(req_wanted, req_mask, NETDEV_FEATURE_COUNT,
243				 tb[ETHTOOL_A_FEATURES_WANTED],
244				 netdev_features_strings, info->extack);
245	if (ret < 0)
246		goto out_ops;
247	if (ethnl_bitmap_to_features(req_mask) & ~NETIF_F_ETHTOOL_BITS) {
248		GENL_SET_ERR_MSG(info, "attempt to change non-ethtool features");
249		ret = -EINVAL;
250		goto out_ops;
251	}
252
253	/* set req_wanted bits not in req_mask from old_wanted */
254	bitmap_and(req_wanted, req_wanted, req_mask, NETDEV_FEATURE_COUNT);
255	bitmap_andnot(new_wanted, old_wanted, req_mask, NETDEV_FEATURE_COUNT);
256	bitmap_or(req_wanted, new_wanted, req_wanted, NETDEV_FEATURE_COUNT);
257	if (!bitmap_equal(req_wanted, old_wanted, NETDEV_FEATURE_COUNT)) {
258		dev->wanted_features &= ~dev->hw_features;
259		dev->wanted_features |= ethnl_bitmap_to_features(req_wanted) & dev->hw_features;
260		__netdev_update_features(dev);
261	}
262	ethnl_features_to_bitmap(new_active, dev->features);
263	mod = !bitmap_equal(old_active, new_active, NETDEV_FEATURE_COUNT);
264
265	ret = 0;
266	if (!(req_info.flags & ETHTOOL_FLAG_OMIT_REPLY)) {
267		bool compact = req_info.flags & ETHTOOL_FLAG_COMPACT_BITSETS;
268
269		bitmap_xor(wanted_diff_mask, req_wanted, new_active,
270			   NETDEV_FEATURE_COUNT);
271		bitmap_xor(active_diff_mask, old_active, new_active,
272			   NETDEV_FEATURE_COUNT);
273		bitmap_and(wanted_diff_mask, wanted_diff_mask, req_mask,
274			   NETDEV_FEATURE_COUNT);
275		bitmap_and(req_wanted, req_wanted, wanted_diff_mask,
276			   NETDEV_FEATURE_COUNT);
277		bitmap_and(new_active, new_active, active_diff_mask,
278			   NETDEV_FEATURE_COUNT);
279
280		ret = features_send_reply(dev, info, req_wanted,
281					  wanted_diff_mask, new_active,
282					  active_diff_mask, compact);
283	}
284	if (mod)
285		netdev_features_change(dev);
286
287out_ops:
288	ethnl_ops_complete(dev);
289out_rtnl:
290	rtnl_unlock();
291	ethnl_parse_header_dev_put(&req_info);
292	return ret;
293}