[NETLINK]: attr: add nested compat attribute type
Add a nested compat attribute type that can be used to convert attributes that contain a structure to nested attributes in a backwards compatible way. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
334a8132d9
commit
1092cb2197
|
@ -118,6 +118,9 @@
|
||||||
* Nested Attributes Construction:
|
* Nested Attributes Construction:
|
||||||
* nla_nest_start(skb, type) start a nested attribute
|
* nla_nest_start(skb, type) start a nested attribute
|
||||||
* nla_nest_end(skb, nla) finalize a nested attribute
|
* nla_nest_end(skb, nla) finalize a nested attribute
|
||||||
|
* nla_nest_compat_start(skb, type, start a nested compat attribute
|
||||||
|
* len, data)
|
||||||
|
* nla_nest_compat_end(skb, type) finalize a nested compat attribute
|
||||||
* nla_nest_cancel(skb, nla) cancel nested attribute construction
|
* nla_nest_cancel(skb, nla) cancel nested attribute construction
|
||||||
*
|
*
|
||||||
* Attribute Length Calculations:
|
* Attribute Length Calculations:
|
||||||
|
@ -152,6 +155,7 @@
|
||||||
* nla_find_nested() find attribute in nested attributes
|
* nla_find_nested() find attribute in nested attributes
|
||||||
* nla_parse() parse and validate stream of attrs
|
* nla_parse() parse and validate stream of attrs
|
||||||
* nla_parse_nested() parse nested attribuets
|
* nla_parse_nested() parse nested attribuets
|
||||||
|
* nla_parse_nested_compat() parse nested compat attributes
|
||||||
* nla_for_each_attr() loop over all attributes
|
* nla_for_each_attr() loop over all attributes
|
||||||
* nla_for_each_nested() loop over the nested attributes
|
* nla_for_each_nested() loop over the nested attributes
|
||||||
*=========================================================================
|
*=========================================================================
|
||||||
|
@ -170,6 +174,7 @@ enum {
|
||||||
NLA_FLAG,
|
NLA_FLAG,
|
||||||
NLA_MSECS,
|
NLA_MSECS,
|
||||||
NLA_NESTED,
|
NLA_NESTED,
|
||||||
|
NLA_NESTED_COMPAT,
|
||||||
NLA_NUL_STRING,
|
NLA_NUL_STRING,
|
||||||
NLA_BINARY,
|
NLA_BINARY,
|
||||||
__NLA_TYPE_MAX,
|
__NLA_TYPE_MAX,
|
||||||
|
@ -190,6 +195,7 @@ enum {
|
||||||
* NLA_NUL_STRING Maximum length of string (excluding NUL)
|
* NLA_NUL_STRING Maximum length of string (excluding NUL)
|
||||||
* NLA_FLAG Unused
|
* NLA_FLAG Unused
|
||||||
* NLA_BINARY Maximum length of attribute payload
|
* NLA_BINARY Maximum length of attribute payload
|
||||||
|
* NLA_NESTED_COMPAT Exact length of structure payload
|
||||||
* All other Exact length of attribute payload
|
* All other Exact length of attribute payload
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
|
@ -733,6 +739,39 @@ static inline int nla_parse_nested(struct nlattr *tb[], int maxtype,
|
||||||
{
|
{
|
||||||
return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
|
return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nla_parse_nested_compat - parse nested compat attributes
|
||||||
|
* @tb: destination array with maxtype+1 elements
|
||||||
|
* @maxtype: maximum attribute type to be expected
|
||||||
|
* @nla: attribute containing the nested attributes
|
||||||
|
* @data: pointer to point to contained structure
|
||||||
|
* @len: length of contained structure
|
||||||
|
* @policy: validation policy
|
||||||
|
*
|
||||||
|
* Parse a nested compat attribute. The compat attribute contains a structure
|
||||||
|
* and optionally a set of nested attributes. On success the data pointer
|
||||||
|
* points to the nested data and tb contains the parsed attributes
|
||||||
|
* (see nla_parse).
|
||||||
|
*/
|
||||||
|
static inline int __nla_parse_nested_compat(struct nlattr *tb[], int maxtype,
|
||||||
|
struct nlattr *nla,
|
||||||
|
const struct nla_policy *policy,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
if (nla_len(nla) < len)
|
||||||
|
return -1;
|
||||||
|
if (nla_len(nla) >= NLA_ALIGN(len) + sizeof(struct nlattr))
|
||||||
|
return nla_parse_nested(tb, maxtype,
|
||||||
|
nla_data(nla) + NLA_ALIGN(len),
|
||||||
|
policy);
|
||||||
|
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define nla_parse_nested_compat(tb, maxtype, nla, policy, data, len) \
|
||||||
|
({ data = nla_len(nla) >= len ? nla_data(nla) : NULL; \
|
||||||
|
__nla_parse_nested_compat(tb, maxtype, nla, policy, len); })
|
||||||
/**
|
/**
|
||||||
* nla_put_u8 - Add a u16 netlink attribute to a socket buffer
|
* nla_put_u8 - Add a u16 netlink attribute to a socket buffer
|
||||||
* @skb: socket buffer to add attribute to
|
* @skb: socket buffer to add attribute to
|
||||||
|
@ -964,6 +1003,51 @@ static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start)
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nla_nest_compat_start - Start a new level of nested compat attributes
|
||||||
|
* @skb: socket buffer to add attributes to
|
||||||
|
* @attrtype: attribute type of container
|
||||||
|
* @attrlen: length of structure
|
||||||
|
* @data: pointer to structure
|
||||||
|
*
|
||||||
|
* Start a nested compat attribute that contains both a structure and
|
||||||
|
* a set of nested attributes.
|
||||||
|
*
|
||||||
|
* Returns the container attribute
|
||||||
|
*/
|
||||||
|
static inline struct nlattr *nla_nest_compat_start(struct sk_buff *skb,
|
||||||
|
int attrtype, int attrlen,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
struct nlattr *start = (struct nlattr *)skb_tail_pointer(skb);
|
||||||
|
|
||||||
|
if (nla_put(skb, attrtype, attrlen, data) < 0)
|
||||||
|
return NULL;
|
||||||
|
if (nla_nest_start(skb, attrtype) == NULL) {
|
||||||
|
nlmsg_trim(skb, start);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nla_nest_compat_end - Finalize nesting of compat attributes
|
||||||
|
* @skb: socket buffer the attribtues are stored in
|
||||||
|
* @start: container attribute
|
||||||
|
*
|
||||||
|
* Corrects the container attribute header to include the all
|
||||||
|
* appeneded attributes.
|
||||||
|
*
|
||||||
|
* Returns the total data length of the skb.
|
||||||
|
*/
|
||||||
|
static inline int nla_nest_compat_end(struct sk_buff *skb, struct nlattr *start)
|
||||||
|
{
|
||||||
|
struct nlattr *nest = (void *)start + NLMSG_ALIGN(start->nla_len);
|
||||||
|
|
||||||
|
start->nla_len = skb_tail_pointer(skb) - (unsigned char *)start;
|
||||||
|
return nla_nest_end(skb, nest);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nla_nest_cancel - Cancel nesting of attributes
|
* nla_nest_cancel - Cancel nesting of attributes
|
||||||
* @skb: socket buffer the message is stored in
|
* @skb: socket buffer the message is stored in
|
||||||
|
|
|
@ -72,6 +72,17 @@ static int validate_nla(struct nlattr *nla, int maxtype,
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NLA_NESTED_COMPAT:
|
||||||
|
if (attrlen < pt->len)
|
||||||
|
return -ERANGE;
|
||||||
|
if (attrlen < NLA_ALIGN(pt->len))
|
||||||
|
break;
|
||||||
|
if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN)
|
||||||
|
return -ERANGE;
|
||||||
|
nla = nla_data(nla) + NLA_ALIGN(pt->len);
|
||||||
|
if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla))
|
||||||
|
return -ERANGE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (pt->len)
|
if (pt->len)
|
||||||
minlen = pt->len;
|
minlen = pt->len;
|
||||||
|
|
Loading…
Reference in New Issue