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_BITFIELD32,
|
||||||
NLA_REJECT,
|
NLA_REJECT,
|
||||||
NLA_EXACT_LEN,
|
NLA_EXACT_LEN,
|
||||||
NLA_EXACT_LEN_WARN,
|
|
||||||
NLA_MIN_LEN,
|
NLA_MIN_LEN,
|
||||||
__NLA_TYPE_MAX,
|
__NLA_TYPE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
|
#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 {
|
enum nla_policy_validation {
|
||||||
NLA_VALIDATE_NONE,
|
NLA_VALIDATE_NONE,
|
||||||
NLA_VALIDATE_RANGE,
|
NLA_VALIDATE_RANGE,
|
||||||
NLA_VALIDATE_MIN,
|
NLA_VALIDATE_MIN,
|
||||||
NLA_VALIDATE_MAX,
|
NLA_VALIDATE_MAX,
|
||||||
|
NLA_VALIDATE_RANGE_PTR,
|
||||||
NLA_VALIDATE_FUNCTION,
|
NLA_VALIDATE_FUNCTION,
|
||||||
|
NLA_VALIDATE_WARN_TOO_LONG,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -217,7 +226,7 @@ enum nla_policy_validation {
|
|||||||
* NLA_NESTED,
|
* NLA_NESTED,
|
||||||
* NLA_NESTED_ARRAY Length verification is done by checking len of
|
* NLA_NESTED_ARRAY Length verification is done by checking len of
|
||||||
* nested header (or empty); len field is used if
|
* 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.
|
* number in the nested policy.
|
||||||
* NLA_U8, NLA_U16,
|
* NLA_U8, NLA_U16,
|
||||||
* NLA_U32, NLA_U64,
|
* NLA_U32, NLA_U64,
|
||||||
@ -228,34 +237,32 @@ enum nla_policy_validation {
|
|||||||
* just like "All other"
|
* just like "All other"
|
||||||
* NLA_BITFIELD32 Unused
|
* NLA_BITFIELD32 Unused
|
||||||
* NLA_REJECT Unused
|
* NLA_REJECT Unused
|
||||||
* NLA_EXACT_LEN Attribute must have exactly this length, otherwise
|
* NLA_EXACT_LEN Attribute should have exactly this length, otherwise
|
||||||
* it is rejected.
|
* it is rejected or warned about, the latter happening
|
||||||
* NLA_EXACT_LEN_WARN Attribute should have exactly this length, a warning
|
* if and only if the `validation_type' is set to
|
||||||
* is logged if it is longer, shorter is rejected.
|
* NLA_VALIDATE_WARN_TOO_LONG.
|
||||||
* NLA_MIN_LEN Minimum length of attribute payload
|
* NLA_MIN_LEN Minimum length of attribute payload
|
||||||
* All other 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
|
* NLA_BITFIELD32 This is a 32-bit bitmap/bitselector attribute and
|
||||||
* validation data must point to a u32 value of valid
|
* `bitfield32_valid' is the u32 value of valid flags
|
||||||
* flags
|
* NLA_REJECT This attribute is always rejected and `reject_message'
|
||||||
* NLA_REJECT This attribute is always rejected and validation data
|
|
||||||
* may point to a string to report as the error instead
|
* may point to a string to report as the error instead
|
||||||
* of the generic one in extended ACK.
|
* of the generic one in extended ACK.
|
||||||
* NLA_NESTED Points to a nested policy to validate, must also set
|
* NLA_NESTED `nested_policy' to a nested policy to validate, must
|
||||||
* `len' to the max attribute number.
|
* 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
|
* Note that nla_parse() will validate, but of course not
|
||||||
* parse, the nested sub-policies.
|
* parse, the nested sub-policies.
|
||||||
* NLA_NESTED_ARRAY Points to a nested policy to validate, must also set
|
* NLA_NESTED_ARRAY `nested_policy' points to a nested policy to validate,
|
||||||
* `len' to the max attribute number. The difference to
|
* must also set `len' to the max attribute number. Use
|
||||||
* NLA_NESTED is the structure - NLA_NESTED has the
|
* the provided NLA_POLICY_NESTED_ARRAY() macro.
|
||||||
* nested attributes directly inside, while an array has
|
* The difference to NLA_NESTED is the structure:
|
||||||
* the nested attributes at another level down and the
|
* NLA_NESTED has the nested attributes directly inside
|
||||||
* attributes directly in the nesting don't matter.
|
* while an array has the nested attributes at another
|
||||||
* All other Unused - but note that it's a union
|
* level down and the attribute types directly in the
|
||||||
*
|
* nesting don't matter.
|
||||||
* Meaning of `min' and `max' fields, use via NLA_POLICY_MIN, NLA_POLICY_MAX
|
|
||||||
* and NLA_POLICY_RANGE:
|
|
||||||
* NLA_U8,
|
* NLA_U8,
|
||||||
* NLA_U16,
|
* NLA_U16,
|
||||||
* NLA_U32,
|
* NLA_U32,
|
||||||
@ -263,29 +270,47 @@ enum nla_policy_validation {
|
|||||||
* NLA_S8,
|
* NLA_S8,
|
||||||
* NLA_S16,
|
* NLA_S16,
|
||||||
* NLA_S32,
|
* NLA_S32,
|
||||||
* NLA_S64 These are used depending on the validation_type
|
* NLA_S64 The `min' and `max' fields are used depending on the
|
||||||
* field, if that is min/max/range then the minimum,
|
* validation_type field, if that is min/max/range then
|
||||||
* maximum and both are used (respectively) to check
|
* the min, max or both are used (respectively) to check
|
||||||
* the value of the integer attribute.
|
* the value of the integer attribute.
|
||||||
* Note that in the interest of code simplicity and
|
* Note that in the interest of code simplicity and
|
||||||
* struct size both limits are s16, so you cannot
|
* struct size both limits are s16, so you cannot
|
||||||
* enforce a range that doesn't fall within the range
|
* enforce a range that doesn't fall within the range
|
||||||
* of s16 - do that as usual in the code instead.
|
* 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
|
* All other Unused - but note that it's a union
|
||||||
*
|
*
|
||||||
* Meaning of `validate' field, use via NLA_POLICY_VALIDATE_FN:
|
* Meaning of `validate' field, use via NLA_POLICY_VALIDATE_FN:
|
||||||
* NLA_BINARY Validation function called for the attribute,
|
* 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.
|
|
||||||
* All other Unused - but note that it's a union
|
* All other Unused - but note that it's a union
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
|
*
|
||||||
|
* static const u32 myvalidflags = 0xff231023;
|
||||||
|
*
|
||||||
* static const struct nla_policy my_policy[ATTR_MAX+1] = {
|
* static const struct nla_policy my_policy[ATTR_MAX+1] = {
|
||||||
* [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] = { .type = NLA_EXACT_LEN, .len = sizeof(struct mystruct) },
|
* [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 {
|
struct nla_policy {
|
||||||
@ -293,7 +318,11 @@ struct nla_policy {
|
|||||||
u8 validation_type;
|
u8 validation_type;
|
||||||
u16 len;
|
u16 len;
|
||||||
union {
|
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 {
|
struct {
|
||||||
s16 min, max;
|
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(_len) { .type = NLA_EXACT_LEN, .len = _len }
|
||||||
#define NLA_POLICY_EXACT_LEN_WARN(_len) { .type = NLA_EXACT_LEN_WARN, \
|
#define NLA_POLICY_EXACT_LEN_WARN(_len) \
|
||||||
.len = _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_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 NLA_POLICY_EXACT_LEN(ETH_ALEN)
|
||||||
#define NLA_POLICY_ETH_ADDR_COMPAT NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN)
|
#define NLA_POLICY_ETH_ADDR_COMPAT NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN)
|
||||||
|
|
||||||
#define _NLA_POLICY_NESTED(maxattr, policy) \
|
#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) \
|
#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) \
|
#define NLA_POLICY_NESTED(policy) \
|
||||||
_NLA_POLICY_NESTED(ARRAY_SIZE(policy) - 1, policy)
|
_NLA_POLICY_NESTED(ARRAY_SIZE(policy) - 1, policy)
|
||||||
#define NLA_POLICY_NESTED_ARRAY(policy) \
|
#define NLA_POLICY_NESTED_ARRAY(policy) \
|
||||||
_NLA_POLICY_NESTED_ARRAY(ARRAY_SIZE(policy) - 1, 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(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) \
|
#define NLA_ENSURE_INT_TYPE(tp) \
|
||||||
(__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \
|
(__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \
|
||||||
tp == NLA_S16 || tp == NLA_U16 || \
|
tp == NLA_S16 || tp == NLA_U16 || \
|
||||||
tp == NLA_S32 || tp == NLA_U32 || \
|
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) \
|
#define NLA_ENSURE_NO_VALIDATION_PTR(tp) \
|
||||||
(__NLA_ENSURE(tp != NLA_BITFIELD32 && \
|
(__NLA_ENSURE(tp != NLA_BITFIELD32 && \
|
||||||
tp != NLA_REJECT && \
|
tp != NLA_REJECT && \
|
||||||
@ -356,6 +396,18 @@ struct nla_policy {
|
|||||||
.max = _max \
|
.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) { \
|
#define NLA_POLICY_MIN(tp, _min) { \
|
||||||
.type = NLA_ENSURE_INT_TYPE(tp), \
|
.type = NLA_ENSURE_INT_TYPE(tp), \
|
||||||
.validation_type = NLA_VALIDATE_MIN, \
|
.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;
|
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
|
#endif
|
||||||
|
@ -48,6 +48,7 @@ enum {
|
|||||||
CTRL_CMD_NEWMCAST_GRP,
|
CTRL_CMD_NEWMCAST_GRP,
|
||||||
CTRL_CMD_DELMCAST_GRP,
|
CTRL_CMD_DELMCAST_GRP,
|
||||||
CTRL_CMD_GETMCAST_GRP, /* unused */
|
CTRL_CMD_GETMCAST_GRP, /* unused */
|
||||||
|
CTRL_CMD_GETPOLICY,
|
||||||
__CTRL_CMD_MAX,
|
__CTRL_CMD_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,6 +63,7 @@ enum {
|
|||||||
CTRL_ATTR_MAXATTR,
|
CTRL_ATTR_MAXATTR,
|
||||||
CTRL_ATTR_OPS,
|
CTRL_ATTR_OPS,
|
||||||
CTRL_ATTR_MCAST_GROUPS,
|
CTRL_ATTR_MCAST_GROUPS,
|
||||||
|
CTRL_ATTR_POLICY,
|
||||||
__CTRL_ATTR_MAX,
|
__CTRL_ATTR_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -249,4 +249,107 @@ struct nla_bitfield32 {
|
|||||||
__u32 selector;
|
__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 */
|
#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),
|
[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,
|
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);
|
const struct nla_bitfield32 *bf = nla_data(nla);
|
||||||
|
|
||||||
@ -53,11 +67,11 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/*disallow invalid bit selector */
|
/*disallow invalid bit selector */
|
||||||
if (bf->selector & ~*valid_flags_mask)
|
if (bf->selector & ~valid_flags_mask)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/*disallow invalid bit values */
|
/*disallow invalid bit values */
|
||||||
if (bf->value & ~*valid_flags_mask)
|
if (bf->value & ~valid_flags_mask)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/*disallow valid bit values that are not selected*/
|
/*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,
|
static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
|
||||||
const struct nla_policy *policy,
|
const struct nla_policy *policy,
|
||||||
struct netlink_ext_ack *extack,
|
struct netlink_ext_ack *extack,
|
||||||
unsigned int validate)
|
unsigned int validate, unsigned int depth)
|
||||||
{
|
{
|
||||||
const struct nlattr *entry;
|
const struct nlattr *entry;
|
||||||
int rem;
|
int rem;
|
||||||
@ -87,8 +101,9 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
|
|||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = __nla_validate(nla_data(entry), nla_len(entry),
|
ret = __nla_validate_parse(nla_data(entry), nla_len(entry),
|
||||||
maxtype, policy, validate, extack);
|
maxtype, policy, validate, extack,
|
||||||
|
NULL, depth + 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -96,17 +111,58 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nla_validate_int_range(const struct nla_policy *pt,
|
void nla_get_range_unsigned(const struct nla_policy *pt,
|
||||||
const struct nlattr *nla,
|
struct netlink_range_validation *range)
|
||||||
struct netlink_ext_ack *extack)
|
|
||||||
{
|
{
|
||||||
bool validate_min, validate_max;
|
WARN_ON_ONCE(pt->validation_type != NLA_VALIDATE_RANGE_PTR &&
|
||||||
s64 value;
|
(pt->min < 0 || pt->max < 0));
|
||||||
|
|
||||||
validate_min = pt->validation_type == NLA_VALIDATE_RANGE ||
|
range->min = 0;
|
||||||
pt->validation_type == NLA_VALIDATE_MIN;
|
|
||||||
validate_max = pt->validation_type == NLA_VALIDATE_RANGE ||
|
switch (pt->type) {
|
||||||
pt->validation_type == NLA_VALIDATE_MAX;
|
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) {
|
switch (pt->type) {
|
||||||
case NLA_U8:
|
case NLA_U8:
|
||||||
@ -118,6 +174,77 @@ static int nla_validate_int_range(const struct nla_policy *pt,
|
|||||||
case NLA_U32:
|
case NLA_U32:
|
||||||
value = nla_get_u32(nla);
|
value = nla_get_u32(nla);
|
||||||
break;
|
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:
|
case NLA_S8:
|
||||||
value = nla_get_s8(nla);
|
value = nla_get_s8(nla);
|
||||||
break;
|
break;
|
||||||
@ -130,22 +257,13 @@ static int nla_validate_int_range(const struct nla_policy *pt,
|
|||||||
case NLA_S64:
|
case NLA_S64:
|
||||||
value = nla_get_s64(nla);
|
value = nla_get_s64(nla);
|
||||||
break;
|
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:
|
default:
|
||||||
WARN_ON(1);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((validate_min && value < pt->min) ||
|
nla_get_range_signed(pt, &range);
|
||||||
(validate_max && value > pt->max)) {
|
|
||||||
|
if (value < range.min || value > range.max) {
|
||||||
NL_SET_ERR_MSG_ATTR(extack, nla,
|
NL_SET_ERR_MSG_ATTR(extack, nla,
|
||||||
"integer out of range");
|
"integer out of range");
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
@ -154,9 +272,31 @@ static int nla_validate_int_range(const struct nla_policy *pt,
|
|||||||
return 0;
|
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,
|
static int validate_nla(const struct nlattr *nla, int maxtype,
|
||||||
const struct nla_policy *policy, unsigned int validate,
|
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;
|
u16 strict_start_type = policy[0].strict_start_type;
|
||||||
const struct nla_policy *pt;
|
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);
|
BUG_ON(pt->type > NLA_TYPE_MAX);
|
||||||
|
|
||||||
if ((nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) ||
|
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",
|
pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n",
|
||||||
current->comm, type);
|
current->comm, type);
|
||||||
if (validate & NL_VALIDATE_STRICT_ATTRS) {
|
if (validate & NL_VALIDATE_STRICT_ATTRS) {
|
||||||
@ -200,15 +342,10 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (pt->type) {
|
switch (pt->type) {
|
||||||
case NLA_EXACT_LEN:
|
|
||||||
if (attrlen != pt->len)
|
|
||||||
goto out_err;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NLA_REJECT:
|
case NLA_REJECT:
|
||||||
if (extack && pt->validation_data) {
|
if (extack && pt->reject_message) {
|
||||||
NL_SET_BAD_ATTR(extack, nla);
|
NL_SET_BAD_ATTR(extack, nla);
|
||||||
extack->_msg = pt->validation_data;
|
extack->_msg = pt->reject_message;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
@ -223,7 +360,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
|||||||
if (attrlen != sizeof(struct nla_bitfield32))
|
if (attrlen != sizeof(struct nla_bitfield32))
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
err = validate_nla_bitfield32(nla, pt->validation_data);
|
err = validate_nla_bitfield32(nla, pt->bitfield32_valid);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
break;
|
break;
|
||||||
@ -268,10 +405,11 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
|||||||
break;
|
break;
|
||||||
if (attrlen < NLA_HDRLEN)
|
if (attrlen < NLA_HDRLEN)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
if (pt->validation_data) {
|
if (pt->nested_policy) {
|
||||||
err = __nla_validate(nla_data(nla), nla_len(nla), pt->len,
|
err = __nla_validate_parse(nla_data(nla), nla_len(nla),
|
||||||
pt->validation_data, validate,
|
pt->len, pt->nested_policy,
|
||||||
extack);
|
validate, extack, NULL,
|
||||||
|
depth + 1);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
/*
|
/*
|
||||||
* return directly to preserve the inner
|
* return directly to preserve the inner
|
||||||
@ -289,12 +427,12 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
|||||||
break;
|
break;
|
||||||
if (attrlen < NLA_HDRLEN)
|
if (attrlen < NLA_HDRLEN)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
if (pt->validation_data) {
|
if (pt->nested_policy) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = nla_validate_array(nla_data(nla), nla_len(nla),
|
err = nla_validate_array(nla_data(nla), nla_len(nla),
|
||||||
pt->len, pt->validation_data,
|
pt->len, pt->nested_policy,
|
||||||
extack, validate);
|
extack, validate, depth);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
/*
|
/*
|
||||||
* return directly to preserve the inner
|
* return directly to preserve the inner
|
||||||
@ -317,6 +455,13 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
|||||||
goto out_err;
|
goto out_err;
|
||||||
break;
|
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:
|
default:
|
||||||
if (pt->len)
|
if (pt->len)
|
||||||
minlen = pt->len;
|
minlen = pt->len;
|
||||||
@ -332,6 +477,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
|
|||||||
case NLA_VALIDATE_NONE:
|
case NLA_VALIDATE_NONE:
|
||||||
/* nothing to do */
|
/* nothing to do */
|
||||||
break;
|
break;
|
||||||
|
case NLA_VALIDATE_RANGE_PTR:
|
||||||
case NLA_VALIDATE_RANGE:
|
case NLA_VALIDATE_RANGE:
|
||||||
case NLA_VALIDATE_MIN:
|
case NLA_VALIDATE_MIN:
|
||||||
case NLA_VALIDATE_MAX:
|
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,
|
const struct nla_policy *policy,
|
||||||
unsigned int validate,
|
unsigned int validate,
|
||||||
struct netlink_ext_ack *extack,
|
struct netlink_ext_ack *extack,
|
||||||
struct nlattr **tb)
|
struct nlattr **tb, unsigned int depth)
|
||||||
{
|
{
|
||||||
const struct nlattr *nla;
|
const struct nlattr *nla;
|
||||||
int rem;
|
int rem;
|
||||||
|
|
||||||
|
if (depth >= MAX_POLICY_RECURSION_DEPTH) {
|
||||||
|
NL_SET_ERR_MSG(extack,
|
||||||
|
"allowed policy recursion depth exceeded");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (tb)
|
if (tb)
|
||||||
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
|
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) {
|
if (policy) {
|
||||||
int err = validate_nla(nla, maxtype, policy,
|
int err = validate_nla(nla, maxtype, policy,
|
||||||
validate, extack);
|
validate, extack, depth);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
@ -421,7 +573,7 @@ int __nla_validate(const struct nlattr *head, int len, int maxtype,
|
|||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
return __nla_validate_parse(head, len, maxtype, policy, validate,
|
return __nla_validate_parse(head, len, maxtype, policy, validate,
|
||||||
extack, NULL);
|
extack, NULL, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__nla_validate);
|
EXPORT_SYMBOL(__nla_validate);
|
||||||
|
|
||||||
@ -476,7 +628,7 @@ int __nla_parse(struct nlattr **tb, int maxtype,
|
|||||||
struct netlink_ext_ack *extack)
|
struct netlink_ext_ack *extack)
|
||||||
{
|
{
|
||||||
return __nla_validate_parse(head, len, maxtype, policy, validate,
|
return __nla_validate_parse(head, len, maxtype, policy, validate,
|
||||||
extack, tb);
|
extack, tb, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__nla_parse);
|
EXPORT_SYMBOL(__nla_parse);
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# Makefile for the netlink driver.
|
# 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
|
obj-$(CONFIG_NETLINK_DIAG) += netlink_diag.o
|
||||||
netlink_diag-y := 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;
|
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[] = {
|
static const struct genl_ops genl_ctrl_ops[] = {
|
||||||
{
|
{
|
||||||
.cmd = CTRL_CMD_GETFAMILY,
|
.cmd = CTRL_CMD_GETFAMILY,
|
||||||
@ -1050,6 +1124,10 @@ static const struct genl_ops genl_ctrl_ops[] = {
|
|||||||
.doit = ctrl_getfamily,
|
.doit = ctrl_getfamily,
|
||||||
.dumpit = ctrl_dumpfamily,
|
.dumpit = ctrl_dumpfamily,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.cmd = CTRL_CMD_GETPOLICY,
|
||||||
|
.dumpit = ctrl_dumppolicy,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct genl_multicast_group genl_ctrl_groups[] = {
|
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;
|
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] = {
|
static const struct nla_policy tcf_action_policy[TCA_ACT_MAX + 1] = {
|
||||||
[TCA_ACT_KIND] = { .type = NLA_STRING },
|
[TCA_ACT_KIND] = { .type = NLA_STRING },
|
||||||
[TCA_ACT_INDEX] = { .type = NLA_U32 },
|
[TCA_ACT_INDEX] = { .type = NLA_U32 },
|
||||||
[TCA_ACT_COOKIE] = { .type = NLA_BINARY,
|
[TCA_ACT_COOKIE] = { .type = NLA_BINARY,
|
||||||
.len = TC_COOKIE_MAX_SIZE },
|
.len = TC_COOKIE_MAX_SIZE },
|
||||||
[TCA_ACT_OPTIONS] = { .type = NLA_NESTED },
|
[TCA_ACT_OPTIONS] = { .type = NLA_NESTED },
|
||||||
[TCA_ACT_FLAGS] = { .type = NLA_BITFIELD32,
|
[TCA_ACT_FLAGS] = NLA_POLICY_BITFIELD32(TCA_ACT_FLAGS_NO_PERCPU_STATS),
|
||||||
.validation_data = &tca_act_flags_allowed },
|
[TCA_ACT_HW_STATS] = NLA_POLICY_BITFIELD32(TCA_ACT_HW_STATS_ANY),
|
||||||
[TCA_ACT_HW_STATS] = { .type = NLA_BITFIELD32,
|
|
||||||
.validation_data = &tca_act_hw_stats_allowed },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 tcaa_root_flags_allowed = TCA_FLAG_LARGE_DUMP_ON;
|
|
||||||
static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
|
static const struct nla_policy tcaa_policy[TCA_ROOT_MAX + 1] = {
|
||||||
[TCA_ROOT_FLAGS] = { .type = NLA_BITFIELD32,
|
[TCA_ROOT_FLAGS] = NLA_POLICY_BITFIELD32(TCA_FLAG_LARGE_DUMP_ON),
|
||||||
.validation_data = &tcaa_root_flags_allowed },
|
|
||||||
[TCA_ROOT_TIME_DELTA] = { .type = NLA_U32 },
|
[TCA_ROOT_TIME_DELTA] = { .type = NLA_U32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ struct red_sched_data {
|
|||||||
struct Qdisc *qdisc;
|
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)
|
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_PARMS] = { .len = sizeof(struct tc_red_qopt) },
|
||||||
[TCA_RED_STAB] = { .len = RED_STAB_SIZE },
|
[TCA_RED_STAB] = { .len = RED_STAB_SIZE },
|
||||||
[TCA_RED_MAX_P] = { .type = NLA_U32 },
|
[TCA_RED_MAX_P] = { .type = NLA_U32 },
|
||||||
[TCA_RED_FLAGS] = { .type = NLA_BITFIELD32,
|
[TCA_RED_FLAGS] = NLA_POLICY_BITFIELD32(TC_RED_SUPPORTED_FLAGS),
|
||||||
.validation_data = &red_supported_flags },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int red_change(struct Qdisc *sch, struct nlattr *opt,
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
err = red_get_flags(ctl->flags, TC_RED_HISTORIC_FLAGS,
|
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);
|
&flags_bf, &userbits, extack);
|
||||||
if (err)
|
if (err)
|
||||||
return 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) ||
|
if (nla_put(skb, TCA_RED_PARMS, sizeof(opt), &opt) ||
|
||||||
nla_put_u32(skb, TCA_RED_MAX_P, q->parms.max_P) ||
|
nla_put_u32(skb, TCA_RED_MAX_P, q->parms.max_P) ||
|
||||||
nla_put_bitfield32(skb, TCA_RED_FLAGS,
|
nla_put_bitfield32(skb, TCA_RED_FLAGS,
|
||||||
q->flags, red_supported_flags))
|
q->flags, TC_RED_SUPPORTED_FLAGS))
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
return nla_nest_end(skb, opts);
|
return nla_nest_end(skb, opts);
|
||||||
|
|
||||||
|
@ -253,6 +253,8 @@ static int validate_ie_attr(const struct nlattr *attr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* policy for the attributes */
|
/* policy for the attributes */
|
||||||
|
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR];
|
||||||
|
|
||||||
static const struct nla_policy
|
static const struct nla_policy
|
||||||
nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
|
nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
|
||||||
[NL80211_FTM_RESP_ATTR_ENABLED] = { .type = NLA_FLAG, },
|
[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
|
static const struct nla_policy
|
||||||
nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
|
nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
|
||||||
[NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
|
[NL80211_PMSR_PEER_ATTR_ADDR] = NLA_POLICY_ETH_ADDR,
|
||||||
/*
|
[NL80211_PMSR_PEER_ATTR_CHAN] = NLA_POLICY_NESTED(nl80211_policy),
|
||||||
* 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_REQ] =
|
[NL80211_PMSR_PEER_ATTR_REQ] =
|
||||||
NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy),
|
NLA_POLICY_NESTED(nl80211_pmsr_req_attr_policy),
|
||||||
[NL80211_PMSR_PEER_ATTR_RESP] = { .type = NLA_REJECT },
|
[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),
|
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 },
|
[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
|
||||||
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
|
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
|
[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_IFINDEX] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
|
[NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
|
||||||
|
|
||||||
[NL80211_ATTR_MAC] = { .type = NLA_EXACT_LEN_WARN, .len = ETH_ALEN },
|
[NL80211_ATTR_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||||
[NL80211_ATTR_PREV_BSSID] = {
|
[NL80211_ATTR_PREV_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = ETH_ALEN
|
|
||||||
},
|
|
||||||
|
|
||||||
[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
|
[NL80211_ATTR_KEY] = { .type = NLA_NESTED, },
|
||||||
[NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
|
[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_MESH_CONFIG] = { .type = NLA_NESTED },
|
||||||
[NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
|
[NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
|
||||||
|
|
||||||
[NL80211_ATTR_HT_CAPABILITY] = {
|
[NL80211_ATTR_HT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_HT_CAPABILITY_LEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = NL80211_HT_CAPABILITY_LEN
|
|
||||||
},
|
|
||||||
|
|
||||||
[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
|
[NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
|
||||||
[NL80211_ATTR_IE] = NLA_POLICY_VALIDATE_FN(NLA_BINARY,
|
[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_WPA_VERSIONS] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_PID] = { .type = NLA_U32 },
|
[NL80211_ATTR_PID] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
|
[NL80211_ATTR_4ADDR] = { .type = NLA_U8 },
|
||||||
[NL80211_ATTR_PMKID] = {
|
[NL80211_ATTR_PMKID] = NLA_POLICY_EXACT_LEN_WARN(WLAN_PMKID_LEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = WLAN_PMKID_LEN
|
|
||||||
},
|
|
||||||
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
|
[NL80211_ATTR_DURATION] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
|
[NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
|
||||||
[NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
|
[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_WDEV] = { .type = NLA_U64 },
|
||||||
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
|
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
|
[NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
|
||||||
[NL80211_ATTR_VHT_CAPABILITY] = {
|
[NL80211_ATTR_VHT_CAPABILITY] = NLA_POLICY_EXACT_LEN_WARN(NL80211_VHT_CAPABILITY_LEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = NL80211_VHT_CAPABILITY_LEN
|
|
||||||
},
|
|
||||||
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
|
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127),
|
[NL80211_ATTR_P2P_CTWINDOW] = NLA_POLICY_MAX(NLA_U8, 127),
|
||||||
[NL80211_ATTR_P2P_OPPPS] = NLA_POLICY_MAX(NLA_U8, 1),
|
[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_VENDOR_DATA] = { .type = NLA_BINARY },
|
||||||
[NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
|
[NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
|
||||||
.len = IEEE80211_QOS_MAP_LEN_MAX },
|
.len = IEEE80211_QOS_MAP_LEN_MAX },
|
||||||
[NL80211_ATTR_MAC_HINT] = {
|
[NL80211_ATTR_MAC_HINT] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = ETH_ALEN
|
|
||||||
},
|
|
||||||
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
|
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
|
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_SOCKET_OWNER] = { .type = NLA_FLAG },
|
[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_ADMITTED_TIME] = { .type = NLA_U16 },
|
||||||
[NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
|
[NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
|
||||||
[NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 },
|
[NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 },
|
||||||
[NL80211_ATTR_MAC_MASK] = {
|
[NL80211_ATTR_MAC_MASK] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = ETH_ALEN
|
|
||||||
},
|
|
||||||
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
|
[NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
|
||||||
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
|
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .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] = {
|
[NL80211_ATTR_MU_MIMO_GROUP_DATA] = {
|
||||||
.len = VHT_MUMIMO_GROUPS_DATA_LEN
|
.len = VHT_MUMIMO_GROUPS_DATA_LEN
|
||||||
},
|
},
|
||||||
[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = {
|
[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = ETH_ALEN
|
|
||||||
},
|
|
||||||
[NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1),
|
[NL80211_ATTR_NAN_MASTER_PREF] = NLA_POLICY_MIN(NLA_U8, 1),
|
||||||
[NL80211_ATTR_BANDS] = { .type = NLA_U32 },
|
[NL80211_ATTR_BANDS] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
|
[NL80211_ATTR_NAN_FUNC] = { .type = NLA_NESTED },
|
||||||
[NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
|
[NL80211_ATTR_FILS_KEK] = { .type = NLA_BINARY,
|
||||||
.len = FILS_MAX_KEK_LEN },
|
.len = FILS_MAX_KEK_LEN },
|
||||||
[NL80211_ATTR_FILS_NONCES] = {
|
[NL80211_ATTR_FILS_NONCES] = NLA_POLICY_EXACT_LEN_WARN(2 * FILS_NONCE_LEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = 2 * FILS_NONCE_LEN
|
|
||||||
},
|
|
||||||
[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
|
[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_RELATIVE_RSSI] = { .type = NLA_S8 },
|
||||||
[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
|
[NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST] = {
|
||||||
.len = sizeof(struct nl80211_bss_select_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_NEXT_SEQ_NUM] = { .type = NLA_U16 },
|
||||||
[NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
|
[NL80211_ATTR_FILS_ERP_RRK] = { .type = NLA_BINARY,
|
||||||
.len = FILS_ERP_MAX_RRK_LEN },
|
.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_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
|
||||||
[NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
|
[NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
|
||||||
[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .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_policy[NUM_NL80211_WOWLAN_TCP] = {
|
||||||
[NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
|
[NL80211_WOWLAN_TCP_SRC_IPV4] = { .type = NLA_U32 },
|
||||||
[NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
|
[NL80211_WOWLAN_TCP_DST_IPV4] = { .type = NLA_U32 },
|
||||||
[NL80211_WOWLAN_TCP_DST_MAC] = {
|
[NL80211_WOWLAN_TCP_DST_MAC] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = ETH_ALEN
|
|
||||||
},
|
|
||||||
[NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
|
[NL80211_WOWLAN_TCP_SRC_PORT] = { .type = NLA_U16 },
|
||||||
[NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
|
[NL80211_WOWLAN_TCP_DST_PORT] = { .type = NLA_U16 },
|
||||||
[NL80211_WOWLAN_TCP_DATA_PAYLOAD] = { .type = NLA_MIN_LEN, .len = 1 },
|
[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 */
|
/* policy for GTK rekey offload attributes */
|
||||||
static const struct nla_policy
|
static const struct nla_policy
|
||||||
nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
|
nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = {
|
||||||
[NL80211_REKEY_DATA_KEK] = {
|
[NL80211_REKEY_DATA_KEK] = NLA_POLICY_EXACT_LEN_WARN(NL80211_KEK_LEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
[NL80211_REKEY_DATA_KCK] = NLA_POLICY_EXACT_LEN_WARN(NL80211_KCK_LEN),
|
||||||
.len = NL80211_KEK_LEN,
|
[NL80211_REKEY_DATA_REPLAY_CTR] = NLA_POLICY_EXACT_LEN_WARN(NL80211_REPLAY_CTR_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
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct nla_policy
|
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_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = {
|
||||||
[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
|
[NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY,
|
||||||
.len = IEEE80211_MAX_SSID_LEN },
|
.len = IEEE80211_MAX_SSID_LEN },
|
||||||
[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = {
|
[NL80211_SCHED_SCAN_MATCH_ATTR_BSSID] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = ETH_ALEN
|
|
||||||
},
|
|
||||||
[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
|
[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 },
|
||||||
[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
|
[NL80211_SCHED_SCAN_MATCH_PER_BAND_RSSI] =
|
||||||
NLA_POLICY_NESTED(nl80211_match_band_rssi_policy),
|
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_SUBSCRIBE_ACTIVE] = { .type = NLA_FLAG },
|
||||||
[NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
|
[NL80211_NAN_FUNC_FOLLOW_UP_ID] = { .type = NLA_U8 },
|
||||||
[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
|
[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] = { .type = NLA_U8 },
|
||||||
[NL80211_NAN_FUNC_FOLLOW_UP_DEST] = {
|
[NL80211_NAN_FUNC_FOLLOW_UP_DEST] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = ETH_ALEN
|
|
||||||
},
|
|
||||||
[NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
|
[NL80211_NAN_FUNC_CLOSE_RANGE] = { .type = NLA_FLAG },
|
||||||
[NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
|
[NL80211_NAN_FUNC_TTL] = { .type = NLA_U32 },
|
||||||
[NL80211_NAN_FUNC_SERVICE_INFO] = { .type = NLA_BINARY,
|
[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 },
|
.len = NL80211_MAX_SUPP_RATES },
|
||||||
[NL80211_TXRATE_HT] = { .type = NLA_BINARY,
|
[NL80211_TXRATE_HT] = { .type = NLA_BINARY,
|
||||||
.len = NL80211_MAX_SUPP_HT_RATES },
|
.len = NL80211_MAX_SUPP_HT_RATES },
|
||||||
[NL80211_TXRATE_VHT] = {
|
[NL80211_TXRATE_VHT] = NLA_POLICY_EXACT_LEN_WARN(sizeof(struct nl80211_txrate_vht)),
|
||||||
.type = NLA_EXACT_LEN_WARN,
|
|
||||||
.len = sizeof(struct nl80211_txrate_vht),
|
|
||||||
},
|
|
||||||
[NL80211_TXRATE_GI] = { .type = NLA_U8 },
|
[NL80211_TXRATE_GI] = { .type = NLA_U8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,8 +11,6 @@
|
|||||||
int nl80211_init(void);
|
int nl80211_init(void);
|
||||||
void nl80211_exit(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,
|
void *nl80211hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
|
||||||
int flags, u8 cmd);
|
int flags, u8 cmd);
|
||||||
bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
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 */
|
/* reuse info->attrs */
|
||||||
memset(info->attrs, 0, sizeof(*info->attrs) * (NL80211_ATTR_MAX + 1));
|
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,
|
err = nla_parse_nested_deprecated(info->attrs, NL80211_ATTR_MAX,
|
||||||
tb[NL80211_PMSR_PEER_ATTR_CHAN],
|
tb[NL80211_PMSR_PEER_ATTR_CHAN],
|
||||||
nl80211_policy, info->extack);
|
NULL, info->extack);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user