18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * NETLINK      Netlink attributes
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * 		Authors:	Thomas Graf <tgraf@suug.ch>
68c2ecf20Sopenharmony_ci * 				Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/export.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
138c2ecf20Sopenharmony_ci#include <linux/nospec.h>
148c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
158c2ecf20Sopenharmony_ci#include <linux/string.h>
168c2ecf20Sopenharmony_ci#include <linux/types.h>
178c2ecf20Sopenharmony_ci#include <net/netlink.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* For these data types, attribute length should be exactly the given
208c2ecf20Sopenharmony_ci * size. However, to maintain compatibility with broken commands, if the
218c2ecf20Sopenharmony_ci * attribute length does not match the expected size a warning is emitted
228c2ecf20Sopenharmony_ci * to the user that the command is sending invalid data and needs to be fixed.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_cistatic const u8 nla_attr_len[NLA_TYPE_MAX+1] = {
258c2ecf20Sopenharmony_ci	[NLA_U8]	= sizeof(u8),
268c2ecf20Sopenharmony_ci	[NLA_U16]	= sizeof(u16),
278c2ecf20Sopenharmony_ci	[NLA_U32]	= sizeof(u32),
288c2ecf20Sopenharmony_ci	[NLA_U64]	= sizeof(u64),
298c2ecf20Sopenharmony_ci	[NLA_S8]	= sizeof(s8),
308c2ecf20Sopenharmony_ci	[NLA_S16]	= sizeof(s16),
318c2ecf20Sopenharmony_ci	[NLA_S32]	= sizeof(s32),
328c2ecf20Sopenharmony_ci	[NLA_S64]	= sizeof(s64),
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
368c2ecf20Sopenharmony_ci	[NLA_U8]	= sizeof(u8),
378c2ecf20Sopenharmony_ci	[NLA_U16]	= sizeof(u16),
388c2ecf20Sopenharmony_ci	[NLA_U32]	= sizeof(u32),
398c2ecf20Sopenharmony_ci	[NLA_U64]	= sizeof(u64),
408c2ecf20Sopenharmony_ci	[NLA_MSECS]	= sizeof(u64),
418c2ecf20Sopenharmony_ci	[NLA_NESTED]	= NLA_HDRLEN,
428c2ecf20Sopenharmony_ci	[NLA_S8]	= sizeof(s8),
438c2ecf20Sopenharmony_ci	[NLA_S16]	= sizeof(s16),
448c2ecf20Sopenharmony_ci	[NLA_S32]	= sizeof(s32),
458c2ecf20Sopenharmony_ci	[NLA_S64]	= sizeof(s64),
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/*
498c2ecf20Sopenharmony_ci * Nested policies might refer back to the original
508c2ecf20Sopenharmony_ci * policy in some cases, and userspace could try to
518c2ecf20Sopenharmony_ci * abuse that and recurse by nesting in the right
528c2ecf20Sopenharmony_ci * ways. Limit recursion to avoid this problem.
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_ci#define MAX_POLICY_RECURSION_DEPTH	10
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
578c2ecf20Sopenharmony_ci				const struct nla_policy *policy,
588c2ecf20Sopenharmony_ci				unsigned int validate,
598c2ecf20Sopenharmony_ci				struct netlink_ext_ack *extack,
608c2ecf20Sopenharmony_ci				struct nlattr **tb, unsigned int depth);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int validate_nla_bitfield32(const struct nlattr *nla,
638c2ecf20Sopenharmony_ci				   const u32 valid_flags_mask)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	const struct nla_bitfield32 *bf = nla_data(nla);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (!valid_flags_mask)
688c2ecf20Sopenharmony_ci		return -EINVAL;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/*disallow invalid bit selector */
718c2ecf20Sopenharmony_ci	if (bf->selector & ~valid_flags_mask)
728c2ecf20Sopenharmony_ci		return -EINVAL;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/*disallow invalid bit values */
758c2ecf20Sopenharmony_ci	if (bf->value & ~valid_flags_mask)
768c2ecf20Sopenharmony_ci		return -EINVAL;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	/*disallow valid bit values that are not selected*/
798c2ecf20Sopenharmony_ci	if (bf->value & ~bf->selector)
808c2ecf20Sopenharmony_ci		return -EINVAL;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return 0;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic int nla_validate_array(const struct nlattr *head, int len, int maxtype,
868c2ecf20Sopenharmony_ci			      const struct nla_policy *policy,
878c2ecf20Sopenharmony_ci			      struct netlink_ext_ack *extack,
888c2ecf20Sopenharmony_ci			      unsigned int validate, unsigned int depth)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	const struct nlattr *entry;
918c2ecf20Sopenharmony_ci	int rem;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	nla_for_each_attr(entry, head, len, rem) {
948c2ecf20Sopenharmony_ci		int ret;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		if (nla_len(entry) == 0)
978c2ecf20Sopenharmony_ci			continue;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		if (nla_len(entry) < NLA_HDRLEN) {
1008c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, entry, policy,
1018c2ecf20Sopenharmony_ci						"Array element too short");
1028c2ecf20Sopenharmony_ci			return -ERANGE;
1038c2ecf20Sopenharmony_ci		}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci		ret = __nla_validate_parse(nla_data(entry), nla_len(entry),
1068c2ecf20Sopenharmony_ci					   maxtype, policy, validate, extack,
1078c2ecf20Sopenharmony_ci					   NULL, depth + 1);
1088c2ecf20Sopenharmony_ci		if (ret < 0)
1098c2ecf20Sopenharmony_ci			return ret;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return 0;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_civoid nla_get_range_unsigned(const struct nla_policy *pt,
1168c2ecf20Sopenharmony_ci			    struct netlink_range_validation *range)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	WARN_ON_ONCE(pt->validation_type != NLA_VALIDATE_RANGE_PTR &&
1198c2ecf20Sopenharmony_ci		     (pt->min < 0 || pt->max < 0));
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	range->min = 0;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	switch (pt->type) {
1248c2ecf20Sopenharmony_ci	case NLA_U8:
1258c2ecf20Sopenharmony_ci		range->max = U8_MAX;
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci	case NLA_U16:
1288c2ecf20Sopenharmony_ci	case NLA_BINARY:
1298c2ecf20Sopenharmony_ci		range->max = U16_MAX;
1308c2ecf20Sopenharmony_ci		break;
1318c2ecf20Sopenharmony_ci	case NLA_U32:
1328c2ecf20Sopenharmony_ci		range->max = U32_MAX;
1338c2ecf20Sopenharmony_ci		break;
1348c2ecf20Sopenharmony_ci	case NLA_U64:
1358c2ecf20Sopenharmony_ci	case NLA_MSECS:
1368c2ecf20Sopenharmony_ci		range->max = U64_MAX;
1378c2ecf20Sopenharmony_ci		break;
1388c2ecf20Sopenharmony_ci	default:
1398c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
1408c2ecf20Sopenharmony_ci		return;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	switch (pt->validation_type) {
1448c2ecf20Sopenharmony_ci	case NLA_VALIDATE_RANGE:
1458c2ecf20Sopenharmony_ci	case NLA_VALIDATE_RANGE_WARN_TOO_LONG:
1468c2ecf20Sopenharmony_ci		range->min = pt->min;
1478c2ecf20Sopenharmony_ci		range->max = pt->max;
1488c2ecf20Sopenharmony_ci		break;
1498c2ecf20Sopenharmony_ci	case NLA_VALIDATE_RANGE_PTR:
1508c2ecf20Sopenharmony_ci		*range = *pt->range;
1518c2ecf20Sopenharmony_ci		break;
1528c2ecf20Sopenharmony_ci	case NLA_VALIDATE_MIN:
1538c2ecf20Sopenharmony_ci		range->min = pt->min;
1548c2ecf20Sopenharmony_ci		break;
1558c2ecf20Sopenharmony_ci	case NLA_VALIDATE_MAX:
1568c2ecf20Sopenharmony_ci		range->max = pt->max;
1578c2ecf20Sopenharmony_ci		break;
1588c2ecf20Sopenharmony_ci	default:
1598c2ecf20Sopenharmony_ci		break;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int nla_validate_range_unsigned(const struct nla_policy *pt,
1648c2ecf20Sopenharmony_ci				       const struct nlattr *nla,
1658c2ecf20Sopenharmony_ci				       struct netlink_ext_ack *extack,
1668c2ecf20Sopenharmony_ci				       unsigned int validate)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct netlink_range_validation range;
1698c2ecf20Sopenharmony_ci	u64 value;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	switch (pt->type) {
1728c2ecf20Sopenharmony_ci	case NLA_U8:
1738c2ecf20Sopenharmony_ci		value = nla_get_u8(nla);
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	case NLA_U16:
1768c2ecf20Sopenharmony_ci		value = nla_get_u16(nla);
1778c2ecf20Sopenharmony_ci		break;
1788c2ecf20Sopenharmony_ci	case NLA_U32:
1798c2ecf20Sopenharmony_ci		value = nla_get_u32(nla);
1808c2ecf20Sopenharmony_ci		break;
1818c2ecf20Sopenharmony_ci	case NLA_U64:
1828c2ecf20Sopenharmony_ci	case NLA_MSECS:
1838c2ecf20Sopenharmony_ci		value = nla_get_u64(nla);
1848c2ecf20Sopenharmony_ci		break;
1858c2ecf20Sopenharmony_ci	case NLA_BINARY:
1868c2ecf20Sopenharmony_ci		value = nla_len(nla);
1878c2ecf20Sopenharmony_ci		break;
1888c2ecf20Sopenharmony_ci	default:
1898c2ecf20Sopenharmony_ci		return -EINVAL;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	nla_get_range_unsigned(pt, &range);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (pt->validation_type == NLA_VALIDATE_RANGE_WARN_TOO_LONG &&
1958c2ecf20Sopenharmony_ci	    pt->type == NLA_BINARY && value > range.max) {
1968c2ecf20Sopenharmony_ci		pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n",
1978c2ecf20Sopenharmony_ci				    current->comm, pt->type);
1988c2ecf20Sopenharmony_ci		if (validate & NL_VALIDATE_STRICT_ATTRS) {
1998c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
2008c2ecf20Sopenharmony_ci						"invalid attribute length");
2018c2ecf20Sopenharmony_ci			return -EINVAL;
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		/* this assumes min <= max (don't validate against min) */
2058c2ecf20Sopenharmony_ci		return 0;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	if (value < range.min || value > range.max) {
2098c2ecf20Sopenharmony_ci		bool binary = pt->type == NLA_BINARY;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci		if (binary)
2128c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
2138c2ecf20Sopenharmony_ci						"binary attribute size out of range");
2148c2ecf20Sopenharmony_ci		else
2158c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
2168c2ecf20Sopenharmony_ci						"integer out of range");
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci		return -ERANGE;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return 0;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_civoid nla_get_range_signed(const struct nla_policy *pt,
2258c2ecf20Sopenharmony_ci			  struct netlink_range_validation_signed *range)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	switch (pt->type) {
2288c2ecf20Sopenharmony_ci	case NLA_S8:
2298c2ecf20Sopenharmony_ci		range->min = S8_MIN;
2308c2ecf20Sopenharmony_ci		range->max = S8_MAX;
2318c2ecf20Sopenharmony_ci		break;
2328c2ecf20Sopenharmony_ci	case NLA_S16:
2338c2ecf20Sopenharmony_ci		range->min = S16_MIN;
2348c2ecf20Sopenharmony_ci		range->max = S16_MAX;
2358c2ecf20Sopenharmony_ci		break;
2368c2ecf20Sopenharmony_ci	case NLA_S32:
2378c2ecf20Sopenharmony_ci		range->min = S32_MIN;
2388c2ecf20Sopenharmony_ci		range->max = S32_MAX;
2398c2ecf20Sopenharmony_ci		break;
2408c2ecf20Sopenharmony_ci	case NLA_S64:
2418c2ecf20Sopenharmony_ci		range->min = S64_MIN;
2428c2ecf20Sopenharmony_ci		range->max = S64_MAX;
2438c2ecf20Sopenharmony_ci		break;
2448c2ecf20Sopenharmony_ci	default:
2458c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
2468c2ecf20Sopenharmony_ci		return;
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	switch (pt->validation_type) {
2508c2ecf20Sopenharmony_ci	case NLA_VALIDATE_RANGE:
2518c2ecf20Sopenharmony_ci		range->min = pt->min;
2528c2ecf20Sopenharmony_ci		range->max = pt->max;
2538c2ecf20Sopenharmony_ci		break;
2548c2ecf20Sopenharmony_ci	case NLA_VALIDATE_RANGE_PTR:
2558c2ecf20Sopenharmony_ci		*range = *pt->range_signed;
2568c2ecf20Sopenharmony_ci		break;
2578c2ecf20Sopenharmony_ci	case NLA_VALIDATE_MIN:
2588c2ecf20Sopenharmony_ci		range->min = pt->min;
2598c2ecf20Sopenharmony_ci		break;
2608c2ecf20Sopenharmony_ci	case NLA_VALIDATE_MAX:
2618c2ecf20Sopenharmony_ci		range->max = pt->max;
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	default:
2648c2ecf20Sopenharmony_ci		break;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic int nla_validate_int_range_signed(const struct nla_policy *pt,
2698c2ecf20Sopenharmony_ci					 const struct nlattr *nla,
2708c2ecf20Sopenharmony_ci					 struct netlink_ext_ack *extack)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct netlink_range_validation_signed range;
2738c2ecf20Sopenharmony_ci	s64 value;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	switch (pt->type) {
2768c2ecf20Sopenharmony_ci	case NLA_S8:
2778c2ecf20Sopenharmony_ci		value = nla_get_s8(nla);
2788c2ecf20Sopenharmony_ci		break;
2798c2ecf20Sopenharmony_ci	case NLA_S16:
2808c2ecf20Sopenharmony_ci		value = nla_get_s16(nla);
2818c2ecf20Sopenharmony_ci		break;
2828c2ecf20Sopenharmony_ci	case NLA_S32:
2838c2ecf20Sopenharmony_ci		value = nla_get_s32(nla);
2848c2ecf20Sopenharmony_ci		break;
2858c2ecf20Sopenharmony_ci	case NLA_S64:
2868c2ecf20Sopenharmony_ci		value = nla_get_s64(nla);
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	default:
2898c2ecf20Sopenharmony_ci		return -EINVAL;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	nla_get_range_signed(pt, &range);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (value < range.min || value > range.max) {
2958c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
2968c2ecf20Sopenharmony_ci					"integer out of range");
2978c2ecf20Sopenharmony_ci		return -ERANGE;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return 0;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int nla_validate_int_range(const struct nla_policy *pt,
3048c2ecf20Sopenharmony_ci				  const struct nlattr *nla,
3058c2ecf20Sopenharmony_ci				  struct netlink_ext_ack *extack,
3068c2ecf20Sopenharmony_ci				  unsigned int validate)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	switch (pt->type) {
3098c2ecf20Sopenharmony_ci	case NLA_U8:
3108c2ecf20Sopenharmony_ci	case NLA_U16:
3118c2ecf20Sopenharmony_ci	case NLA_U32:
3128c2ecf20Sopenharmony_ci	case NLA_U64:
3138c2ecf20Sopenharmony_ci	case NLA_MSECS:
3148c2ecf20Sopenharmony_ci	case NLA_BINARY:
3158c2ecf20Sopenharmony_ci		return nla_validate_range_unsigned(pt, nla, extack, validate);
3168c2ecf20Sopenharmony_ci	case NLA_S8:
3178c2ecf20Sopenharmony_ci	case NLA_S16:
3188c2ecf20Sopenharmony_ci	case NLA_S32:
3198c2ecf20Sopenharmony_ci	case NLA_S64:
3208c2ecf20Sopenharmony_ci		return nla_validate_int_range_signed(pt, nla, extack);
3218c2ecf20Sopenharmony_ci	default:
3228c2ecf20Sopenharmony_ci		WARN_ON(1);
3238c2ecf20Sopenharmony_ci		return -EINVAL;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic int nla_validate_mask(const struct nla_policy *pt,
3288c2ecf20Sopenharmony_ci			     const struct nlattr *nla,
3298c2ecf20Sopenharmony_ci			     struct netlink_ext_ack *extack)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	u64 value;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	switch (pt->type) {
3348c2ecf20Sopenharmony_ci	case NLA_U8:
3358c2ecf20Sopenharmony_ci		value = nla_get_u8(nla);
3368c2ecf20Sopenharmony_ci		break;
3378c2ecf20Sopenharmony_ci	case NLA_U16:
3388c2ecf20Sopenharmony_ci		value = nla_get_u16(nla);
3398c2ecf20Sopenharmony_ci		break;
3408c2ecf20Sopenharmony_ci	case NLA_U32:
3418c2ecf20Sopenharmony_ci		value = nla_get_u32(nla);
3428c2ecf20Sopenharmony_ci		break;
3438c2ecf20Sopenharmony_ci	case NLA_U64:
3448c2ecf20Sopenharmony_ci		value = nla_get_u64(nla);
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	default:
3478c2ecf20Sopenharmony_ci		return -EINVAL;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (value & ~(u64)pt->mask) {
3518c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, nla, "reserved bit set");
3528c2ecf20Sopenharmony_ci		return -EINVAL;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return 0;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic int validate_nla(const struct nlattr *nla, int maxtype,
3598c2ecf20Sopenharmony_ci			const struct nla_policy *policy, unsigned int validate,
3608c2ecf20Sopenharmony_ci			struct netlink_ext_ack *extack, unsigned int depth)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	u16 strict_start_type = policy[0].strict_start_type;
3638c2ecf20Sopenharmony_ci	const struct nla_policy *pt;
3648c2ecf20Sopenharmony_ci	int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla);
3658c2ecf20Sopenharmony_ci	int err = -ERANGE;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (strict_start_type && type >= strict_start_type)
3688c2ecf20Sopenharmony_ci		validate |= NL_VALIDATE_STRICT;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (type <= 0 || type > maxtype)
3718c2ecf20Sopenharmony_ci		return 0;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	type = array_index_nospec(type, maxtype + 1);
3748c2ecf20Sopenharmony_ci	pt = &policy[type];
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	BUG_ON(pt->type > NLA_TYPE_MAX);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (nla_attr_len[pt->type] && attrlen != nla_attr_len[pt->type]) {
3798c2ecf20Sopenharmony_ci		pr_warn_ratelimited("netlink: '%s': attribute type %d has an invalid length.\n",
3808c2ecf20Sopenharmony_ci				    current->comm, type);
3818c2ecf20Sopenharmony_ci		if (validate & NL_VALIDATE_STRICT_ATTRS) {
3828c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
3838c2ecf20Sopenharmony_ci						"invalid attribute length");
3848c2ecf20Sopenharmony_ci			return -EINVAL;
3858c2ecf20Sopenharmony_ci		}
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (validate & NL_VALIDATE_NESTED) {
3898c2ecf20Sopenharmony_ci		if ((pt->type == NLA_NESTED || pt->type == NLA_NESTED_ARRAY) &&
3908c2ecf20Sopenharmony_ci		    !(nla->nla_type & NLA_F_NESTED)) {
3918c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
3928c2ecf20Sopenharmony_ci						"NLA_F_NESTED is missing");
3938c2ecf20Sopenharmony_ci			return -EINVAL;
3948c2ecf20Sopenharmony_ci		}
3958c2ecf20Sopenharmony_ci		if (pt->type != NLA_NESTED && pt->type != NLA_NESTED_ARRAY &&
3968c2ecf20Sopenharmony_ci		    pt->type != NLA_UNSPEC && (nla->nla_type & NLA_F_NESTED)) {
3978c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
3988c2ecf20Sopenharmony_ci						"NLA_F_NESTED not expected");
3998c2ecf20Sopenharmony_ci			return -EINVAL;
4008c2ecf20Sopenharmony_ci		}
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	switch (pt->type) {
4048c2ecf20Sopenharmony_ci	case NLA_REJECT:
4058c2ecf20Sopenharmony_ci		if (extack && pt->reject_message) {
4068c2ecf20Sopenharmony_ci			NL_SET_BAD_ATTR(extack, nla);
4078c2ecf20Sopenharmony_ci			extack->_msg = pt->reject_message;
4088c2ecf20Sopenharmony_ci			return -EINVAL;
4098c2ecf20Sopenharmony_ci		}
4108c2ecf20Sopenharmony_ci		err = -EINVAL;
4118c2ecf20Sopenharmony_ci		goto out_err;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	case NLA_FLAG:
4148c2ecf20Sopenharmony_ci		if (attrlen > 0)
4158c2ecf20Sopenharmony_ci			goto out_err;
4168c2ecf20Sopenharmony_ci		break;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	case NLA_BITFIELD32:
4198c2ecf20Sopenharmony_ci		if (attrlen != sizeof(struct nla_bitfield32))
4208c2ecf20Sopenharmony_ci			goto out_err;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		err = validate_nla_bitfield32(nla, pt->bitfield32_valid);
4238c2ecf20Sopenharmony_ci		if (err)
4248c2ecf20Sopenharmony_ci			goto out_err;
4258c2ecf20Sopenharmony_ci		break;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	case NLA_NUL_STRING:
4288c2ecf20Sopenharmony_ci		if (pt->len)
4298c2ecf20Sopenharmony_ci			minlen = min_t(int, attrlen, pt->len + 1);
4308c2ecf20Sopenharmony_ci		else
4318c2ecf20Sopenharmony_ci			minlen = attrlen;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) {
4348c2ecf20Sopenharmony_ci			err = -EINVAL;
4358c2ecf20Sopenharmony_ci			goto out_err;
4368c2ecf20Sopenharmony_ci		}
4378c2ecf20Sopenharmony_ci		/* fall through */
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	case NLA_STRING:
4408c2ecf20Sopenharmony_ci		if (attrlen < 1)
4418c2ecf20Sopenharmony_ci			goto out_err;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci		if (pt->len) {
4448c2ecf20Sopenharmony_ci			char *buf = nla_data(nla);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci			if (buf[attrlen - 1] == '\0')
4478c2ecf20Sopenharmony_ci				attrlen--;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci			if (attrlen > pt->len)
4508c2ecf20Sopenharmony_ci				goto out_err;
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci		break;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	case NLA_BINARY:
4558c2ecf20Sopenharmony_ci		if (pt->len && attrlen > pt->len)
4568c2ecf20Sopenharmony_ci			goto out_err;
4578c2ecf20Sopenharmony_ci		break;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	case NLA_NESTED:
4608c2ecf20Sopenharmony_ci		/* a nested attributes is allowed to be empty; if its not,
4618c2ecf20Sopenharmony_ci		 * it must have a size of at least NLA_HDRLEN.
4628c2ecf20Sopenharmony_ci		 */
4638c2ecf20Sopenharmony_ci		if (attrlen == 0)
4648c2ecf20Sopenharmony_ci			break;
4658c2ecf20Sopenharmony_ci		if (attrlen < NLA_HDRLEN)
4668c2ecf20Sopenharmony_ci			goto out_err;
4678c2ecf20Sopenharmony_ci		if (pt->nested_policy) {
4688c2ecf20Sopenharmony_ci			err = __nla_validate_parse(nla_data(nla), nla_len(nla),
4698c2ecf20Sopenharmony_ci						   pt->len, pt->nested_policy,
4708c2ecf20Sopenharmony_ci						   validate, extack, NULL,
4718c2ecf20Sopenharmony_ci						   depth + 1);
4728c2ecf20Sopenharmony_ci			if (err < 0) {
4738c2ecf20Sopenharmony_ci				/*
4748c2ecf20Sopenharmony_ci				 * return directly to preserve the inner
4758c2ecf20Sopenharmony_ci				 * error message/attribute pointer
4768c2ecf20Sopenharmony_ci				 */
4778c2ecf20Sopenharmony_ci				return err;
4788c2ecf20Sopenharmony_ci			}
4798c2ecf20Sopenharmony_ci		}
4808c2ecf20Sopenharmony_ci		break;
4818c2ecf20Sopenharmony_ci	case NLA_NESTED_ARRAY:
4828c2ecf20Sopenharmony_ci		/* a nested array attribute is allowed to be empty; if its not,
4838c2ecf20Sopenharmony_ci		 * it must have a size of at least NLA_HDRLEN.
4848c2ecf20Sopenharmony_ci		 */
4858c2ecf20Sopenharmony_ci		if (attrlen == 0)
4868c2ecf20Sopenharmony_ci			break;
4878c2ecf20Sopenharmony_ci		if (attrlen < NLA_HDRLEN)
4888c2ecf20Sopenharmony_ci			goto out_err;
4898c2ecf20Sopenharmony_ci		if (pt->nested_policy) {
4908c2ecf20Sopenharmony_ci			int err;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci			err = nla_validate_array(nla_data(nla), nla_len(nla),
4938c2ecf20Sopenharmony_ci						 pt->len, pt->nested_policy,
4948c2ecf20Sopenharmony_ci						 extack, validate, depth);
4958c2ecf20Sopenharmony_ci			if (err < 0) {
4968c2ecf20Sopenharmony_ci				/*
4978c2ecf20Sopenharmony_ci				 * return directly to preserve the inner
4988c2ecf20Sopenharmony_ci				 * error message/attribute pointer
4998c2ecf20Sopenharmony_ci				 */
5008c2ecf20Sopenharmony_ci				return err;
5018c2ecf20Sopenharmony_ci			}
5028c2ecf20Sopenharmony_ci		}
5038c2ecf20Sopenharmony_ci		break;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	case NLA_UNSPEC:
5068c2ecf20Sopenharmony_ci		if (validate & NL_VALIDATE_UNSPEC) {
5078c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, nla,
5088c2ecf20Sopenharmony_ci					    "Unsupported attribute");
5098c2ecf20Sopenharmony_ci			return -EINVAL;
5108c2ecf20Sopenharmony_ci		}
5118c2ecf20Sopenharmony_ci		if (attrlen < pt->len)
5128c2ecf20Sopenharmony_ci			goto out_err;
5138c2ecf20Sopenharmony_ci		break;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	default:
5168c2ecf20Sopenharmony_ci		if (pt->len)
5178c2ecf20Sopenharmony_ci			minlen = pt->len;
5188c2ecf20Sopenharmony_ci		else
5198c2ecf20Sopenharmony_ci			minlen = nla_attr_minlen[pt->type];
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci		if (attrlen < minlen)
5228c2ecf20Sopenharmony_ci			goto out_err;
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/* further validation */
5268c2ecf20Sopenharmony_ci	switch (pt->validation_type) {
5278c2ecf20Sopenharmony_ci	case NLA_VALIDATE_NONE:
5288c2ecf20Sopenharmony_ci		/* nothing to do */
5298c2ecf20Sopenharmony_ci		break;
5308c2ecf20Sopenharmony_ci	case NLA_VALIDATE_RANGE_PTR:
5318c2ecf20Sopenharmony_ci	case NLA_VALIDATE_RANGE:
5328c2ecf20Sopenharmony_ci	case NLA_VALIDATE_RANGE_WARN_TOO_LONG:
5338c2ecf20Sopenharmony_ci	case NLA_VALIDATE_MIN:
5348c2ecf20Sopenharmony_ci	case NLA_VALIDATE_MAX:
5358c2ecf20Sopenharmony_ci		err = nla_validate_int_range(pt, nla, extack, validate);
5368c2ecf20Sopenharmony_ci		if (err)
5378c2ecf20Sopenharmony_ci			return err;
5388c2ecf20Sopenharmony_ci		break;
5398c2ecf20Sopenharmony_ci	case NLA_VALIDATE_MASK:
5408c2ecf20Sopenharmony_ci		err = nla_validate_mask(pt, nla, extack);
5418c2ecf20Sopenharmony_ci		if (err)
5428c2ecf20Sopenharmony_ci			return err;
5438c2ecf20Sopenharmony_ci		break;
5448c2ecf20Sopenharmony_ci	case NLA_VALIDATE_FUNCTION:
5458c2ecf20Sopenharmony_ci		if (pt->validate) {
5468c2ecf20Sopenharmony_ci			err = pt->validate(nla, extack);
5478c2ecf20Sopenharmony_ci			if (err)
5488c2ecf20Sopenharmony_ci				return err;
5498c2ecf20Sopenharmony_ci		}
5508c2ecf20Sopenharmony_ci		break;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	return 0;
5548c2ecf20Sopenharmony_ciout_err:
5558c2ecf20Sopenharmony_ci	NL_SET_ERR_MSG_ATTR_POL(extack, nla, pt,
5568c2ecf20Sopenharmony_ci				"Attribute failed policy validation");
5578c2ecf20Sopenharmony_ci	return err;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
5618c2ecf20Sopenharmony_ci				const struct nla_policy *policy,
5628c2ecf20Sopenharmony_ci				unsigned int validate,
5638c2ecf20Sopenharmony_ci				struct netlink_ext_ack *extack,
5648c2ecf20Sopenharmony_ci				struct nlattr **tb, unsigned int depth)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	const struct nlattr *nla;
5678c2ecf20Sopenharmony_ci	int rem;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (depth >= MAX_POLICY_RECURSION_DEPTH) {
5708c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack,
5718c2ecf20Sopenharmony_ci			       "allowed policy recursion depth exceeded");
5728c2ecf20Sopenharmony_ci		return -EINVAL;
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	if (tb)
5768c2ecf20Sopenharmony_ci		memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	nla_for_each_attr(nla, head, len, rem) {
5798c2ecf20Sopenharmony_ci		u16 type = nla_type(nla);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		if (type == 0 || type > maxtype) {
5828c2ecf20Sopenharmony_ci			if (validate & NL_VALIDATE_MAXTYPE) {
5838c2ecf20Sopenharmony_ci				NL_SET_ERR_MSG_ATTR(extack, nla,
5848c2ecf20Sopenharmony_ci						    "Unknown attribute type");
5858c2ecf20Sopenharmony_ci				return -EINVAL;
5868c2ecf20Sopenharmony_ci			}
5878c2ecf20Sopenharmony_ci			continue;
5888c2ecf20Sopenharmony_ci		}
5898c2ecf20Sopenharmony_ci		type = array_index_nospec(type, maxtype + 1);
5908c2ecf20Sopenharmony_ci		if (policy) {
5918c2ecf20Sopenharmony_ci			int err = validate_nla(nla, maxtype, policy,
5928c2ecf20Sopenharmony_ci					       validate, extack, depth);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci			if (err < 0)
5958c2ecf20Sopenharmony_ci				return err;
5968c2ecf20Sopenharmony_ci		}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		if (tb)
5998c2ecf20Sopenharmony_ci			tb[type] = (struct nlattr *)nla;
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (unlikely(rem > 0)) {
6038c2ecf20Sopenharmony_ci		pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n",
6048c2ecf20Sopenharmony_ci				    rem, current->comm);
6058c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "bytes leftover after parsing attributes");
6068c2ecf20Sopenharmony_ci		if (validate & NL_VALIDATE_TRAILING)
6078c2ecf20Sopenharmony_ci			return -EINVAL;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci/**
6148c2ecf20Sopenharmony_ci * __nla_validate - Validate a stream of attributes
6158c2ecf20Sopenharmony_ci * @head: head of attribute stream
6168c2ecf20Sopenharmony_ci * @len: length of attribute stream
6178c2ecf20Sopenharmony_ci * @maxtype: maximum attribute type to be expected
6188c2ecf20Sopenharmony_ci * @policy: validation policy
6198c2ecf20Sopenharmony_ci * @validate: validation strictness
6208c2ecf20Sopenharmony_ci * @extack: extended ACK report struct
6218c2ecf20Sopenharmony_ci *
6228c2ecf20Sopenharmony_ci * Validates all attributes in the specified attribute stream against the
6238c2ecf20Sopenharmony_ci * specified policy. Validation depends on the validate flags passed, see
6248c2ecf20Sopenharmony_ci * &enum netlink_validation for more details on that.
6258c2ecf20Sopenharmony_ci * See documenation of struct nla_policy for more details.
6268c2ecf20Sopenharmony_ci *
6278c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code.
6288c2ecf20Sopenharmony_ci */
6298c2ecf20Sopenharmony_ciint __nla_validate(const struct nlattr *head, int len, int maxtype,
6308c2ecf20Sopenharmony_ci		   const struct nla_policy *policy, unsigned int validate,
6318c2ecf20Sopenharmony_ci		   struct netlink_ext_ack *extack)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	return __nla_validate_parse(head, len, maxtype, policy, validate,
6348c2ecf20Sopenharmony_ci				    extack, NULL, 0);
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nla_validate);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci/**
6398c2ecf20Sopenharmony_ci * nla_policy_len - Determin the max. length of a policy
6408c2ecf20Sopenharmony_ci * @policy: policy to use
6418c2ecf20Sopenharmony_ci * @n: number of policies
6428c2ecf20Sopenharmony_ci *
6438c2ecf20Sopenharmony_ci * Determines the max. length of the policy.  It is currently used
6448c2ecf20Sopenharmony_ci * to allocated Netlink buffers roughly the size of the actual
6458c2ecf20Sopenharmony_ci * message.
6468c2ecf20Sopenharmony_ci *
6478c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code.
6488c2ecf20Sopenharmony_ci */
6498c2ecf20Sopenharmony_ciint
6508c2ecf20Sopenharmony_cinla_policy_len(const struct nla_policy *p, int n)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	int i, len = 0;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++, p++) {
6558c2ecf20Sopenharmony_ci		if (p->len)
6568c2ecf20Sopenharmony_ci			len += nla_total_size(p->len);
6578c2ecf20Sopenharmony_ci		else if (nla_attr_len[p->type])
6588c2ecf20Sopenharmony_ci			len += nla_total_size(nla_attr_len[p->type]);
6598c2ecf20Sopenharmony_ci		else if (nla_attr_minlen[p->type])
6608c2ecf20Sopenharmony_ci			len += nla_total_size(nla_attr_minlen[p->type]);
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	return len;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_policy_len);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci/**
6688c2ecf20Sopenharmony_ci * __nla_parse - Parse a stream of attributes into a tb buffer
6698c2ecf20Sopenharmony_ci * @tb: destination array with maxtype+1 elements
6708c2ecf20Sopenharmony_ci * @maxtype: maximum attribute type to be expected
6718c2ecf20Sopenharmony_ci * @head: head of attribute stream
6728c2ecf20Sopenharmony_ci * @len: length of attribute stream
6738c2ecf20Sopenharmony_ci * @policy: validation policy
6748c2ecf20Sopenharmony_ci * @validate: validation strictness
6758c2ecf20Sopenharmony_ci * @extack: extended ACK pointer
6768c2ecf20Sopenharmony_ci *
6778c2ecf20Sopenharmony_ci * Parses a stream of attributes and stores a pointer to each attribute in
6788c2ecf20Sopenharmony_ci * the tb array accessible via the attribute type.
6798c2ecf20Sopenharmony_ci * Validation is controlled by the @validate parameter.
6808c2ecf20Sopenharmony_ci *
6818c2ecf20Sopenharmony_ci * Returns 0 on success or a negative error code.
6828c2ecf20Sopenharmony_ci */
6838c2ecf20Sopenharmony_ciint __nla_parse(struct nlattr **tb, int maxtype,
6848c2ecf20Sopenharmony_ci		const struct nlattr *head, int len,
6858c2ecf20Sopenharmony_ci		const struct nla_policy *policy, unsigned int validate,
6868c2ecf20Sopenharmony_ci		struct netlink_ext_ack *extack)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	return __nla_validate_parse(head, len, maxtype, policy, validate,
6898c2ecf20Sopenharmony_ci				    extack, tb, 0);
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nla_parse);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci/**
6948c2ecf20Sopenharmony_ci * nla_find - Find a specific attribute in a stream of attributes
6958c2ecf20Sopenharmony_ci * @head: head of attribute stream
6968c2ecf20Sopenharmony_ci * @len: length of attribute stream
6978c2ecf20Sopenharmony_ci * @attrtype: type of attribute to look for
6988c2ecf20Sopenharmony_ci *
6998c2ecf20Sopenharmony_ci * Returns the first attribute in the stream matching the specified type.
7008c2ecf20Sopenharmony_ci */
7018c2ecf20Sopenharmony_cistruct nlattr *nla_find(const struct nlattr *head, int len, int attrtype)
7028c2ecf20Sopenharmony_ci{
7038c2ecf20Sopenharmony_ci	const struct nlattr *nla;
7048c2ecf20Sopenharmony_ci	int rem;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	nla_for_each_attr(nla, head, len, rem)
7078c2ecf20Sopenharmony_ci		if (nla_type(nla) == attrtype)
7088c2ecf20Sopenharmony_ci			return (struct nlattr *)nla;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	return NULL;
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_find);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci/**
7158c2ecf20Sopenharmony_ci * nla_strlcpy - Copy string attribute payload into a sized buffer
7168c2ecf20Sopenharmony_ci * @dst: where to copy the string to
7178c2ecf20Sopenharmony_ci * @nla: attribute to copy the string from
7188c2ecf20Sopenharmony_ci * @dstsize: size of destination buffer
7198c2ecf20Sopenharmony_ci *
7208c2ecf20Sopenharmony_ci * Copies at most dstsize - 1 bytes into the destination buffer.
7218c2ecf20Sopenharmony_ci * The result is always a valid NUL-terminated string. Unlike
7228c2ecf20Sopenharmony_ci * strlcpy the destination buffer is always padded out.
7238c2ecf20Sopenharmony_ci *
7248c2ecf20Sopenharmony_ci * Returns the length of the source buffer.
7258c2ecf20Sopenharmony_ci */
7268c2ecf20Sopenharmony_cisize_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	size_t srclen = nla_len(nla);
7298c2ecf20Sopenharmony_ci	char *src = nla_data(nla);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	if (srclen > 0 && src[srclen - 1] == '\0')
7328c2ecf20Sopenharmony_ci		srclen--;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (dstsize > 0) {
7358c2ecf20Sopenharmony_ci		size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci		memset(dst, 0, dstsize);
7388c2ecf20Sopenharmony_ci		memcpy(dst, src, len);
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	return srclen;
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_strlcpy);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci/**
7468c2ecf20Sopenharmony_ci * nla_strdup - Copy string attribute payload into a newly allocated buffer
7478c2ecf20Sopenharmony_ci * @nla: attribute to copy the string from
7488c2ecf20Sopenharmony_ci * @flags: the type of memory to allocate (see kmalloc).
7498c2ecf20Sopenharmony_ci *
7508c2ecf20Sopenharmony_ci * Returns a pointer to the allocated buffer or NULL on error.
7518c2ecf20Sopenharmony_ci */
7528c2ecf20Sopenharmony_cichar *nla_strdup(const struct nlattr *nla, gfp_t flags)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	size_t srclen = nla_len(nla);
7558c2ecf20Sopenharmony_ci	char *src = nla_data(nla), *dst;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (srclen > 0 && src[srclen - 1] == '\0')
7588c2ecf20Sopenharmony_ci		srclen--;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	dst = kmalloc(srclen + 1, flags);
7618c2ecf20Sopenharmony_ci	if (dst != NULL) {
7628c2ecf20Sopenharmony_ci		memcpy(dst, src, srclen);
7638c2ecf20Sopenharmony_ci		dst[srclen] = '\0';
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci	return dst;
7668c2ecf20Sopenharmony_ci}
7678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_strdup);
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci/**
7708c2ecf20Sopenharmony_ci * nla_memcpy - Copy a netlink attribute into another memory area
7718c2ecf20Sopenharmony_ci * @dest: where to copy to memcpy
7728c2ecf20Sopenharmony_ci * @src: netlink attribute to copy from
7738c2ecf20Sopenharmony_ci * @count: size of the destination area
7748c2ecf20Sopenharmony_ci *
7758c2ecf20Sopenharmony_ci * Note: The number of bytes copied is limited by the length of
7768c2ecf20Sopenharmony_ci *       attribute's payload. memcpy
7778c2ecf20Sopenharmony_ci *
7788c2ecf20Sopenharmony_ci * Returns the number of bytes copied.
7798c2ecf20Sopenharmony_ci */
7808c2ecf20Sopenharmony_ciint nla_memcpy(void *dest, const struct nlattr *src, int count)
7818c2ecf20Sopenharmony_ci{
7828c2ecf20Sopenharmony_ci	int minlen = min_t(int, count, nla_len(src));
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	memcpy(dest, nla_data(src), minlen);
7858c2ecf20Sopenharmony_ci	if (count > minlen)
7868c2ecf20Sopenharmony_ci		memset(dest + minlen, 0, count - minlen);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	return minlen;
7898c2ecf20Sopenharmony_ci}
7908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_memcpy);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci/**
7938c2ecf20Sopenharmony_ci * nla_memcmp - Compare an attribute with sized memory area
7948c2ecf20Sopenharmony_ci * @nla: netlink attribute
7958c2ecf20Sopenharmony_ci * @data: memory area
7968c2ecf20Sopenharmony_ci * @size: size of memory area
7978c2ecf20Sopenharmony_ci */
7988c2ecf20Sopenharmony_ciint nla_memcmp(const struct nlattr *nla, const void *data,
7998c2ecf20Sopenharmony_ci			     size_t size)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	int d = nla_len(nla) - size;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (d == 0)
8048c2ecf20Sopenharmony_ci		d = memcmp(nla_data(nla), data, size);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	return d;
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_memcmp);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci/**
8118c2ecf20Sopenharmony_ci * nla_strcmp - Compare a string attribute against a string
8128c2ecf20Sopenharmony_ci * @nla: netlink string attribute
8138c2ecf20Sopenharmony_ci * @str: another string
8148c2ecf20Sopenharmony_ci */
8158c2ecf20Sopenharmony_ciint nla_strcmp(const struct nlattr *nla, const char *str)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	int len = strlen(str);
8188c2ecf20Sopenharmony_ci	char *buf = nla_data(nla);
8198c2ecf20Sopenharmony_ci	int attrlen = nla_len(nla);
8208c2ecf20Sopenharmony_ci	int d;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	while (attrlen > 0 && buf[attrlen - 1] == '\0')
8238c2ecf20Sopenharmony_ci		attrlen--;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	d = attrlen - len;
8268c2ecf20Sopenharmony_ci	if (d == 0)
8278c2ecf20Sopenharmony_ci		d = memcmp(nla_data(nla), str, len);
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	return d;
8308c2ecf20Sopenharmony_ci}
8318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_strcmp);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci#ifdef CONFIG_NET
8348c2ecf20Sopenharmony_ci/**
8358c2ecf20Sopenharmony_ci * __nla_reserve - reserve room for attribute on the skb
8368c2ecf20Sopenharmony_ci * @skb: socket buffer to reserve room on
8378c2ecf20Sopenharmony_ci * @attrtype: attribute type
8388c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
8398c2ecf20Sopenharmony_ci *
8408c2ecf20Sopenharmony_ci * Adds a netlink attribute header to a socket buffer and reserves
8418c2ecf20Sopenharmony_ci * room for the payload but does not copy it.
8428c2ecf20Sopenharmony_ci *
8438c2ecf20Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
8448c2ecf20Sopenharmony_ci * tailroom for the attribute header and payload.
8458c2ecf20Sopenharmony_ci */
8468c2ecf20Sopenharmony_cistruct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	struct nlattr *nla;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	nla = skb_put(skb, nla_total_size(attrlen));
8518c2ecf20Sopenharmony_ci	nla->nla_type = attrtype;
8528c2ecf20Sopenharmony_ci	nla->nla_len = nla_attr_size(attrlen);
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen));
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	return nla;
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nla_reserve);
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci/**
8618c2ecf20Sopenharmony_ci * __nla_reserve_64bit - reserve room for attribute on the skb and align it
8628c2ecf20Sopenharmony_ci * @skb: socket buffer to reserve room on
8638c2ecf20Sopenharmony_ci * @attrtype: attribute type
8648c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
8658c2ecf20Sopenharmony_ci * @padattr: attribute type for the padding
8668c2ecf20Sopenharmony_ci *
8678c2ecf20Sopenharmony_ci * Adds a netlink attribute header to a socket buffer and reserves
8688c2ecf20Sopenharmony_ci * room for the payload but does not copy it. It also ensure that this
8698c2ecf20Sopenharmony_ci * attribute will have a 64-bit aligned nla_data() area.
8708c2ecf20Sopenharmony_ci *
8718c2ecf20Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
8728c2ecf20Sopenharmony_ci * tailroom for the attribute header and payload.
8738c2ecf20Sopenharmony_ci */
8748c2ecf20Sopenharmony_cistruct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype,
8758c2ecf20Sopenharmony_ci				   int attrlen, int padattr)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	nla_align_64bit(skb, padattr);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	return __nla_reserve(skb, attrtype, attrlen);
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nla_reserve_64bit);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci/**
8848c2ecf20Sopenharmony_ci * __nla_reserve_nohdr - reserve room for attribute without header
8858c2ecf20Sopenharmony_ci * @skb: socket buffer to reserve room on
8868c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
8878c2ecf20Sopenharmony_ci *
8888c2ecf20Sopenharmony_ci * Reserves room for attribute payload without a header.
8898c2ecf20Sopenharmony_ci *
8908c2ecf20Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
8918c2ecf20Sopenharmony_ci * tailroom for the payload.
8928c2ecf20Sopenharmony_ci */
8938c2ecf20Sopenharmony_civoid *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	return skb_put_zero(skb, NLA_ALIGN(attrlen));
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nla_reserve_nohdr);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci/**
9008c2ecf20Sopenharmony_ci * nla_reserve - reserve room for attribute on the skb
9018c2ecf20Sopenharmony_ci * @skb: socket buffer to reserve room on
9028c2ecf20Sopenharmony_ci * @attrtype: attribute type
9038c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
9048c2ecf20Sopenharmony_ci *
9058c2ecf20Sopenharmony_ci * Adds a netlink attribute header to a socket buffer and reserves
9068c2ecf20Sopenharmony_ci * room for the payload but does not copy it.
9078c2ecf20Sopenharmony_ci *
9088c2ecf20Sopenharmony_ci * Returns NULL if the tailroom of the skb is insufficient to store
9098c2ecf20Sopenharmony_ci * the attribute header and payload.
9108c2ecf20Sopenharmony_ci */
9118c2ecf20Sopenharmony_cistruct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
9148c2ecf20Sopenharmony_ci		return NULL;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	return __nla_reserve(skb, attrtype, attrlen);
9178c2ecf20Sopenharmony_ci}
9188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_reserve);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci/**
9218c2ecf20Sopenharmony_ci * nla_reserve_64bit - reserve room for attribute on the skb and align it
9228c2ecf20Sopenharmony_ci * @skb: socket buffer to reserve room on
9238c2ecf20Sopenharmony_ci * @attrtype: attribute type
9248c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
9258c2ecf20Sopenharmony_ci * @padattr: attribute type for the padding
9268c2ecf20Sopenharmony_ci *
9278c2ecf20Sopenharmony_ci * Adds a netlink attribute header to a socket buffer and reserves
9288c2ecf20Sopenharmony_ci * room for the payload but does not copy it. It also ensure that this
9298c2ecf20Sopenharmony_ci * attribute will have a 64-bit aligned nla_data() area.
9308c2ecf20Sopenharmony_ci *
9318c2ecf20Sopenharmony_ci * Returns NULL if the tailroom of the skb is insufficient to store
9328c2ecf20Sopenharmony_ci * the attribute header and payload.
9338c2ecf20Sopenharmony_ci */
9348c2ecf20Sopenharmony_cistruct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype, int attrlen,
9358c2ecf20Sopenharmony_ci				 int padattr)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	size_t len;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	if (nla_need_padding_for_64bit(skb))
9408c2ecf20Sopenharmony_ci		len = nla_total_size_64bit(attrlen);
9418c2ecf20Sopenharmony_ci	else
9428c2ecf20Sopenharmony_ci		len = nla_total_size(attrlen);
9438c2ecf20Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < len))
9448c2ecf20Sopenharmony_ci		return NULL;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	return __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_reserve_64bit);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci/**
9518c2ecf20Sopenharmony_ci * nla_reserve_nohdr - reserve room for attribute without header
9528c2ecf20Sopenharmony_ci * @skb: socket buffer to reserve room on
9538c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
9548c2ecf20Sopenharmony_ci *
9558c2ecf20Sopenharmony_ci * Reserves room for attribute payload without a header.
9568c2ecf20Sopenharmony_ci *
9578c2ecf20Sopenharmony_ci * Returns NULL if the tailroom of the skb is insufficient to store
9588c2ecf20Sopenharmony_ci * the attribute payload.
9598c2ecf20Sopenharmony_ci */
9608c2ecf20Sopenharmony_civoid *nla_reserve_nohdr(struct sk_buff *skb, int attrlen)
9618c2ecf20Sopenharmony_ci{
9628c2ecf20Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
9638c2ecf20Sopenharmony_ci		return NULL;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	return __nla_reserve_nohdr(skb, attrlen);
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_reserve_nohdr);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci/**
9708c2ecf20Sopenharmony_ci * __nla_put - Add a netlink attribute to a socket buffer
9718c2ecf20Sopenharmony_ci * @skb: socket buffer to add attribute to
9728c2ecf20Sopenharmony_ci * @attrtype: attribute type
9738c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
9748c2ecf20Sopenharmony_ci * @data: head of attribute payload
9758c2ecf20Sopenharmony_ci *
9768c2ecf20Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
9778c2ecf20Sopenharmony_ci * tailroom for the attribute header and payload.
9788c2ecf20Sopenharmony_ci */
9798c2ecf20Sopenharmony_civoid __nla_put(struct sk_buff *skb, int attrtype, int attrlen,
9808c2ecf20Sopenharmony_ci			     const void *data)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	struct nlattr *nla;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	nla = __nla_reserve(skb, attrtype, attrlen);
9858c2ecf20Sopenharmony_ci	memcpy(nla_data(nla), data, attrlen);
9868c2ecf20Sopenharmony_ci}
9878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nla_put);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci/**
9908c2ecf20Sopenharmony_ci * __nla_put_64bit - Add a netlink attribute to a socket buffer and align it
9918c2ecf20Sopenharmony_ci * @skb: socket buffer to add attribute to
9928c2ecf20Sopenharmony_ci * @attrtype: attribute type
9938c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
9948c2ecf20Sopenharmony_ci * @data: head of attribute payload
9958c2ecf20Sopenharmony_ci * @padattr: attribute type for the padding
9968c2ecf20Sopenharmony_ci *
9978c2ecf20Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
9988c2ecf20Sopenharmony_ci * tailroom for the attribute header and payload.
9998c2ecf20Sopenharmony_ci */
10008c2ecf20Sopenharmony_civoid __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
10018c2ecf20Sopenharmony_ci		     const void *data, int padattr)
10028c2ecf20Sopenharmony_ci{
10038c2ecf20Sopenharmony_ci	struct nlattr *nla;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	nla = __nla_reserve_64bit(skb, attrtype, attrlen, padattr);
10068c2ecf20Sopenharmony_ci	memcpy(nla_data(nla), data, attrlen);
10078c2ecf20Sopenharmony_ci}
10088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nla_put_64bit);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci/**
10118c2ecf20Sopenharmony_ci * __nla_put_nohdr - Add a netlink attribute without header
10128c2ecf20Sopenharmony_ci * @skb: socket buffer to add attribute to
10138c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
10148c2ecf20Sopenharmony_ci * @data: head of attribute payload
10158c2ecf20Sopenharmony_ci *
10168c2ecf20Sopenharmony_ci * The caller is responsible to ensure that the skb provides enough
10178c2ecf20Sopenharmony_ci * tailroom for the attribute payload.
10188c2ecf20Sopenharmony_ci */
10198c2ecf20Sopenharmony_civoid __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	void *start;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	start = __nla_reserve_nohdr(skb, attrlen);
10248c2ecf20Sopenharmony_ci	memcpy(start, data, attrlen);
10258c2ecf20Sopenharmony_ci}
10268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__nla_put_nohdr);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci/**
10298c2ecf20Sopenharmony_ci * nla_put - Add a netlink attribute to a socket buffer
10308c2ecf20Sopenharmony_ci * @skb: socket buffer to add attribute to
10318c2ecf20Sopenharmony_ci * @attrtype: attribute type
10328c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
10338c2ecf20Sopenharmony_ci * @data: head of attribute payload
10348c2ecf20Sopenharmony_ci *
10358c2ecf20Sopenharmony_ci * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
10368c2ecf20Sopenharmony_ci * the attribute header and payload.
10378c2ecf20Sopenharmony_ci */
10388c2ecf20Sopenharmony_ciint nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen)))
10418c2ecf20Sopenharmony_ci		return -EMSGSIZE;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	__nla_put(skb, attrtype, attrlen, data);
10448c2ecf20Sopenharmony_ci	return 0;
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_put);
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci/**
10498c2ecf20Sopenharmony_ci * nla_put_64bit - Add a netlink attribute to a socket buffer and align it
10508c2ecf20Sopenharmony_ci * @skb: socket buffer to add attribute to
10518c2ecf20Sopenharmony_ci * @attrtype: attribute type
10528c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
10538c2ecf20Sopenharmony_ci * @data: head of attribute payload
10548c2ecf20Sopenharmony_ci * @padattr: attribute type for the padding
10558c2ecf20Sopenharmony_ci *
10568c2ecf20Sopenharmony_ci * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
10578c2ecf20Sopenharmony_ci * the attribute header and payload.
10588c2ecf20Sopenharmony_ci */
10598c2ecf20Sopenharmony_ciint nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen,
10608c2ecf20Sopenharmony_ci		  const void *data, int padattr)
10618c2ecf20Sopenharmony_ci{
10628c2ecf20Sopenharmony_ci	size_t len;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	if (nla_need_padding_for_64bit(skb))
10658c2ecf20Sopenharmony_ci		len = nla_total_size_64bit(attrlen);
10668c2ecf20Sopenharmony_ci	else
10678c2ecf20Sopenharmony_ci		len = nla_total_size(attrlen);
10688c2ecf20Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < len))
10698c2ecf20Sopenharmony_ci		return -EMSGSIZE;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	__nla_put_64bit(skb, attrtype, attrlen, data, padattr);
10728c2ecf20Sopenharmony_ci	return 0;
10738c2ecf20Sopenharmony_ci}
10748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_put_64bit);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci/**
10778c2ecf20Sopenharmony_ci * nla_put_nohdr - Add a netlink attribute without header
10788c2ecf20Sopenharmony_ci * @skb: socket buffer to add attribute to
10798c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
10808c2ecf20Sopenharmony_ci * @data: head of attribute payload
10818c2ecf20Sopenharmony_ci *
10828c2ecf20Sopenharmony_ci * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
10838c2ecf20Sopenharmony_ci * the attribute payload.
10848c2ecf20Sopenharmony_ci */
10858c2ecf20Sopenharmony_ciint nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data)
10868c2ecf20Sopenharmony_ci{
10878c2ecf20Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
10888c2ecf20Sopenharmony_ci		return -EMSGSIZE;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	__nla_put_nohdr(skb, attrlen, data);
10918c2ecf20Sopenharmony_ci	return 0;
10928c2ecf20Sopenharmony_ci}
10938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_put_nohdr);
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci/**
10968c2ecf20Sopenharmony_ci * nla_append - Add a netlink attribute without header or padding
10978c2ecf20Sopenharmony_ci * @skb: socket buffer to add attribute to
10988c2ecf20Sopenharmony_ci * @attrlen: length of attribute payload
10998c2ecf20Sopenharmony_ci * @data: head of attribute payload
11008c2ecf20Sopenharmony_ci *
11018c2ecf20Sopenharmony_ci * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store
11028c2ecf20Sopenharmony_ci * the attribute payload.
11038c2ecf20Sopenharmony_ci */
11048c2ecf20Sopenharmony_ciint nla_append(struct sk_buff *skb, int attrlen, const void *data)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen)))
11078c2ecf20Sopenharmony_ci		return -EMSGSIZE;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	skb_put_data(skb, data, attrlen);
11108c2ecf20Sopenharmony_ci	return 0;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nla_append);
11138c2ecf20Sopenharmony_ci#endif
1114