162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * NETLINK      Netlink attributes
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * 		Authors:	Thomas Graf <tgraf@suug.ch>
662306a36Sopenharmony_ci * 				Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/export.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <linux/jiffies.h>
1362306a36Sopenharmony_ci#include <linux/nospec.h>
1462306a36Sopenharmony_ci#include <linux/skbuff.h>
1562306a36Sopenharmony_ci#include <linux/string.h>
1662306a36Sopenharmony_ci#include <linux/types.h>
1762306a36Sopenharmony_ci#include <net/netlink.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* For these data types, attribute length should be exactly the given
2062306a36Sopenharmony_ci * size. However, to maintain compatibility with broken commands, if the
2162306a36Sopenharmony_ci * attribute length does not match the expected size a warning is emitted
2262306a36Sopenharmony_ci * to the user that the command is sending invalid data and needs to be fixed.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_cistatic const u8 nla_attr_len[NLA_TYPE_MAX+1] = {
2562306a36Sopenharmony_ci	[NLA_U8]	= sizeof(u8),
2662306a36Sopenharmony_ci	[NLA_U16]	= sizeof(u16),
2762306a36Sopenharmony_ci	[NLA_U32]	= sizeof(u32),
2862306a36Sopenharmony_ci	[NLA_U64]	= sizeof(u64),
2962306a36Sopenharmony_ci	[NLA_S8]	= sizeof(s8),
3062306a36Sopenharmony_ci	[NLA_S16]	= sizeof(s16),
3162306a36Sopenharmony_ci	[NLA_S32]	= sizeof(s32),
3262306a36Sopenharmony_ci	[NLA_S64]	= sizeof(s64),
3362306a36Sopenharmony_ci	[NLA_BE16]	= sizeof(__be16),
3462306a36Sopenharmony_ci	[NLA_BE32]	= sizeof(__be32),
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
3862306a36Sopenharmony_ci	[NLA_U8]	= sizeof(u8),
3962306a36Sopenharmony_ci	[NLA_U16]	= sizeof(u16),
4062306a36Sopenharmony_ci	[NLA_U32]	= sizeof(u32),
4162306a36Sopenharmony_ci	[NLA_U64]	= sizeof(u64),
4262306a36Sopenharmony_ci	[NLA_MSECS]	= sizeof(u64),
4362306a36Sopenharmony_ci	[NLA_NESTED]	= NLA_HDRLEN,
4462306a36Sopenharmony_ci	[NLA_S8]	= sizeof(s8),
4562306a36Sopenharmony_ci	[NLA_S16]	= sizeof(s16),
4662306a36Sopenharmony_ci	[NLA_S32]	= sizeof(s32),
4762306a36Sopenharmony_ci	[NLA_S64]	= sizeof(s64),
4862306a36Sopenharmony_ci	[NLA_BE16]	= sizeof(__be16),
4962306a36Sopenharmony_ci	[NLA_BE32]	= sizeof(__be32),
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/*
5362306a36Sopenharmony_ci * Nested policies might refer back to the original
5462306a36Sopenharmony_ci * policy in some cases, and userspace could try to
5562306a36Sopenharmony_ci * abuse that and recurse by nesting in the right
5662306a36Sopenharmony_ci * ways. Limit recursion to avoid this problem.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci#define MAX_POLICY_RECURSION_DEPTH	10
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
6162306a36Sopenharmony_ci				const struct nla_policy *policy,
6262306a36Sopenharmony_ci				unsigned int validate,
6362306a36Sopenharmony_ci				struct netlink_ext_ack *extack,
6462306a36Sopenharmony_ci				struct nlattr **tb, unsigned int depth);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic int validate_nla_bitfield32(const struct nlattr *nla,
6762306a36Sopenharmony_ci				   const u32 valid_flags_mask)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	const struct nla_bitfield32 *bf = nla_data(nla);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (!valid_flags_mask)
7262306a36Sopenharmony_ci		return -EINVAL;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/*disallow invalid bit selector */
7562306a36Sopenharmony_ci	if (bf->selector & ~valid_flags_mask)
7662306a36Sopenharmony_ci		return -EINVAL;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/*disallow invalid bit values */
7962306a36Sopenharmony_ci	if (bf->value & ~valid_flags_mask)
8062306a36Sopenharmony_ci		return -EINVAL;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/*disallow valid bit values that are not selected*/
8362306a36Sopenharmony_ci	if (bf->value & ~bf->selector)
8462306a36Sopenharmony_ci		return -EINVAL;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return 0;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int nla_validate_array(const struct nlattr *head, int len, int maxtype,
9062306a36Sopenharmony_ci			      const struct nla_policy *policy,
9162306a36Sopenharmony_ci			      struct netlink_ext_ack *extack,
9262306a36Sopenharmony_ci			      unsigned int validate, unsigned int depth)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	const struct nlattr *entry;
9562306a36Sopenharmony_ci	int rem;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	nla_for_each_attr(entry, head, len, rem) {
9862306a36Sopenharmony_ci		int ret;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		if (nla_len(entry) == 0)
10162306a36Sopenharmony_ci			continue;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		if (nla_len(entry) < NLA_HDRLEN) {
10462306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, entry, policy,
10562306a36Sopenharmony_ci						"Array element too short");
10662306a36Sopenharmony_ci			return -ERANGE;
10762306a36Sopenharmony_ci		}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		ret = __nla_validate_parse(nla_data(entry), nla_len(entry),
11062306a36Sopenharmony_ci					   maxtype, policy, validate, extack,
11162306a36Sopenharmony_ci					   NULL, depth + 1);
11262306a36Sopenharmony_ci		if (ret < 0)
11362306a36Sopenharmony_ci			return ret;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_civoid nla_get_range_unsigned(const struct nla_policy *pt,
12062306a36Sopenharmony_ci			    struct netlink_range_validation *range)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	WARN_ON_ONCE(pt->validation_type != NLA_VALIDATE_RANGE_PTR &&
12362306a36Sopenharmony_ci		     (pt->min < 0 || pt->max < 0));
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	range->min = 0;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	switch (pt->type) {
12862306a36Sopenharmony_ci	case NLA_U8:
12962306a36Sopenharmony_ci		range->max = U8_MAX;
13062306a36Sopenharmony_ci		break;
13162306a36Sopenharmony_ci	case NLA_U16:
13262306a36Sopenharmony_ci	case NLA_BE16:
13362306a36Sopenharmony_ci	case NLA_BINARY:
13462306a36Sopenharmony_ci		range->max = U16_MAX;
13562306a36Sopenharmony_ci		break;
13662306a36Sopenharmony_ci	case NLA_U32:
13762306a36Sopenharmony_ci	case NLA_BE32:
13862306a36Sopenharmony_ci		range->max = U32_MAX;
13962306a36Sopenharmony_ci		break;
14062306a36Sopenharmony_ci	case NLA_U64:
14162306a36Sopenharmony_ci	case NLA_MSECS:
14262306a36Sopenharmony_ci		range->max = U64_MAX;
14362306a36Sopenharmony_ci		break;
14462306a36Sopenharmony_ci	default:
14562306a36Sopenharmony_ci		WARN_ON_ONCE(1);
14662306a36Sopenharmony_ci		return;
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	switch (pt->validation_type) {
15062306a36Sopenharmony_ci	case NLA_VALIDATE_RANGE:
15162306a36Sopenharmony_ci	case NLA_VALIDATE_RANGE_WARN_TOO_LONG:
15262306a36Sopenharmony_ci		range->min = pt->min;
15362306a36Sopenharmony_ci		range->max = pt->max;
15462306a36Sopenharmony_ci		break;
15562306a36Sopenharmony_ci	case NLA_VALIDATE_RANGE_PTR:
15662306a36Sopenharmony_ci		*range = *pt->range;
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	case NLA_VALIDATE_MIN:
15962306a36Sopenharmony_ci		range->min = pt->min;
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	case NLA_VALIDATE_MAX:
16262306a36Sopenharmony_ci		range->max = pt->max;
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	default:
16562306a36Sopenharmony_ci		break;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int nla_validate_range_unsigned(const struct nla_policy *pt,
17062306a36Sopenharmony_ci				       const struct nlattr *nla,
17162306a36Sopenharmony_ci				       struct netlink_ext_ack *extack,
17262306a36Sopenharmony_ci				       unsigned int validate)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	struct netlink_range_validation range;
17562306a36Sopenharmony_ci	u64 value;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	switch (pt->type) {
17862306a36Sopenharmony_ci	case NLA_U8:
17962306a36Sopenharmony_ci		value = nla_get_u8(nla);
18062306a36Sopenharmony_ci		break;
18162306a36Sopenharmony_ci	case NLA_U16:
18262306a36Sopenharmony_ci		value = nla_get_u16(nla);
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci	case NLA_U32:
18562306a36Sopenharmony_ci		value = nla_get_u32(nla);
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci	case NLA_U64:
18862306a36Sopenharmony_ci		value = nla_get_u64(nla);
18962306a36Sopenharmony_ci		break;
19062306a36Sopenharmony_ci	case NLA_MSECS:
19162306a36Sopenharmony_ci		value = nla_get_u64(nla);
19262306a36Sopenharmony_ci		break;
19362306a36Sopenharmony_ci	case NLA_BINARY:
19462306a36Sopenharmony_ci		value = nla_len(nla);
19562306a36Sopenharmony_ci		break;
19662306a36Sopenharmony_ci	case NLA_BE16:
19762306a36Sopenharmony_ci		value = ntohs(nla_get_be16(nla));
19862306a36Sopenharmony_ci		break;
19962306a36Sopenharmony_ci	case NLA_BE32:
20062306a36Sopenharmony_ci		value = ntohl(nla_get_be32(nla));
20162306a36Sopenharmony_ci		break;
20262306a36Sopenharmony_ci	default:
20362306a36Sopenharmony_ci		return -EINVAL;
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	nla_get_range_unsigned(pt, &range);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	if (pt->validation_type == NLA_VALIDATE_RANGE_WARN_TOO_LONG &&
20962306a36Sopenharmony_ci	    pt->type == NLA_BINARY && value > range.max) {
21062306a36Sopenharmony_ci		pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n",
21162306a36Sopenharmony_ci				    current->comm, pt->type);
21262306a36Sopenharmony_ci		if (validate & NL_VALIDATE_STRICT_ATTRS) {
21362306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
21462306a36Sopenharmony_ci						"invalid attribute length");
21562306a36Sopenharmony_ci			return -EINVAL;
21662306a36Sopenharmony_ci		}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		/* this assumes min <= max (don't validate against min) */
21962306a36Sopenharmony_ci		return 0;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (value < range.min || value > range.max) {
22362306a36Sopenharmony_ci		bool binary = pt->type == NLA_BINARY;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		if (binary)
22662306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
22762306a36Sopenharmony_ci						"binary attribute size out of range");
22862306a36Sopenharmony_ci		else
22962306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
23062306a36Sopenharmony_ci						"integer out of range");
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		return -ERANGE;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return 0;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_civoid nla_get_range_signed(const struct nla_policy *pt,
23962306a36Sopenharmony_ci			  struct netlink_range_validation_signed *range)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	switch (pt->type) {
24262306a36Sopenharmony_ci	case NLA_S8:
24362306a36Sopenharmony_ci		range->min = S8_MIN;
24462306a36Sopenharmony_ci		range->max = S8_MAX;
24562306a36Sopenharmony_ci		break;
24662306a36Sopenharmony_ci	case NLA_S16:
24762306a36Sopenharmony_ci		range->min = S16_MIN;
24862306a36Sopenharmony_ci		range->max = S16_MAX;
24962306a36Sopenharmony_ci		break;
25062306a36Sopenharmony_ci	case NLA_S32:
25162306a36Sopenharmony_ci		range->min = S32_MIN;
25262306a36Sopenharmony_ci		range->max = S32_MAX;
25362306a36Sopenharmony_ci		break;
25462306a36Sopenharmony_ci	case NLA_S64:
25562306a36Sopenharmony_ci		range->min = S64_MIN;
25662306a36Sopenharmony_ci		range->max = S64_MAX;
25762306a36Sopenharmony_ci		break;
25862306a36Sopenharmony_ci	default:
25962306a36Sopenharmony_ci		WARN_ON_ONCE(1);
26062306a36Sopenharmony_ci		return;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	switch (pt->validation_type) {
26462306a36Sopenharmony_ci	case NLA_VALIDATE_RANGE:
26562306a36Sopenharmony_ci		range->min = pt->min;
26662306a36Sopenharmony_ci		range->max = pt->max;
26762306a36Sopenharmony_ci		break;
26862306a36Sopenharmony_ci	case NLA_VALIDATE_RANGE_PTR:
26962306a36Sopenharmony_ci		*range = *pt->range_signed;
27062306a36Sopenharmony_ci		break;
27162306a36Sopenharmony_ci	case NLA_VALIDATE_MIN:
27262306a36Sopenharmony_ci		range->min = pt->min;
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci	case NLA_VALIDATE_MAX:
27562306a36Sopenharmony_ci		range->max = pt->max;
27662306a36Sopenharmony_ci		break;
27762306a36Sopenharmony_ci	default:
27862306a36Sopenharmony_ci		break;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int nla_validate_int_range_signed(const struct nla_policy *pt,
28362306a36Sopenharmony_ci					 const struct nlattr *nla,
28462306a36Sopenharmony_ci					 struct netlink_ext_ack *extack)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct netlink_range_validation_signed range;
28762306a36Sopenharmony_ci	s64 value;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	switch (pt->type) {
29062306a36Sopenharmony_ci	case NLA_S8:
29162306a36Sopenharmony_ci		value = nla_get_s8(nla);
29262306a36Sopenharmony_ci		break;
29362306a36Sopenharmony_ci	case NLA_S16:
29462306a36Sopenharmony_ci		value = nla_get_s16(nla);
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	case NLA_S32:
29762306a36Sopenharmony_ci		value = nla_get_s32(nla);
29862306a36Sopenharmony_ci		break;
29962306a36Sopenharmony_ci	case NLA_S64:
30062306a36Sopenharmony_ci		value = nla_get_s64(nla);
30162306a36Sopenharmony_ci		break;
30262306a36Sopenharmony_ci	default:
30362306a36Sopenharmony_ci		return -EINVAL;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	nla_get_range_signed(pt, &range);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (value < range.min || value > range.max) {
30962306a36Sopenharmony_ci		NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
31062306a36Sopenharmony_ci					"integer out of range");
31162306a36Sopenharmony_ci		return -ERANGE;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int nla_validate_int_range(const struct nla_policy *pt,
31862306a36Sopenharmony_ci				  const struct nlattr *nla,
31962306a36Sopenharmony_ci				  struct netlink_ext_ack *extack,
32062306a36Sopenharmony_ci				  unsigned int validate)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	switch (pt->type) {
32362306a36Sopenharmony_ci	case NLA_U8:
32462306a36Sopenharmony_ci	case NLA_U16:
32562306a36Sopenharmony_ci	case NLA_U32:
32662306a36Sopenharmony_ci	case NLA_U64:
32762306a36Sopenharmony_ci	case NLA_MSECS:
32862306a36Sopenharmony_ci	case NLA_BINARY:
32962306a36Sopenharmony_ci	case NLA_BE16:
33062306a36Sopenharmony_ci	case NLA_BE32:
33162306a36Sopenharmony_ci		return nla_validate_range_unsigned(pt, nla, extack, validate);
33262306a36Sopenharmony_ci	case NLA_S8:
33362306a36Sopenharmony_ci	case NLA_S16:
33462306a36Sopenharmony_ci	case NLA_S32:
33562306a36Sopenharmony_ci	case NLA_S64:
33662306a36Sopenharmony_ci		return nla_validate_int_range_signed(pt, nla, extack);
33762306a36Sopenharmony_ci	default:
33862306a36Sopenharmony_ci		WARN_ON(1);
33962306a36Sopenharmony_ci		return -EINVAL;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int nla_validate_mask(const struct nla_policy *pt,
34462306a36Sopenharmony_ci			     const struct nlattr *nla,
34562306a36Sopenharmony_ci			     struct netlink_ext_ack *extack)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	u64 value;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	switch (pt->type) {
35062306a36Sopenharmony_ci	case NLA_U8:
35162306a36Sopenharmony_ci		value = nla_get_u8(nla);
35262306a36Sopenharmony_ci		break;
35362306a36Sopenharmony_ci	case NLA_U16:
35462306a36Sopenharmony_ci		value = nla_get_u16(nla);
35562306a36Sopenharmony_ci		break;
35662306a36Sopenharmony_ci	case NLA_U32:
35762306a36Sopenharmony_ci		value = nla_get_u32(nla);
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci	case NLA_U64:
36062306a36Sopenharmony_ci		value = nla_get_u64(nla);
36162306a36Sopenharmony_ci		break;
36262306a36Sopenharmony_ci	case NLA_BE16:
36362306a36Sopenharmony_ci		value = ntohs(nla_get_be16(nla));
36462306a36Sopenharmony_ci		break;
36562306a36Sopenharmony_ci	case NLA_BE32:
36662306a36Sopenharmony_ci		value = ntohl(nla_get_be32(nla));
36762306a36Sopenharmony_ci		break;
36862306a36Sopenharmony_ci	default:
36962306a36Sopenharmony_ci		return -EINVAL;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (value & ~(u64)pt->mask) {
37362306a36Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, nla, "reserved bit set");
37462306a36Sopenharmony_ci		return -EINVAL;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return 0;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int validate_nla(const struct nlattr *nla, int maxtype,
38162306a36Sopenharmony_ci			const struct nla_policy *policy, unsigned int validate,
38262306a36Sopenharmony_ci			struct netlink_ext_ack *extack, unsigned int depth)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	u16 strict_start_type = policy[0].strict_start_type;
38562306a36Sopenharmony_ci	const struct nla_policy *pt;
38662306a36Sopenharmony_ci	int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla);
38762306a36Sopenharmony_ci	int err = -ERANGE;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (strict_start_type && type >= strict_start_type)
39062306a36Sopenharmony_ci		validate |= NL_VALIDATE_STRICT;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (type <= 0 || type > maxtype)
39362306a36Sopenharmony_ci		return 0;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	type = array_index_nospec(type, maxtype + 1);
39662306a36Sopenharmony_ci	pt = &policy[type];
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	BUG_ON(pt->type > NLA_TYPE_MAX);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) {
40162306a36Sopenharmony_ci		pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n",
40262306a36Sopenharmony_ci				    current->comm, type);
40362306a36Sopenharmony_ci		if (validate & NL_VALIDATE_STRICT_ATTRS) {
40462306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
40562306a36Sopenharmony_ci						"invalid attribute length");
40662306a36Sopenharmony_ci			return -EINVAL;
40762306a36Sopenharmony_ci		}
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (validate & NL_VALIDATE_NESTED) {
41162306a36Sopenharmony_ci		if ((pt->type == NLA_NESTED || pt->type == NLA_NESTED_ARRAY) &&
41262306a36Sopenharmony_ci		    !(nla->nla_type & NLA_F_NESTED)) {
41362306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
41462306a36Sopenharmony_ci						"NLA_F_NESTED is missing");
41562306a36Sopenharmony_ci			return -EINVAL;
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci		if (pt->type != NLA_NESTED && pt->type != NLA_NESTED_ARRAY &&
41862306a36Sopenharmony_ci		    pt->type != NLA_UNSPEC && (nla->nla_type & NLA_F_NESTED)) {
41962306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
42062306a36Sopenharmony_ci						"NLA_F_NESTED not expected");
42162306a36Sopenharmony_ci			return -EINVAL;
42262306a36Sopenharmony_ci		}
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	switch (pt->type) {
42662306a36Sopenharmony_ci	case NLA_REJECT:
42762306a36Sopenharmony_ci		if (extack && pt->reject_message) {
42862306a36Sopenharmony_ci			NL_SET_BAD_ATTR(extack, nla);
42962306a36Sopenharmony_ci			extack->_msg = pt->reject_message;
43062306a36Sopenharmony_ci			return -EINVAL;
43162306a36Sopenharmony_ci		}
43262306a36Sopenharmony_ci		err = -EINVAL;
43362306a36Sopenharmony_ci		goto out_err;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	case NLA_FLAG:
43662306a36Sopenharmony_ci		if (attrlen > 0)
43762306a36Sopenharmony_ci			goto out_err;
43862306a36Sopenharmony_ci		break;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	case NLA_BITFIELD32:
44162306a36Sopenharmony_ci		if (attrlen != sizeof(struct nla_bitfield32))
44262306a36Sopenharmony_ci			goto out_err;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		err = validate_nla_bitfield32(nla, pt->bitfield32_valid);
44562306a36Sopenharmony_ci		if (err)
44662306a36Sopenharmony_ci			goto out_err;
44762306a36Sopenharmony_ci		break;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	case NLA_NUL_STRING:
45062306a36Sopenharmony_ci		if (pt->len)
45162306a36Sopenharmony_ci			minlen = min_t(int, attrlen, pt->len + 1);
45262306a36Sopenharmony_ci		else
45362306a36Sopenharmony_ci			minlen = attrlen;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) {
45662306a36Sopenharmony_ci			err = -EINVAL;
45762306a36Sopenharmony_ci			goto out_err;
45862306a36Sopenharmony_ci		}
45962306a36Sopenharmony_ci		fallthrough;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	case NLA_STRING:
46262306a36Sopenharmony_ci		if (attrlen < 1)
46362306a36Sopenharmony_ci			goto out_err;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		if (pt->len) {
46662306a36Sopenharmony_ci			char *buf = nla_data(nla);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci			if (buf[attrlen - 1] == '\0')
46962306a36Sopenharmony_ci				attrlen--;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci			if (attrlen > pt->len)
47262306a36Sopenharmony_ci				goto out_err;
47362306a36Sopenharmony_ci		}
47462306a36Sopenharmony_ci		break;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	case NLA_BINARY:
47762306a36Sopenharmony_ci		if (pt->len && attrlen > pt->len)
47862306a36Sopenharmony_ci			goto out_err;
47962306a36Sopenharmony_ci		break;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	case NLA_NESTED:
48262306a36Sopenharmony_ci		/* a nested attributes is allowed to be empty; if its not,
48362306a36Sopenharmony_ci		 * it must have a size of at least NLA_HDRLEN.
48462306a36Sopenharmony_ci		 */
48562306a36Sopenharmony_ci		if (attrlen == 0)
48662306a36Sopenharmony_ci			break;
48762306a36Sopenharmony_ci		if (attrlen < NLA_HDRLEN)
48862306a36Sopenharmony_ci			goto out_err;
48962306a36Sopenharmony_ci		if (pt->nested_policy) {
49062306a36Sopenharmony_ci			err = __nla_validate_parse(nla_data(nla), nla_len(nla),
49162306a36Sopenharmony_ci						   pt->len, pt->nested_policy,
49262306a36Sopenharmony_ci						   validate, extack, NULL,
49362306a36Sopenharmony_ci						   depth + 1);
49462306a36Sopenharmony_ci			if (err < 0) {
49562306a36Sopenharmony_ci				/*
49662306a36Sopenharmony_ci				 * return directly to preserve the inner
49762306a36Sopenharmony_ci				 * error message/attribute pointer
49862306a36Sopenharmony_ci				 */
49962306a36Sopenharmony_ci				return err;
50062306a36Sopenharmony_ci			}
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci		break;
50362306a36Sopenharmony_ci	case NLA_NESTED_ARRAY:
50462306a36Sopenharmony_ci		/* a nested array attribute is allowed to be empty; if its not,
50562306a36Sopenharmony_ci		 * it must have a size of at least NLA_HDRLEN.
50662306a36Sopenharmony_ci		 */
50762306a36Sopenharmony_ci		if (attrlen == 0)
50862306a36Sopenharmony_ci			break;
50962306a36Sopenharmony_ci		if (attrlen < NLA_HDRLEN)
51062306a36Sopenharmony_ci			goto out_err;
51162306a36Sopenharmony_ci		if (pt->nested_policy) {
51262306a36Sopenharmony_ci			int err;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci			err = nla_validate_array(nla_data(nla), nla_len(nla),
51562306a36Sopenharmony_ci						 pt->len, pt->nested_policy,
51662306a36Sopenharmony_ci						 extack, validate, depth);
51762306a36Sopenharmony_ci			if (err < 0) {
51862306a36Sopenharmony_ci				/*
51962306a36Sopenharmony_ci				 * return directly to preserve the inner
52062306a36Sopenharmony_ci				 * error message/attribute pointer
52162306a36Sopenharmony_ci				 */
52262306a36Sopenharmony_ci				return err;
52362306a36Sopenharmony_ci			}
52462306a36Sopenharmony_ci		}
52562306a36Sopenharmony_ci		break;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	case NLA_UNSPEC:
52862306a36Sopenharmony_ci		if (validate & NL_VALIDATE_UNSPEC) {
52962306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, nla,
53062306a36Sopenharmony_ci					    "Unsupported attribute");
53162306a36Sopenharmony_ci			return -EINVAL;
53262306a36Sopenharmony_ci		}
53362306a36Sopenharmony_ci		if (attrlen < pt->len)
53462306a36Sopenharmony_ci			goto out_err;
53562306a36Sopenharmony_ci		break;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	default:
53862306a36Sopenharmony_ci		if (pt->len)
53962306a36Sopenharmony_ci			minlen = pt->len;
54062306a36Sopenharmony_ci		else
54162306a36Sopenharmony_ci			minlen = nla_attr_minlen[pt->type];
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		if (attrlen < minlen)
54462306a36Sopenharmony_ci			goto out_err;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* further validation */
54862306a36Sopenharmony_ci	switch (pt->validation_type) {
54962306a36Sopenharmony_ci	case NLA_VALIDATE_NONE:
55062306a36Sopenharmony_ci		/* nothing to do */
55162306a36Sopenharmony_ci		break;
55262306a36Sopenharmony_ci	case NLA_VALIDATE_RANGE_PTR:
55362306a36Sopenharmony_ci	case NLA_VALIDATE_RANGE:
55462306a36Sopenharmony_ci	case NLA_VALIDATE_RANGE_WARN_TOO_LONG:
55562306a36Sopenharmony_ci	case NLA_VALIDATE_MIN:
55662306a36Sopenharmony_ci	case NLA_VALIDATE_MAX:
55762306a36Sopenharmony_ci		err = nla_validate_int_range(pt, nla, extack, validate);
55862306a36Sopenharmony_ci		if (err)
55962306a36Sopenharmony_ci			return err;
56062306a36Sopenharmony_ci		break;
56162306a36Sopenharmony_ci	case NLA_VALIDATE_MASK:
56262306a36Sopenharmony_ci		err = nla_validate_mask(pt, nla, extack);
56362306a36Sopenharmony_ci		if (err)
56462306a36Sopenharmony_ci			return err;
56562306a36Sopenharmony_ci		break;
56662306a36Sopenharmony_ci	case NLA_VALIDATE_FUNCTION:
56762306a36Sopenharmony_ci		if (pt->validate) {
56862306a36Sopenharmony_ci			err = pt->validate(nla, extack);
56962306a36Sopenharmony_ci			if (err)
57062306a36Sopenharmony_ci				return err;
57162306a36Sopenharmony_ci		}
57262306a36Sopenharmony_ci		break;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return 0;
57662306a36Sopenharmony_ciout_err:
57762306a36Sopenharmony_ci	NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
57862306a36Sopenharmony_ci				"Attribute failed policy validation");
57962306a36Sopenharmony_ci	return err;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
58362306a36Sopenharmony_ci				const struct nla_policy *policy,
58462306a36Sopenharmony_ci				unsigned int validate,
58562306a36Sopenharmony_ci				struct netlink_ext_ack *extack,
58662306a36Sopenharmony_ci				struct nlattr **tb, unsigned int depth)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	const struct nlattr *nla;
58962306a36Sopenharmony_ci	int rem;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (depth >= MAX_POLICY_RECURSION_DEPTH) {
59262306a36Sopenharmony_ci		NL_SET_ERR_MSG(extack,
59362306a36Sopenharmony_ci			       "allowed policy recursion depth exceeded");
59462306a36Sopenharmony_ci		return -EINVAL;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	if (tb)
59862306a36Sopenharmony_ci		memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	nla_for_each_attr(nla, head, len, rem) {
60162306a36Sopenharmony_ci		u16 type = nla_type(nla);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci		if (type == 0 || type > maxtype) {
60462306a36Sopenharmony_ci			if (validate & NL_VALIDATE_MAXTYPE) {
60562306a36Sopenharmony_ci				NL_SET_ERR_MSG_ATTR(extack, nla,
60662306a36Sopenharmony_ci						    "Unknown attribute type");
60762306a36Sopenharmony_ci				return -EINVAL;
60862306a36Sopenharmony_ci			}
60962306a36Sopenharmony_ci			continue;
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci		type = array_index_nospec(type, maxtype + 1);
61262306a36Sopenharmony_ci		if (policy) {
61362306a36Sopenharmony_ci			int err = validate_nla(nla, maxtype, policy,
61462306a36Sopenharmony_ci					       validate, extack, depth);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci			if (err < 0)
61762306a36Sopenharmony_ci				return err;
61862306a36Sopenharmony_ci		}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		if (tb)
62162306a36Sopenharmony_ci			tb[type] = (struct nlattr *)nla;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (unlikely(rem > 0)) {
62562306a36Sopenharmony_ci		pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n",
62662306a36Sopenharmony_ci				    rem, current->comm);
62762306a36Sopenharmony_ci		NL_SET_ERR_MSG(extack, "bytes leftover after parsing attributes");
62862306a36Sopenharmony_ci		if (validate & NL_VALIDATE_TRAILING)
62962306a36Sopenharmony_ci			return -EINVAL;
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	return 0;
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci/**
63662306a36Sopenharmony_ci * __nla_validate - Validate a stream of attributes
63762306a36Sopenharmony_ci * @head: head of attribute stream
63862306a36Sopenharmony_ci * @len: length of attribute stream
63962306a36Sopenharmony_ci * @maxtype: maximum attribute type to be expected
64062306a36Sopenharmony_ci * @policy: validation policy
64162306a36Sopenharmony_ci * @validate: validation strictness
64262306a36Sopenharmony_ci * @extack: extended ACK report struct
64362306a36Sopenharmony_ci *
64462306a36Sopenharmony_ci * Validates all attributes in the specified attribute stream against the
64562306a36Sopenharmony_ci * specified policy. Validation depends on the validate flags passed, see
64662306a36Sopenharmony_ci * &enum netlink_validation for more details on that.
64762306a36Sopenharmony_ci * See documentation of struct nla_policy for more details.
64862306a36Sopenharmony_ci *
64962306a36Sopenharmony_ci * Returns 0 on success or a negative error code.
65062306a36Sopenharmony_ci */
65162306a36Sopenharmony_ciint __nla_validate(const struct nlattr *head, int len, int maxtype,
65262306a36Sopenharmony_ci		   const struct nla_policy *policy, unsigned int validate,
65362306a36Sopenharmony_ci		   struct netlink_ext_ack *extack)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	return __nla_validate_parse(head, len, maxtype, policy, validate,
65662306a36Sopenharmony_ci				    extack, NULL, 0);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ciEXPORT_SYMBOL(__nla_validate);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci/**
66162306a36Sopenharmony_ci * nla_policy_len - Determine the max. length of a policy
66262306a36Sopenharmony_ci * @p: policy to use
66362306a36Sopenharmony_ci * @n: number of policies
66462306a36Sopenharmony_ci *
66562306a36Sopenharmony_ci * Determines the max. length of the policy.  It is currently used
66662306a36Sopenharmony_ci * to allocated Netlink buffers roughly the size of the actual
66762306a36Sopenharmony_ci * message.
66862306a36Sopenharmony_ci *
66962306a36Sopenharmony_ci * Returns 0 on success or a negative error code.
67062306a36Sopenharmony_ci */
67162306a36Sopenharmony_ciint
67262306a36Sopenharmony_cinla_policy_len(const struct nla_policy *p, int n)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	int i, len = 0;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	for (i = 0; i < n; i++, p++) {
67762306a36Sopenharmony_ci		if (p->len)
67862306a36Sopenharmony_ci			len += nla_total_size(p->len);
67962306a36Sopenharmony_ci		else if (nla_attr_len[p->type])
68062306a36Sopenharmony_ci			len += nla_total_size(nla_attr_len[p->type]);
68162306a36Sopenharmony_ci		else if (nla_attr_minlen[p->type])
68262306a36Sopenharmony_ci			len += nla_total_size(nla_attr_minlen[p->type]);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	return len;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ciEXPORT_SYMBOL(nla_policy_len);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci/**
69062306a36Sopenharmony_ci * __nla_parse - Parse a stream of attributes into a tb buffer
69162306a36Sopenharmony_ci * @tb: destination array with maxtype+1 elements
69262306a36Sopenharmony_ci * @maxtype: maximum attribute type to be expected
69362306a36Sopenharmony_ci * @head: head of attribute stream
69462306a36Sopenharmony_ci * @len: length of attribute stream
69562306a36Sopenharmony_ci * @policy: validation policy
69662306a36Sopenharmony_ci * @validate: validation strictness
69762306a36Sopenharmony_ci * @extack: extended ACK pointer
69862306a36Sopenharmony_ci *
69962306a36Sopenharmony_ci * Parses a stream of attributes and stores a pointer to each attribute in
70062306a36Sopenharmony_ci * the tb array accessible via the attribute type.
70162306a36Sopenharmony_ci * Validation is controlled by the @validate parameter.
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci * Returns 0 on success or a negative error code.
70462306a36Sopenharmony_ci */
70562306a36Sopenharmony_ciint __nla_parse(struct nlattr **tb, int maxtype,
70662306a36Sopenharmony_ci		const struct nlattr *head, int len,
70762306a36Sopenharmony_ci		const struct nla_policy *policy, unsigned int validate,
70862306a36Sopenharmony_ci		struct netlink_ext_ack *extack)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	return __nla_validate_parse(head, len, maxtype, policy, validate,
71162306a36Sopenharmony_ci				    extack, tb, 0);
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ciEXPORT_SYMBOL(__nla_parse);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/**
71662306a36Sopenharmony_ci * nla_find - Find a specific attribute in a stream of attributes
71762306a36Sopenharmony_ci * @head: head of attribute stream
71862306a36Sopenharmony_ci * @len: length of attribute stream
71962306a36Sopenharmony_ci * @attrtype: type of attribute to look for
72062306a36Sopenharmony_ci *
72162306a36Sopenharmony_ci * Returns the first attribute in the stream matching the specified type.
72262306a36Sopenharmony_ci */
72362306a36Sopenharmony_cistruct nlattr *nla_find(const struct nlattr *head, int len, int attrtype)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	const struct nlattr *nla;
72662306a36Sopenharmony_ci	int rem;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	nla_for_each_attr(nla, head, len, rem)
72962306a36Sopenharmony_ci		if (nla_type(nla) == attrtype)
73062306a36Sopenharmony_ci			return (struct nlattr *)nla;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	return NULL;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ciEXPORT_SYMBOL(nla_find);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci/**
73762306a36Sopenharmony_ci * nla_strscpy - Copy string attribute payload into a sized buffer
73862306a36Sopenharmony_ci * @dst: Where to copy the string to.
73962306a36Sopenharmony_ci * @nla: Attribute to copy the string from.
74062306a36Sopenharmony_ci * @dstsize: Size of destination buffer.
74162306a36Sopenharmony_ci *
74262306a36Sopenharmony_ci * Copies at most dstsize - 1 bytes into the destination buffer.
74362306a36Sopenharmony_ci * Unlike strlcpy the destination buffer is always padded out.
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci * Return:
74662306a36Sopenharmony_ci * * srclen - Returns @nla length (not including the trailing %NUL).
74762306a36Sopenharmony_ci * * -E2BIG - If @dstsize is 0 or greater than U16_MAX or @nla length greater
74862306a36Sopenharmony_ci *            than @dstsize.
74962306a36Sopenharmony_ci */
75062306a36Sopenharmony_cissize_t nla_strscpy(char *dst, const struct nlattr *nla, size_t dstsize)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	size_t srclen = nla_len(nla);
75362306a36Sopenharmony_ci	char *src = nla_data(nla);
75462306a36Sopenharmony_ci	ssize_t ret;
75562306a36Sopenharmony_ci	size_t len;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (dstsize == 0 || WARN_ON_ONCE(dstsize > U16_MAX))
75862306a36Sopenharmony_ci		return -E2BIG;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (srclen > 0 && src[srclen - 1] == '\0')
76162306a36Sopenharmony_ci		srclen--;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (srclen >= dstsize) {
76462306a36Sopenharmony_ci		len = dstsize - 1;
76562306a36Sopenharmony_ci		ret = -E2BIG;
76662306a36Sopenharmony_ci	} else {
76762306a36Sopenharmony_ci		len = srclen;
76862306a36Sopenharmony_ci		ret = len;
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	memcpy(dst, src, len);
77262306a36Sopenharmony_ci	/* Zero pad end of dst. */
77362306a36Sopenharmony_ci	memset(dst + len, 0, dstsize - len);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	return ret;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ciEXPORT_SYMBOL(nla_strscpy);
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci/**
78062306a36Sopenharmony_ci * nla_strdup - Copy string attribute payload into a newly allocated buffer
78162306a36Sopenharmony_ci * @nla: attribute to copy the string from
78262306a36Sopenharmony_ci * @flags: the type of memory to allocate (see kmalloc).
78362306a36Sopenharmony_ci *
78462306a36Sopenharmony_ci * Returns a pointer to the allocated buffer or NULL on error.
78562306a36Sopenharmony_ci */
78662306a36Sopenharmony_cichar *nla_strdup(const struct nlattr *nla, gfp_t flags)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	size_t srclen = nla_len(nla);
78962306a36Sopenharmony_ci	char *src = nla_data(nla), *dst;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (srclen > 0 && src[srclen - 1] == '\0')
79262306a36Sopenharmony_ci		srclen--;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	dst = kmalloc(srclen + 1, flags);
79562306a36Sopenharmony_ci	if (dst != NULL) {
79662306a36Sopenharmony_ci		memcpy(dst, src, srclen);
79762306a36Sopenharmony_ci		dst[srclen] = '\0';
79862306a36Sopenharmony_ci	}
79962306a36Sopenharmony_ci	return dst;
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ciEXPORT_SYMBOL(nla_strdup);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci/**
80462306a36Sopenharmony_ci * nla_memcpy - Copy a netlink attribute into another memory area
80562306a36Sopenharmony_ci * @dest: where to copy to memcpy
80662306a36Sopenharmony_ci * @src: netlink attribute to copy from
80762306a36Sopenharmony_ci * @count: size of the destination area
80862306a36Sopenharmony_ci *
80962306a36Sopenharmony_ci * Note: The number of bytes copied is limited by the length of
81062306a36Sopenharmony_ci *       attribute's payload. memcpy
81162306a36Sopenharmony_ci *
81262306a36Sopenharmony_ci * Returns the number of bytes copied.
81362306a36Sopenharmony_ci */
81462306a36Sopenharmony_ciint nla_memcpy(void *dest, const struct nlattr *src, int count)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	int minlen = min_t(int, count, nla_len(src));
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	memcpy(dest, nla_data(src), minlen);
81962306a36Sopenharmony_ci	if (count > minlen)
82062306a36Sopenharmony_ci		memset(dest + minlen, 0, count - minlen);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	return minlen;
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ciEXPORT_SYMBOL(nla_memcpy);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci/**
82762306a36Sopenharmony_ci * nla_memcmp - Compare an attribute with sized memory area
82862306a36Sopenharmony_ci * @nla: netlink attribute
82962306a36Sopenharmony_ci * @data: memory area
83062306a36Sopenharmony_ci * @size: size of memory area
83162306a36Sopenharmony_ci */
83262306a36Sopenharmony_ciint nla_memcmp(const struct nlattr *nla, const void *data,
83362306a36Sopenharmony_ci			     size_t size)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	int d = nla_len(nla) - size;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	if (d == 0)
83862306a36Sopenharmony_ci		d = memcmp(nla_data(nla), data, size);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	return d;
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ciEXPORT_SYMBOL(nla_memcmp);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci/**
84562306a36Sopenharmony_ci * nla_strcmp - Compare a string attribute against a string
84662306a36Sopenharmony_ci * @nla: netlink string attribute
84762306a36Sopenharmony_ci * @str: another string
84862306a36Sopenharmony_ci */
84962306a36Sopenharmony_ciint nla_strcmp(const struct nlattr *nla, const char *str)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	int len = strlen(str);
85262306a36Sopenharmony_ci	char *buf = nla_data(nla);
85362306a36Sopenharmony_ci	int attrlen = nla_len(nla);
85462306a36Sopenharmony_ci	int d;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	while (attrlen > 0 && buf[attrlen - 1] == '\0')
85762306a36Sopenharmony_ci		attrlen--;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	d = attrlen - len;
86062306a36Sopenharmony_ci	if (d == 0)
86162306a36Sopenharmony_ci		d = memcmp(nla_data(nla), str, len);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	return d;
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ciEXPORT_SYMBOL(nla_strcmp);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci#ifdef CONFIG_NET
86862306a36Sopenharmony_ci/**
86962306a36Sopenharmony_ci * __nla_reserve - reserve room for attribute on the skb
87062306a36Sopenharmony_ci * @skb: socket buffer to reserve room on
87162306a36Sopenharmony_ci * @attrtype: attribute type
87262306a36Sopenharmony_ci * @attrlen: length of attribute payload
87362306a36Sopenharmony_ci *
87462306a36Sopenharmony_ci * Adds a netlink attribute header to a socket buffer and reserves
87562306a36Sopenharmony_ci * room for the payload but does not copy it.
87662306a36Sopenharmony_ci *
87762306a36Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
87862306a36Sopenharmony_ci * tailroom for the attribute header and payload.
87962306a36Sopenharmony_ci */
88062306a36Sopenharmony_cistruct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	struct nlattr *nla;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	nla = skb_put(skb, nla_total_size(attrlen));
88562306a36Sopenharmony_ci	nla->nla_type = attrtype;
88662306a36Sopenharmony_ci	nla->nla_len = nla_attr_size(attrlen);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	return nla;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ciEXPORT_SYMBOL(__nla_reserve);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci/**
89562306a36Sopenharmony_ci * __nla_reserve_64bit - reserve room for attribute on the skb and align it
89662306a36Sopenharmony_ci * @skb: socket buffer to reserve room on
89762306a36Sopenharmony_ci * @attrtype: attribute type
89862306a36Sopenharmony_ci * @attrlen: length of attribute payload
89962306a36Sopenharmony_ci * @padattr: attribute type for the padding
90062306a36Sopenharmony_ci *
90162306a36Sopenharmony_ci * Adds a netlink attribute header to a socket buffer and reserves
90262306a36Sopenharmony_ci * room for the payload but does not copy it. It also ensure that this
90362306a36Sopenharmony_ci * attribute will have a 64-bit aligned nla_data() area.
90462306a36Sopenharmony_ci *
90562306a36Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
90662306a36Sopenharmony_ci * tailroom for the attribute header and payload.
90762306a36Sopenharmony_ci */
90862306a36Sopenharmony_cistruct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype,
90962306a36Sopenharmony_ci				   int attrlen, int padattr)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	nla_align_64bit(skb, padattr);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	return __nla_reserve(skb, attrtype, attrlen);
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ciEXPORT_SYMBOL(__nla_reserve_64bit);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci/**
91862306a36Sopenharmony_ci * __nla_reserve_nohdr - reserve room for attribute without header
91962306a36Sopenharmony_ci * @skb: socket buffer to reserve room on
92062306a36Sopenharmony_ci * @attrlen: length of attribute payload
92162306a36Sopenharmony_ci *
92262306a36Sopenharmony_ci * Reserves room for attribute payload without a header.
92362306a36Sopenharmony_ci *
92462306a36Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
92562306a36Sopenharmony_ci * tailroom for the payload.
92662306a36Sopenharmony_ci */
92762306a36Sopenharmony_civoid *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	return skb_put_zero(skb, NLA_ALIGN(attrlen));
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ciEXPORT_SYMBOL(__nla_reserve_nohdr);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci/**
93462306a36Sopenharmony_ci * nla_reserve - reserve room for attribute on the skb
93562306a36Sopenharmony_ci * @skb: socket buffer to reserve room on
93662306a36Sopenharmony_ci * @attrtype: attribute type
93762306a36Sopenharmony_ci * @attrlen: length of attribute payload
93862306a36Sopenharmony_ci *
93962306a36Sopenharmony_ci * Adds a netlink attribute header to a socket buffer and reserves
94062306a36Sopenharmony_ci * room for the payload but does not copy it.
94162306a36Sopenharmony_ci *
94262306a36Sopenharmony_ci * Returns NULL if the tailroom of the skb is insufficient to store
94362306a36Sopenharmony_ci * the attribute header and payload.
94462306a36Sopenharmony_ci */
94562306a36Sopenharmony_cistruct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
94862306a36Sopenharmony_ci		return NULL;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return __nla_reserve(skb, attrtype, attrlen);
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ciEXPORT_SYMBOL(nla_reserve);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci/**
95562306a36Sopenharmony_ci * nla_reserve_64bit - reserve room for attribute on the skb and align it
95662306a36Sopenharmony_ci * @skb: socket buffer to reserve room on
95762306a36Sopenharmony_ci * @attrtype: attribute type
95862306a36Sopenharmony_ci * @attrlen: length of attribute payload
95962306a36Sopenharmony_ci * @padattr: attribute type for the padding
96062306a36Sopenharmony_ci *
96162306a36Sopenharmony_ci * Adds a netlink attribute header to a socket buffer and reserves
96262306a36Sopenharmony_ci * room for the payload but does not copy it. It also ensure that this
96362306a36Sopenharmony_ci * attribute will have a 64-bit aligned nla_data() area.
96462306a36Sopenharmony_ci *
96562306a36Sopenharmony_ci * Returns NULL if the tailroom of the skb is insufficient to store
96662306a36Sopenharmony_ci * the attribute header and payload.
96762306a36Sopenharmony_ci */
96862306a36Sopenharmony_cistruct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype, int attrlen,
96962306a36Sopenharmony_ci				 int padattr)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	size_t len;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	if (nla_need_padding_for_64bit(skb))
97462306a36Sopenharmony_ci		len = nla_total_size_64bit(attrlen);
97562306a36Sopenharmony_ci	else
97662306a36Sopenharmony_ci		len = nla_total_size(attrlen);
97762306a36Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < len))
97862306a36Sopenharmony_ci		return NULL;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	return __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
98162306a36Sopenharmony_ci}
98262306a36Sopenharmony_ciEXPORT_SYMBOL(nla_reserve_64bit);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci/**
98562306a36Sopenharmony_ci * nla_reserve_nohdr - reserve room for attribute without header
98662306a36Sopenharmony_ci * @skb: socket buffer to reserve room on
98762306a36Sopenharmony_ci * @attrlen: length of attribute payload
98862306a36Sopenharmony_ci *
98962306a36Sopenharmony_ci * Reserves room for attribute payload without a header.
99062306a36Sopenharmony_ci *
99162306a36Sopenharmony_ci * Returns NULL if the tailroom of the skb is insufficient to store
99262306a36Sopenharmony_ci * the attribute payload.
99362306a36Sopenharmony_ci */
99462306a36Sopenharmony_civoid *nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
99562306a36Sopenharmony_ci{
99662306a36Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
99762306a36Sopenharmony_ci		return NULL;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	return __nla_reserve_nohdr(skb, attrlen);
100062306a36Sopenharmony_ci}
100162306a36Sopenharmony_ciEXPORT_SYMBOL(nla_reserve_nohdr);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci/**
100462306a36Sopenharmony_ci * __nla_put - Add a netlink attribute to a socket buffer
100562306a36Sopenharmony_ci * @skb: socket buffer to add attribute to
100662306a36Sopenharmony_ci * @attrtype: attribute type
100762306a36Sopenharmony_ci * @attrlen: length of attribute payload
100862306a36Sopenharmony_ci * @data: head of attribute payload
100962306a36Sopenharmony_ci *
101062306a36Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
101162306a36Sopenharmony_ci * tailroom for the attribute header and payload.
101262306a36Sopenharmony_ci */
101362306a36Sopenharmony_civoid __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
101462306a36Sopenharmony_ci			     const void *data)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	struct nlattr *nla;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	nla = __nla_reserve(skb, attrtype, attrlen);
101962306a36Sopenharmony_ci	memcpy(nla_data(nla), data, attrlen);
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ciEXPORT_SYMBOL(__nla_put);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci/**
102462306a36Sopenharmony_ci * __nla_put_64bit - Add a netlink attribute to a socket buffer and align it
102562306a36Sopenharmony_ci * @skb: socket buffer to add attribute to
102662306a36Sopenharmony_ci * @attrtype: attribute type
102762306a36Sopenharmony_ci * @attrlen: length of attribute payload
102862306a36Sopenharmony_ci * @data: head of attribute payload
102962306a36Sopenharmony_ci * @padattr: attribute type for the padding
103062306a36Sopenharmony_ci *
103162306a36Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
103262306a36Sopenharmony_ci * tailroom for the attribute header and payload.
103362306a36Sopenharmony_ci */
103462306a36Sopenharmony_civoid __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
103562306a36Sopenharmony_ci		     const void *data, int padattr)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	struct nlattr *nla;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	nla = __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
104062306a36Sopenharmony_ci	memcpy(nla_data(nla), data, attrlen);
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ciEXPORT_SYMBOL(__nla_put_64bit);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci/**
104562306a36Sopenharmony_ci * __nla_put_nohdr - Add a netlink attribute without header
104662306a36Sopenharmony_ci * @skb: socket buffer to add attribute to
104762306a36Sopenharmony_ci * @attrlen: length of attribute payload
104862306a36Sopenharmony_ci * @data: head of attribute payload
104962306a36Sopenharmony_ci *
105062306a36Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
105162306a36Sopenharmony_ci * tailroom for the attribute payload.
105262306a36Sopenharmony_ci */
105362306a36Sopenharmony_civoid __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	void *start;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	start = __nla_reserve_nohdr(skb, attrlen);
105862306a36Sopenharmony_ci	memcpy(start, data, attrlen);
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ciEXPORT_SYMBOL(__nla_put_nohdr);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci/**
106362306a36Sopenharmony_ci * nla_put - Add a netlink attribute to a socket buffer
106462306a36Sopenharmony_ci * @skb: socket buffer to add attribute to
106562306a36Sopenharmony_ci * @attrtype: attribute type
106662306a36Sopenharmony_ci * @attrlen: length of attribute payload
106762306a36Sopenharmony_ci * @data: head of attribute payload
106862306a36Sopenharmony_ci *
106962306a36Sopenharmony_ci * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
107062306a36Sopenharmony_ci * the attribute header and payload.
107162306a36Sopenharmony_ci */
107262306a36Sopenharmony_ciint nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
107562306a36Sopenharmony_ci		return -EMSGSIZE;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	__nla_put(skb, attrtype, attrlen, data);
107862306a36Sopenharmony_ci	return 0;
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ciEXPORT_SYMBOL(nla_put);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci/**
108362306a36Sopenharmony_ci * nla_put_64bit - Add a netlink attribute to a socket buffer and align it
108462306a36Sopenharmony_ci * @skb: socket buffer to add attribute to
108562306a36Sopenharmony_ci * @attrtype: attribute type
108662306a36Sopenharmony_ci * @attrlen: length of attribute payload
108762306a36Sopenharmony_ci * @data: head of attribute payload
108862306a36Sopenharmony_ci * @padattr: attribute type for the padding
108962306a36Sopenharmony_ci *
109062306a36Sopenharmony_ci * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
109162306a36Sopenharmony_ci * the attribute header and payload.
109262306a36Sopenharmony_ci */
109362306a36Sopenharmony_ciint nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
109462306a36Sopenharmony_ci		  const void *data, int padattr)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	size_t len;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (nla_need_padding_for_64bit(skb))
109962306a36Sopenharmony_ci		len = nla_total_size_64bit(attrlen);
110062306a36Sopenharmony_ci	else
110162306a36Sopenharmony_ci		len = nla_total_size(attrlen);
110262306a36Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < len))
110362306a36Sopenharmony_ci		return -EMSGSIZE;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	__nla_put_64bit(skb, attrtype, attrlen, data, padattr);
110662306a36Sopenharmony_ci	return 0;
110762306a36Sopenharmony_ci}
110862306a36Sopenharmony_ciEXPORT_SYMBOL(nla_put_64bit);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci/**
111162306a36Sopenharmony_ci * nla_put_nohdr - Add a netlink attribute without header
111262306a36Sopenharmony_ci * @skb: socket buffer to add attribute to
111362306a36Sopenharmony_ci * @attrlen: length of attribute payload
111462306a36Sopenharmony_ci * @data: head of attribute payload
111562306a36Sopenharmony_ci *
111662306a36Sopenharmony_ci * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
111762306a36Sopenharmony_ci * the attribute payload.
111862306a36Sopenharmony_ci */
111962306a36Sopenharmony_ciint nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
112262306a36Sopenharmony_ci		return -EMSGSIZE;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	__nla_put_nohdr(skb, attrlen, data);
112562306a36Sopenharmony_ci	return 0;
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ciEXPORT_SYMBOL(nla_put_nohdr);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci/**
113062306a36Sopenharmony_ci * nla_append - Add a netlink attribute without header or padding
113162306a36Sopenharmony_ci * @skb: socket buffer to add attribute to
113262306a36Sopenharmony_ci * @attrlen: length of attribute payload
113362306a36Sopenharmony_ci * @data: head of attribute payload
113462306a36Sopenharmony_ci *
113562306a36Sopenharmony_ci * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
113662306a36Sopenharmony_ci * the attribute payload.
113762306a36Sopenharmony_ci */
113862306a36Sopenharmony_ciint nla_append(struct sk_buff *skb, int attrlen, const void *data)
113962306a36Sopenharmony_ci{
114062306a36Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
114162306a36Sopenharmony_ci		return -EMSGSIZE;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	skb_put_data(skb, data, attrlen);
114462306a36Sopenharmony_ci	return 0;
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ciEXPORT_SYMBOL(nla_append);
114762306a36Sopenharmony_ci#endif
1148