Commit 64c83d83 authored by Jamal Hadi Salim's avatar Jamal Hadi Salim Committed by David S. Miller

net netlink: Add new type NLA_BITFIELD32

Generic bitflags attribute content sent to the kernel by user.
With this netlink attr type the user can either set or unset a
flag in the kernel.

The value is a bitmap that defines the bit values being set
The selector is a bitmask that defines which value bit is to be
considered.

A check is made to ensure the rules that a kernel subsystem always
conforms to bitflags the kernel already knows about. i.e
if the user tries to set a bit flag that is not understood then
the _it will be rejected_.

In the most basic form, the user specifies the attribute policy as:
[ATTR_GOO] = { .type = NLA_BITFIELD32, .validation_data = &myvalidflags },

where myvalidflags is the bit mask of the flags the kernel understands.

If the user _does not_ provide myvalidflags then the attribute will
also be rejected.

Examples:
value = 0x0, and selector = 0x1
implies we are selecting bit 1 and we want to set its value to 0.

value = 0x2, and selector = 0x2
implies we are selecting bit 2 and we want to set its value to 1.
Suggested-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fbbeefdd
...@@ -178,6 +178,7 @@ enum { ...@@ -178,6 +178,7 @@ enum {
NLA_S16, NLA_S16,
NLA_S32, NLA_S32,
NLA_S64, NLA_S64,
NLA_BITFIELD32,
__NLA_TYPE_MAX, __NLA_TYPE_MAX,
}; };
...@@ -206,6 +207,7 @@ enum { ...@@ -206,6 +207,7 @@ enum {
* NLA_MSECS Leaving the length field zero will verify the * NLA_MSECS Leaving the length field zero will verify the
* given type fits, using it verifies minimum length * given type fits, using it verifies minimum length
* just like "All other" * just like "All other"
* NLA_BITFIELD32 A 32-bit bitmap/bitselector attribute
* All other Minimum length of attribute payload * All other Minimum length of attribute payload
* *
* Example: * Example:
...@@ -213,11 +215,13 @@ enum { ...@@ -213,11 +215,13 @@ enum {
* [ATTR_FOO] = { .type = NLA_U16 }, * [ATTR_FOO] = { .type = NLA_U16 },
* [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ }, * [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ },
* [ATTR_BAZ] = { .len = sizeof(struct mystruct) }, * [ATTR_BAZ] = { .len = sizeof(struct mystruct) },
* [ATTR_GOO] = { .type = NLA_BITFIELD32, .validation_data = &myvalidflags },
* }; * };
*/ */
struct nla_policy { struct nla_policy {
u16 type; u16 type;
u16 len; u16 len;
void *validation_data;
}; };
/** /**
...@@ -1202,6 +1206,18 @@ static inline struct in6_addr nla_get_in6_addr(const struct nlattr *nla) ...@@ -1202,6 +1206,18 @@ static inline struct in6_addr nla_get_in6_addr(const struct nlattr *nla)
return tmp; return tmp;
} }
/**
* nla_get_bitfield32 - return payload of 32 bitfield attribute
* @nla: nla_bitfield32 attribute
*/
static inline struct nla_bitfield32 nla_get_bitfield32(const struct nlattr *nla)
{
struct nla_bitfield32 tmp;
nla_memcpy(&tmp, nla, sizeof(tmp));
return tmp;
}
/** /**
* nla_memdup - duplicate attribute memory (kmemdup) * nla_memdup - duplicate attribute memory (kmemdup)
* @src: netlink attribute to duplicate from * @src: netlink attribute to duplicate from
......
...@@ -226,5 +226,22 @@ struct nlattr { ...@@ -226,5 +226,22 @@ struct nlattr {
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
/* Generic 32 bitflags attribute content sent to the kernel.
*
* The value is a bitmap that defines the values being set
* The selector is a bitmask that defines which value is legit
*
* Examples:
* value = 0x0, and selector = 0x1
* implies we are selecting bit 1 and we want to set its value to 0.
*
* value = 0x2, and selector = 0x2
* implies we are selecting bit 2 and we want to set its value to 1.
*
*/
struct nla_bitfield32 {
__u32 value;
__u32 selector;
};
#endif /* _UAPI__LINUX_NETLINK_H */ #endif /* _UAPI__LINUX_NETLINK_H */
...@@ -27,6 +27,30 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = { ...@@ -27,6 +27,30 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
[NLA_S64] = sizeof(s64), [NLA_S64] = sizeof(s64),
}; };
static int validate_nla_bitfield32(const struct nlattr *nla,
u32 *valid_flags_allowed)
{
const struct nla_bitfield32 *bf = nla_data(nla);
u32 *valid_flags_mask = valid_flags_allowed;
if (!valid_flags_allowed)
return -EINVAL;
/*disallow invalid bit selector */
if (bf->selector & ~*valid_flags_mask)
return -EINVAL;
/*disallow invalid bit values */
if (bf->value & ~*valid_flags_mask)
return -EINVAL;
/*disallow valid bit values that are not selected*/
if (bf->value & ~bf->selector)
return -EINVAL;
return 0;
}
static int validate_nla(const struct nlattr *nla, int maxtype, static int validate_nla(const struct nlattr *nla, int maxtype,
const struct nla_policy *policy) const struct nla_policy *policy)
{ {
...@@ -46,6 +70,12 @@ static int validate_nla(const struct nlattr *nla, int maxtype, ...@@ -46,6 +70,12 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
return -ERANGE; return -ERANGE;
break; break;
case NLA_BITFIELD32:
if (attrlen != sizeof(struct nla_bitfield32))
return -ERANGE;
return validate_nla_bitfield32(nla, pt->validation_data);
case NLA_NUL_STRING: case NLA_NUL_STRING:
if (pt->len) if (pt->len)
minlen = min_t(int, attrlen, pt->len + 1); minlen = min_t(int, attrlen, pt->len + 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment