#include <linux/ethtool_netlink.h>
#include <linux/bitmap.h>
#include "netlink.h"
#include "bitset.h"
static u32 ethnl_lower_bits(unsigned int n)
{ … }
static u32 ethnl_upper_bits(unsigned int n)
{ … }
static void ethnl_bitmap32_clear(u32 *dst, unsigned int start, unsigned int end,
bool *mod)
{ … }
static bool ethnl_bitmap32_not_zero(const u32 *map, unsigned int start,
unsigned int end)
{ … }
static void ethnl_bitmap32_update(u32 *dst, unsigned int nbits,
const u32 *value, const u32 *mask, bool *mod)
{ … }
static bool ethnl_bitmap32_test_bit(const u32 *map, unsigned int index)
{ … }
int ethnl_bitset32_size(const u32 *val, const u32 *mask, unsigned int nbits,
ethnl_string_array_t names, bool compact)
{ … }
int ethnl_put_bitset32(struct sk_buff *skb, int attrtype, const u32 *val,
const u32 *mask, unsigned int nbits,
ethnl_string_array_t names, bool compact)
{ … }
static const struct nla_policy bitset_policy[] = …;
static const struct nla_policy bit_policy[] = …;
int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact)
{ … }
static int ethnl_name_to_idx(ethnl_string_array_t names, unsigned int n_names,
const char *name)
{ … }
static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits,
const struct nlattr *bit_attr, bool no_mask,
ethnl_string_array_t names,
struct netlink_ext_ack *extack)
{ … }
static int
ethnl_update_bitset32_verbose(u32 *bitmap, unsigned int nbits,
const struct nlattr *attr, struct nlattr **tb,
ethnl_string_array_t names,
struct netlink_ext_ack *extack, bool *mod)
{ … }
static int ethnl_compact_sanity_checks(unsigned int nbits,
const struct nlattr *nest,
struct nlattr **tb,
struct netlink_ext_ack *extack)
{ … }
int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits,
const struct nlattr *attr, ethnl_string_array_t names,
struct netlink_ext_ack *extack, bool *mod)
{ … }
int ethnl_parse_bitset(unsigned long *val, unsigned long *mask,
unsigned int nbits, const struct nlattr *attr,
ethnl_string_array_t names,
struct netlink_ext_ack *extack)
{ … }
#if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN)
#define ETHNL_SMALL_BITMAP_BITS …
#define ETHNL_SMALL_BITMAP_WORDS …
int ethnl_bitset_size(const unsigned long *val, const unsigned long *mask,
unsigned int nbits, ethnl_string_array_t names,
bool compact)
{
u32 small_mask32[ETHNL_SMALL_BITMAP_WORDS];
u32 small_val32[ETHNL_SMALL_BITMAP_WORDS];
u32 *mask32;
u32 *val32;
int ret;
if (nbits > ETHNL_SMALL_BITMAP_BITS) {
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
val32 = kmalloc_array(2 * nwords, sizeof(u32), GFP_KERNEL);
if (!val32)
return -ENOMEM;
mask32 = val32 + nwords;
} else {
val32 = small_val32;
mask32 = small_mask32;
}
bitmap_to_arr32(val32, val, nbits);
if (mask)
bitmap_to_arr32(mask32, mask, nbits);
else
mask32 = NULL;
ret = ethnl_bitset32_size(val32, mask32, nbits, names, compact);
if (nbits > ETHNL_SMALL_BITMAP_BITS)
kfree(val32);
return ret;
}
int ethnl_put_bitset(struct sk_buff *skb, int attrtype,
const unsigned long *val, const unsigned long *mask,
unsigned int nbits, ethnl_string_array_t names,
bool compact)
{
u32 small_mask32[ETHNL_SMALL_BITMAP_WORDS];
u32 small_val32[ETHNL_SMALL_BITMAP_WORDS];
u32 *mask32;
u32 *val32;
int ret;
if (nbits > ETHNL_SMALL_BITMAP_BITS) {
unsigned int nwords = DIV_ROUND_UP(nbits, 32);
val32 = kmalloc_array(2 * nwords, sizeof(u32), GFP_KERNEL);
if (!val32)
return -ENOMEM;
mask32 = val32 + nwords;
} else {
val32 = small_val32;
mask32 = small_mask32;
}
bitmap_to_arr32(val32, val, nbits);
if (mask)
bitmap_to_arr32(mask32, mask, nbits);
else
mask32 = NULL;
ret = ethnl_put_bitset32(skb, attrtype, val32, mask32, nbits, names,
compact);
if (nbits > ETHNL_SMALL_BITMAP_BITS)
kfree(val32);
return ret;
}
int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
const struct nlattr *attr, ethnl_string_array_t names,
struct netlink_ext_ack *extack, bool *mod)
{
u32 small_bitmap32[ETHNL_SMALL_BITMAP_WORDS];
u32 *bitmap32 = small_bitmap32;
bool u32_mod = false;
int ret;
if (nbits > ETHNL_SMALL_BITMAP_BITS) {
unsigned int dst_words = DIV_ROUND_UP(nbits, 32);
bitmap32 = kmalloc_array(dst_words, sizeof(u32), GFP_KERNEL);
if (!bitmap32)
return -ENOMEM;
}
bitmap_to_arr32(bitmap32, bitmap, nbits);
ret = ethnl_update_bitset32(bitmap32, nbits, attr, names, extack,
&u32_mod);
if (u32_mod) {
bitmap_from_arr32(bitmap, bitmap32, nbits);
*mod = true;
}
if (nbits > ETHNL_SMALL_BITMAP_BITS)
kfree(bitmap32);
return ret;
}
#else
int ethnl_bitset_size(const unsigned long *val, const unsigned long *mask,
unsigned int nbits, ethnl_string_array_t names,
bool compact)
{ … }
int ethnl_put_bitset(struct sk_buff *skb, int attrtype,
const unsigned long *val, const unsigned long *mask,
unsigned int nbits, ethnl_string_array_t names,
bool compact)
{ … }
int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits,
const struct nlattr *attr, ethnl_string_array_t names,
struct netlink_ext_ack *extack, bool *mod)
{ … }
#endif