Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include <linux/ethtool_netlink.h>
0004 #include <linux/bitmap.h>
0005 #include "netlink.h"
0006 #include "bitset.h"
0007 
0008 /* Some bitmaps are internally represented as an array of unsigned long, some
0009  * as an array of u32 (some even as single u32 for now). To avoid the need of
0010  * wrappers on caller side, we provide two set of functions: those with "32"
0011  * suffix in their names expect u32 based bitmaps, those without it expect
0012  * unsigned long bitmaps.
0013  */
0014 
0015 static u32 ethnl_lower_bits(unsigned int n)
0016 {
0017     return ~(u32)0 >> (32 - n % 32);
0018 }
0019 
0020 static u32 ethnl_upper_bits(unsigned int n)
0021 {
0022     return ~(u32)0 << (n % 32);
0023 }
0024 
0025 /**
0026  * ethnl_bitmap32_clear() - Clear u32 based bitmap
0027  * @dst:   bitmap to clear
0028  * @start: beginning of the interval
0029  * @end:   end of the interval
0030  * @mod:   set if bitmap was modified
0031  *
0032  * Clear @nbits bits of a bitmap with indices @start <= i < @end
0033  */
0034 static void ethnl_bitmap32_clear(u32 *dst, unsigned int start, unsigned int end,
0035                  bool *mod)
0036 {
0037     unsigned int start_word = start / 32;
0038     unsigned int end_word = end / 32;
0039     unsigned int i;
0040     u32 mask;
0041 
0042     if (end <= start)
0043         return;
0044 
0045     if (start % 32) {
0046         mask = ethnl_upper_bits(start);
0047         if (end_word == start_word) {
0048             mask &= ethnl_lower_bits(end);
0049             if (dst[start_word] & mask) {
0050                 dst[start_word] &= ~mask;
0051                 *mod = true;
0052             }
0053             return;
0054         }
0055         if (dst[start_word] & mask) {
0056             dst[start_word] &= ~mask;
0057             *mod = true;
0058         }
0059         start_word++;
0060     }
0061 
0062     for (i = start_word; i < end_word; i++) {
0063         if (dst[i]) {
0064             dst[i] = 0;
0065             *mod = true;
0066         }
0067     }
0068     if (end % 32) {
0069         mask = ethnl_lower_bits(end);
0070         if (dst[end_word] & mask) {
0071             dst[end_word] &= ~mask;
0072             *mod = true;
0073         }
0074     }
0075 }
0076 
0077 /**
0078  * ethnl_bitmap32_not_zero() - Check if any bit is set in an interval
0079  * @map:   bitmap to test
0080  * @start: beginning of the interval
0081  * @end:   end of the interval
0082  *
0083  * Return: true if there is non-zero bit with  index @start <= i < @end,
0084  *         false if the whole interval is zero
0085  */
0086 static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start,
0087                     unsigned int end)
0088 {
0089     unsigned int start_word = start / 32;
0090     unsigned int end_word = end / 32;
0091     u32 mask;
0092 
0093     if (end <= start)
0094         return true;
0095 
0096     if (start % 32) {
0097         mask = ethnl_upper_bits(start);
0098         if (end_word == start_word) {
0099             mask &= ethnl_lower_bits(end);
0100             return map[start_word] & mask;
0101         }
0102         if (map[start_word] & mask)
0103             return true;
0104         start_word++;
0105     }
0106 
0107     if (!memchr_inv(map + start_word, '\0',
0108             (end_word - start_word) * sizeof(u32)))
0109         return true;
0110     if (end % 32 == 0)
0111         return true;
0112     return map[end_word] & ethnl_lower_bits(end);
0113 }
0114 
0115 /**
0116  * ethnl_bitmap32_update() - Modify u32 based bitmap according to value/mask
0117  *               pair
0118  * @dst:   bitmap to update
0119  * @nbits: bit size of the bitmap
0120  * @value: values to set
0121  * @mask:  mask of bits to set
0122  * @mod:   set to true if bitmap is modified, preserve if not
0123  *
0124  * Set bits in @dst bitmap which are set in @mask to values from @value, leave
0125  * the rest untouched. If destination bitmap was modified, set @mod to true,
0126  * leave as it is if not.
0127  */
0128 static void ethnl_bitmap32_update(u32 *dst, unsigned int nbits,
0129                   const u32 *value, const u32 *mask, bool *mod)
0130 {
0131     while (nbits > 0) {
0132         u32 real_mask = mask ? *mask : ~(u32)0;
0133         u32 new_value;
0134 
0135         if (nbits < 32)
0136             real_mask &= ethnl_lower_bits(nbits);
0137         new_value = (*dst & ~real_mask) | (*value & real_mask);
0138         if (new_value != *dst) {
0139             *dst = new_value;
0140             *mod = true;
0141         }
0142 
0143         if (nbits <= 32)
0144             break;
0145         dst++;
0146         nbits -= 32;
0147         value++;
0148         if (mask)
0149             mask++;
0150     }
0151 }
0152 
0153 static bool ethnl_bitmap32_test_bit(const u32 *map, unsigned int index)
0154 {
0155     return map[index / 32] & (1U << (index % 32));
0156 }
0157 
0158 /**
0159  * ethnl_bitset32_size() - Calculate size of bitset nested attribute
0160  * @val:     value bitmap (u32 based)
0161  * @mask:    mask bitmap (u32 based, optional)
0162  * @nbits:   bit length of the bitset
0163  * @names:   array of bit names (optional)
0164  * @compact: assume compact format for output
0165  *
0166  * Estimate length of netlink attribute composed by a later call to
0167  * ethnl_put_bitset32() call with the same arguments.
0168  *
0169  * Return: negative error code or attribute length estimate
0170  */
0171 int ethnl_bitset32_size(const u32 *val, const u32 *mask, unsigned int nbits,
0172             ethnl_string_array_t names, bool compact)
0173 {
0174     unsigned int len = 0;
0175 
0176     /* list flag */
0177     if (!mask)
0178         len += nla_total_size(sizeof(u32));
0179     /* size */
0180     len += nla_total_size(sizeof(u32));
0181 
0182     if (compact) {
0183         unsigned int nwords = DIV_ROUND_UP(nbits, 32);
0184 
0185         /* value, mask */
0186         len += (mask ? 2 : 1) * nla_total_size(nwords * sizeof(u32));
0187     } else {
0188         unsigned int bits_len = 0;
0189         unsigned int bit_len, i;
0190 
0191         for (i = 0; i < nbits; i++) {
0192             const char *name = names ? names[i] : NULL;
0193 
0194             if (!ethnl_bitmap32_test_bit(mask ?: val, i))
0195                 continue;
0196             /* index */
0197             bit_len = nla_total_size(sizeof(u32));
0198             /* name */
0199             if (name)
0200                 bit_len += ethnl_strz_size(name);
0201             /* value */
0202             if (mask && ethnl_bitmap32_test_bit(val, i))
0203                 bit_len += nla_total_size(0);
0204 
0205             /* bit nest */
0206             bits_len += nla_total_size(bit_len);
0207         }
0208         /* bits nest */
0209         len += nla_total_size(bits_len);
0210     }
0211 
0212     /* outermost nest */
0213     return nla_total_size(len);
0214 }
0215 
0216 /**
0217  * ethnl_put_bitset32() - Put a bitset nest into a message
0218  * @skb:      skb with the message
0219  * @attrtype: attribute type for the bitset nest
0220  * @val:      value bitmap (u32 based)
0221  * @mask:     mask bitmap (u32 based, optional)
0222  * @nbits:    bit length of the bitset
0223  * @names:    array of bit names (optional)
0224  * @compact:  use compact format for the output
0225  *
0226  * Compose a nested attribute representing a bitset. If @mask is null, simple
0227  * bitmap (bit list) is created, if @mask is provided, represent a value/mask
0228  * pair. Bit names are only used in verbose mode and when provided by calller.
0229  *
0230  * Return: 0 on success, negative error value on error
0231  */
0232 int ethnl_put_bitset32(struct sk_buff *skb, int attrtype, const u32 *val,
0233                const u32 *mask, unsigned int nbits,
0234                ethnl_string_array_t names, bool compact)
0235 {
0236     struct nlattr *nest;
0237     struct nlattr *attr;
0238 
0239     nest = nla_nest_start(skb, attrtype);
0240     if (!nest)
0241         return -EMSGSIZE;
0242 
0243     if (!mask && nla_put_flag(skb, ETHTOOL_A_BITSET_NOMASK))
0244         goto nla_put_failure;
0245     if (nla_put_u32(skb, ETHTOOL_A_BITSET_SIZE, nbits))
0246         goto nla_put_failure;
0247     if (compact) {
0248         unsigned int nwords = DIV_ROUND_UP(nbits, 32);
0249         unsigned int nbytes = nwords * sizeof(u32);
0250         u32 *dst;
0251 
0252         attr = nla_reserve(skb, ETHTOOL_A_BITSET_VALUE, nbytes);
0253         if (!attr)
0254             goto nla_put_failure;
0255         dst = nla_data(attr);
0256         memcpy(dst, val, nbytes);
0257         if (nbits % 32)
0258             dst[nwords - 1] &= ethnl_lower_bits(nbits);
0259 
0260         if (mask) {
0261             attr = nla_reserve(skb, ETHTOOL_A_BITSET_MASK, nbytes);
0262             if (!attr)
0263                 goto nla_put_failure;
0264             dst = nla_data(attr);
0265             memcpy(dst, mask, nbytes);
0266             if (nbits % 32)
0267                 dst[nwords - 1] &= ethnl_lower_bits(nbits);
0268         }
0269     } else {
0270         struct nlattr *bits;
0271         unsigned int i;
0272 
0273         bits = nla_nest_start(skb, ETHTOOL_A_BITSET_BITS);
0274         if (!bits)
0275             goto nla_put_failure;
0276         for (i = 0; i < nbits; i++) {
0277             const char *name = names ? names[i] : NULL;
0278 
0279             if (!ethnl_bitmap32_test_bit(mask ?: val, i))
0280                 continue;
0281             attr = nla_nest_start(skb, ETHTOOL_A_BITSET_BITS_BIT);
0282             if (!attr)
0283                 goto nla_put_failure;
0284             if (nla_put_u32(skb, ETHTOOL_A_BITSET_BIT_INDEX, i))
0285                 goto nla_put_failure;
0286             if (name &&
0287                 ethnl_put_strz(skb, ETHTOOL_A_BITSET_BIT_NAME, name))
0288                 goto nla_put_failure;
0289             if (mask && ethnl_bitmap32_test_bit(val, i) &&
0290                 nla_put_flag(skb, ETHTOOL_A_BITSET_BIT_VALUE))
0291                 goto nla_put_failure;
0292             nla_nest_end(skb, attr);
0293         }
0294         nla_nest_end(skb, bits);
0295     }
0296 
0297     nla_nest_end(skb, nest);
0298     return 0;
0299 
0300 nla_put_failure:
0301     nla_nest_cancel(skb, nest);
0302     return -EMSGSIZE;
0303 }
0304 
0305 static const struct nla_policy bitset_policy[] = {
0306     [ETHTOOL_A_BITSET_NOMASK]   = { .type = NLA_FLAG },
0307     [ETHTOOL_A_BITSET_SIZE]     = NLA_POLICY_MAX(NLA_U32,
0308                              ETHNL_MAX_BITSET_SIZE),
0309     [ETHTOOL_A_BITSET_BITS]     = { .type = NLA_NESTED },
0310     [ETHTOOL_A_BITSET_VALUE]    = { .type = NLA_BINARY },
0311     [ETHTOOL_A_BITSET_MASK]     = { .type = NLA_BINARY },
0312 };
0313 
0314 static const struct nla_policy bit_policy[] = {
0315     [ETHTOOL_A_BITSET_BIT_INDEX]    = { .type = NLA_U32 },
0316     [ETHTOOL_A_BITSET_BIT_NAME] = { .type = NLA_NUL_STRING },
0317     [ETHTOOL_A_BITSET_BIT_VALUE]    = { .type = NLA_FLAG },
0318 };
0319 
0320 /**
0321  * ethnl_bitset_is_compact() - check if bitset attribute represents a compact
0322  *                 bitset
0323  * @bitset:  nested attribute representing a bitset
0324  * @compact: pointer for return value
0325  *
0326  * Return: 0 on success, negative error code on failure
0327  */
0328 int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact)
0329 {
0330     struct nlattr *tb[ARRAY_SIZE(bitset_policy)];
0331     int ret;
0332 
0333     ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, bitset,
0334                    bitset_policy, NULL);
0335     if (ret < 0)
0336         return ret;
0337 
0338     if (tb[ETHTOOL_A_BITSET_BITS]) {
0339         if (tb[ETHTOOL_A_BITSET_VALUE] || tb[ETHTOOL_A_BITSET_MASK])
0340             return -EINVAL;
0341         *compact = false;
0342         return 0;
0343     }
0344     if (!tb[ETHTOOL_A_BITSET_SIZE] || !tb[ETHTOOL_A_BITSET_VALUE])
0345         return -EINVAL;
0346 
0347     *compact = true;
0348     return 0;
0349 }
0350 
0351 /**
0352  * ethnl_name_to_idx() - look up string index for a name
0353  * @names:   array of ETH_GSTRING_LEN sized strings
0354  * @n_names: number of strings in the array
0355  * @name:    name to look up
0356  *
0357  * Return: index of the string if found, -ENOENT if not found
0358  */
0359 static int ethnl_name_to_idx(ethnl_string_array_t names, unsigned int n_names,
0360                  const char *name)
0361 {
0362     unsigned int i;
0363 
0364     if (!names)
0365         return -ENOENT;
0366 
0367     for (i = 0; i < n_names; i++) {
0368         /* names[i] may not be null terminated */
0369         if (!strncmp(names[i], name, ETH_GSTRING_LEN) &&
0370             strlen(name) <= ETH_GSTRING_LEN)
0371             return i;
0372     }
0373 
0374     return -ENOENT;
0375 }
0376 
0377 static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,
0378                const struct nlattr *bit_attr, bool no_mask,
0379                ethnl_string_array_t names,
0380                struct netlink_ext_ack *extack)
0381 {
0382     struct nlattr *tb[ARRAY_SIZE(bit_policy)];
0383     int ret, idx;
0384 
0385     ret = nla_parse_nested(tb, ARRAY_SIZE(bit_policy) - 1, bit_attr,
0386                    bit_policy, extack);
0387     if (ret < 0)
0388         return ret;
0389 
0390     if (tb[ETHTOOL_A_BITSET_BIT_INDEX]) {
0391         const char *name;
0392 
0393         idx = nla_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);
0394         if (idx >= nbits) {
0395             NL_SET_ERR_MSG_ATTR(extack,
0396                         tb[ETHTOOL_A_BITSET_BIT_INDEX],
0397                         "bit index too high");
0398             return -EOPNOTSUPP;
0399         }
0400         name = names ? names[idx] : NULL;
0401         if (tb[ETHTOOL_A_BITSET_BIT_NAME] && name &&
0402             strncmp(nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]), name,
0403                 nla_len(tb[ETHTOOL_A_BITSET_BIT_NAME]))) {
0404             NL_SET_ERR_MSG_ATTR(extack, bit_attr,
0405                         "bit index and name mismatch");
0406             return -EINVAL;
0407         }
0408     } else if (tb[ETHTOOL_A_BITSET_BIT_NAME]) {
0409         idx = ethnl_name_to_idx(names, nbits,
0410                     nla_data(tb[ETHTOOL_A_BITSET_BIT_NAME]));
0411         if (idx < 0) {
0412             NL_SET_ERR_MSG_ATTR(extack,
0413                         tb[ETHTOOL_A_BITSET_BIT_NAME],
0414                         "bit name not found");
0415             return -EOPNOTSUPP;
0416         }
0417     } else {
0418         NL_SET_ERR_MSG_ATTR(extack, bit_attr,
0419                     "neither bit index nor name specified");
0420         return -EINVAL;
0421     }
0422 
0423     *index = idx;
0424     *val = no_mask || tb[ETHTOOL_A_BITSET_BIT_VALUE];
0425     return 0;
0426 }
0427 
0428 static int
0429 ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
0430                   const struct nlattr *attr, struct nlattr **tb,
0431                   ethnl_string_array_t names,
0432                   struct netlink_ext_ack *extack, bool *mod)
0433 {
0434     struct nlattr *bit_attr;
0435     bool no_mask;
0436     int rem;
0437     int ret;
0438 
0439     if (tb[ETHTOOL_A_BITSET_VALUE]) {
0440         NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
0441                     "value only allowed in compact bitset");
0442         return -EINVAL;
0443     }
0444     if (tb[ETHTOOL_A_BITSET_MASK]) {
0445         NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
0446                     "mask only allowed in compact bitset");
0447         return -EINVAL;
0448     }
0449 
0450     no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
0451     if (no_mask)
0452         ethnl_bitmap32_clear(bitmap, 0, nbits, mod);
0453 
0454     nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
0455         bool old_val, new_val;
0456         unsigned int idx;
0457 
0458         if (nla_type(bit_attr) != ETHTOOL_A_BITSET_BITS_BIT) {
0459             NL_SET_ERR_MSG_ATTR(extack, bit_attr,
0460                         "only ETHTOOL_A_BITSET_BITS_BIT allowed in ETHTOOL_A_BITSET_BITS");
0461             return -EINVAL;
0462         }
0463         ret = ethnl_parse_bit(&idx, &new_val, nbits, bit_attr, no_mask,
0464                       names, extack);
0465         if (ret < 0)
0466             return ret;
0467         old_val = bitmap[idx / 32] & ((u32)1 << (idx % 32));
0468         if (new_val != old_val) {
0469             if (new_val)
0470                 bitmap[idx / 32] |= ((u32)1 << (idx % 32));
0471             else
0472                 bitmap[idx / 32] &= ~((u32)1 << (idx % 32));
0473             *mod = true;
0474         }
0475     }
0476 
0477     return 0;
0478 }
0479 
0480 static int ethnl_compact_sanity_checks(unsigned int nbits,
0481                        const struct nlattr *nest,
0482                        struct nlattr **tb,
0483                        struct netlink_ext_ack *extack)
0484 {
0485     bool no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
0486     unsigned int attr_nbits, attr_nwords;
0487     const struct nlattr *test_attr;
0488 
0489     if (no_mask && tb[ETHTOOL_A_BITSET_MASK]) {
0490         NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
0491                     "mask not allowed in list bitset");
0492         return -EINVAL;
0493     }
0494     if (!tb[ETHTOOL_A_BITSET_SIZE]) {
0495         NL_SET_ERR_MSG_ATTR(extack, nest,
0496                     "missing size in compact bitset");
0497         return -EINVAL;
0498     }
0499     if (!tb[ETHTOOL_A_BITSET_VALUE]) {
0500         NL_SET_ERR_MSG_ATTR(extack, nest,
0501                     "missing value in compact bitset");
0502         return -EINVAL;
0503     }
0504     if (!no_mask && !tb[ETHTOOL_A_BITSET_MASK]) {
0505         NL_SET_ERR_MSG_ATTR(extack, nest,
0506                     "missing mask in compact nonlist bitset");
0507         return -EINVAL;
0508     }
0509 
0510     attr_nbits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);
0511     attr_nwords = DIV_ROUND_UP(attr_nbits, 32);
0512     if (nla_len(tb[ETHTOOL_A_BITSET_VALUE]) != attr_nwords * sizeof(u32)) {
0513         NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
0514                     "bitset value length does not match size");
0515         return -EINVAL;
0516     }
0517     if (tb[ETHTOOL_A_BITSET_MASK] &&
0518         nla_len(tb[ETHTOOL_A_BITSET_MASK]) != attr_nwords * sizeof(u32)) {
0519         NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
0520                     "bitset mask length does not match size");
0521         return -EINVAL;
0522     }
0523     if (attr_nbits <= nbits)
0524         return 0;
0525 
0526     test_attr = no_mask ? tb[ETHTOOL_A_BITSET_VALUE] :
0527                   tb[ETHTOOL_A_BITSET_MASK];
0528     if (ethnl_bitmap32_not_zero(nla_data(test_attr), nbits, attr_nbits)) {
0529         NL_SET_ERR_MSG_ATTR(extack, test_attr,
0530                     "cannot modify bits past kernel bitset size");
0531         return -EINVAL;
0532     }
0533     return 0;
0534 }
0535 
0536 /**
0537  * ethnl_update_bitset32() - Apply a bitset nest to a u32 based bitmap
0538  * @bitmap:  bitmap to update
0539  * @nbits:   size of the updated bitmap in bits
0540  * @attr:    nest attribute to parse and apply
0541  * @names:   array of bit names; may be null for compact format
0542  * @extack:  extack for error reporting
0543  * @mod:     set this to true if bitmap is modified, leave as it is if not
0544  *
0545  * Apply bitset netsted attribute to a bitmap. If the attribute represents
0546  * a bit list, @bitmap is set to its contents; otherwise, bits in mask are
0547  * set to values from value. Bitmaps in the attribute may be longer than
0548  * @nbits but the message must not request modifying any bits past @nbits.
0549  *
0550  * Return: negative error code on failure, 0 on success
0551  */
0552 int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits,
0553               const struct nlattr *attr, ethnl_string_array_t names,
0554               struct netlink_ext_ack *extack, bool *mod)
0555 {
0556     struct nlattr *tb[ARRAY_SIZE(bitset_policy)];
0557     unsigned int change_bits;
0558     bool no_mask;
0559     int ret;
0560 
0561     if (!attr)
0562         return 0;
0563     ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr,
0564                    bitset_policy, extack);
0565     if (ret < 0)
0566         return ret;
0567 
0568     if (tb[ETHTOOL_A_BITSET_BITS])
0569         return ethnl_update_bitset32_verbose(bitmap, nbits, attr, tb,
0570                              names, extack, mod);
0571     ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack);
0572     if (ret < 0)
0573         return ret;
0574 
0575     no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
0576     change_bits = min_t(unsigned int,
0577                 nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]), nbits);
0578     ethnl_bitmap32_update(bitmap, change_bits,
0579                   nla_data(tb[ETHTOOL_A_BITSET_VALUE]),
0580                   no_mask ? NULL :
0581                     nla_data(tb[ETHTOOL_A_BITSET_MASK]),
0582                   mod);
0583     if (no_mask && change_bits < nbits)
0584         ethnl_bitmap32_clear(bitmap, change_bits, nbits, mod);
0585 
0586     return 0;
0587 }
0588 
0589 /**
0590  * ethnl_parse_bitset() - Compute effective value and mask from bitset nest
0591  * @val:     unsigned long based bitmap to put value into
0592  * @mask:    unsigned long based bitmap to put mask into
0593  * @nbits:   size of @val and @mask bitmaps
0594  * @attr:    nest attribute to parse and apply
0595  * @names:   array of bit names; may be null for compact format
0596  * @extack:  extack for error reporting
0597  *
0598  * Provide @nbits size long bitmaps for value and mask so that
0599  * x = (val & mask) | (x & ~mask) would modify any @nbits sized bitmap x
0600  * the same way ethnl_update_bitset() with the same bitset attribute would.
0601  *
0602  * Return:   negative error code on failure, 0 on success
0603  */
0604 int ethnl_parse_bitset(unsigned long *val, unsigned long *mask,
0605                unsigned int nbits, const struct nlattr *attr,
0606                ethnl_string_array_t names,
0607                struct netlink_ext_ack *extack)
0608 {
0609     struct nlattr *tb[ARRAY_SIZE(bitset_policy)];
0610     const struct nlattr *bit_attr;
0611     bool no_mask;
0612     int rem;
0613     int ret;
0614 
0615     if (!attr)
0616         return 0;
0617     ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr,
0618                    bitset_policy, extack);
0619     if (ret < 0)
0620         return ret;
0621     no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
0622 
0623     if (!tb[ETHTOOL_A_BITSET_BITS]) {
0624         unsigned int change_bits;
0625 
0626         ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack);
0627         if (ret < 0)
0628             return ret;
0629 
0630         change_bits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);
0631         if (change_bits > nbits)
0632             change_bits = nbits;
0633         bitmap_from_arr32(val, nla_data(tb[ETHTOOL_A_BITSET_VALUE]),
0634                   change_bits);
0635         if (change_bits < nbits)
0636             bitmap_clear(val, change_bits, nbits - change_bits);
0637         if (no_mask) {
0638             bitmap_fill(mask, nbits);
0639         } else {
0640             bitmap_from_arr32(mask,
0641                       nla_data(tb[ETHTOOL_A_BITSET_MASK]),
0642                       change_bits);
0643             if (change_bits < nbits)
0644                 bitmap_clear(mask, change_bits,
0645                          nbits - change_bits);
0646         }
0647 
0648         return 0;
0649     }
0650 
0651     if (tb[ETHTOOL_A_BITSET_VALUE]) {
0652         NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE],
0653                     "value only allowed in compact bitset");
0654         return -EINVAL;
0655     }
0656     if (tb[ETHTOOL_A_BITSET_MASK]) {
0657         NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK],
0658                     "mask only allowed in compact bitset");
0659         return -EINVAL;
0660     }
0661 
0662     bitmap_zero(val, nbits);
0663     if (no_mask)
0664         bitmap_fill(mask, nbits);
0665     else
0666         bitmap_zero(mask, nbits);
0667 
0668     nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) {
0669         unsigned int idx;
0670         bool bit_val;
0671 
0672         ret = ethnl_parse_bit(&idx, &bit_val, nbits, bit_attr, no_mask,
0673                       names, extack);
0674         if (ret < 0)
0675             return ret;
0676         if (bit_val)
0677             __set_bit(idx, val);
0678         if (!no_mask)
0679             __set_bit(idx, mask);
0680     }
0681 
0682     return 0;
0683 }
0684 
0685 #if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN)
0686 
0687 /* 64-bit big endian architectures are the only case when u32 based bitmaps
0688  * and unsigned long based bitmaps have different memory layout so that we
0689  * cannot simply cast the latter to the former and need actual wrappers
0690  * converting the latter to the former.
0691  *
0692  * To reduce the number of slab allocations, the wrappers use fixed size local
0693  * variables for bitmaps up to ETHNL_SMALL_BITMAP_BITS bits which is the
0694  * majority of bitmaps used by ethtool.
0695  */
0696 #define ETHNL_SMALL_BITMAP_BITS 128
0697 #define ETHNL_SMALL_BITMAP_WORDS DIV_ROUND_UP(ETHNL_SMALL_BITMAP_BITS, 32)
0698 
0699 int ethnl_bitset_size(const unsigned long *val, const unsigned long *mask,
0700               unsigned int nbits, ethnl_string_array_t names,
0701               bool compact)
0702 {
0703     u32 small_mask32[ETHNL_SMALL_BITMAP_WORDS];
0704     u32 small_val32[ETHNL_SMALL_BITMAP_WORDS];
0705     u32 *mask32;
0706     u32 *val32;
0707     int ret;
0708 
0709     if (nbits > ETHNL_SMALL_BITMAP_BITS) {
0710         unsigned int nwords = DIV_ROUND_UP(nbits, 32);
0711 
0712         val32 = kmalloc_array(2 * nwords, sizeof(u32), GFP_KERNEL);
0713         if (!val32)
0714             return -ENOMEM;
0715         mask32 = val32 + nwords;
0716     } else {
0717         val32 = small_val32;
0718         mask32 = small_mask32;
0719     }
0720 
0721     bitmap_to_arr32(val32, val, nbits);
0722     if (mask)
0723         bitmap_to_arr32(mask32, mask, nbits);
0724     else
0725         mask32 = NULL;
0726     ret = ethnl_bitset32_size(val32, mask32, nbits, names, compact);
0727 
0728     if (nbits > ETHNL_SMALL_BITMAP_BITS)
0729         kfree(val32);
0730 
0731     return ret;
0732 }
0733 
0734 int ethnl_put_bitset(struct sk_buff *skb, int attrtype,
0735              const unsigned long *val, const unsigned long *mask,
0736              unsigned int nbits, ethnl_string_array_t names,
0737              bool compact)
0738 {
0739     u32 small_mask32[ETHNL_SMALL_BITMAP_WORDS];
0740     u32 small_val32[ETHNL_SMALL_BITMAP_WORDS];
0741     u32 *mask32;
0742     u32 *val32;
0743     int ret;
0744 
0745     if (nbits > ETHNL_SMALL_BITMAP_BITS) {
0746         unsigned int nwords = DIV_ROUND_UP(nbits, 32);
0747 
0748         val32 = kmalloc_array(2 * nwords, sizeof(u32), GFP_KERNEL);
0749         if (!val32)
0750             return -ENOMEM;
0751         mask32 = val32 + nwords;
0752     } else {
0753         val32 = small_val32;
0754         mask32 = small_mask32;
0755     }
0756 
0757     bitmap_to_arr32(val32, val, nbits);
0758     if (mask)
0759         bitmap_to_arr32(mask32, mask, nbits);
0760     else
0761         mask32 = NULL;
0762     ret = ethnl_put_bitset32(skb, attrtype, val32, mask32, nbits, names,
0763                  compact);
0764 
0765     if (nbits > ETHNL_SMALL_BITMAP_BITS)
0766         kfree(val32);
0767 
0768     return ret;
0769 }
0770 
0771 int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
0772             const struct nlattr *attr, ethnl_string_array_t names,
0773             struct netlink_ext_ack *extack, bool *mod)
0774 {
0775     u32 small_bitmap32[ETHNL_SMALL_BITMAP_WORDS];
0776     u32 *bitmap32 = small_bitmap32;
0777     bool u32_mod = false;
0778     int ret;
0779 
0780     if (nbits > ETHNL_SMALL_BITMAP_BITS) {
0781         unsigned int dst_words = DIV_ROUND_UP(nbits, 32);
0782 
0783         bitmap32 = kmalloc_array(dst_words, sizeof(u32), GFP_KERNEL);
0784         if (!bitmap32)
0785             return -ENOMEM;
0786     }
0787 
0788     bitmap_to_arr32(bitmap32, bitmap, nbits);
0789     ret = ethnl_update_bitset32(bitmap32, nbits, attr, names, extack,
0790                     &u32_mod);
0791     if (u32_mod) {
0792         bitmap_from_arr32(bitmap, bitmap32, nbits);
0793         *mod = true;
0794     }
0795 
0796     if (nbits > ETHNL_SMALL_BITMAP_BITS)
0797         kfree(bitmap32);
0798 
0799     return ret;
0800 }
0801 
0802 #else
0803 
0804 /* On little endian 64-bit and all 32-bit architectures, an unsigned long
0805  * based bitmap can be interpreted as u32 based one using a simple cast.
0806  */
0807 
0808 int ethnl_bitset_size(const unsigned long *val, const unsigned long *mask,
0809               unsigned int nbits, ethnl_string_array_t names,
0810               bool compact)
0811 {
0812     return ethnl_bitset32_size((const u32 *)val, (const u32 *)mask, nbits,
0813                    names, compact);
0814 }
0815 
0816 int ethnl_put_bitset(struct sk_buff *skb, int attrtype,
0817              const unsigned long *val, const unsigned long *mask,
0818              unsigned int nbits, ethnl_string_array_t names,
0819              bool compact)
0820 {
0821     return ethnl_put_bitset32(skb, attrtype, (const u32 *)val,
0822                   (const u32 *)mask, nbits, names, compact);
0823 }
0824 
0825 int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
0826             const struct nlattr *attr, ethnl_string_array_t names,
0827             struct netlink_ext_ack *extack, bool *mod)
0828 {
0829     return ethnl_update_bitset32((u32 *)bitmap, nbits, attr, names, extack,
0830                      mod);
0831 }
0832 
0833 #endif /* BITS_PER_LONG == 64 && defined(__BIG_ENDIAN) */