Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : :
3 : : #include <linux/ethtool_netlink.h>
4 : : #include <linux/bitmap.h>
5 : : #include "netlink.h"
6 : : #include "bitset.h"
7 : :
8 : : /* Some bitmaps are internally represented as an array of unsigned long, some
9 : : * as an array of u32 (some even as single u32 for now). To avoid the need of
10 : : * wrappers on caller side, we provide two set of functions: those with "32"
11 : : * suffix in their names expect u32 based bitmaps, those without it expect
12 : : * unsigned long bitmaps.
13 : : */
14 : :
15 : 0 : static u32 ethnl_lower_bits(unsigned int n)
16 : : {
17 : 0 : return ~(u32)0 >> (32 - n % 32);
18 : : }
19 : :
20 : 0 : static u32 ethnl_upper_bits(unsigned int n)
21 : : {
22 : 0 : return ~(u32)0 << (n % 32);
23 : : }
24 : :
25 : : /**
26 : : * ethnl_bitmap32_clear() - Clear u32 based bitmap
27 : : * @dst: bitmap to clear
28 : : * @start: beginning of the interval
29 : : * @end: end of the interval
30 : : * @mod: set if bitmap was modified
31 : : *
32 : : * Clear @nbits bits of a bitmap with indices @start <= i < @end
33 : : */
34 : 0 : static void ethnl_bitmap32_clear(u32 *dst, unsigned int start, unsigned int end,
35 : : bool *mod)
36 : : {
37 : 0 : unsigned int start_word = start / 32;
38 : 0 : unsigned int end_word = end / 32;
39 : 0 : unsigned int i;
40 : 0 : u32 mask;
41 : :
42 [ # # ]: 0 : if (end <= start)
43 : : return;
44 : :
45 [ # # ]: 0 : if (start % 32) {
46 : 0 : mask = ethnl_upper_bits(start);
47 [ # # ]: 0 : if (end_word == start_word) {
48 : 0 : mask &= ethnl_lower_bits(end);
49 [ # # ]: 0 : if (dst[start_word] & mask) {
50 : 0 : dst[start_word] &= ~mask;
51 : 0 : *mod = true;
52 : : }
53 : 0 : return;
54 : : }
55 [ # # ]: 0 : if (dst[start_word] & mask) {
56 : 0 : dst[start_word] &= ~mask;
57 : 0 : *mod = true;
58 : : }
59 : 0 : start_word++;
60 : : }
61 : :
62 [ # # ]: 0 : for (i = start_word; i < end_word; i++) {
63 [ # # ]: 0 : if (dst[i]) {
64 : 0 : dst[i] = 0;
65 : 0 : *mod = true;
66 : : }
67 : : }
68 [ # # ]: 0 : if (end % 32) {
69 : 0 : mask = ethnl_lower_bits(end);
70 [ # # ]: 0 : if (dst[end_word] & mask) {
71 : 0 : dst[end_word] &= ~mask;
72 : 0 : *mod = true;
73 : : }
74 : : }
75 : : }
76 : :
77 : : /**
78 : : * ethnl_bitmap32_not_zero() - Check if any bit is set in an interval
79 : : * @map: bitmap to test
80 : : * @start: beginning of the interval
81 : : * @end: end of the interval
82 : : *
83 : : * Return: true if there is non-zero bit with index @start <= i < @end,
84 : : * false if the whole interval is zero
85 : : */
86 : 0 : static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start,
87 : : unsigned int end)
88 : : {
89 : 0 : unsigned int start_word = start / 32;
90 : 0 : unsigned int end_word = end / 32;
91 : 0 : u32 mask;
92 : :
93 [ # # ]: 0 : if (end <= start)
94 : : return true;
95 : :
96 [ # # ]: 0 : if (start % 32) {
97 : 0 : mask = ethnl_upper_bits(start);
98 [ # # ]: 0 : if (end_word == start_word) {
99 : 0 : mask &= ethnl_lower_bits(end);
100 : 0 : return map[start_word] & mask;
101 : : }
102 [ # # ]: 0 : if (map[start_word] & mask)
103 : : return true;
104 : 0 : start_word++;
105 : : }
106 : :
107 [ # # ]: 0 : if (!memchr_inv(map + start_word, '\0',
108 : 0 : (end_word - start_word) * sizeof(u32)))
109 : : return true;
110 [ # # ]: 0 : if (end % 32 == 0)
111 : : return true;
112 : 0 : return map[end_word] & ethnl_lower_bits(end);
113 : : }
114 : :
115 : : /**
116 : : * ethnl_bitmap32_update() - Modify u32 based bitmap according to value/mask
117 : : * pair
118 : : * @dst: bitmap to update
119 : : * @nbits: bit size of the bitmap
120 : : * @value: values to set
121 : : * @mask: mask of bits to set
122 : : * @mod: set to true if bitmap is modified, preserve if not
123 : : *
124 : : * Set bits in @dst bitmap which are set in @mask to values from @value, leave
125 : : * the rest untouched. If destination bitmap was modified, set @mod to true,
126 : : * leave as it is if not.
127 : : */
128 : 0 : static void ethnl_bitmap32_update(u32 *dst, unsigned int nbits,
129 : : const u32 *value, const u32 *mask, bool *mod)
130 : : {
131 [ # # ]: 0 : while (nbits > 0) {
132 [ # # ]: 0 : u32 real_mask = mask ? *mask : ~(u32)0;
133 : 0 : u32 new_value;
134 : :
135 [ # # ]: 0 : if (nbits < 32)
136 : 0 : real_mask &= ethnl_lower_bits(nbits);
137 : 0 : new_value = (*dst & ~real_mask) | (*value & real_mask);
138 [ # # ]: 0 : if (new_value != *dst) {
139 : 0 : *dst = new_value;
140 : 0 : *mod = true;
141 : : }
142 : :
143 [ # # ]: 0 : if (nbits <= 32)
144 : : break;
145 : 0 : dst++;
146 : 0 : nbits -= 32;
147 : 0 : value++;
148 [ # # ]: 0 : if (mask)
149 : 0 : mask++;
150 : : }
151 : 0 : }
152 : :
153 : 0 : static bool ethnl_bitmap32_test_bit(const u32 *map, unsigned int index)
154 : : {
155 : 0 : return map[index / 32] & (1U << (index % 32));
156 : : }
157 : :
158 : : /**
159 : : * ethnl_bitset32_size() - Calculate size of bitset nested attribute
160 : : * @val: value bitmap (u32 based)
161 : : * @mask: mask bitmap (u32 based, optional)
162 : : * @nbits: bit length of the bitset
163 : : * @names: array of bit names (optional)
164 : : * @compact: assume compact format for output
165 : : *
166 : : * Estimate length of netlink attribute composed by a later call to
167 : : * ethnl_put_bitset32() call with the same arguments.
168 : : *
169 : : * Return: negative error code or attribute length estimate
170 : : */
171 : 0 : int ethnl_bitset32_size(const u32 *val, const u32 *mask, unsigned int nbits,
172 : : ethnl_string_array_t names, bool compact)
173 : : {
174 : 0 : unsigned int len = 0;
175 : :
176 : : /* list flag */
177 [ # # ]: 0 : if (!mask)
178 : 0 : len += nla_total_size(sizeof(u32));
179 : : /* size */
180 [ # # ]: 0 : len += nla_total_size(sizeof(u32));
181 : :
182 [ # # ]: 0 : if (compact) {
183 : 0 : unsigned int nwords = DIV_ROUND_UP(nbits, 32);
184 : :
185 : : /* value, mask */
186 [ # # ]: 0 : len += (mask ? 2 : 1) * nla_total_size(nwords * sizeof(u32));
187 : : } else {
188 : : unsigned int bits_len = 0;
189 : : unsigned int bit_len, i;
190 : :
191 [ # # ]: 0 : for (i = 0; i < nbits; i++) {
192 [ # # ]: 0 : const char *name = names ? names[i] : NULL;
193 : :
194 [ # # # # ]: 0 : if (!ethnl_bitmap32_test_bit(mask ?: val, i))
195 : 0 : continue;
196 : : /* index */
197 [ # # ]: 0 : bit_len = nla_total_size(sizeof(u32));
198 : : /* name */
199 [ # # ]: 0 : if (name)
200 : 0 : bit_len += ethnl_strz_size(name);
201 : : /* value */
202 [ # # # # ]: 0 : if (mask && ethnl_bitmap32_test_bit(val, i))
203 : 0 : bit_len += nla_total_size(0);
204 : :
205 : : /* bit nest */
206 : 0 : bits_len += nla_total_size(bit_len);
207 : : }
208 : : /* bits nest */
209 : 0 : len += nla_total_size(bits_len);
210 : : }
211 : :
212 : : /* outermost nest */
213 : 0 : return nla_total_size(len);
214 : : }
215 : :
216 : : /**
217 : : * ethnl_put_bitset32() - Put a bitset nest into a message
218 : : * @skb: skb with the message
219 : : * @attrtype: attribute type for the bitset nest
220 : : * @val: value bitmap (u32 based)
221 : : * @mask: mask bitmap (u32 based, optional)
222 : : * @nbits: bit length of the bitset
223 : : * @names: array of bit names (optional)
224 : : * @compact: use compact format for the output
225 : : *
226 : : * Compose a nested attribute representing a bitset. If @mask is null, simple
227 : : * bitmap (bit list) is created, if @mask is provided, represent a value/mask
228 : : * pair. Bit names are only used in verbose mode and when provided by calller.
229 : : *
230 : : * Return: 0 on success, negative error value on error
231 : : */
232 : 0 : int ethnl_put_bitset32(struct sk_buff *skb, int attrtype, const u32 *val,
233 : : const u32 *mask, unsigned int nbits,
234 : : ethnl_string_array_t names, bool compact)
235 : : {
236 : 0 : struct nlattr *nest;
237 : 0 : struct nlattr *attr;
238 : :
239 : 0 : nest = nla_nest_start(skb, attrtype);
240 [ # # ]: 0 : if (!nest)
241 : : return -EMSGSIZE;
242 : :
243 [ # # # # ]: 0 : if (!mask && nla_put_flag(skb, ETHTOOL_A_BITSET_NOMASK))
244 : 0 : goto nla_put_failure;
245 [ # # ]: 0 : if (nla_put_u32(skb, ETHTOOL_A_BITSET_SIZE, nbits))
246 : 0 : goto nla_put_failure;
247 [ # # ]: 0 : if (compact) {
248 : 0 : unsigned int nwords = DIV_ROUND_UP(nbits, 32);
249 : 0 : unsigned int nbytes = nwords * sizeof(u32);
250 : 0 : u32 *dst;
251 : :
252 : 0 : attr = nla_reserve(skb, ETHTOOL_A_BITSET_VALUE, nbytes);
253 [ # # ]: 0 : if (!attr)
254 : 0 : goto nla_put_failure;
255 [ # # ]: 0 : dst = nla_data(attr);
256 : 0 : memcpy(dst, val, nbytes);
257 [ # # ]: 0 : if (nbits % 32)
258 : 0 : dst[nwords - 1] &= ethnl_lower_bits(nbits);
259 : :
260 [ # # ]: 0 : if (mask) {
261 : 0 : attr = nla_reserve(skb, ETHTOOL_A_BITSET_MASK, nbytes);
262 [ # # ]: 0 : if (!attr)
263 : 0 : goto nla_put_failure;
264 [ # # ]: 0 : dst = nla_data(attr);
265 : 0 : memcpy(dst, mask, nbytes);
266 [ # # ]: 0 : if (nbits % 32)
267 : 0 : dst[nwords - 1] &= ethnl_lower_bits(nbits);
268 : : }
269 : : } else {
270 : 0 : struct nlattr *bits;
271 : 0 : unsigned int i;
272 : :
273 : 0 : bits = nla_nest_start(skb, ETHTOOL_A_BITSET_BITS);
274 [ # # ]: 0 : if (!bits)
275 : 0 : goto nla_put_failure;
276 [ # # ]: 0 : for (i = 0; i < nbits; i++) {
277 [ # # ]: 0 : const char *name = names ? names[i] : NULL;
278 : :
279 [ # # # # ]: 0 : if (!ethnl_bitmap32_test_bit(mask ?: val, i))
280 : 0 : continue;
281 : 0 : attr = nla_nest_start(skb, ETHTOOL_A_BITSET_BITS_BIT);
282 [ # # ]: 0 : if (!attr)
283 : 0 : goto nla_put_failure;
284 [ # # ]: 0 : if (nla_put_u32(skb, ETHTOOL_A_BITSET_BIT_INDEX, i))
285 : 0 : goto nla_put_failure;
286 [ # # # # ]: 0 : if (name &&
287 : 0 : ethnl_put_strz(skb, ETHTOOL_A_BITSET_BIT_NAME, name))
288 : 0 : goto nla_put_failure;
289 [ # # # # : 0 : if (mask && ethnl_bitmap32_test_bit(val, i) &&
# # ]
290 : : nla_put_flag(skb, ETHTOOL_A_BITSET_BIT_VALUE))
291 : 0 : goto nla_put_failure;
292 : 0 : nla_nest_end(skb, attr);
293 : : }
294 : 0 : nla_nest_end(skb, bits);
295 : : }
296 : :
297 : 0 : nla_nest_end(skb, nest);
298 : 0 : return 0;
299 : :
300 : 0 : nla_put_failure:
301 : 0 : nla_nest_cancel(skb, nest);
302 : 0 : return -EMSGSIZE;
303 : : }
304 : :
305 : : static const struct nla_policy bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = {
306 : : [ETHTOOL_A_BITSET_UNSPEC] = { .type = NLA_REJECT },
307 : : [ETHTOOL_A_BITSET_NOMASK] = { .type = NLA_FLAG },
308 : : [ETHTOOL_A_BITSET_SIZE] = NLA_POLICY_MAX(NLA_U32,
309 : : ETHNL_MAX_BITSET_SIZE),
310 : : [ETHTOOL_A_BITSET_BITS] = { .type = NLA_NESTED },
311 : : [ETHTOOL_A_BITSET_VALUE] = { .type = NLA_BINARY },
312 : : [ETHTOOL_A_BITSET_MASK] = { .type = NLA_BINARY },
313 : : };
314 : :
315 : : static const struct nla_policy bit_policy[ETHTOOL_A_BITSET_BIT_MAX + 1] = {
316 : : [ETHTOOL_A_BITSET_BIT_UNSPEC] = { .type = NLA_REJECT },
317 : : [ETHTOOL_A_BITSET_BIT_INDEX] = { .type = NLA_U32 },
318 : : [ETHTOOL_A_BITSET_BIT_NAME] = { .type = NLA_NUL_STRING },
319 : : [ETHTOOL_A_BITSET_BIT_VALUE] = { .type = NLA_FLAG },
320 : : };
321 : :
322 : : /**
323 : : * ethnl_bitset_is_compact() - check if bitset attribute represents a compact
324 : : * bitset
325 : : * @bitset: nested attribute representing a bitset
326 : : * @compact: pointer for return value
327 : : *
328 : : * Return: 0 on success, negative error code on failure
329 : : */
330 : 0 : int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact)
331 : : {
332 : 0 : struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1];
333 : 0 : int ret;
334 : :
335 [ # # ]: 0 : ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, bitset,
336 : : bitset_policy, NULL);
337 [ # # ]: 0 : if (ret < 0)
338 : 0 : return ret;
339 : :
340 [ # # ]: 0 : if (tb[ETHTOOL_A_BITSET_BITS]) {
341 [ # # # # ]: 0 : if (tb[ETHTOOL_A_BITSET_VALUE] || tb[ETHTOOL_A_BITSET_MASK])
342 : : return -EINVAL;
343 : 0 : *compact = false;
344 : 0 : return 0;
345 : : }
346 [ # # # # ]: 0 : if (!tb[ETHTOOL_A_BITSET_SIZE] || !tb[ETHTOOL_A_BITSET_VALUE])
347 : : return -EINVAL;
348 : :
349 : 0 : *compact = true;
350 : 0 : return 0;
351 : : }
352 : :
353 : : /**
354 : : * ethnl_name_to_idx() - look up string index for a name
355 : : * @names: array of ETH_GSTRING_LEN sized strings
356 : : * @n_names: number of strings in the array
357 : : * @name: name to look up
358 : : *
359 : : * Return: index of the string if found, -ENOENT if not found
360 : : */
361 : 0 : static int ethnl_name_to_idx(ethnl_string_array_t names, unsigned int n_names,
362 : : const char *name)
363 : : {
364 : 0 : unsigned int i;
365 : :
366 [ # # ]: 0 : if (!names)
367 : : return -ENOENT;
368 : :
369 [ # # ]: 0 : for (i = 0; i < n_names; i++) {
370 : : /* names[i] may not be null terminated */
371 [ # # ]: 0 : if (!strncmp(names[i], name, ETH_GSTRING_LEN) &&
372 [ # # ]: 0 : strlen(name) <= ETH_GSTRING_LEN)
373 : 0 : return i;
374 : : }
375 : :
376 : : return -ENOENT;
377 : : }
378 : :
379 : 0 : static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,
380 : : const struct nlattr *bit_attr, bool no_mask,
381 : : ethnl_string_array_t names,
382 : : struct netlink_ext_ack *extack)
383 : : {
384 : 0 : struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1];
385 : 0 : int ret, idx;
386 : :
387 : 0 : ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_BIT_MAX, bit_attr,
388 : : bit_policy, extack);
389 [ # # ]: 0 : if (ret < 0)
390 : : return ret;
391 : :
392 [ # # ]: 0 : if (tb[ETHTOOL_A_BITSET_BIT_INDEX]) {
393 : 0 : const char *name;
394 : :
395 [ # # ]: 0 : idx = nla_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);
396 [ # # ]: 0 : if (idx >= nbits) {
397 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack,
398 : : tb[ETHTOOL_A_BITSET_BIT_INDEX],
399 : : "bit index too high");
400 : 0 : return -EOPNOTSUPP;
401 : : }
402 [ # # ]: 0 : name = names ? names[idx] : NULL;
403 [ # # # # : 0 : if (tb[ETHTOOL_A_BITSET_BIT_NAME] && name &&
# # ]
404 [ # # ]: 0 : strncmp(nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]), name,
405 [ # # ]: 0 : nla_len(tb[ETHTOOL_A_BITSET_BIT_NAME]))) {
406 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, bit_attr,
407 : : "bit index and name mismatch");
408 : 0 : return -EINVAL;
409 : : }
410 [ # # ]: 0 : } else if (tb[ETHTOOL_A_BITSET_BIT_NAME]) {
411 [ # # ]: 0 : idx = ethnl_name_to_idx(names, nbits,
412 : : nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]));
413 [ # # ]: 0 : if (idx < 0) {
414 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack,
415 : : tb[ETHTOOL_A_BITSET_BIT_NAME],
416 : : "bit name not found");
417 : 0 : return -EOPNOTSUPP;
418 : : }
419 : : } else {
420 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, bit_attr,
421 : : "neither bit index nor name specified");
422 : 0 : return -EINVAL;
423 : : }
424 : :
425 : 0 : *index = idx;
426 [ # # # # ]: 0 : *val = no_mask || tb[ETHTOOL_A_BITSET_BIT_VALUE];
427 : 0 : return 0;
428 : : }
429 : :
430 : : static int
431 : : ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
432 : : const struct nlattr *attr, struct nlattr **tb,
433 : : ethnl_string_array_t names,
434 : : struct netlink_ext_ack *extack, bool *mod)
435 : : {
436 : : struct nlattr *bit_attr;
437 : : bool no_mask;
438 : : int rem;
439 : : int ret;
440 : :
441 : : if (tb[ETHTOOL_A_BITSET_VALUE]) {
442 : : NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
443 : : "value only allowed in compact bitset");
444 : : return -EINVAL;
445 : : }
446 : : if (tb[ETHTOOL_A_BITSET_MASK]) {
447 : : NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
448 : : "mask only allowed in compact bitset");
449 : : return -EINVAL;
450 : : }
451 : :
452 : : no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
453 : : if (no_mask)
454 : : ethnl_bitmap32_clear(bitmap, 0, nbits, mod);
455 : :
456 : : nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
457 : : bool old_val, new_val;
458 : : unsigned int idx;
459 : :
460 : : if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {
461 : : NL_SET_ERR_MSG_ATTR(extack, bit_attr,
462 : : "only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS");
463 : : return -EINVAL;
464 : : }
465 : : ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask,
466 : : names, extack);
467 : : if (ret < 0)
468 : : return ret;
469 : : old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32));
470 : : if (new_val != old_val) {
471 : : if (new_val)
472 : : bitmap[idx / 32] |= ((u32)1 << (idx % 32));
473 : : else
474 : : bitmap[idx / 32] &= ~((u32)1 << (idx % 32));
475 : : *mod = true;
476 : : }
477 : : }
478 : :
479 : : return 0;
480 : : }
481 : :
482 : 0 : static int ethnl_compact_sanity_checks(unsigned int nbits,
483 : : const struct nlattr *nest,
484 : : struct nlattr **tb,
485 : : struct netlink_ext_ack *extack)
486 : : {
487 : 0 : bool no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
488 : 0 : unsigned int attr_nbits, attr_nwords;
489 : 0 : const struct nlattr *test_attr;
490 : :
491 [ # # # # ]: 0 : if (no_mask && tb[ETHTOOL_A_BITSET_MASK]) {
492 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
493 : : "mask not allowed in list bitset");
494 : 0 : return -EINVAL;
495 : : }
496 [ # # ]: 0 : if (!tb[ETHTOOL_A_BITSET_SIZE]) {
497 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, nest,
498 : : "missing size in compact bitset");
499 : 0 : return -EINVAL;
500 : : }
501 [ # # ]: 0 : if (!tb[ETHTOOL_A_BITSET_VALUE]) {
502 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, nest,
503 : : "missing value in compact bitset");
504 : 0 : return -EINVAL;
505 : : }
506 [ # # # # ]: 0 : if (!no_mask && !tb[ETHTOOL_A_BITSET_MASK]) {
507 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, nest,
508 : : "missing mask in compact nonlist bitset");
509 : 0 : return -EINVAL;
510 : : }
511 : :
512 [ # # ]: 0 : attr_nbits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);
513 : 0 : attr_nwords = DIV_ROUND_UP(attr_nbits, 32);
514 [ # # ]: 0 : if (nla_len(tb[ETHTOOL_A_BITSET_VALUE]) != attr_nwords * sizeof(u32)) {
515 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
516 : : "bitset value length does not match size");
517 : 0 : return -EINVAL;
518 : : }
519 [ # # # # ]: 0 : if (tb[ETHTOOL_A_BITSET_MASK] &&
520 [ # # ]: 0 : nla_len(tb[ETHTOOL_A_BITSET_MASK]) != attr_nwords * sizeof(u32)) {
521 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
522 : : "bitset mask length does not match size");
523 : 0 : return -EINVAL;
524 : : }
525 [ # # ]: 0 : if (attr_nbits <= nbits)
526 : : return 0;
527 : :
528 [ # # ]: 0 : test_attr = no_mask ? tb[ETHTOOL_A_BITSET_VALUE] :
529 : : tb[ETHTOOL_A_BITSET_MASK];
530 [ # # ]: 0 : if (ethnl_bitmap32_not_zero(nla_data(test_attr), nbits, attr_nbits)) {
531 [ # # ]: 0 : NL_SET_ERR_MSG_ATTR(extack, test_attr,
532 : : "cannot modify bits past kernel bitset size");
533 : 0 : return -EINVAL;
534 : : }
535 : : return 0;
536 : : }
537 : :
538 : : /**
539 : : * ethnl_update_bitset32() - Apply a bitset nest to a u32 based bitmap
540 : : * @bitmap: bitmap to update
541 : : * @nbits: size of the updated bitmap in bits
542 : : * @attr: nest attribute to parse and apply
543 : : * @names: array of bit names; may be null for compact format
544 : : * @extack: extack for error reporting
545 : : * @mod: set this to true if bitmap is modified, leave as it is if not
546 : : *
547 : : * Apply bitset netsted attribute to a bitmap. If the attribute represents
548 : : * a bit list, @bitmap is set to its contents; otherwise, bits in mask are
549 : : * set to values from value. Bitmaps in the attribute may be longer than
550 : : * @nbits but the message must not request modifying any bits past @nbits.
551 : : *
552 : : * Return: negative error code on failure, 0 on success
553 : : */
554 : 0 : int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits,
555 : : const struct nlattr *attr, ethnl_string_array_t names,
556 : : struct netlink_ext_ack *extack, bool *mod)
557 : : {
558 : 0 : struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1];
559 : 0 : unsigned int change_bits;
560 : 0 : bool no_mask;
561 : 0 : int ret;
562 : :
563 [ # # ]: 0 : if (!attr)
564 : : return 0;
565 : 0 : ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, attr, bitset_policy,
566 : : extack);
567 [ # # ]: 0 : if (ret < 0)
568 : : return ret;
569 : :
570 [ # # ]: 0 : if (tb[ETHTOOL_A_BITSET_BITS])
571 : 0 : return ethnl_update_bitset32_verbose(bitmap, nbits, attr, tb,
572 : : names, extack, mod);
573 : 0 : ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack);
574 [ # # ]: 0 : if (ret < 0)
575 : : return ret;
576 : :
577 : 0 : no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
578 [ # # ]: 0 : change_bits = min_t(unsigned int,
579 : : nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]), nbits);
580 [ # # ]: 0 : ethnl_bitmap32_update(bitmap, change_bits,
581 : 0 : nla_data(tb[ETHTOOL_A_BITSET_VALUE]),
582 : : no_mask ? NULL :
583 : 0 : nla_data(tb[ETHTOOL_A_BITSET_MASK]),
584 : : mod);
585 [ # # ]: 0 : if (no_mask && change_bits < nbits)
586 : 0 : ethnl_bitmap32_clear(bitmap, change_bits, nbits, mod);
587 : :
588 : : return 0;
589 : : }
590 : :
591 : : #if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN)
592 : :
593 : : /* 64-bit big endian architectures are the only case when u32 based bitmaps
594 : : * and unsigned long based bitmaps have different memory layout so that we
595 : : * cannot simply cast the latter to the former and need actual wrappers
596 : : * converting the latter to the former.
597 : : *
598 : : * To reduce the number of slab allocations, the wrappers use fixed size local
599 : : * variables for bitmaps up to ETHNL_SMALL_BITMAP_BITS bits which is the
600 : : * majority of bitmaps used by ethtool.
601 : : */
602 : : #define ETHNL_SMALL_BITMAP_BITS 128
603 : : #define ETHNL_SMALL_BITMAP_WORDS DIV_ROUND_UP(ETHNL_SMALL_BITMAP_BITS, 32)
604 : :
605 : : int ethnl_bitset_size(const unsigned long *val, const unsigned long *mask,
606 : : unsigned int nbits, ethnl_string_array_t names,
607 : : bool compact)
608 : : {
609 : : u32 small_mask32[ETHNL_SMALL_BITMAP_WORDS];
610 : : u32 small_val32[ETHNL_SMALL_BITMAP_WORDS];
611 : : u32 *mask32;
612 : : u32 *val32;
613 : : int ret;
614 : :
615 : : if (nbits > ETHNL_SMALL_BITMAP_BITS) {
616 : : unsigned int nwords = DIV_ROUND_UP(nbits, 32);
617 : :
618 : : val32 = kmalloc_array(2 * nwords, sizeof(u32), GFP_KERNEL);
619 : : if (!val32)
620 : : return -ENOMEM;
621 : : mask32 = val32 + nwords;
622 : : } else {
623 : : val32 = small_val32;
624 : : mask32 = small_mask32;
625 : : }
626 : :
627 : : bitmap_to_arr32(val32, val, nbits);
628 : : if (mask)
629 : : bitmap_to_arr32(mask32, mask, nbits);
630 : : else
631 : : mask32 = NULL;
632 : : ret = ethnl_bitset32_size(val32, mask32, nbits, names, compact);
633 : :
634 : : if (nbits > ETHNL_SMALL_BITMAP_BITS)
635 : : kfree(val32);
636 : :
637 : : return ret;
638 : : }
639 : :
640 : : int ethnl_put_bitset(struct sk_buff *skb, int attrtype,
641 : : const unsigned long *val, const unsigned long *mask,
642 : : unsigned int nbits, ethnl_string_array_t names,
643 : : bool compact)
644 : : {
645 : : u32 small_mask32[ETHNL_SMALL_BITMAP_WORDS];
646 : : u32 small_val32[ETHNL_SMALL_BITMAP_WORDS];
647 : : u32 *mask32;
648 : : u32 *val32;
649 : : int ret;
650 : :
651 : : if (nbits > ETHNL_SMALL_BITMAP_BITS) {
652 : : unsigned int nwords = DIV_ROUND_UP(nbits, 32);
653 : :
654 : : val32 = kmalloc_array(2 * nwords, sizeof(u32), GFP_KERNEL);
655 : : if (!val32)
656 : : return -ENOMEM;
657 : : mask32 = val32 + nwords;
658 : : } else {
659 : : val32 = small_val32;
660 : : mask32 = small_mask32;
661 : : }
662 : :
663 : : bitmap_to_arr32(val32, val, nbits);
664 : : if (mask)
665 : : bitmap_to_arr32(mask32, mask, nbits);
666 : : else
667 : : mask32 = NULL;
668 : : ret = ethnl_put_bitset32(skb, attrtype, val32, mask32, nbits, names,
669 : : compact);
670 : :
671 : : if (nbits > ETHNL_SMALL_BITMAP_BITS)
672 : : kfree(val32);
673 : :
674 : : return ret;
675 : : }
676 : :
677 : : int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
678 : : const struct nlattr *attr, ethnl_string_array_t names,
679 : : struct netlink_ext_ack *extack, bool *mod)
680 : : {
681 : : u32 small_bitmap32[ETHNL_SMALL_BITMAP_WORDS];
682 : : u32 *bitmap32 = small_bitmap32;
683 : : bool u32_mod = false;
684 : : int ret;
685 : :
686 : : if (nbits > ETHNL_SMALL_BITMAP_BITS) {
687 : : unsigned int dst_words = DIV_ROUND_UP(nbits, 32);
688 : :
689 : : bitmap32 = kmalloc_array(dst_words, sizeof(u32), GFP_KERNEL);
690 : : if (!bitmap32)
691 : : return -ENOMEM;
692 : : }
693 : :
694 : : bitmap_to_arr32(bitmap32, bitmap, nbits);
695 : : ret = ethnl_update_bitset32(bitmap32, nbits, attr, names, extack,
696 : : &u32_mod);
697 : : if (u32_mod) {
698 : : bitmap_from_arr32(bitmap, bitmap32, nbits);
699 : : *mod = true;
700 : : }
701 : :
702 : : if (nbits > ETHNL_SMALL_BITMAP_BITS)
703 : : kfree(bitmap32);
704 : :
705 : : return ret;
706 : : }
707 : :
708 : : #else
709 : :
710 : : /* On little endian 64-bit and all 32-bit architectures, an unsigned long
711 : : * based bitmap can be interpreted as u32 based one using a simple cast.
712 : : */
713 : :
714 : 0 : int ethnl_bitset_size(const unsigned long *val, const unsigned long *mask,
715 : : unsigned int nbits, ethnl_string_array_t names,
716 : : bool compact)
717 : : {
718 : 0 : return ethnl_bitset32_size((const u32 *)val, (const u32 *)mask, nbits,
719 : : names, compact);
720 : : }
721 : :
722 : 0 : int ethnl_put_bitset(struct sk_buff *skb, int attrtype,
723 : : const unsigned long *val, const unsigned long *mask,
724 : : unsigned int nbits, ethnl_string_array_t names,
725 : : bool compact)
726 : : {
727 : 0 : return ethnl_put_bitset32(skb, attrtype, (const u32 *)val,
728 : : (const u32 *)mask, nbits, names, compact);
729 : : }
730 : :
731 : 0 : int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
732 : : const struct nlattr *attr, ethnl_string_array_t names,
733 : : struct netlink_ext_ack *extack, bool *mod)
734 : : {
735 : 0 : return ethnl_update_bitset32((u32 *)bitmap, nbits, attr, names, extack,
736 : : mod);
737 : : }
738 : :
739 : : #endif /* BITS_PER_LONG == 64 && defined(__BIG_ENDIAN) */
|