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