Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/ethtool/bitset.c
26278 views
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
static u32 ethnl_lower_bits(unsigned int n)
16
{
17
return ~(u32)0 >> (32 - n % 32);
18
}
19
20
static u32 ethnl_upper_bits(unsigned int n)
21
{
22
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
static void ethnl_bitmap32_clear(u32 *dst, unsigned int start, unsigned int end,
35
bool *mod)
36
{
37
unsigned int start_word = start / 32;
38
unsigned int end_word = end / 32;
39
unsigned int i;
40
u32 mask;
41
42
if (end <= start)
43
return;
44
45
if (start % 32) {
46
mask = ethnl_upper_bits(start);
47
if (end_word == start_word) {
48
mask &= ethnl_lower_bits(end);
49
if (dst[start_word] & mask) {
50
dst[start_word] &= ~mask;
51
*mod = true;
52
}
53
return;
54
}
55
if (dst[start_word] & mask) {
56
dst[start_word] &= ~mask;
57
*mod = true;
58
}
59
start_word++;
60
}
61
62
for (i = start_word; i < end_word; i++) {
63
if (dst[i]) {
64
dst[i] = 0;
65
*mod = true;
66
}
67
}
68
if (end % 32) {
69
mask = ethnl_lower_bits(end);
70
if (dst[end_word] & mask) {
71
dst[end_word] &= ~mask;
72
*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
static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start,
87
unsigned int end)
88
{
89
unsigned int start_word = start / 32;
90
unsigned int end_word = end / 32;
91
u32 mask;
92
93
if (end <= start)
94
return true;
95
96
if (start % 32) {
97
mask = ethnl_upper_bits(start);
98
if (end_word == start_word) {
99
mask &= ethnl_lower_bits(end);
100
return map[start_word] & mask;
101
}
102
if (map[start_word] & mask)
103
return true;
104
start_word++;
105
}
106
107
if (!memchr_inv(map + start_word, '\0',
108
(end_word - start_word) * sizeof(u32)))
109
return true;
110
if (end % 32 == 0)
111
return true;
112
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
static void ethnl_bitmap32_update(u32 *dst, unsigned int nbits,
129
const u32 *value, const u32 *mask, bool *mod)
130
{
131
while (nbits > 0) {
132
u32 real_mask = mask ? *mask : ~(u32)0;
133
u32 new_value;
134
135
if (nbits < 32)
136
real_mask &= ethnl_lower_bits(nbits);
137
new_value = (*dst & ~real_mask) | (*value & real_mask);
138
if (new_value != *dst) {
139
*dst = new_value;
140
*mod = true;
141
}
142
143
if (nbits <= 32)
144
break;
145
dst++;
146
nbits -= 32;
147
value++;
148
if (mask)
149
mask++;
150
}
151
}
152
153
static bool ethnl_bitmap32_test_bit(const u32 *map, unsigned int index)
154
{
155
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
int ethnl_bitset32_size(const u32 *val, const u32 *mask, unsigned int nbits,
172
ethnl_string_array_t names, bool compact)
173
{
174
unsigned int len = 0;
175
176
/* list flag */
177
if (!mask)
178
len += nla_total_size(sizeof(u32));
179
/* size */
180
len += nla_total_size(sizeof(u32));
181
182
if (compact) {
183
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
184
185
/* value, mask */
186
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
for (i = 0; i < nbits; i++) {
192
const char *name = names ? names[i] : NULL;
193
194
if (!ethnl_bitmap32_test_bit(mask ?: val, i))
195
continue;
196
/* index */
197
bit_len = nla_total_size(sizeof(u32));
198
/* name */
199
if (name)
200
bit_len += ethnl_strz_size(name);
201
/* value */
202
if (mask && ethnl_bitmap32_test_bit(val, i))
203
bit_len += nla_total_size(0);
204
205
/* bit nest */
206
bits_len += nla_total_size(bit_len);
207
}
208
/* bits nest */
209
len += nla_total_size(bits_len);
210
}
211
212
/* outermost nest */
213
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
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
struct nlattr *nest;
237
struct nlattr *attr;
238
239
nest = nla_nest_start(skb, attrtype);
240
if (!nest)
241
return -EMSGSIZE;
242
243
if (!mask && nla_put_flag(skb, ETHTOOL_A_BITSET_NOMASK))
244
goto nla_put_failure;
245
if (nla_put_u32(skb, ETHTOOL_A_BITSET_SIZE, nbits))
246
goto nla_put_failure;
247
if (compact) {
248
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
249
unsigned int nbytes = nwords * sizeof(u32);
250
u32 *dst;
251
252
attr = nla_reserve(skb, ETHTOOL_A_BITSET_VALUE, nbytes);
253
if (!attr)
254
goto nla_put_failure;
255
dst = nla_data(attr);
256
memcpy(dst, val, nbytes);
257
if (nbits % 32)
258
dst[nwords - 1] &= ethnl_lower_bits(nbits);
259
260
if (mask) {
261
attr = nla_reserve(skb, ETHTOOL_A_BITSET_MASK, nbytes);
262
if (!attr)
263
goto nla_put_failure;
264
dst = nla_data(attr);
265
memcpy(dst, mask, nbytes);
266
if (nbits % 32)
267
dst[nwords - 1] &= ethnl_lower_bits(nbits);
268
}
269
} else {
270
struct nlattr *bits;
271
unsigned int i;
272
273
bits = nla_nest_start(skb, ETHTOOL_A_BITSET_BITS);
274
if (!bits)
275
goto nla_put_failure;
276
for (i = 0; i < nbits; i++) {
277
const char *name = names ? names[i] : NULL;
278
279
if (!ethnl_bitmap32_test_bit(mask ?: val, i))
280
continue;
281
attr = nla_nest_start(skb, ETHTOOL_A_BITSET_BITS_BIT);
282
if (!attr)
283
goto nla_put_failure;
284
if (nla_put_u32(skb, ETHTOOL_A_BITSET_BIT_INDEX, i))
285
goto nla_put_failure;
286
if (name &&
287
ethnl_put_strz(skb, ETHTOOL_A_BITSET_BIT_NAME, name))
288
goto nla_put_failure;
289
if (mask && ethnl_bitmap32_test_bit(val, i) &&
290
nla_put_flag(skb, ETHTOOL_A_BITSET_BIT_VALUE))
291
goto nla_put_failure;
292
nla_nest_end(skb, attr);
293
}
294
nla_nest_end(skb, bits);
295
}
296
297
nla_nest_end(skb, nest);
298
return 0;
299
300
nla_put_failure:
301
nla_nest_cancel(skb, nest);
302
return -EMSGSIZE;
303
}
304
305
static const struct nla_policy bitset_policy[] = {
306
[ETHTOOL_A_BITSET_NOMASK] = { .type = NLA_FLAG },
307
[ETHTOOL_A_BITSET_SIZE] = NLA_POLICY_MAX(NLA_U32,
308
ETHNL_MAX_BITSET_SIZE),
309
[ETHTOOL_A_BITSET_BITS] = { .type = NLA_NESTED },
310
[ETHTOOL_A_BITSET_VALUE] = { .type = NLA_BINARY },
311
[ETHTOOL_A_BITSET_MASK] = { .type = NLA_BINARY },
312
};
313
314
static const struct nla_policy bit_policy[] = {
315
[ETHTOOL_A_BITSET_BIT_INDEX] = { .type = NLA_U32 },
316
[ETHTOOL_A_BITSET_BIT_NAME] = { .type = NLA_NUL_STRING },
317
[ETHTOOL_A_BITSET_BIT_VALUE] = { .type = NLA_FLAG },
318
};
319
320
/**
321
* ethnl_bitset_is_compact() - check if bitset attribute represents a compact
322
* bitset
323
* @bitset: nested attribute representing a bitset
324
* @compact: pointer for return value
325
*
326
* Return: 0 on success, negative error code on failure
327
*/
328
int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact)
329
{
330
struct nlattr *tb[ARRAY_SIZE(bitset_policy)];
331
int ret;
332
333
ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, bitset,
334
bitset_policy, NULL);
335
if (ret < 0)
336
return ret;
337
338
if (tb[ETHTOOL_A_BITSET_BITS]) {
339
if (tb[ETHTOOL_A_BITSET_VALUE] || tb[ETHTOOL_A_BITSET_MASK])
340
return -EINVAL;
341
*compact = false;
342
return 0;
343
}
344
if (!tb[ETHTOOL_A_BITSET_SIZE] || !tb[ETHTOOL_A_BITSET_VALUE])
345
return -EINVAL;
346
347
*compact = true;
348
return 0;
349
}
350
351
/**
352
* ethnl_name_to_idx() - look up string index for a name
353
* @names: array of ETH_GSTRING_LEN sized strings
354
* @n_names: number of strings in the array
355
* @name: name to look up
356
*
357
* Return: index of the string if found, -ENOENT if not found
358
*/
359
static int ethnl_name_to_idx(ethnl_string_array_t names, unsigned int n_names,
360
const char *name)
361
{
362
unsigned int i;
363
364
if (!names)
365
return -ENOENT;
366
367
for (i = 0; i < n_names; i++) {
368
/* names[i] may not be null terminated */
369
if (!strncmp(names[i], name, ETH_GSTRING_LEN) &&
370
strlen(name) <= ETH_GSTRING_LEN)
371
return i;
372
}
373
374
return -ENOENT;
375
}
376
377
static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,
378
const struct nlattr *bit_attr, bool no_mask,
379
ethnl_string_array_t names,
380
struct netlink_ext_ack *extack)
381
{
382
struct nlattr *tb[ARRAY_SIZE(bit_policy)];
383
int ret, idx;
384
385
ret = nla_parse_nested(tb, ARRAY_SIZE(bit_policy) - 1, bit_attr,
386
bit_policy, extack);
387
if (ret < 0)
388
return ret;
389
390
if (tb[ETHTOOL_A_BITSET_BIT_INDEX]) {
391
const char *name;
392
393
idx = nla_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);
394
if (idx >= nbits) {
395
NL_SET_ERR_MSG_ATTR(extack,
396
tb[ETHTOOL_A_BITSET_BIT_INDEX],
397
"bit index too high");
398
return -EOPNOTSUPP;
399
}
400
name = names ? names[idx] : NULL;
401
if (tb[ETHTOOL_A_BITSET_BIT_NAME] && name &&
402
strncmp(nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]), name,
403
nla_len(tb[ETHTOOL_A_BITSET_BIT_NAME]))) {
404
NL_SET_ERR_MSG_ATTR(extack, bit_attr,
405
"bit index and name mismatch");
406
return -EINVAL;
407
}
408
} else if (tb[ETHTOOL_A_BITSET_BIT_NAME]) {
409
idx = ethnl_name_to_idx(names, nbits,
410
nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]));
411
if (idx < 0) {
412
NL_SET_ERR_MSG_ATTR(extack,
413
tb[ETHTOOL_A_BITSET_BIT_NAME],
414
"bit name not found");
415
return -EOPNOTSUPP;
416
}
417
} else {
418
NL_SET_ERR_MSG_ATTR(extack, bit_attr,
419
"neither bit index nor name specified");
420
return -EINVAL;
421
}
422
423
*index = idx;
424
*val = no_mask || tb[ETHTOOL_A_BITSET_BIT_VALUE];
425
return 0;
426
}
427
428
/**
429
* ethnl_bitmap32_equal() - Compare two bitmaps
430
* @map1: first bitmap
431
* @map2: second bitmap
432
* @nbits: bit size to compare
433
*
434
* Return: true if first @nbits are equal, false if not
435
*/
436
static bool ethnl_bitmap32_equal(const u32 *map1, const u32 *map2,
437
unsigned int nbits)
438
{
439
if (memcmp(map1, map2, nbits / 32 * sizeof(u32)))
440
return false;
441
if (nbits % 32 == 0)
442
return true;
443
return !((map1[nbits / 32] ^ map2[nbits / 32]) &
444
ethnl_lower_bits(nbits % 32));
445
}
446
447
static int
448
ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
449
const struct nlattr *attr, struct nlattr **tb,
450
ethnl_string_array_t names,
451
struct netlink_ext_ack *extack, bool *mod)
452
{
453
u32 *saved_bitmap = NULL;
454
struct nlattr *bit_attr;
455
bool no_mask;
456
int rem;
457
int ret;
458
459
if (tb[ETHTOOL_A_BITSET_VALUE]) {
460
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
461
"value only allowed in compact bitset");
462
return -EINVAL;
463
}
464
if (tb[ETHTOOL_A_BITSET_MASK]) {
465
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
466
"mask only allowed in compact bitset");
467
return -EINVAL;
468
}
469
470
no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
471
if (no_mask) {
472
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
473
unsigned int nbytes = nwords * sizeof(u32);
474
bool dummy;
475
476
/* The bitmap size is only the size of the map part without
477
* its mask part.
478
*/
479
saved_bitmap = kcalloc(nwords, sizeof(u32), GFP_KERNEL);
480
if (!saved_bitmap)
481
return -ENOMEM;
482
memcpy(saved_bitmap, bitmap, nbytes);
483
ethnl_bitmap32_clear(bitmap, 0, nbits, &dummy);
484
}
485
486
nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
487
bool old_val, new_val;
488
unsigned int idx;
489
490
if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {
491
NL_SET_ERR_MSG_ATTR(extack, bit_attr,
492
"only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS");
493
kfree(saved_bitmap);
494
return -EINVAL;
495
}
496
ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask,
497
names, extack);
498
if (ret < 0) {
499
kfree(saved_bitmap);
500
return ret;
501
}
502
old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32));
503
if (new_val != old_val) {
504
if (new_val)
505
bitmap[idx / 32] |= ((u32)1 << (idx % 32));
506
else
507
bitmap[idx / 32] &= ~((u32)1 << (idx % 32));
508
if (!no_mask)
509
*mod = true;
510
}
511
}
512
513
if (no_mask && !ethnl_bitmap32_equal(saved_bitmap, bitmap, nbits))
514
*mod = true;
515
516
kfree(saved_bitmap);
517
return 0;
518
}
519
520
static int ethnl_compact_sanity_checks(unsigned int nbits,
521
const struct nlattr *nest,
522
struct nlattr **tb,
523
struct netlink_ext_ack *extack)
524
{
525
bool no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
526
unsigned int attr_nbits, attr_nwords;
527
const struct nlattr *test_attr;
528
529
if (no_mask && tb[ETHTOOL_A_BITSET_MASK]) {
530
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
531
"mask not allowed in list bitset");
532
return -EINVAL;
533
}
534
if (!tb[ETHTOOL_A_BITSET_SIZE]) {
535
NL_SET_ERR_MSG_ATTR(extack, nest,
536
"missing size in compact bitset");
537
return -EINVAL;
538
}
539
if (!tb[ETHTOOL_A_BITSET_VALUE]) {
540
NL_SET_ERR_MSG_ATTR(extack, nest,
541
"missing value in compact bitset");
542
return -EINVAL;
543
}
544
if (!no_mask && !tb[ETHTOOL_A_BITSET_MASK]) {
545
NL_SET_ERR_MSG_ATTR(extack, nest,
546
"missing mask in compact nonlist bitset");
547
return -EINVAL;
548
}
549
550
attr_nbits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);
551
attr_nwords = DIV_ROUND_UP(attr_nbits, 32);
552
if (nla_len(tb[ETHTOOL_A_BITSET_VALUE]) != attr_nwords * sizeof(u32)) {
553
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
554
"bitset value length does not match size");
555
return -EINVAL;
556
}
557
if (tb[ETHTOOL_A_BITSET_MASK] &&
558
nla_len(tb[ETHTOOL_A_BITSET_MASK]) != attr_nwords * sizeof(u32)) {
559
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
560
"bitset mask length does not match size");
561
return -EINVAL;
562
}
563
if (attr_nbits <= nbits)
564
return 0;
565
566
test_attr = no_mask ? tb[ETHTOOL_A_BITSET_VALUE] :
567
tb[ETHTOOL_A_BITSET_MASK];
568
if (ethnl_bitmap32_not_zero(nla_data(test_attr), nbits, attr_nbits)) {
569
NL_SET_ERR_MSG_ATTR(extack, test_attr,
570
"cannot modify bits past kernel bitset size");
571
return -EINVAL;
572
}
573
return 0;
574
}
575
576
/**
577
* ethnl_update_bitset32() - Apply a bitset nest to a u32 based bitmap
578
* @bitmap: bitmap to update
579
* @nbits: size of the updated bitmap in bits
580
* @attr: nest attribute to parse and apply
581
* @names: array of bit names; may be null for compact format
582
* @extack: extack for error reporting
583
* @mod: set this to true if bitmap is modified, leave as it is if not
584
*
585
* Apply bitset netsted attribute to a bitmap. If the attribute represents
586
* a bit list, @bitmap is set to its contents; otherwise, bits in mask are
587
* set to values from value. Bitmaps in the attribute may be longer than
588
* @nbits but the message must not request modifying any bits past @nbits.
589
*
590
* Return: negative error code on failure, 0 on success
591
*/
592
int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits,
593
const struct nlattr *attr, ethnl_string_array_t names,
594
struct netlink_ext_ack *extack, bool *mod)
595
{
596
struct nlattr *tb[ARRAY_SIZE(bitset_policy)];
597
unsigned int change_bits;
598
bool no_mask;
599
int ret;
600
601
if (!attr)
602
return 0;
603
ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr,
604
bitset_policy, extack);
605
if (ret < 0)
606
return ret;
607
608
if (tb[ETHTOOL_A_BITSET_BITS])
609
return ethnl_update_bitset32_verbose(bitmap, nbits, attr, tb,
610
names, extack, mod);
611
ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack);
612
if (ret < 0)
613
return ret;
614
615
no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
616
change_bits = min_t(unsigned int,
617
nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]), nbits);
618
ethnl_bitmap32_update(bitmap, change_bits,
619
nla_data(tb[ETHTOOL_A_BITSET_VALUE]),
620
no_mask ? NULL :
621
nla_data(tb[ETHTOOL_A_BITSET_MASK]),
622
mod);
623
if (no_mask && change_bits < nbits)
624
ethnl_bitmap32_clear(bitmap, change_bits, nbits, mod);
625
626
return 0;
627
}
628
629
/**
630
* ethnl_parse_bitset() - Compute effective value and mask from bitset nest
631
* @val: unsigned long based bitmap to put value into
632
* @mask: unsigned long based bitmap to put mask into
633
* @nbits: size of @val and @mask bitmaps
634
* @attr: nest attribute to parse and apply
635
* @names: array of bit names; may be null for compact format
636
* @extack: extack for error reporting
637
*
638
* Provide @nbits size long bitmaps for value and mask so that
639
* x = (val & mask) | (x & ~mask) would modify any @nbits sized bitmap x
640
* the same way ethnl_update_bitset() with the same bitset attribute would.
641
*
642
* Return: negative error code on failure, 0 on success
643
*/
644
int ethnl_parse_bitset(unsigned long *val, unsigned long *mask,
645
unsigned int nbits, const struct nlattr *attr,
646
ethnl_string_array_t names,
647
struct netlink_ext_ack *extack)
648
{
649
struct nlattr *tb[ARRAY_SIZE(bitset_policy)];
650
const struct nlattr *bit_attr;
651
bool no_mask;
652
int rem;
653
int ret;
654
655
if (!attr)
656
return 0;
657
ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr,
658
bitset_policy, extack);
659
if (ret < 0)
660
return ret;
661
no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
662
663
if (!tb[ETHTOOL_A_BITSET_BITS]) {
664
unsigned int change_bits;
665
666
ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack);
667
if (ret < 0)
668
return ret;
669
670
change_bits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);
671
if (change_bits > nbits)
672
change_bits = nbits;
673
bitmap_from_arr32(val, nla_data(tb[ETHTOOL_A_BITSET_VALUE]),
674
change_bits);
675
if (change_bits < nbits)
676
bitmap_clear(val, change_bits, nbits - change_bits);
677
if (no_mask) {
678
bitmap_fill(mask, nbits);
679
} else {
680
bitmap_from_arr32(mask,
681
nla_data(tb[ETHTOOL_A_BITSET_MASK]),
682
change_bits);
683
if (change_bits < nbits)
684
bitmap_clear(mask, change_bits,
685
nbits - change_bits);
686
}
687
688
return 0;
689
}
690
691
if (tb[ETHTOOL_A_BITSET_VALUE]) {
692
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
693
"value only allowed in compact bitset");
694
return -EINVAL;
695
}
696
if (tb[ETHTOOL_A_BITSET_MASK]) {
697
NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
698
"mask only allowed in compact bitset");
699
return -EINVAL;
700
}
701
702
bitmap_zero(val, nbits);
703
if (no_mask)
704
bitmap_fill(mask, nbits);
705
else
706
bitmap_zero(mask, nbits);
707
708
nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
709
unsigned int idx;
710
bool bit_val;
711
712
ret = ethnl_parse_bit(&idx, &bit_val, nbits, bit_attr, no_mask,
713
names, extack);
714
if (ret < 0)
715
return ret;
716
if (bit_val)
717
__set_bit(idx, val);
718
if (!no_mask)
719
__set_bit(idx, mask);
720
}
721
722
return 0;
723
}
724
725
#if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN)
726
727
/* 64-bit big endian architectures are the only case when u32 based bitmaps
728
* and unsigned long based bitmaps have different memory layout so that we
729
* cannot simply cast the latter to the former and need actual wrappers
730
* converting the latter to the former.
731
*
732
* To reduce the number of slab allocations, the wrappers use fixed size local
733
* variables for bitmaps up to ETHNL_SMALL_BITMAP_BITS bits which is the
734
* majority of bitmaps used by ethtool.
735
*/
736
#define ETHNL_SMALL_BITMAP_BITS 128
737
#define ETHNL_SMALL_BITMAP_WORDS DIV_ROUND_UP(ETHNL_SMALL_BITMAP_BITS, 32)
738
739
int ethnl_bitset_size(const unsigned long *val, const unsigned long *mask,
740
unsigned int nbits, ethnl_string_array_t names,
741
bool compact)
742
{
743
u32 small_mask32[ETHNL_SMALL_BITMAP_WORDS];
744
u32 small_val32[ETHNL_SMALL_BITMAP_WORDS];
745
u32 *mask32;
746
u32 *val32;
747
int ret;
748
749
if (nbits > ETHNL_SMALL_BITMAP_BITS) {
750
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
751
752
val32 = kmalloc_array(2 * nwords, sizeof(u32), GFP_KERNEL);
753
if (!val32)
754
return -ENOMEM;
755
mask32 = val32 + nwords;
756
} else {
757
val32 = small_val32;
758
mask32 = small_mask32;
759
}
760
761
bitmap_to_arr32(val32, val, nbits);
762
if (mask)
763
bitmap_to_arr32(mask32, mask, nbits);
764
else
765
mask32 = NULL;
766
ret = ethnl_bitset32_size(val32, mask32, nbits, names, compact);
767
768
if (nbits > ETHNL_SMALL_BITMAP_BITS)
769
kfree(val32);
770
771
return ret;
772
}
773
774
int ethnl_put_bitset(struct sk_buff *skb, int attrtype,
775
const unsigned long *val, const unsigned long *mask,
776
unsigned int nbits, ethnl_string_array_t names,
777
bool compact)
778
{
779
u32 small_mask32[ETHNL_SMALL_BITMAP_WORDS];
780
u32 small_val32[ETHNL_SMALL_BITMAP_WORDS];
781
u32 *mask32;
782
u32 *val32;
783
int ret;
784
785
if (nbits > ETHNL_SMALL_BITMAP_BITS) {
786
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
787
788
val32 = kmalloc_array(2 * nwords, sizeof(u32), GFP_KERNEL);
789
if (!val32)
790
return -ENOMEM;
791
mask32 = val32 + nwords;
792
} else {
793
val32 = small_val32;
794
mask32 = small_mask32;
795
}
796
797
bitmap_to_arr32(val32, val, nbits);
798
if (mask)
799
bitmap_to_arr32(mask32, mask, nbits);
800
else
801
mask32 = NULL;
802
ret = ethnl_put_bitset32(skb, attrtype, val32, mask32, nbits, names,
803
compact);
804
805
if (nbits > ETHNL_SMALL_BITMAP_BITS)
806
kfree(val32);
807
808
return ret;
809
}
810
811
int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
812
const struct nlattr *attr, ethnl_string_array_t names,
813
struct netlink_ext_ack *extack, bool *mod)
814
{
815
u32 small_bitmap32[ETHNL_SMALL_BITMAP_WORDS];
816
u32 *bitmap32 = small_bitmap32;
817
bool u32_mod = false;
818
int ret;
819
820
if (nbits > ETHNL_SMALL_BITMAP_BITS) {
821
unsigned int dst_words = DIV_ROUND_UP(nbits, 32);
822
823
bitmap32 = kmalloc_array(dst_words, sizeof(u32), GFP_KERNEL);
824
if (!bitmap32)
825
return -ENOMEM;
826
}
827
828
bitmap_to_arr32(bitmap32, bitmap, nbits);
829
ret = ethnl_update_bitset32(bitmap32, nbits, attr, names, extack,
830
&u32_mod);
831
if (u32_mod) {
832
bitmap_from_arr32(bitmap, bitmap32, nbits);
833
*mod = true;
834
}
835
836
if (nbits > ETHNL_SMALL_BITMAP_BITS)
837
kfree(bitmap32);
838
839
return ret;
840
}
841
842
#else
843
844
/* On little endian 64-bit and all 32-bit architectures, an unsigned long
845
* based bitmap can be interpreted as u32 based one using a simple cast.
846
*/
847
848
int ethnl_bitset_size(const unsigned long *val, const unsigned long *mask,
849
unsigned int nbits, ethnl_string_array_t names,
850
bool compact)
851
{
852
return ethnl_bitset32_size((const u32 *)val, (const u32 *)mask, nbits,
853
names, compact);
854
}
855
856
int ethnl_put_bitset(struct sk_buff *skb, int attrtype,
857
const unsigned long *val, const unsigned long *mask,
858
unsigned int nbits, ethnl_string_array_t names,
859
bool compact)
860
{
861
return ethnl_put_bitset32(skb, attrtype, (const u32 *)val,
862
(const u32 *)mask, nbits, names, compact);
863
}
864
865
int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
866
const struct nlattr *attr, ethnl_string_array_t names,
867
struct netlink_ext_ack *extack, bool *mod)
868
{
869
return ethnl_update_bitset32((u32 *)bitmap, nbits, attr, names, extack,
870
mod);
871
}
872
873
#endif /* BITS_PER_LONG == 64 && defined(__BIG_ENDIAN) */
874
875