Merge branch 'netlink-validation-improvements-refactoring'
Johannes Berg says: ==================== netlink validation improvements/refactoring Alright, this is the resend now, really just changing - the WARN_ON_ONCE() as spotted by Jakub; - mark the export patch no longer RFC. I wasn't actually sure if you meant this one too, and I really should dig out and polish the code that showed it in userspace. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
550cbea0b0
@ -182,19 +182,28 @@ enum {
|
||||
NLA_BITFIELD32,
|
||||
NLA_REJECT,
|
||||
NLA_EXACT_LEN,
|
||||
NLA_EXACT_LEN_WARN,
|
||||
NLA_MIN_LEN,
|
||||
__NLA_TYPE_MAX,
|
||||
};
|
||||
|
||||
#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
|
||||
|
||||
struct netlink_range_validation {
|
||||
u64 min, max;
|
||||
};
|
||||
|
||||
struct netlink_range_validation_signed {
|
||||
s64 min, max;
|
||||
};
|
||||
|
||||
enum nla_policy_validation {
|
||||
NLA_VALIDATE_NONE,
|
||||
NLA_VALIDATE_RANGE,
|
||||
NLA_VALIDATE_MIN,
|
||||
NLA_VALIDATE_MAX,
|
||||
NLA_VALIDATE_RANGE_PTR,
|
||||
NLA_VALIDATE_FUNCTION,
|
||||
NLA_VALIDATE_WARN_TOO_LONG,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -217,7 +226,7 @@ enum nla_policy_validation {
|
||||
* NLA_NESTED,
|
||||
* NLA_NESTED_ARRAY Length verification is done by checking len of
|
||||
* nested header (or empty); len field is used if
|
||||
* validation_data is also used, for the max attr
|
||||
* nested_policy is also used, for the max attr
|
||||
* number in the nested policy.
|
||||
* NLA_U8, NLA_U16,
|
||||
* NLA_U32, NLA_U64,
|
||||
@ -228,34 +237,32 @@ enum nla_policy_validation {
|
||||
* just like "All other"
|
||||
* NLA_BITFIELD32 Unused
|
||||
* NLA_REJECT Unused
|
||||
* NLA_EXACT_LEN Attribute must have exactly this length, otherwise
|
||||
* it is rejected.
|
||||
* NLA_EXACT_LEN_WARN Attribute should have exactly this length, a warning
|
||||
* is logged if it is longer, shorter is rejected.
|
||||
* NLA_EXACT_LEN Attribute should have exactly this length, otherwise
|
||||
* it is rejected or warned about, the latter happening
|
||||
* if and only if the `validation_type' is set to
|
||||
* NLA_VALIDATE_WARN_TOO_LONG.
|
||||
* NLA_MIN_LEN Minimum length of attribute payload
|
||||
* All other Minimum length of attribute payload
|
||||
*
|
||||
* Meaning of `validation_data' field:
|
||||
* Meaning of validation union:
|
||||
* NLA_BITFIELD32 This is a 32-bit bitmap/bitselector attribute and
|
||||
* validation data must point to a u32 value of valid
|
||||
* flags
|
||||
* NLA_REJECT This attribute is always rejected and validation data
|
||||
* `bitfield32_valid' is the u32 value of valid flags
|
||||
* NLA_REJECT This attribute is always rejected and `reject_message'
|
||||
* may point to a string to report as the error instead
|
||||
* of the generic one in extended ACK.
|
||||
* NLA_NESTED Points to a nested policy to validate, must also set
|
||||
* `len' to the max attribute number.
|
||||
* NLA_NESTED `nested_policy' to a nested policy to validate, must
|
||||
* also set `len' to the max attribute number. Use the
|
||||
* provided NLA_POLICY_NESTED() macro.
|
||||
* Note that nla_parse() will validate, but of course not
|
||||
* parse, the nested sub-policies.
|
||||
* NLA_NESTED_ARRAY Points to a nested policy to validate, must also set
|
||||
* `len' to the max attribute number. The difference to
|
||||
* NLA_NESTED is the structure - NLA_NESTED has the
|
||||
* nested attributes directly inside, while an array has
|
||||
* the nested attributes at another level down and the
|
||||
* attributes directly in the nesting don't matter.
|
||||
* All other Unused - but note that it's a union
|
||||
*
|
||||
* Meaning of `min' and `max' fields, use via NLA_POLICY_MIN, NLA_POLICY_MAX
|
||||
* and NLA_POLICY_RANGE:
|
||||
* NLA_NESTED_ARRAY `nested_policy' points to a nested policy to validate,
|
||||
* must also set `len' to the max attribute number. Use
|
||||
* the provided NLA_POLICY_NESTED_ARRAY() macro.
|
||||
* The difference to NLA_NESTED is the structure:
|
||||
* NLA_NESTED has the nested attributes directly inside
|
||||
* while an array has the nested attributes at another
|
||||
* level down and the attribute types directly in the
|
||||
* nesting don't matter.
|
||||
* NLA_U8,
|
||||
* NLA_U16,
|
||||
* NLA_U32,
|
||||
@ -263,29 +270,47 @@ enum nla_policy_validation {
|
||||
* NLA_S8,
|
||||
* NLA_S16,
|
||||
* NLA_S32,
|
||||
* NLA_S64 These are used depending on the validation_type
|
||||
* field, if that is min/max/range then the minimum,
|
||||
* maximum and both are used (respectively) to check
|
||||
* NLA_S64 The `min' and `max' fields are used depending on the
|
||||
* validation_type field, if that is min/max/range then
|
||||
* the min, max or both are used (respectively) to check
|
||||
* the value of the integer attribute.
|
||||
* Note that in the interest of code simplicity and
|
||||
* struct size both limits are s16, so you cannot
|
||||
* enforce a range that doesn't fall within the range
|
||||
* of s16 - do that as usual in the code instead.
|
||||
* Use the NLA_POLICY_MIN(), NLA_POLICY_MAX() and
|
||||
* NLA_POLICY_RANGE() macros.
|
||||
* NLA_U8,
|
||||
* NLA_U16,
|
||||
* NLA_U32,
|
||||
* NLA_U64 If the validation_type field instead is set to
|
||||
* NLA_VALIDATE_RANGE_PTR, `range' must be a pointer
|
||||
* to a struct netlink_range_validation that indicates
|
||||
* the min/max values.
|
||||
* Use NLA_POLICY_FULL_RANGE().
|
||||
* NLA_S8,
|
||||
* NLA_S16,
|
||||
* NLA_S32,
|
||||
* NLA_S64 If the validation_type field instead is set to
|
||||
* NLA_VALIDATE_RANGE_PTR, `range_signed' must be a
|
||||
* pointer to a struct netlink_range_validation_signed
|
||||
* that indicates the min/max values.
|
||||
* Use NLA_POLICY_FULL_RANGE_SIGNED().
|
||||
* All other Unused - but note that it's a union
|
||||
*
|
||||
* Meaning of `validate' field, use via NLA_POLICY_VALIDATE_FN:
|
||||
* NLA_BINARY Validation function called for the attribute,
|
||||
* not compatible with use of the validation_data
|
||||
* as in NLA_BITFIELD32, NLA_REJECT, NLA_NESTED and
|
||||
* NLA_NESTED_ARRAY.
|
||||
* NLA_BINARY Validation function called for the attribute.
|
||||
* All other Unused - but note that it's a union
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* static const u32 myvalidflags = 0xff231023;
|
||||
*
|
||||
* static const struct nla_policy my_policy[ATTR_MAX+1] = {
|
||||
* [ATTR_FOO] = { .type = NLA_U16 },
|
||||
* [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ },
|
||||
* [ATTR_BAZ] = { .type = NLA_EXACT_LEN, .len = sizeof(struct mystruct) },
|
||||
* [ATTR_GOO] = { .type = NLA_BITFIELD32, .validation_data = &myvalidflags },
|
||||
* [ATTR_GOO] = NLA_POLICY_BITFIELD32(myvalidflags),
|
||||
* };
|
||||
*/
|
||||
struct nla_policy {
|
||||
@ -293,7 +318,11 @@ struct nla_policy {
|
||||
u8 validation_type;
|
||||
u16 len;
|
||||
union {
|
||||
const void *validation_data;
|
||||
const u32 bitfield32_valid;
|
||||
const char *reject_message;
|
||||
const struct nla_policy *nested_policy;
|
||||
struct netlink_range_validation *range;
|
||||
struct netlink_range_validation_signed *range_signed;
|
||||
struct {
|
||||
s16 min, max;
|
||||
};
|
||||
@ -321,28 +350,39 @@ struct nla_policy {
|
||||
};
|
||||
|
||||
#define NLA_POLICY_EXACT_LEN(_len) { .type = NLA_EXACT_LEN, .len = _len }
|
||||
#define NLA_POLICY_EXACT_LEN_WARN(_len) { .type = NLA_EXACT_LEN_WARN, \
|
||||
.len = _len }
|
||||
#define NLA_POLICY_EXACT_LEN_WARN(_len) \
|
||||
{ .type = NLA_EXACT_LEN, .len = _len, \
|
||||
.validation_type = NLA_VALIDATE_WARN_TOO_LONG, }
|
||||
#define NLA_POLICY_MIN_LEN(_len) { .type = NLA_MIN_LEN, .len = _len }
|
||||
|
||||
#define NLA_POLICY_ETH_ADDR NLA_POLICY_EXACT_LEN(ETH_ALEN)
|
||||
#define NLA_POLICY_ETH_ADDR_COMPAT NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN)
|
||||
|
||||
#define _NLA_POLICY_NESTED(maxattr, policy) \
|
||||
{ .type = NLA_NESTED, .validation_data = policy, .len = maxattr }
|
||||
{ .type = NLA_NESTED, .nested_policy = policy, .len = maxattr }
|
||||
#define _NLA_POLICY_NESTED_ARRAY(maxattr, policy) \
|
||||
{ .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr }
|
||||
{ .type = NLA_NESTED_ARRAY, .nested_policy = policy, .len = maxattr }
|
||||
#define NLA_POLICY_NESTED(policy) \
|
||||
_NLA_POLICY_NESTED(ARRAY_SIZE(policy) - 1, policy)
|
||||
#define NLA_POLICY_NESTED_ARRAY(policy) \
|
||||
_NLA_POLICY_NESTED_ARRAY(ARRAY_SIZE(policy) - 1, policy)
|
||||
#define NLA_POLICY_BITFIELD32(valid) \
|
||||
{ .type = NLA_BITFIELD32, .bitfield32_valid = valid }
|
||||
|
||||
#define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition))
|
||||
#define NLA_ENSURE_UINT_TYPE(tp) \
|
||||
(__NLA_ENSURE(tp == NLA_U8 || tp == NLA_U16 || \
|
||||
tp == NLA_U32 || tp == NLA_U64 || \
|
||||
tp == NLA_MSECS) + tp)
|
||||
#define NLA_ENSURE_SINT_TYPE(tp) \
|
||||
(__NLA_ENSURE(tp == NLA_S8 || tp == NLA_S16 || \
|
||||
tp == NLA_S32 || tp == NLA_S64) + tp)
|
||||
#define NLA_ENSURE_INT_TYPE(tp) \
|
||||
(__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \
|
||||
tp == NLA_S16 || tp == NLA_U16 || \
|
||||
tp == NLA_S32 || tp == NLA_U32 || \
|
||||
tp == NLA_S64 || tp == NLA_U64) + tp)
|
||||
tp == NLA_S64 || tp == NLA_U64 || \
|
||||
tp == NLA_MSECS) + tp)
|
||||
#define NLA_ENSURE_NO_VALIDATION_PTR(tp) \
|
||||
(__NLA_ENSURE(tp != NLA_BITFIELD32 && \
|
||||
tp != NLA_REJECT && \
|
||||
@ -356,6 +396,18 @@ struct nla_policy {
|
||||
.max = _max \
|
||||
}
|
||||
|
||||
#define NLA_POLICY_FULL_RANGE(tp, _range) { \
|
||||
.type = NLA_ENSURE_UINT_TYPE(tp), \
|
||||
.validation_type = NLA_VALIDATE_RANGE_PTR, \
|
||||
.range = _range, \
|
||||
}
|
||||
|
||||
#define NLA_POLICY_FULL_RANGE_SIGNED(tp, _range) { \
|
||||
.type = NLA_ENSURE_SINT_TYPE(tp), \
|
||||
.validation_type = NLA_VALIDATE_RANGE_PTR, \
|
||||
.range_signed = _range, \
|
||||
}
|
||||
|
||||
#define NLA_POLICY_MIN(tp, _min) { \
|
||||
.type = NLA_ENSURE_INT_TYPE(tp), \
|
||||
.validation_type = NLA_VALIDATE_MIN, \
|
||||
@ -1876,4 +1928,15 @@ static inline bool nla_is_last(const struct nlattr *nla, int rem)
|
||||
return nla->nla_len == rem;
|
||||
}
|
||||
|
||||
void nla_get_range_unsigned(const struct nla_policy *pt,
|
||||
struct netlink_range_validation *range);
|
||||
void nla_get_range_signed(const struct nla_policy *pt,
|
||||
struct netlink_range_validation_signed *range);
|
||||
|
||||
int netlink_policy_dump_start(const struct nla_policy *policy,
|
||||
unsigned int maxtype,
|
||||
unsigned long *state);
|
||||
bool netlink_policy_dump_loop(unsigned long *state);
|
||||
int netlink_policy_dump_write(struct sk_buff *skb, unsigned long state);
|
||||
|
||||
#endif
|
||||
|
@ -48,6 +48,7 @@ enum {
|
||||
CTRL_CMD_NEWMCAST_GRP,
|
||||
CTRL_CMD_DELMCAST_GRP,
|
||||
CTRL_CMD_GETMCAST_GRP, /* unused */
|
||||
CTRL_CMD_GETPOLICY,
|
||||
__CTRL_CMD_MAX,
|
||||
};
|
||||
|
||||
@ -62,6 +63,7 @@ enum {
|
||||
CTRL_ATTR_MAXATTR,
|
||||
CTRL_ATTR_OPS,
|
||||
CTRL_ATTR_MCAST_GROUPS,
|
||||
CTRL_ATTR_POLICY,
|
||||
__CTRL_ATTR_MAX,
|
||||
};
|
||||
|
||||
|
@ -249,4 +249,107 @@ struct nla_bitfield32 {
|
||||
__u32 selector;
|
||||
};
|
||||
|
||||
/*
|
||||
* policy descriptions - it's specific to each family how this is used
|
||||
* Normally, it should be retrieved via a dump inside another attribute
|
||||
* specifying where it applies.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum netlink_attribute_type - type of an attribute
|
||||
* @NL_ATTR_TYPE_INVALID: unused
|
||||
* @NL_ATTR_TYPE_FLAG: flag attribute (present/not present)
|
||||
* @NL_ATTR_TYPE_U8: 8-bit unsigned attribute
|
||||
* @NL_ATTR_TYPE_U16: 16-bit unsigned attribute
|
||||
* @NL_ATTR_TYPE_U32: 32-bit unsigned attribute
|
||||
* @NL_ATTR_TYPE_U64: 64-bit unsigned attribute
|
||||
* @NL_ATTR_TYPE_S8: 8-bit signed attribute
|
||||
* @NL_ATTR_TYPE_S16: 16-bit signed attribute
|
||||
* @NL_ATTR_TYPE_S32: 32-bit signed attribute
|
||||
* @NL_ATTR_TYPE_S64: 64-bit signed attribute
|
||||
* @NL_ATTR_TYPE_BINARY: binary data, min/max length may be specified
|
||||
* @NL_ATTR_TYPE_STRING: string, min/max length may be specified
|
||||
* @NL_ATTR_TYPE_NUL_STRING: NUL-terminated string,
|
||||
* min/max length may be specified
|
||||
* @NL_ATTR_TYPE_NESTED: nested, i.e. the content of this attribute
|
||||
* consists of sub-attributes. The nested policy and maxtype
|
||||
* inside may be specified.
|
||||
* @NL_ATTR_TYPE_NESTED_ARRAY: nested array, i.e. the content of this
|
||||
* attribute contains sub-attributes whose type is irrelevant
|
||||
* (just used to separate the array entries) and each such array
|
||||
* entry has attributes again, the policy for those inner ones
|
||||
* and the corresponding maxtype may be specified.
|
||||
* @NL_ATTR_TYPE_BITFIELD32: &struct nla_bitfield32 attribute
|
||||
*/
|
||||
enum netlink_attribute_type {
|
||||
NL_ATTR_TYPE_INVALID,
|
||||
|
||||
NL_ATTR_TYPE_FLAG,
|
||||
|
||||
NL_ATTR_TYPE_U8,
|
||||
NL_ATTR_TYPE_U16,
|
||||
NL_ATTR_TYPE_U32,
|
||||
NL_ATTR_TYPE_U64,
|
||||
|
||||
NL_ATTR_TYPE_S8,
|
||||
NL_ATTR_TYPE_S16,
|
||||
NL_ATTR_TYPE_S32,
|
||||
NL_ATTR_TYPE_S64,
|
||||
|
||||
NL_ATTR_TYPE_BINARY,
|
||||
NL_ATTR_TYPE_STRING,
|
||||
NL_ATTR_TYPE_NUL_STRING,
|
||||
|
||||
NL_ATTR_TYPE_NESTED,
|
||||
NL_ATTR_TYPE_NESTED_ARRAY,
|
||||
|
||||
NL_ATTR_TYPE_BITFIELD32,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum netlink_policy_type_attr - policy type attributes
|
||||
* @NL_POLICY_TYPE_ATTR_UNSPEC: unused
|
||||
* @NL_POLICY_TYPE_ATTR_TYPE: type of the attribute,
|
||||
* &enum netlink_attribute_type (U32)
|
||||
* @NL_POLICY_TYPE_ATTR_MIN_VALUE_S: minimum value for signed
|
||||
* integers (S64)
|
||||
* @NL_POLICY_TYPE_ATTR_MAX_VALUE_S: maximum value for signed
|
||||
* integers (S64)
|
||||
* @NL_POLICY_TYPE_ATTR_MIN_VALUE_U: minimum value for unsigned
|
||||
* integers (U64)
|
||||
* @NL_POLICY_TYPE_ATTR_MAX_VALUE_U: maximum value for unsigned
|
||||
* integers (U64)
|
||||
* @NL_POLICY_TYPE_ATTR_MIN_LENGTH: minimum length for binary
|
||||
* attributes, no minimum if not given (U32)
|
||||
* @NL_POLICY_TYPE_ATTR_MAX_LENGTH: maximum length for binary
|
||||
* attributes, no maximum if not given (U32)
|
||||
* @NL_POLICY_TYPE_ATTR_POLICY_IDX: sub policy for nested and
|
||||
* nested array types (U32)
|
||||
* @NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE: maximum sub policy
|
||||
* attribute for nested and nested array types, this can
|
||||
* in theory be < the size of the policy pointed to by
|
||||
* the index, if limited inside the nesting (U32)
|
||||
* @NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: valid mask for the
|
||||
* bitfield32 type (U32)
|
||||
* @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment
|
||||
*/
|
||||
enum netlink_policy_type_attr {
|
||||
NL_POLICY_TYPE_ATTR_UNSPEC,
|
||||
NL_POLICY_TYPE_ATTR_TYPE,
|
||||
NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
|
||||
NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
|
||||
NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
|
||||
NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
|
||||
NL_POLICY_TYPE_ATTR_MIN_LENGTH,
|
||||
NL_POLICY_TYPE_ATTR_MAX_LENGTH,
|
||||
NL_POLICY_TYPE_ATTR_POLICY_IDX,
|
||||
NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
|
||||
NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
|
||||
NL_POLICY_TYPE_ATTR_PAD,
|
||||
|
||||
/* keep last */
|
||||
__NL_POLICY_TYPE_ATTR_MAX,
|
||||
NL_POLICY_TYPE_ATTR_MAX = __NL_POLICY_TYPE_ATTR_MAX - 1
|
||||
};
|
||||
|
||||
#endif /* _UAPI__LINUX_NETLINK_H */
|
||||
|
248
lib/nlattr.c
248
lib/nlattr.c
@ -44,8 +44,22 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
|
||||
[NLA_S64] = sizeof(s64),
|
||||
};
|
||||
|
||||
/*
|
||||
* Nested policies might refer back to the original
|
||||
* policy in some cases, and userspace could try to
|
||||
* abuse that and recurse by nesting in the right
|
||||
* ways. Limit recursion to avoid this problem.
|
||||
*/
|
||||
#define MAX_POLICY_RECURSION_DEPTH 10
|
||||
|
||||
static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
|
||||
const struct nla_policy *policy,
|
||||
unsigned int validate,
|
||||
struct netlink_ext_ack *extack,
|
||||
struct nlattr **tb, unsigned int depth);
|
||||
|
||||
static int validate_nla_bitfield32(const struct nlattr *nla,
|
||||
const u32 *valid_flags_mask)
|
||||
const u32 valid_flags_mask)
|
||||
{
|
||||
const struct nla_bitfield32 *bf = nla_data(nla);
|
||||
|
||||
@ -53,11 +67,11 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
|
||||
return -EINVAL;
|
||||
|
||||
/*disallow invalid bit selector */
|
||||
if (bf->selector & ~*valid_flags_mask)
|
||||
if (bf->selector & ~valid_flags_mask)
|
||||
return -EINVAL;
|
||||
|
||||
/*disallow invalid bit values */
|
||||
if (bf->value & ~*valid_flags_mask)
|
||||
if (bf->value & ~valid_flags_mask)
|
||||
return -EINVAL;
|
||||
|
||||
/*disallow valid bit values that are not selected*/
|
||||
@ -70,7 +84,7 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
|
||||
static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
|
||||
const struct nla_policy *policy,
|
||||
struct netlink_ext_ack *extack,
|
||||
unsigned int validate)
|
||||
unsigned int validate, unsigned int depth)
|
||||
{
|
||||
const struct nlattr *entry;
|
||||
int rem;
|
||||
@ -87,8 +101,9 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
ret = __nla_validate(nla_data(entry), nla_len(entry),
|
||||
maxtype, policy, validate, extack);
|
||||
ret = __nla_validate_parse(nla_data(entry), nla_len(entry),
|
||||
maxtype, policy, validate, extack,
|
||||
NULL, depth + 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@ -96,17 +111,58 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nla_validate_int_range(const struct nla_policy *pt,
|
||||
const struct nlattr *nla,
|
||||
struct netlink_ext_ack *extack)
|
||||
void nla_get_range_unsigned(const struct nla_policy *pt,
|
||||
struct netlink_range_validation *range)
|
||||
{
|
||||
bool validate_min, validate_max;
|
||||
s64 value;
|
||||
WARN_ON_ONCE(pt->validation_type != NLA_VALIDATE_RANGE_PTR &&
|
||||
(pt->min < 0 || pt->max < 0));
|
||||
|
||||
validate_min = pt->validation_type == NLA_VALIDATE_RANGE ||
|
||||
pt->validation_type == NLA_VALIDATE_MIN;
|
||||
validate_max = pt->validation_type == NLA_VALIDATE_RANGE ||
|
||||
pt->validation_type == NLA_VALIDATE_MAX;
|
||||
range->min = 0;
|
||||
|
||||
switch (pt->type) {
|
||||
case NLA_U8:
|
||||
range->max = U8_MAX;
|
||||
break;
|
||||
case NLA_U16:
|
||||
range->max = U16_MAX;
|
||||
break;
|
||||
case NLA_U32:
|
||||
range->max = U32_MAX;
|
||||
break;
|
||||
case NLA_U64:
|
||||
case NLA_MSECS:
|
||||
range->max = U64_MAX;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pt->validation_type) {
|
||||
case NLA_VALIDATE_RANGE:
|
||||
range->min = pt->min;
|
||||
range->max = pt->max;
|
||||
break;
|
||||
case NLA_VALIDATE_RANGE_PTR:
|
||||
*range = *pt->range;
|
||||
break;
|
||||
case NLA_VALIDATE_MIN:
|
||||
range->min = pt->min;
|
||||
break;
|
||||
case NLA_VALIDATE_MAX:
|
||||
range->max = pt->max;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int nla_validate_int_range_unsigned(const struct nla_policy *pt,
|
||||
const struct nlattr *nla,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netlink_range_validation range;
|
||||
u64 value;
|
||||
|
||||
switch (pt->type) {
|
||||
case NLA_U8:
|
||||
@ -118,6 +174,77 @@ static int nla_validate_int_range(const struct nla_policy *pt,
|
||||
case NLA_U32:
|
||||
value = nla_get_u32(nla);
|
||||
break;
|
||||
case NLA_U64:
|
||||
case NLA_MSECS:
|
||||
value = nla_get_u64(nla);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nla_get_range_unsigned(pt, &range);
|
||||
|
||||
if (value < range.min || value > range.max) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, nla,
|
||||
"integer out of range");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nla_get_range_signed(const struct nla_policy *pt,
|
||||
struct netlink_range_validation_signed *range)
|
||||
{
|
||||
switch (pt->type) {
|
||||
case NLA_S8:
|
||||
range->min = S8_MIN;
|
||||
range->max = S8_MAX;
|
||||
break;
|
||||
case NLA_S16:
|
||||
range->min = S16_MIN;
|
||||
range->max = S16_MAX;
|
||||
break;
|
||||
case NLA_S32:
|
||||
range->min = S32_MIN;
|
||||
range->max = S32_MAX;
|
||||
break;
|
||||
case NLA_S64:
|
||||
range->min = S64_MIN;
|
||||
range->max = S64_MAX;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pt->validation_type) {
|
||||
case NLA_VALIDATE_RANGE:
|
||||
range->min = pt->min;
|
||||
range->max = pt->max;
|
||||
break;
|
||||
case NLA_VALIDATE_RANGE_PTR:
|
||||
*range = *pt->range_signed;
|
||||
break;
|
||||
case NLA_VALIDATE_MIN:
|
||||
range->min = pt->min;
|
||||
break;
|
||||
case NLA_VALIDATE_MAX:
|
||||
range->max = pt->max;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int nla_validate_int_range_signed(const struct nla_policy *pt,
|
||||
const struct nlattr *nla,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct netlink_range_validation_signed range;
|
||||
s64 value;
|
||||
|
||||
switch (pt->type) {
|
||||
case NLA_S8:
|
||||
value = nla_get_s8(nla);
|
||||
break;
|
||||
@ -130,22 +257,13 @@ static int nla_validate_int_range(const struct nla_policy *pt,
|
||||
case NLA_S64:
|
||||
value = nla_get_s64(nla);
|
||||
break;
|
||||
case NLA_U64:
|
||||
/* treat this one specially, since it may not fit into s64 */
|
||||
if ((validate_min && nla_get_u64(nla) < pt->min) ||
|
||||
(validate_max && nla_get_u64(nla) > pt->max)) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, nla,
|
||||
"integer out of range");
|
||||
return -ERANGE;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((validate_min && value < pt->min) ||
|
||||
(validate_max && value > pt->max)) {
|
||||
nla_get_range_signed(pt, &range);
|
||||
|
||||
if (value < range.min || value > range.max) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, nla,
|
||||
"integer out of range");
|
||||
return -ERANGE;
|
||||
@ -154,9 +272,31 @@ static int nla_validate_int_range(const struct nla_policy *pt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nla_validate_int_range(const struct nla_policy *pt,
|
||||
const struct nlattr *nla,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
switch (pt->type) {
|
||||
case NLA_U8:
|
||||
case NLA_U16:
|
||||
case NLA_U32:
|
||||
case NLA_U64:
|
||||
case NLA_MSECS:
|
||||
return nla_validate_int_range_unsigned(pt, nla, extack);
|
||||
case NLA_S8:
|
||||
case NLA_S16:
|
||||
case NLA_S32:
|
||||
case NLA_S64:
|
||||
return nla_validate_int_range_signed(pt, nla, extack);
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
const struct nla_policy *policy, unsigned int validate,
|
||||
struct netlink_ext_ack *extack)
|
||||
struct netlink_ext_ack *extack, unsigned int depth)
|
||||
{
|
||||
u16 strict_start_type = policy[0].strict_start_type;
|
||||
const struct nla_policy *pt;
|
||||
@ -174,7 +314,9 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
BUG_ON(pt->type > NLA_TYPE_MAX);
|
||||
|
||||
if ((nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) ||
|
||||
(pt->type == NLA_EXACT_LEN_WARN && attrlen != pt->len)) {
|
||||
(pt->type == NLA_EXACT_LEN &&
|
||||
pt->validation_type == NLA_VALIDATE_WARN_TOO_LONG &&
|
||||
attrlen != pt->len)) {
|
||||
pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n",
|
||||
current->comm, type);
|
||||
if (validate & NL_VALIDATE_STRICT_ATTRS) {
|
||||
@ -200,15 +342,10 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
}
|
||||
|
||||
switch (pt->type) {
|
||||
case NLA_EXACT_LEN:
|
||||
if (attrlen != pt->len)
|
||||
goto out_err;
|
||||
break;
|
||||
|
||||
case NLA_REJECT:
|
||||
if (extack && pt->validation_data) {
|
||||
if (extack && pt->reject_message) {
|
||||
NL_SET_BAD_ATTR(extack, nla);
|
||||
extack->_msg = pt->validation_data;
|
||||
extack->_msg = pt->reject_message;
|
||||
return -EINVAL;
|
||||
}
|
||||
err = -EINVAL;
|
||||
@ -223,7 +360,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
if (attrlen != sizeof(struct nla_bitfield32))
|
||||
goto out_err;
|
||||
|
||||
err = validate_nla_bitfield32(nla, pt->validation_data);
|
||||
err = validate_nla_bitfield32(nla, pt->bitfield32_valid);
|
||||
if (err)
|
||||
goto out_err;
|
||||
break;
|
||||
@ -268,10 +405,11 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
break;
|
||||
if (attrlen < NLA_HDRLEN)
|
||||
goto out_err;
|
||||
if (pt->validation_data) {
|
||||
err = __nla_validate(nla_data(nla), nla_len(nla), pt->len,
|
||||
pt->validation_data, validate,
|
||||
extack);
|
||||
if (pt->nested_policy) {
|
||||
err = __nla_validate_parse(nla_data(nla), nla_len(nla),
|
||||
pt->len, pt->nested_policy,
|
||||
validate, extack, NULL,
|
||||
depth + 1);
|
||||
if (err < 0) {
|
||||
/*
|
||||
* return directly to preserve the inner
|
||||
@ -289,12 +427,12 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
break;
|
||||
if (attrlen < NLA_HDRLEN)
|
||||
goto out_err;
|
||||
if (pt->validation_data) {
|
||||
if (pt->nested_policy) {
|
||||
int err;
|
||||
|
||||
err = nla_validate_array(nla_data(nla), nla_len(nla),
|
||||
pt->len, pt->validation_data,
|
||||
extack, validate);
|
||||
pt->len, pt->nested_policy,
|
||||
extack, validate, depth);
|
||||
if (err < 0) {
|
||||
/*
|
||||
* return directly to preserve the inner
|
||||
@ -317,6 +455,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
goto out_err;
|
||||
break;
|
||||
|
||||
case NLA_EXACT_LEN:
|
||||
if (pt->validation_type != NLA_VALIDATE_WARN_TOO_LONG) {
|
||||
if (attrlen != pt->len)
|
||||
goto out_err;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
if (pt->len)
|
||||
minlen = pt->len;
|
||||
@ -332,6 +477,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||
case NLA_VALIDATE_NONE:
|
||||
/* nothing to do */
|
||||
break;
|
||||
case NLA_VALIDATE_RANGE_PTR:
|
||||
case NLA_VALIDATE_RANGE:
|
||||
case NLA_VALIDATE_MIN:
|
||||
case NLA_VALIDATE_MAX:
|
||||
@ -358,11 +504,17 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
|
||||
const struct nla_policy *policy,
|
||||
unsigned int validate,
|
||||
struct netlink_ext_ack *extack,
|
||||
struct nlattr **tb)
|
||||
struct nlattr **tb, unsigned int depth)
|
||||
{
|
||||
const struct nlattr *nla;
|
||||
int rem;
|
||||
|
||||
if (depth >= MAX_POLICY_RECURSION_DEPTH) {
|
||||
NL_SET_ERR_MSG(extack,
|
||||
"allowed policy recursion depth exceeded");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tb)
|
||||
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
|
||||
|
||||
@ -379,7 +531,7 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
|
||||
}
|
||||
if (policy) {
|
||||
int err = validate_nla(nla, maxtype, policy,
|
||||
validate, extack);
|
||||
validate, extack, depth);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -421,7 +573,7 @@ int __nla_validate(const struct nlattr *head, int len, int maxtype,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return __nla_validate_parse(head, len, maxtype, policy, validate,
|
||||
extack, NULL);
|
||||
extack, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(__nla_validate);
|
||||
|
||||
@ -476,7 +628,7 @@ int __nla_parse(struct nlattr **tb, int maxtype,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return __nla_validate_parse(head, len, maxtype, policy, validate,
|
||||
extack, tb);
|
||||
extack, tb, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(__nla_parse);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
# Makefile for the netlink driver.
|
||||
#
|
||||
|
||||
obj-y := af_netlink.o genetlink.o
|
||||
obj-y := af_netlink.o genetlink.o policy.o
|
||||
|
||||
obj-$(CONFIG_NETLINK_DIAG) += netlink_diag.o
|
||||
netlink_diag-y := diag.o
|
||||
|
@ -1043,6 +1043,80 @@ static int genl_ctrl_event(int event, const struct genl_family *family,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_dumppolicy(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct genl_family *rt;
|
||||
unsigned int fam_id = cb->args[0];
|
||||
int err;
|
||||
|
||||
if (!fam_id) {
|
||||
struct nlattr *tb[CTRL_ATTR_MAX + 1];
|
||||
|
||||
err = genlmsg_parse(cb->nlh, &genl_ctrl, tb,
|
||||
genl_ctrl.maxattr,
|
||||
genl_ctrl.policy, cb->extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!tb[CTRL_ATTR_FAMILY_ID] && !tb[CTRL_ATTR_FAMILY_NAME])
|
||||
return -EINVAL;
|
||||
|
||||
if (tb[CTRL_ATTR_FAMILY_ID]) {
|
||||
fam_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
|
||||
} else {
|
||||
rt = genl_family_find_byname(
|
||||
nla_data(tb[CTRL_ATTR_FAMILY_NAME]));
|
||||
if (!rt)
|
||||
return -ENOENT;
|
||||
fam_id = rt->id;
|
||||
}
|
||||
}
|
||||
|
||||
rt = genl_family_find_byid(fam_id);
|
||||
if (!rt)
|
||||
return -ENOENT;
|
||||
|
||||
if (!rt->policy)
|
||||
return -ENODATA;
|
||||
|
||||
err = netlink_policy_dump_start(rt->policy, rt->maxattr, &cb->args[1]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
while (netlink_policy_dump_loop(&cb->args[1])) {
|
||||
void *hdr;
|
||||
struct nlattr *nest;
|
||||
|
||||
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, &genl_ctrl,
|
||||
NLM_F_MULTI, CTRL_CMD_GETPOLICY);
|
||||
if (!hdr)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, rt->id))
|
||||
goto nla_put_failure;
|
||||
|
||||
nest = nla_nest_start(skb, CTRL_ATTR_POLICY);
|
||||
if (!nest)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (netlink_policy_dump_write(skb, cb->args[1]))
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
continue;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(skb, hdr);
|
||||
break;
|
||||
}
|
||||
|
||||
cb->args[0] = fam_id;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
static const struct genl_ops genl_ctrl_ops[] = {
|
||||
{
|
||||
.cmd = CTRL_CMD_GETFAMILY,
|
||||
@ -1050,6 +1124,10 @@ static const struct genl_ops genl_ctrl_ops[] = {
|
||||
.doit = ctrl_getfamily,
|
||||
.dumpit = ctrl_dumpfamily,
|
||||
},
|
||||
{
|
||||
.cmd = CTRL_CMD_GETPOLICY,
|
||||
.dumpit = ctrl_dumppolicy,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group genl_ctrl_groups[] = {
|
||||
|
308
net/netlink/policy.c
Normal file
308
net/netlink/policy.c
Normal file
@ -0,0 +1,308 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* NETLINK Policy advertisement to userspace
|
||||
*
|
||||
* Authors: Johannes Berg <johannes@sipsolutions.net>
|
||||
*
|
||||
* Copyright 2019 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#define INITIAL_POLICIES_ALLOC 10
|
||||
|
||||
struct nl_policy_dump {
|
||||
unsigned int policy_idx;
|
||||
unsigned int attr_idx;
|
||||
unsigned int n_alloc;
|
||||
struct {
|
||||
const struct nla_policy *policy;
|
||||
unsigned int maxtype;
|
||||
} policies[];
|
||||
};
|
||||
|
||||
static int add_policy(struct nl_policy_dump **statep,
|
||||
const struct nla_policy *policy,
|
||||
unsigned int maxtype)
|
||||
{
|
||||
struct nl_policy_dump *state = *statep;
|
||||
unsigned int n_alloc, i;
|
||||
|
||||
if (!policy || !maxtype)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < state->n_alloc; i++) {
|
||||
if (state->policies[i].policy == policy)
|
||||
return 0;
|
||||
|
||||
if (!state->policies[i].policy) {
|
||||
state->policies[i].policy = policy;
|
||||
state->policies[i].maxtype = maxtype;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
n_alloc = state->n_alloc + INITIAL_POLICIES_ALLOC;
|
||||
state = krealloc(state, struct_size(state, policies, n_alloc),
|
||||
GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
state->policies[state->n_alloc].policy = policy;
|
||||
state->policies[state->n_alloc].maxtype = maxtype;
|
||||
state->n_alloc = n_alloc;
|
||||
*statep = state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int get_policy_idx(struct nl_policy_dump *state,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < state->n_alloc; i++) {
|
||||
if (state->policies[i].policy == policy)
|
||||
return i;
|
||||
}
|
||||
|
||||
WARN_ON_ONCE(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int netlink_policy_dump_start(const struct nla_policy *policy,
|
||||
unsigned int maxtype,
|
||||
unsigned long *_state)
|
||||
{
|
||||
struct nl_policy_dump *state;
|
||||
unsigned int policy_idx;
|
||||
int err;
|
||||
|
||||
/* also returns 0 if "*_state" is our ERR_PTR() end marker */
|
||||
if (*_state)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* walk the policies and nested ones first, and build
|
||||
* a linear list of them.
|
||||
*/
|
||||
|
||||
state = kzalloc(struct_size(state, policies, INITIAL_POLICIES_ALLOC),
|
||||
GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
state->n_alloc = INITIAL_POLICIES_ALLOC;
|
||||
|
||||
err = add_policy(&state, policy, maxtype);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (policy_idx = 0;
|
||||
policy_idx < state->n_alloc && state->policies[policy_idx].policy;
|
||||
policy_idx++) {
|
||||
const struct nla_policy *policy;
|
||||
unsigned int type;
|
||||
|
||||
policy = state->policies[policy_idx].policy;
|
||||
|
||||
for (type = 0;
|
||||
type <= state->policies[policy_idx].maxtype;
|
||||
type++) {
|
||||
switch (policy[type].type) {
|
||||
case NLA_NESTED:
|
||||
case NLA_NESTED_ARRAY:
|
||||
err = add_policy(&state,
|
||||
policy[type].nested_policy,
|
||||
policy[type].len);
|
||||
if (err)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*_state = (unsigned long)state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool netlink_policy_dump_finished(struct nl_policy_dump *state)
|
||||
{
|
||||
return state->policy_idx >= state->n_alloc ||
|
||||
!state->policies[state->policy_idx].policy;
|
||||
}
|
||||
|
||||
bool netlink_policy_dump_loop(unsigned long *_state)
|
||||
{
|
||||
struct nl_policy_dump *state = (void *)*_state;
|
||||
|
||||
if (IS_ERR(state))
|
||||
return false;
|
||||
|
||||
if (netlink_policy_dump_finished(state)) {
|
||||
kfree(state);
|
||||
/* store end marker instead of freed state */
|
||||
*_state = (unsigned long)ERR_PTR(-ENOENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state)
|
||||
{
|
||||
struct nl_policy_dump *state = (void *)_state;
|
||||
const struct nla_policy *pt;
|
||||
struct nlattr *policy, *attr;
|
||||
enum netlink_attribute_type type;
|
||||
bool again;
|
||||
|
||||
send_attribute:
|
||||
again = false;
|
||||
|
||||
pt = &state->policies[state->policy_idx].policy[state->attr_idx];
|
||||
|
||||
policy = nla_nest_start(skb, state->policy_idx);
|
||||
if (!policy)
|
||||
return -ENOBUFS;
|
||||
|
||||
attr = nla_nest_start(skb, state->attr_idx);
|
||||
if (!attr)
|
||||
goto nla_put_failure;
|
||||
|
||||
switch (pt->type) {
|
||||
default:
|
||||
case NLA_UNSPEC:
|
||||
case NLA_REJECT:
|
||||
/* skip - use NLA_MIN_LEN to advertise such */
|
||||
nla_nest_cancel(skb, policy);
|
||||
again = true;
|
||||
goto next;
|
||||
case NLA_NESTED:
|
||||
type = NL_ATTR_TYPE_NESTED;
|
||||
/* fall through */
|
||||
case NLA_NESTED_ARRAY:
|
||||
if (pt->type == NLA_NESTED_ARRAY)
|
||||
type = NL_ATTR_TYPE_NESTED_ARRAY;
|
||||
if (pt->nested_policy && pt->len &&
|
||||
(nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_IDX,
|
||||
get_policy_idx(state, pt->nested_policy)) ||
|
||||
nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
|
||||
pt->len)))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
case NLA_U8:
|
||||
case NLA_U16:
|
||||
case NLA_U32:
|
||||
case NLA_U64:
|
||||
case NLA_MSECS: {
|
||||
struct netlink_range_validation range;
|
||||
|
||||
if (pt->type == NLA_U8)
|
||||
type = NL_ATTR_TYPE_U8;
|
||||
else if (pt->type == NLA_U16)
|
||||
type = NL_ATTR_TYPE_U16;
|
||||
else if (pt->type == NLA_U32)
|
||||
type = NL_ATTR_TYPE_U32;
|
||||
else
|
||||
type = NL_ATTR_TYPE_U64;
|
||||
|
||||
nla_get_range_unsigned(pt, &range);
|
||||
|
||||
if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
|
||||
range.min, NL_POLICY_TYPE_ATTR_PAD) ||
|
||||
nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
|
||||
range.max, NL_POLICY_TYPE_ATTR_PAD))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
}
|
||||
case NLA_S8:
|
||||
case NLA_S16:
|
||||
case NLA_S32:
|
||||
case NLA_S64: {
|
||||
struct netlink_range_validation_signed range;
|
||||
|
||||
if (pt->type == NLA_S8)
|
||||
type = NL_ATTR_TYPE_S8;
|
||||
else if (pt->type == NLA_S16)
|
||||
type = NL_ATTR_TYPE_S16;
|
||||
else if (pt->type == NLA_S32)
|
||||
type = NL_ATTR_TYPE_S32;
|
||||
else
|
||||
type = NL_ATTR_TYPE_S64;
|
||||
|
||||
nla_get_range_signed(pt, &range);
|
||||
|
||||
if (nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
|
||||
range.min, NL_POLICY_TYPE_ATTR_PAD) ||
|
||||
nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
|
||||
range.max, NL_POLICY_TYPE_ATTR_PAD))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
}
|
||||
case NLA_BITFIELD32:
|
||||
type = NL_ATTR_TYPE_BITFIELD32;
|
||||
if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
|
||||
pt->bitfield32_valid))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
case NLA_EXACT_LEN:
|
||||
type = NL_ATTR_TYPE_BINARY;
|
||||
if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH, pt->len) ||
|
||||
nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH, pt->len))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
case NLA_STRING:
|
||||
case NLA_NUL_STRING:
|
||||
case NLA_BINARY:
|
||||
if (pt->type == NLA_STRING)
|
||||
type = NL_ATTR_TYPE_STRING;
|
||||
else if (pt->type == NLA_NUL_STRING)
|
||||
type = NL_ATTR_TYPE_NUL_STRING;
|
||||
else
|
||||
type = NL_ATTR_TYPE_BINARY;
|
||||
if (pt->len && nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
|
||||
pt->len))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
case NLA_MIN_LEN:
|
||||
type = NL_ATTR_TYPE_BINARY;
|
||||
if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH, pt->len))
|
||||
goto nla_put_failure;
|
||||
break;
|
||||
case NLA_FLAG:
|
||||
type = NL_ATTR_TYPE_FLAG;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_TYPE, type))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* finish and move state to next attribute */
|
||||
nla_nest_end(skb, attr);
|
||||
nla_nest_end(skb, policy);
|
||||
|
||||
next:
|
||||
state->attr_idx += 1;
|
||||
if (state->attr_idx > state->policies[state->policy_idx].maxtype) {
|
||||
state->attr_idx = 0;
|
||||
state->policy_idx++;
|
||||
}
|
||||
|
||||
if (again) {
|
||||
if (netlink_policy_dump_finished(state))
|
||||
return -ENODATA;
|
||||
goto send_attribute;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, policy);
|
||||
return -ENOBUFS;
|
||||
}
|
@ -876,19 +876,14 @@ static u8 tcf_action_hw_stats_get(struct nlattr *hw_stats_attr)
|
||||
return hw_stats_bf.value;
|
||||
}
|
||||
|
||||
static const u32 tca_act_flags_allowed = TCA_ACT_FLAGS_NO_PERCPU_STATS;
|
||||
static const u32 tca_act_hw_stats_allowed = TCA_ACT_HW_STATS_ANY;
|
||||
|
||||
static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
|
||||
[TCA_ACT_KIND] = { .type = NLA_STRING },
|
||||
[TCA_ACT_INDEX] = { .type = NLA_U32 },
|
||||
[TCA_ACT_COOKIE] = { .type = NLA_BINARY,
|
||||
.len = TC_COOKIE_MAX_SIZE },
|
||||
[TCA_ACT_OPTIONS] = { .type = NLA_NESTED },
|
||||
[TCA_ACT_FLAGS] = { .type = NLA_BITFIELD32,
|
||||
.validation_data = &tca_act_flags_allowed },
|
||||
[TCA_ACT_HW_STATS] = { .type = NLA_BITFIELD32,
|
||||
.validation_data = &tca_act_hw_stats_allowed },
|
||||
[TCA_ACT_FLAGS] = NLA_POLICY_BITFIELD32(TCA_ACT_FLAGS_NO_PERCPU_STATS),
|
||||
[TCA_ACT_HW_STATS] = NLA_POLICY_BITFIELD32(TCA_ACT_HW_STATS_ANY),
|
||||
};
|
||||
|
||||
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
||||
@ -1454,10 +1449,8 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON;
|
||||
static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
|
||||
[TCA_ROOT_FLAGS] = { .type = NLA_BITFIELD32,
|
||||
.validation_data = &tcaa_root_flags_allowed },
|
||||
[TCA_ROOT_FLAGS] = NLA_POLICY_BITFIELD32(TCA_FLAG_LARGE_DUMP_ON),
|
||||
[TCA_ROOT_TIME_DELTA] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
|
@ -48,7 +48,7 @@ struct red_sched_data {
|
||||
struct Qdisc *qdisc;
|
||||
};
|
||||
|
||||
static const u32 red_supported_flags = TC_RED_HISTORIC_FLAGS | TC_RED_NODROP;
|
||||
#define TC_RED_SUPPORTED_FLAGS (TC_RED_HISTORIC_FLAGS | TC_RED_NODROP)
|
||||
|
||||
static inline int red_use_ecn(struct red_sched_data *q)
|
||||
{
|
||||
@ -212,8 +212,7 @@ static const struct nla_policy red_policy[TCA_RED_MAX + 1] = {
|
||||
[TCA_RED_PARMS] = { .len = sizeof(struct tc_red_qopt) },
|
||||
[TCA_RED_STAB] = { .len = RED_STAB_SIZE },
|
||||
[TCA_RED_MAX_P] = { .type = NLA_U32 },
|
||||
[TCA_RED_FLAGS] = { .type = NLA_BITFIELD32,
|
||||
.validation_data = &red_supported_flags },
|
||||
[TCA_RED_FLAGS] = NLA_POLICY_BITFIELD32(TC_RED_SUPPORTED_FLAGS),
|
||||
};
|
||||
|
||||
static int red_change(struct Qdisc *sch, struct nlattr *opt,
|
||||
@ -248,7 +247,7 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt,
|
||||
return -EINVAL;
|
||||
|
||||
err = red_get_flags(ctl->flags, TC_RED_HISTORIC_FLAGS,
|
||||
tb[TCA_RED_FLAGS], red_supported_flags,
|
||||
tb[TCA_RED_FLAGS], TC_RED_SUPPORTED_FLAGS,
|
||||
&flags_bf, &userbits, extack);
|
||||
if (err)
|
||||
return err;
|
||||
@ -372,7 +371,7 @@ static int red_dump(struct Qdisc *sch, struct sk_buff *skb)
|
||||
if (nla_put(skb, TCA_RED_PARMS, sizeof(opt), &opt) ||
|
||||
nla_put_u32(skb, TCA_RED_MAX_P, q->parms.max_P) ||
|
||||
nla_put_bitfield32(skb, TCA_RED_FLAGS,
|
||||
q->flags, red_supported_flags))
|
||||
q->flags, TC_RED_SUPPORTED_FLAGS))
|
||||
goto nla_put_failure;
|
||||
return nla_nest_end(skb, opts);
|
||||
|
||||
|
@ -253,6 +253,8 @@ static int validate_ie_attr(const struct nlattr *attr,
|
||||
}
|
||||
|
||||
/* policy for the attributes */
|
||||
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR];
|
||||
|
||||
static const struct nla_policy
|
||||
nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
|
||||
[NL80211_FTM_RESP_ATTR_ENABLED] = { .type = NLA_FLAG, },
|
||||
@ -296,11 +298,7 @@ nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = {
|
||||
static const struct nla_policy
|
||||
nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
|
||||
[NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
|
||||
/*
|
||||
* we could specify this again to be the top-level policy,
|
||||
* but that would open us up to recursion problems ...
|
||||
*/
|
||||
[NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED },
|
||||
[NL80211_PMSR_PEER_ATTR_CHAN] = NLA_POLICY_NESTED(nl80211_policy),
|
||||
[NL80211_PMSR_PEER_ATTR_REQ] =
|
||||
NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy),
|
||||
[NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT },
|
||||
@ -347,7 +345,7 @@ nl80211_tid_config_attr_policy[NL80211_TID_CONFIG_ATTR_MAX + 1] = {
|
||||
NLA_POLICY_MAX(NLA_U8, NL80211_TID_CONFIG_DISABLE),
|
||||
};
|
||||
|
||||
const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
|
||||
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
|
||||
@ -378,11 +376,8 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
|
||||
|
||||
[NL80211_ATTR_MAC] = { .type = NLA_EXACT_LEN_WARN, .len = ETH_ALEN },
|
||||
[NL80211_ATTR_PREV_BSSID] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = ETH_ALEN
|
||||
},
|
||||
[NL80211_ATTR_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
[NL80211_ATTR_PREV_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
|
||||
[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
|
||||
[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
|
||||
@ -434,10 +429,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
|
||||
[NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
|
||||
|
||||
[NL80211_ATTR_HT_CAPABILITY] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = NL80211_HT_CAPABILITY_LEN
|
||||
},
|
||||
[NL80211_ATTR_HT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_HT_CAPABILITY_LEN),
|
||||
|
||||
[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_IE] = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
|
||||
@ -468,10 +460,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_PID] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_PMKID] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = WLAN_PMKID_LEN
|
||||
},
|
||||
[NL80211_ATTR_PMKID] = NLA_POLICY_EXACT_LEN_WARN(WLAN_PMKID_LEN),
|
||||
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
|
||||
[NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
|
||||
@ -535,10 +524,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
|
||||
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
|
||||
[NL80211_ATTR_VHT_CAPABILITY] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = NL80211_VHT_CAPABILITY_LEN
|
||||
},
|
||||
[NL80211_ATTR_VHT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_VHT_CAPABILITY_LEN),
|
||||
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127),
|
||||
[NL80211_ATTR_P2P_OPPPS] = NLA_POLICY_MAX(NLA_U8, 1),
|
||||
@ -576,10 +562,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
|
||||
[NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
|
||||
.len = IEEE80211_QOS_MAP_LEN_MAX },
|
||||
[NL80211_ATTR_MAC_HINT] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = ETH_ALEN
|
||||
},
|
||||
[NL80211_ATTR_MAC_HINT] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
|
||||
@ -591,10 +574,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 },
|
||||
[NL80211_ATTR_MAC_MASK] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = ETH_ALEN
|
||||
},
|
||||
[NL80211_ATTR_MAC_MASK] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
|
||||
@ -606,21 +586,15 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
|
||||
.len = VHT_MUMIMO_GROUPS_DATA_LEN
|
||||
},
|
||||
[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = ETH_ALEN
|
||||
},
|
||||
[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
[NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1),
|
||||
[NL80211_ATTR_BANDS] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
|
||||
[NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
|
||||
.len = FILS_MAX_KEK_LEN },
|
||||
[NL80211_ATTR_FILS_NONCES] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = 2 * FILS_NONCE_LEN
|
||||
},
|
||||
[NL80211_ATTR_FILS_NONCES] = NLA_POLICY_EXACT_LEN_WARN(2 * FILS_NONCE_LEN),
|
||||
[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
|
||||
[NL80211_ATTR_BSSID] = { .type = NLA_EXACT_LEN_WARN, .len = ETH_ALEN },
|
||||
[NL80211_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
[NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI] = { .type = NLA_S8 },
|
||||
[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
|
||||
.len = sizeof(struct nl80211_bss_select_rssi_adjust)
|
||||
@ -633,7 +607,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||
[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM] = { .type = NLA_U16 },
|
||||
[NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
|
||||
.len = FILS_ERP_MAX_RRK_LEN },
|
||||
[NL80211_ATTR_FILS_CACHE_ID] = { .type = NLA_EXACT_LEN_WARN, .len = 2 },
|
||||
[NL80211_ATTR_FILS_CACHE_ID] = NLA_POLICY_EXACT_LEN_WARN(2),
|
||||
[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
|
||||
[NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
|
||||
@ -703,10 +677,7 @@ static const struct nla_policy
|
||||
nl80211_wowlan_tcp_policy[NUM_NL80211_WOWLAN_TCP] = {
|
||||
[NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
|
||||
[NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
|
||||
[NL80211_WOWLAN_TCP_DST_MAC] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = ETH_ALEN
|
||||
},
|
||||
[NL80211_WOWLAN_TCP_DST_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
[NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
|
||||
[NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
|
||||
[NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .type = NLA_MIN_LEN, .len = 1 },
|
||||
@ -736,18 +707,9 @@ nl80211_coalesce_policy[NUM_NL80211_ATTR_COALESCE_RULE] = {
|
||||
/* policy for GTK rekey offload attributes */
|
||||
static const struct nla_policy
|
||||
nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
|
||||
[NL80211_REKEY_DATA_KEK] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = NL80211_KEK_LEN,
|
||||
},
|
||||
[NL80211_REKEY_DATA_KCK] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = NL80211_KCK_LEN,
|
||||
},
|
||||
[NL80211_REKEY_DATA_REPLAY_CTR] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = NL80211_REPLAY_CTR_LEN
|
||||
},
|
||||
[NL80211_REKEY_DATA_KEK] = NLA_POLICY_EXACT_LEN_WARN(NL80211_KEK_LEN),
|
||||
[NL80211_REKEY_DATA_KCK] = NLA_POLICY_EXACT_LEN_WARN(NL80211_KCK_LEN),
|
||||
[NL80211_REKEY_DATA_REPLAY_CTR] = NLA_POLICY_EXACT_LEN_WARN(NL80211_REPLAY_CTR_LEN),
|
||||
};
|
||||
|
||||
static const struct nla_policy
|
||||
@ -762,10 +724,7 @@ static const struct nla_policy
|
||||
nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
|
||||
[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
|
||||
.len = IEEE80211_MAX_SSID_LEN },
|
||||
[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = ETH_ALEN
|
||||
},
|
||||
[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
|
||||
[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
|
||||
NLA_POLICY_NESTED(nl80211_match_band_rssi_policy),
|
||||
@ -797,10 +756,7 @@ nl80211_nan_func_policy[NL80211_NAN_FUNC_ATTR_MAX + 1] = {
|
||||
[NL80211_NAN_FUNC_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
|
||||
[NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
|
||||
[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
|
||||
[NL80211_NAN_FUNC_FOLLOW_UP_DEST] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = ETH_ALEN
|
||||
},
|
||||
[NL80211_NAN_FUNC_FOLLOW_UP_DEST] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||
[NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
|
||||
[NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
|
||||
[NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
|
||||
@ -4406,10 +4362,7 @@ static const struct nla_policy nl80211_txattr_policy[NL80211_TXRATE_MAX + 1] = {
|
||||
.len = NL80211_MAX_SUPP_RATES },
|
||||
[NL80211_TXRATE_HT] = { .type = NLA_BINARY,
|
||||
.len = NL80211_MAX_SUPP_HT_RATES },
|
||||
[NL80211_TXRATE_VHT] = {
|
||||
.type = NLA_EXACT_LEN_WARN,
|
||||
.len = sizeof(struct nl80211_txrate_vht),
|
||||
},
|
||||
[NL80211_TXRATE_VHT] = NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_txrate_vht)),
|
||||
[NL80211_TXRATE_GI] = { .type = NLA_U8 },
|
||||
};
|
||||
|
||||
|
@ -11,8 +11,6 @@
|
||||
int nl80211_init(void);
|
||||
void nl80211_exit(void);
|
||||
|
||||
extern const struct nla_policy nl80211_policy[NUM_NL80211_ATTR];
|
||||
|
||||
void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
|
||||
int flags, u8 cmd);
|
||||
bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
|
@ -187,10 +187,9 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
|
||||
|
||||
/* reuse info->attrs */
|
||||
memset(info->attrs, 0, sizeof(*info->attrs) * (NL80211_ATTR_MAX + 1));
|
||||
/* need to validate here, we don't want to have validation recursion */
|
||||
err = nla_parse_nested_deprecated(info->attrs, NL80211_ATTR_MAX,
|
||||
tb[NL80211_PMSR_PEER_ATTR_CHAN],
|
||||
nl80211_policy, info->extack);
|
||||
NULL, info->extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user