162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifndef _UVERBS_IOCTL_ 762306a36Sopenharmony_ci#define _UVERBS_IOCTL_ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <rdma/uverbs_types.h> 1062306a36Sopenharmony_ci#include <linux/uaccess.h> 1162306a36Sopenharmony_ci#include <rdma/rdma_user_ioctl.h> 1262306a36Sopenharmony_ci#include <rdma/ib_user_ioctl_verbs.h> 1362306a36Sopenharmony_ci#include <rdma/ib_user_ioctl_cmds.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * ======================================= 1762306a36Sopenharmony_ci * Verbs action specifications 1862306a36Sopenharmony_ci * ======================================= 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cienum uverbs_attr_type { 2262306a36Sopenharmony_ci UVERBS_ATTR_TYPE_NA, 2362306a36Sopenharmony_ci UVERBS_ATTR_TYPE_PTR_IN, 2462306a36Sopenharmony_ci UVERBS_ATTR_TYPE_PTR_OUT, 2562306a36Sopenharmony_ci UVERBS_ATTR_TYPE_IDR, 2662306a36Sopenharmony_ci UVERBS_ATTR_TYPE_FD, 2762306a36Sopenharmony_ci UVERBS_ATTR_TYPE_RAW_FD, 2862306a36Sopenharmony_ci UVERBS_ATTR_TYPE_ENUM_IN, 2962306a36Sopenharmony_ci UVERBS_ATTR_TYPE_IDRS_ARRAY, 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cienum uverbs_obj_access { 3362306a36Sopenharmony_ci UVERBS_ACCESS_READ, 3462306a36Sopenharmony_ci UVERBS_ACCESS_WRITE, 3562306a36Sopenharmony_ci UVERBS_ACCESS_NEW, 3662306a36Sopenharmony_ci UVERBS_ACCESS_DESTROY 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* Specification of a single attribute inside the ioctl message */ 4062306a36Sopenharmony_ci/* good size 16 */ 4162306a36Sopenharmony_cistruct uverbs_attr_spec { 4262306a36Sopenharmony_ci u8 type; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci /* 4562306a36Sopenharmony_ci * Support extending attributes by length. Allow the user to provide 4662306a36Sopenharmony_ci * more bytes than ptr.len, but check that everything after is zero'd 4762306a36Sopenharmony_ci * by the user. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci u8 zero_trailing:1; 5062306a36Sopenharmony_ci /* 5162306a36Sopenharmony_ci * Valid only for PTR_IN. Allocate and copy the data inside 5262306a36Sopenharmony_ci * the parser 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci u8 alloc_and_copy:1; 5562306a36Sopenharmony_ci u8 mandatory:1; 5662306a36Sopenharmony_ci /* True if this is from UVERBS_ATTR_UHW */ 5762306a36Sopenharmony_ci u8 is_udata:1; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci union { 6062306a36Sopenharmony_ci struct { 6162306a36Sopenharmony_ci /* Current known size to kernel */ 6262306a36Sopenharmony_ci u16 len; 6362306a36Sopenharmony_ci /* User isn't allowed to provide something < min_len */ 6462306a36Sopenharmony_ci u16 min_len; 6562306a36Sopenharmony_ci } ptr; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci struct { 6862306a36Sopenharmony_ci /* 6962306a36Sopenharmony_ci * higher bits mean the namespace and lower bits mean 7062306a36Sopenharmony_ci * the type id within the namespace. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci u16 obj_type; 7362306a36Sopenharmony_ci u8 access; 7462306a36Sopenharmony_ci } obj; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci struct { 7762306a36Sopenharmony_ci u8 num_elems; 7862306a36Sopenharmony_ci } enum_def; 7962306a36Sopenharmony_ci } u; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* This weird split lets us remove some padding */ 8262306a36Sopenharmony_ci union { 8362306a36Sopenharmony_ci struct { 8462306a36Sopenharmony_ci /* 8562306a36Sopenharmony_ci * The enum attribute can select one of the attributes 8662306a36Sopenharmony_ci * contained in the ids array. Currently only PTR_IN 8762306a36Sopenharmony_ci * attributes are supported in the ids array. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci const struct uverbs_attr_spec *ids; 9062306a36Sopenharmony_ci } enum_def; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci struct { 9362306a36Sopenharmony_ci /* 9462306a36Sopenharmony_ci * higher bits mean the namespace and lower bits mean 9562306a36Sopenharmony_ci * the type id within the namespace. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci u16 obj_type; 9862306a36Sopenharmony_ci u16 min_len; 9962306a36Sopenharmony_ci u16 max_len; 10062306a36Sopenharmony_ci u8 access; 10162306a36Sopenharmony_ci } objs_arr; 10262306a36Sopenharmony_ci } u2; 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * Information about the API is loaded into a radix tree. For IOCTL we start 10762306a36Sopenharmony_ci * with a tuple of: 10862306a36Sopenharmony_ci * object_id, attr_id, method_id 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * Which is a 48 bit value, with most of the bits guaranteed to be zero. Based 11162306a36Sopenharmony_ci * on the current kernel support this is compressed into 16 bit key for the 11262306a36Sopenharmony_ci * radix tree. Since this compression is entirely internal to the kernel the 11362306a36Sopenharmony_ci * below limits can be revised if the kernel gains additional data. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * With 64 leafs per node this is a 3 level radix tree. 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * The tree encodes multiple types, and uses a scheme where OBJ_ID,0,0 returns 11862306a36Sopenharmony_ci * the object slot, and OBJ_ID,METH_ID,0 and returns the method slot. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * This also encodes the tables for the write() and write() extended commands 12162306a36Sopenharmony_ci * using the coding 12262306a36Sopenharmony_ci * OBJ_ID,UVERBS_API_METHOD_IS_WRITE,command # 12362306a36Sopenharmony_ci * OBJ_ID,UVERBS_API_METHOD_IS_WRITE_EX,command_ex # 12462306a36Sopenharmony_ci * ie the WRITE path is treated as a special method type in the ioctl 12562306a36Sopenharmony_ci * framework. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_cienum uapi_radix_data { 12862306a36Sopenharmony_ci UVERBS_API_NS_FLAG = 1U << UVERBS_ID_NS_SHIFT, 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci UVERBS_API_ATTR_KEY_BITS = 6, 13162306a36Sopenharmony_ci UVERBS_API_ATTR_KEY_MASK = GENMASK(UVERBS_API_ATTR_KEY_BITS - 1, 0), 13262306a36Sopenharmony_ci UVERBS_API_ATTR_BKEY_LEN = (1 << UVERBS_API_ATTR_KEY_BITS) - 1, 13362306a36Sopenharmony_ci UVERBS_API_WRITE_KEY_NUM = 1 << UVERBS_API_ATTR_KEY_BITS, 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_BITS = 5, 13662306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_SHIFT = UVERBS_API_ATTR_KEY_BITS, 13762306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_NUM_CORE = 22, 13862306a36Sopenharmony_ci UVERBS_API_METHOD_IS_WRITE = 30 << UVERBS_API_METHOD_KEY_SHIFT, 13962306a36Sopenharmony_ci UVERBS_API_METHOD_IS_WRITE_EX = 31 << UVERBS_API_METHOD_KEY_SHIFT, 14062306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_NUM_DRIVER = 14162306a36Sopenharmony_ci (UVERBS_API_METHOD_IS_WRITE >> UVERBS_API_METHOD_KEY_SHIFT) - 14262306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_NUM_CORE, 14362306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_MASK = GENMASK( 14462306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_BITS + UVERBS_API_METHOD_KEY_SHIFT - 1, 14562306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_SHIFT), 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci UVERBS_API_OBJ_KEY_BITS = 5, 14862306a36Sopenharmony_ci UVERBS_API_OBJ_KEY_SHIFT = 14962306a36Sopenharmony_ci UVERBS_API_METHOD_KEY_BITS + UVERBS_API_METHOD_KEY_SHIFT, 15062306a36Sopenharmony_ci UVERBS_API_OBJ_KEY_NUM_CORE = 20, 15162306a36Sopenharmony_ci UVERBS_API_OBJ_KEY_NUM_DRIVER = 15262306a36Sopenharmony_ci (1 << UVERBS_API_OBJ_KEY_BITS) - UVERBS_API_OBJ_KEY_NUM_CORE, 15362306a36Sopenharmony_ci UVERBS_API_OBJ_KEY_MASK = GENMASK(31, UVERBS_API_OBJ_KEY_SHIFT), 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* This id guaranteed to not exist in the radix tree */ 15662306a36Sopenharmony_ci UVERBS_API_KEY_ERR = 0xFFFFFFFF, 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic inline __attribute_const__ u32 uapi_key_obj(u32 id) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci if (id & UVERBS_API_NS_FLAG) { 16262306a36Sopenharmony_ci id &= ~UVERBS_API_NS_FLAG; 16362306a36Sopenharmony_ci if (id >= UVERBS_API_OBJ_KEY_NUM_DRIVER) 16462306a36Sopenharmony_ci return UVERBS_API_KEY_ERR; 16562306a36Sopenharmony_ci id = id + UVERBS_API_OBJ_KEY_NUM_CORE; 16662306a36Sopenharmony_ci } else { 16762306a36Sopenharmony_ci if (id >= UVERBS_API_OBJ_KEY_NUM_CORE) 16862306a36Sopenharmony_ci return UVERBS_API_KEY_ERR; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return id << UVERBS_API_OBJ_KEY_SHIFT; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline __attribute_const__ bool uapi_key_is_object(u32 key) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci return (key & ~UVERBS_API_OBJ_KEY_MASK) == 0; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic inline __attribute_const__ u32 uapi_key_ioctl_method(u32 id) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci if (id & UVERBS_API_NS_FLAG) { 18262306a36Sopenharmony_ci id &= ~UVERBS_API_NS_FLAG; 18362306a36Sopenharmony_ci if (id >= UVERBS_API_METHOD_KEY_NUM_DRIVER) 18462306a36Sopenharmony_ci return UVERBS_API_KEY_ERR; 18562306a36Sopenharmony_ci id = id + UVERBS_API_METHOD_KEY_NUM_CORE; 18662306a36Sopenharmony_ci } else { 18762306a36Sopenharmony_ci id++; 18862306a36Sopenharmony_ci if (id >= UVERBS_API_METHOD_KEY_NUM_CORE) 18962306a36Sopenharmony_ci return UVERBS_API_KEY_ERR; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci return id << UVERBS_API_METHOD_KEY_SHIFT; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic inline __attribute_const__ u32 uapi_key_write_method(u32 id) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci if (id >= UVERBS_API_WRITE_KEY_NUM) 19862306a36Sopenharmony_ci return UVERBS_API_KEY_ERR; 19962306a36Sopenharmony_ci return UVERBS_API_METHOD_IS_WRITE | id; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic inline __attribute_const__ u32 uapi_key_write_ex_method(u32 id) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci if (id >= UVERBS_API_WRITE_KEY_NUM) 20562306a36Sopenharmony_ci return UVERBS_API_KEY_ERR; 20662306a36Sopenharmony_ci return UVERBS_API_METHOD_IS_WRITE_EX | id; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic inline __attribute_const__ u32 21062306a36Sopenharmony_ciuapi_key_attr_to_ioctl_method(u32 attr_key) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci return attr_key & 21362306a36Sopenharmony_ci (UVERBS_API_OBJ_KEY_MASK | UVERBS_API_METHOD_KEY_MASK); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic inline __attribute_const__ bool uapi_key_is_ioctl_method(u32 key) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci unsigned int method = key & UVERBS_API_METHOD_KEY_MASK; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return method != 0 && method < UVERBS_API_METHOD_IS_WRITE && 22162306a36Sopenharmony_ci (key & UVERBS_API_ATTR_KEY_MASK) == 0; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic inline __attribute_const__ bool uapi_key_is_write_method(u32 key) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci return (key & UVERBS_API_METHOD_KEY_MASK) == UVERBS_API_METHOD_IS_WRITE; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic inline __attribute_const__ bool uapi_key_is_write_ex_method(u32 key) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci return (key & UVERBS_API_METHOD_KEY_MASK) == 23262306a36Sopenharmony_ci UVERBS_API_METHOD_IS_WRITE_EX; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic inline __attribute_const__ u32 uapi_key_attrs_start(u32 ioctl_method_key) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci /* 0 is the method slot itself */ 23862306a36Sopenharmony_ci return ioctl_method_key + 1; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic inline __attribute_const__ u32 uapi_key_attr(u32 id) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci /* 24462306a36Sopenharmony_ci * The attr is designed to fit in the typical single radix tree node 24562306a36Sopenharmony_ci * of 64 entries. Since allmost all methods have driver attributes we 24662306a36Sopenharmony_ci * organize things so that the driver and core attributes interleave to 24762306a36Sopenharmony_ci * reduce the length of the attributes array in typical cases. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci if (id & UVERBS_API_NS_FLAG) { 25062306a36Sopenharmony_ci id &= ~UVERBS_API_NS_FLAG; 25162306a36Sopenharmony_ci id++; 25262306a36Sopenharmony_ci if (id >= 1 << (UVERBS_API_ATTR_KEY_BITS - 1)) 25362306a36Sopenharmony_ci return UVERBS_API_KEY_ERR; 25462306a36Sopenharmony_ci id = (id << 1) | 0; 25562306a36Sopenharmony_ci } else { 25662306a36Sopenharmony_ci if (id >= 1 << (UVERBS_API_ATTR_KEY_BITS - 1)) 25762306a36Sopenharmony_ci return UVERBS_API_KEY_ERR; 25862306a36Sopenharmony_ci id = (id << 1) | 1; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return id; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* Only true for ioctl methods */ 26562306a36Sopenharmony_cistatic inline __attribute_const__ bool uapi_key_is_attr(u32 key) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci unsigned int method = key & UVERBS_API_METHOD_KEY_MASK; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return method != 0 && method < UVERBS_API_METHOD_IS_WRITE && 27062306a36Sopenharmony_ci (key & UVERBS_API_ATTR_KEY_MASK) != 0; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* 27462306a36Sopenharmony_ci * This returns a value in the range [0 to UVERBS_API_ATTR_BKEY_LEN), 27562306a36Sopenharmony_ci * basically it undoes the reservation of 0 in the ID numbering. attr_key 27662306a36Sopenharmony_ci * must already be masked with UVERBS_API_ATTR_KEY_MASK, or be the output of 27762306a36Sopenharmony_ci * uapi_key_attr(). 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic inline __attribute_const__ u32 uapi_bkey_attr(u32 attr_key) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci return attr_key - 1; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic inline __attribute_const__ u32 uapi_bkey_to_key_attr(u32 attr_bkey) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci return attr_bkey + 1; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* 29062306a36Sopenharmony_ci * ======================================= 29162306a36Sopenharmony_ci * Verbs definitions 29262306a36Sopenharmony_ci * ======================================= 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistruct uverbs_attr_def { 29662306a36Sopenharmony_ci u16 id; 29762306a36Sopenharmony_ci struct uverbs_attr_spec attr; 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistruct uverbs_method_def { 30162306a36Sopenharmony_ci u16 id; 30262306a36Sopenharmony_ci /* Combination of bits from enum UVERBS_ACTION_FLAG_XXXX */ 30362306a36Sopenharmony_ci u32 flags; 30462306a36Sopenharmony_ci size_t num_attrs; 30562306a36Sopenharmony_ci const struct uverbs_attr_def * const (*attrs)[]; 30662306a36Sopenharmony_ci int (*handler)(struct uverbs_attr_bundle *attrs); 30762306a36Sopenharmony_ci}; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistruct uverbs_object_def { 31062306a36Sopenharmony_ci u16 id; 31162306a36Sopenharmony_ci const struct uverbs_obj_type *type_attrs; 31262306a36Sopenharmony_ci size_t num_methods; 31362306a36Sopenharmony_ci const struct uverbs_method_def * const (*methods)[]; 31462306a36Sopenharmony_ci}; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cienum uapi_definition_kind { 31762306a36Sopenharmony_ci UAPI_DEF_END = 0, 31862306a36Sopenharmony_ci UAPI_DEF_OBJECT_START, 31962306a36Sopenharmony_ci UAPI_DEF_WRITE, 32062306a36Sopenharmony_ci UAPI_DEF_CHAIN_OBJ_TREE, 32162306a36Sopenharmony_ci UAPI_DEF_CHAIN, 32262306a36Sopenharmony_ci UAPI_DEF_IS_SUPPORTED_FUNC, 32362306a36Sopenharmony_ci UAPI_DEF_IS_SUPPORTED_DEV_FN, 32462306a36Sopenharmony_ci}; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cienum uapi_definition_scope { 32762306a36Sopenharmony_ci UAPI_SCOPE_OBJECT = 1, 32862306a36Sopenharmony_ci UAPI_SCOPE_METHOD = 2, 32962306a36Sopenharmony_ci}; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistruct uapi_definition { 33262306a36Sopenharmony_ci u8 kind; 33362306a36Sopenharmony_ci u8 scope; 33462306a36Sopenharmony_ci union { 33562306a36Sopenharmony_ci struct { 33662306a36Sopenharmony_ci u16 object_id; 33762306a36Sopenharmony_ci } object_start; 33862306a36Sopenharmony_ci struct { 33962306a36Sopenharmony_ci u16 command_num; 34062306a36Sopenharmony_ci u8 is_ex:1; 34162306a36Sopenharmony_ci u8 has_udata:1; 34262306a36Sopenharmony_ci u8 has_resp:1; 34362306a36Sopenharmony_ci u8 req_size; 34462306a36Sopenharmony_ci u8 resp_size; 34562306a36Sopenharmony_ci } write; 34662306a36Sopenharmony_ci }; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci union { 34962306a36Sopenharmony_ci bool (*func_is_supported)(struct ib_device *device); 35062306a36Sopenharmony_ci int (*func_write)(struct uverbs_attr_bundle *attrs); 35162306a36Sopenharmony_ci const struct uapi_definition *chain; 35262306a36Sopenharmony_ci const struct uverbs_object_def *chain_obj_tree; 35362306a36Sopenharmony_ci size_t needs_fn_offset; 35462306a36Sopenharmony_ci }; 35562306a36Sopenharmony_ci}; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci/* Define things connected to object_id */ 35862306a36Sopenharmony_ci#define DECLARE_UVERBS_OBJECT(_object_id, ...) \ 35962306a36Sopenharmony_ci { \ 36062306a36Sopenharmony_ci .kind = UAPI_DEF_OBJECT_START, \ 36162306a36Sopenharmony_ci .object_start = { .object_id = _object_id }, \ 36262306a36Sopenharmony_ci }, \ 36362306a36Sopenharmony_ci ##__VA_ARGS__ 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/* Use in a var_args of DECLARE_UVERBS_OBJECT */ 36662306a36Sopenharmony_ci#define DECLARE_UVERBS_WRITE(_command_num, _func, _cmd_desc, ...) \ 36762306a36Sopenharmony_ci { \ 36862306a36Sopenharmony_ci .kind = UAPI_DEF_WRITE, \ 36962306a36Sopenharmony_ci .scope = UAPI_SCOPE_OBJECT, \ 37062306a36Sopenharmony_ci .write = { .is_ex = 0, .command_num = _command_num }, \ 37162306a36Sopenharmony_ci .func_write = _func, \ 37262306a36Sopenharmony_ci _cmd_desc, \ 37362306a36Sopenharmony_ci }, \ 37462306a36Sopenharmony_ci ##__VA_ARGS__ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/* Use in a var_args of DECLARE_UVERBS_OBJECT */ 37762306a36Sopenharmony_ci#define DECLARE_UVERBS_WRITE_EX(_command_num, _func, _cmd_desc, ...) \ 37862306a36Sopenharmony_ci { \ 37962306a36Sopenharmony_ci .kind = UAPI_DEF_WRITE, \ 38062306a36Sopenharmony_ci .scope = UAPI_SCOPE_OBJECT, \ 38162306a36Sopenharmony_ci .write = { .is_ex = 1, .command_num = _command_num }, \ 38262306a36Sopenharmony_ci .func_write = _func, \ 38362306a36Sopenharmony_ci _cmd_desc, \ 38462306a36Sopenharmony_ci }, \ 38562306a36Sopenharmony_ci ##__VA_ARGS__ 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/* 38862306a36Sopenharmony_ci * Object is only supported if the function pointer named ibdev_fn in struct 38962306a36Sopenharmony_ci * ib_device is not NULL. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci#define UAPI_DEF_OBJ_NEEDS_FN(ibdev_fn) \ 39262306a36Sopenharmony_ci { \ 39362306a36Sopenharmony_ci .kind = UAPI_DEF_IS_SUPPORTED_DEV_FN, \ 39462306a36Sopenharmony_ci .scope = UAPI_SCOPE_OBJECT, \ 39562306a36Sopenharmony_ci .needs_fn_offset = \ 39662306a36Sopenharmony_ci offsetof(struct ib_device_ops, ibdev_fn) + \ 39762306a36Sopenharmony_ci BUILD_BUG_ON_ZERO(sizeof_field(struct ib_device_ops, \ 39862306a36Sopenharmony_ci ibdev_fn) != \ 39962306a36Sopenharmony_ci sizeof(void *)), \ 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/* 40362306a36Sopenharmony_ci * Method is only supported if the function pointer named ibdev_fn in struct 40462306a36Sopenharmony_ci * ib_device is not NULL. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci#define UAPI_DEF_METHOD_NEEDS_FN(ibdev_fn) \ 40762306a36Sopenharmony_ci { \ 40862306a36Sopenharmony_ci .kind = UAPI_DEF_IS_SUPPORTED_DEV_FN, \ 40962306a36Sopenharmony_ci .scope = UAPI_SCOPE_METHOD, \ 41062306a36Sopenharmony_ci .needs_fn_offset = \ 41162306a36Sopenharmony_ci offsetof(struct ib_device_ops, ibdev_fn) + \ 41262306a36Sopenharmony_ci BUILD_BUG_ON_ZERO(sizeof_field(struct ib_device_ops, \ 41362306a36Sopenharmony_ci ibdev_fn) != \ 41462306a36Sopenharmony_ci sizeof(void *)), \ 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* Call a function to determine if the entire object is supported or not */ 41862306a36Sopenharmony_ci#define UAPI_DEF_IS_OBJ_SUPPORTED(_func) \ 41962306a36Sopenharmony_ci { \ 42062306a36Sopenharmony_ci .kind = UAPI_DEF_IS_SUPPORTED_FUNC, \ 42162306a36Sopenharmony_ci .scope = UAPI_SCOPE_OBJECT, .func_is_supported = _func, \ 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci/* Include another struct uapi_definition in this one */ 42562306a36Sopenharmony_ci#define UAPI_DEF_CHAIN(_def_var) \ 42662306a36Sopenharmony_ci { \ 42762306a36Sopenharmony_ci .kind = UAPI_DEF_CHAIN, .chain = _def_var, \ 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci/* Temporary until the tree base description is replaced */ 43162306a36Sopenharmony_ci#define UAPI_DEF_CHAIN_OBJ_TREE(_object_enum, _object_ptr, ...) \ 43262306a36Sopenharmony_ci { \ 43362306a36Sopenharmony_ci .kind = UAPI_DEF_CHAIN_OBJ_TREE, \ 43462306a36Sopenharmony_ci .object_start = { .object_id = _object_enum }, \ 43562306a36Sopenharmony_ci .chain_obj_tree = _object_ptr, \ 43662306a36Sopenharmony_ci }, \ 43762306a36Sopenharmony_ci ##__VA_ARGS__ 43862306a36Sopenharmony_ci#define UAPI_DEF_CHAIN_OBJ_TREE_NAMED(_object_enum, ...) \ 43962306a36Sopenharmony_ci UAPI_DEF_CHAIN_OBJ_TREE(_object_enum, \ 44062306a36Sopenharmony_ci PTR_IF(IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS), \ 44162306a36Sopenharmony_ci &UVERBS_OBJECT(_object_enum)), \ 44262306a36Sopenharmony_ci ##__VA_ARGS__) 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci/* 44562306a36Sopenharmony_ci * ======================================= 44662306a36Sopenharmony_ci * Attribute Specifications 44762306a36Sopenharmony_ci * ======================================= 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci#define UVERBS_ATTR_SIZE(_min_len, _len) \ 45162306a36Sopenharmony_ci .u.ptr.min_len = _min_len, .u.ptr.len = _len 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci#define UVERBS_ATTR_NO_DATA() UVERBS_ATTR_SIZE(0, 0) 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci/* 45662306a36Sopenharmony_ci * Specifies a uapi structure that cannot be extended. The user must always 45762306a36Sopenharmony_ci * supply the whole structure and nothing more. The structure must be declared 45862306a36Sopenharmony_ci * in a header under include/uapi/rdma. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci#define UVERBS_ATTR_TYPE(_type) \ 46162306a36Sopenharmony_ci .u.ptr.min_len = sizeof(_type), .u.ptr.len = sizeof(_type) 46262306a36Sopenharmony_ci/* 46362306a36Sopenharmony_ci * Specifies a uapi structure where the user must provide at least up to 46462306a36Sopenharmony_ci * member 'last'. Anything after last and up until the end of the structure 46562306a36Sopenharmony_ci * can be non-zero, anything longer than the end of the structure must be 46662306a36Sopenharmony_ci * zero. The structure must be declared in a header under include/uapi/rdma. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci#define UVERBS_ATTR_STRUCT(_type, _last) \ 46962306a36Sopenharmony_ci .zero_trailing = 1, \ 47062306a36Sopenharmony_ci UVERBS_ATTR_SIZE(offsetofend(_type, _last), sizeof(_type)) 47162306a36Sopenharmony_ci/* 47262306a36Sopenharmony_ci * Specifies at least min_len bytes must be passed in, but the amount can be 47362306a36Sopenharmony_ci * larger, up to the protocol maximum size. No check for zeroing is done. 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ci#define UVERBS_ATTR_MIN_SIZE(_min_len) UVERBS_ATTR_SIZE(_min_len, USHRT_MAX) 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci/* Must be used in the '...' of any UVERBS_ATTR */ 47862306a36Sopenharmony_ci#define UA_ALLOC_AND_COPY .alloc_and_copy = 1 47962306a36Sopenharmony_ci#define UA_MANDATORY .mandatory = 1 48062306a36Sopenharmony_ci#define UA_OPTIONAL .mandatory = 0 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci/* 48362306a36Sopenharmony_ci * min_len must be bigger than 0 and _max_len must be smaller than 4095. Only 48462306a36Sopenharmony_ci * READ\WRITE accesses are supported. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci#define UVERBS_ATTR_IDRS_ARR(_attr_id, _idr_type, _access, _min_len, _max_len, \ 48762306a36Sopenharmony_ci ...) \ 48862306a36Sopenharmony_ci (&(const struct uverbs_attr_def){ \ 48962306a36Sopenharmony_ci .id = (_attr_id) + \ 49062306a36Sopenharmony_ci BUILD_BUG_ON_ZERO((_min_len) == 0 || \ 49162306a36Sopenharmony_ci (_max_len) > \ 49262306a36Sopenharmony_ci PAGE_SIZE / sizeof(void *) || \ 49362306a36Sopenharmony_ci (_min_len) > (_max_len) || \ 49462306a36Sopenharmony_ci (_access) == UVERBS_ACCESS_NEW || \ 49562306a36Sopenharmony_ci (_access) == UVERBS_ACCESS_DESTROY), \ 49662306a36Sopenharmony_ci .attr = { .type = UVERBS_ATTR_TYPE_IDRS_ARRAY, \ 49762306a36Sopenharmony_ci .u2.objs_arr.obj_type = _idr_type, \ 49862306a36Sopenharmony_ci .u2.objs_arr.access = _access, \ 49962306a36Sopenharmony_ci .u2.objs_arr.min_len = _min_len, \ 50062306a36Sopenharmony_ci .u2.objs_arr.max_len = _max_len, \ 50162306a36Sopenharmony_ci __VA_ARGS__ } }) 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/* 50462306a36Sopenharmony_ci * Only for use with UVERBS_ATTR_IDR, allows any uobject type to be accepted, 50562306a36Sopenharmony_ci * the user must validate the type of the uobject instead. 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ci#define UVERBS_IDR_ANY_OBJECT 0xFFFF 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci#define UVERBS_ATTR_IDR(_attr_id, _idr_type, _access, ...) \ 51062306a36Sopenharmony_ci (&(const struct uverbs_attr_def){ \ 51162306a36Sopenharmony_ci .id = _attr_id, \ 51262306a36Sopenharmony_ci .attr = { .type = UVERBS_ATTR_TYPE_IDR, \ 51362306a36Sopenharmony_ci .u.obj.obj_type = _idr_type, \ 51462306a36Sopenharmony_ci .u.obj.access = _access, \ 51562306a36Sopenharmony_ci __VA_ARGS__ } }) 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci#define UVERBS_ATTR_FD(_attr_id, _fd_type, _access, ...) \ 51862306a36Sopenharmony_ci (&(const struct uverbs_attr_def){ \ 51962306a36Sopenharmony_ci .id = (_attr_id) + \ 52062306a36Sopenharmony_ci BUILD_BUG_ON_ZERO((_access) != UVERBS_ACCESS_NEW && \ 52162306a36Sopenharmony_ci (_access) != UVERBS_ACCESS_READ), \ 52262306a36Sopenharmony_ci .attr = { .type = UVERBS_ATTR_TYPE_FD, \ 52362306a36Sopenharmony_ci .u.obj.obj_type = _fd_type, \ 52462306a36Sopenharmony_ci .u.obj.access = _access, \ 52562306a36Sopenharmony_ci __VA_ARGS__ } }) 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci#define UVERBS_ATTR_RAW_FD(_attr_id, ...) \ 52862306a36Sopenharmony_ci (&(const struct uverbs_attr_def){ \ 52962306a36Sopenharmony_ci .id = (_attr_id), \ 53062306a36Sopenharmony_ci .attr = { .type = UVERBS_ATTR_TYPE_RAW_FD, __VA_ARGS__ } }) 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci#define UVERBS_ATTR_PTR_IN(_attr_id, _type, ...) \ 53362306a36Sopenharmony_ci (&(const struct uverbs_attr_def){ \ 53462306a36Sopenharmony_ci .id = _attr_id, \ 53562306a36Sopenharmony_ci .attr = { .type = UVERBS_ATTR_TYPE_PTR_IN, \ 53662306a36Sopenharmony_ci _type, \ 53762306a36Sopenharmony_ci __VA_ARGS__ } }) 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci#define UVERBS_ATTR_PTR_OUT(_attr_id, _type, ...) \ 54062306a36Sopenharmony_ci (&(const struct uverbs_attr_def){ \ 54162306a36Sopenharmony_ci .id = _attr_id, \ 54262306a36Sopenharmony_ci .attr = { .type = UVERBS_ATTR_TYPE_PTR_OUT, \ 54362306a36Sopenharmony_ci _type, \ 54462306a36Sopenharmony_ci __VA_ARGS__ } }) 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci/* _enum_arry should be a 'static const union uverbs_attr_spec[]' */ 54762306a36Sopenharmony_ci#define UVERBS_ATTR_ENUM_IN(_attr_id, _enum_arr, ...) \ 54862306a36Sopenharmony_ci (&(const struct uverbs_attr_def){ \ 54962306a36Sopenharmony_ci .id = _attr_id, \ 55062306a36Sopenharmony_ci .attr = { .type = UVERBS_ATTR_TYPE_ENUM_IN, \ 55162306a36Sopenharmony_ci .u2.enum_def.ids = _enum_arr, \ 55262306a36Sopenharmony_ci .u.enum_def.num_elems = ARRAY_SIZE(_enum_arr), \ 55362306a36Sopenharmony_ci __VA_ARGS__ }, \ 55462306a36Sopenharmony_ci }) 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci/* An input value that is a member in the enum _enum_type. */ 55762306a36Sopenharmony_ci#define UVERBS_ATTR_CONST_IN(_attr_id, _enum_type, ...) \ 55862306a36Sopenharmony_ci UVERBS_ATTR_PTR_IN( \ 55962306a36Sopenharmony_ci _attr_id, \ 56062306a36Sopenharmony_ci UVERBS_ATTR_SIZE( \ 56162306a36Sopenharmony_ci sizeof(u64) + BUILD_BUG_ON_ZERO(!sizeof(_enum_type)), \ 56262306a36Sopenharmony_ci sizeof(u64)), \ 56362306a36Sopenharmony_ci __VA_ARGS__) 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/* 56662306a36Sopenharmony_ci * An input value that is a bitwise combination of values of _enum_type. 56762306a36Sopenharmony_ci * This permits the flag value to be passed as either a u32 or u64, it must 56862306a36Sopenharmony_ci * be retrieved via uverbs_get_flag(). 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci#define UVERBS_ATTR_FLAGS_IN(_attr_id, _enum_type, ...) \ 57162306a36Sopenharmony_ci UVERBS_ATTR_PTR_IN( \ 57262306a36Sopenharmony_ci _attr_id, \ 57362306a36Sopenharmony_ci UVERBS_ATTR_SIZE(sizeof(u32) + BUILD_BUG_ON_ZERO( \ 57462306a36Sopenharmony_ci !sizeof(_enum_type *)), \ 57562306a36Sopenharmony_ci sizeof(u64)), \ 57662306a36Sopenharmony_ci __VA_ARGS__) 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/* 57962306a36Sopenharmony_ci * This spec is used in order to pass information to the hardware driver in a 58062306a36Sopenharmony_ci * legacy way. Every verb that could get driver specific data should get this 58162306a36Sopenharmony_ci * spec. 58262306a36Sopenharmony_ci */ 58362306a36Sopenharmony_ci#define UVERBS_ATTR_UHW() \ 58462306a36Sopenharmony_ci UVERBS_ATTR_PTR_IN(UVERBS_ATTR_UHW_IN, \ 58562306a36Sopenharmony_ci UVERBS_ATTR_MIN_SIZE(0), \ 58662306a36Sopenharmony_ci UA_OPTIONAL, \ 58762306a36Sopenharmony_ci .is_udata = 1), \ 58862306a36Sopenharmony_ci UVERBS_ATTR_PTR_OUT(UVERBS_ATTR_UHW_OUT, \ 58962306a36Sopenharmony_ci UVERBS_ATTR_MIN_SIZE(0), \ 59062306a36Sopenharmony_ci UA_OPTIONAL, \ 59162306a36Sopenharmony_ci .is_udata = 1) 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci/* ================================================= 59462306a36Sopenharmony_ci * Parsing infrastructure 59562306a36Sopenharmony_ci * ================================================= 59662306a36Sopenharmony_ci */ 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistruct uverbs_ptr_attr { 60062306a36Sopenharmony_ci /* 60162306a36Sopenharmony_ci * If UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY is set then the 'ptr' is 60262306a36Sopenharmony_ci * used. 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_ci union { 60562306a36Sopenharmony_ci void *ptr; 60662306a36Sopenharmony_ci u64 data; 60762306a36Sopenharmony_ci }; 60862306a36Sopenharmony_ci u16 len; 60962306a36Sopenharmony_ci u16 uattr_idx; 61062306a36Sopenharmony_ci u8 enum_id; 61162306a36Sopenharmony_ci}; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistruct uverbs_obj_attr { 61462306a36Sopenharmony_ci struct ib_uobject *uobject; 61562306a36Sopenharmony_ci const struct uverbs_api_attr *attr_elm; 61662306a36Sopenharmony_ci}; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistruct uverbs_objs_arr_attr { 61962306a36Sopenharmony_ci struct ib_uobject **uobjects; 62062306a36Sopenharmony_ci u16 len; 62162306a36Sopenharmony_ci}; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistruct uverbs_attr { 62462306a36Sopenharmony_ci union { 62562306a36Sopenharmony_ci struct uverbs_ptr_attr ptr_attr; 62662306a36Sopenharmony_ci struct uverbs_obj_attr obj_attr; 62762306a36Sopenharmony_ci struct uverbs_objs_arr_attr objs_arr_attr; 62862306a36Sopenharmony_ci }; 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistruct uverbs_attr_bundle { 63262306a36Sopenharmony_ci struct ib_udata driver_udata; 63362306a36Sopenharmony_ci struct ib_udata ucore; 63462306a36Sopenharmony_ci struct ib_uverbs_file *ufile; 63562306a36Sopenharmony_ci struct ib_ucontext *context; 63662306a36Sopenharmony_ci struct ib_uobject *uobject; 63762306a36Sopenharmony_ci DECLARE_BITMAP(attr_present, UVERBS_API_ATTR_BKEY_LEN); 63862306a36Sopenharmony_ci struct uverbs_attr attrs[]; 63962306a36Sopenharmony_ci}; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_bundle, 64262306a36Sopenharmony_ci unsigned int idx) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci return test_bit(uapi_bkey_attr(uapi_key_attr(idx)), 64562306a36Sopenharmony_ci attrs_bundle->attr_present); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci/** 64962306a36Sopenharmony_ci * rdma_udata_to_drv_context - Helper macro to get the driver's context out of 65062306a36Sopenharmony_ci * ib_udata which is embedded in uverbs_attr_bundle. 65162306a36Sopenharmony_ci * 65262306a36Sopenharmony_ci * If udata is not NULL this cannot fail. Otherwise a NULL udata will result 65362306a36Sopenharmony_ci * in a NULL ucontext pointer, as a safety precaution. Callers should be using 65462306a36Sopenharmony_ci * 'udata' to determine if the driver call is in user or kernel mode, not 65562306a36Sopenharmony_ci * 'ucontext'. 65662306a36Sopenharmony_ci * 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_cistatic inline struct uverbs_attr_bundle * 65962306a36Sopenharmony_cirdma_udata_to_uverbs_attr_bundle(struct ib_udata *udata) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci return container_of(udata, struct uverbs_attr_bundle, driver_udata); 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci#define rdma_udata_to_drv_context(udata, drv_dev_struct, member) \ 66562306a36Sopenharmony_ci (udata ? container_of(rdma_udata_to_uverbs_attr_bundle(udata)->context, \ 66662306a36Sopenharmony_ci drv_dev_struct, member) : (drv_dev_struct *)NULL) 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci#define IS_UVERBS_COPY_ERR(_ret) ((_ret) && (_ret) != -ENOENT) 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr_bundle *attrs_bundle, 67162306a36Sopenharmony_ci u16 idx) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci if (!uverbs_attr_is_valid(attrs_bundle, idx)) 67462306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return &attrs_bundle->attrs[uapi_bkey_attr(uapi_key_attr(idx))]; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic inline int uverbs_attr_get_enum_id(const struct uverbs_attr_bundle *attrs_bundle, 68062306a36Sopenharmony_ci u16 idx) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (IS_ERR(attr)) 68562306a36Sopenharmony_ci return PTR_ERR(attr); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return attr->ptr_attr.enum_id; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic inline void *uverbs_attr_get_obj(const struct uverbs_attr_bundle *attrs_bundle, 69162306a36Sopenharmony_ci u16 idx) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci const struct uverbs_attr *attr; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci attr = uverbs_attr_get(attrs_bundle, idx); 69662306a36Sopenharmony_ci if (IS_ERR(attr)) 69762306a36Sopenharmony_ci return ERR_CAST(attr); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci return attr->obj_attr.uobject->object; 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic inline struct ib_uobject *uverbs_attr_get_uobject(const struct uverbs_attr_bundle *attrs_bundle, 70362306a36Sopenharmony_ci u16 idx) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (IS_ERR(attr)) 70862306a36Sopenharmony_ci return ERR_CAST(attr); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci return attr->obj_attr.uobject; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic inline int 71462306a36Sopenharmony_ciuverbs_attr_get_len(const struct uverbs_attr_bundle *attrs_bundle, u16 idx) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (IS_ERR(attr)) 71962306a36Sopenharmony_ci return PTR_ERR(attr); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return attr->ptr_attr.len; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_civoid uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *attrs_bundle, 72562306a36Sopenharmony_ci u16 idx); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci/* 72862306a36Sopenharmony_ci * uverbs_attr_ptr_get_array_size() - Get array size pointer by a ptr 72962306a36Sopenharmony_ci * attribute. 73062306a36Sopenharmony_ci * @attrs: The attribute bundle 73162306a36Sopenharmony_ci * @idx: The ID of the attribute 73262306a36Sopenharmony_ci * @elem_size: The size of the element in the array 73362306a36Sopenharmony_ci */ 73462306a36Sopenharmony_cistatic inline int 73562306a36Sopenharmony_ciuverbs_attr_ptr_get_array_size(struct uverbs_attr_bundle *attrs, u16 idx, 73662306a36Sopenharmony_ci size_t elem_size) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci int size = uverbs_attr_get_len(attrs, idx); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (size < 0) 74162306a36Sopenharmony_ci return size; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (size % elem_size) 74462306a36Sopenharmony_ci return -EINVAL; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci return size / elem_size; 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci/** 75062306a36Sopenharmony_ci * uverbs_attr_get_uobjs_arr() - Provides array's properties for attribute for 75162306a36Sopenharmony_ci * UVERBS_ATTR_TYPE_IDRS_ARRAY. 75262306a36Sopenharmony_ci * @arr: Returned pointer to array of pointers for uobjects or NULL if 75362306a36Sopenharmony_ci * the attribute isn't provided. 75462306a36Sopenharmony_ci * 75562306a36Sopenharmony_ci * Return: The array length or 0 if no attribute was provided. 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_cistatic inline int uverbs_attr_get_uobjs_arr( 75862306a36Sopenharmony_ci const struct uverbs_attr_bundle *attrs_bundle, u16 attr_idx, 75962306a36Sopenharmony_ci struct ib_uobject ***arr) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci const struct uverbs_attr *attr = 76262306a36Sopenharmony_ci uverbs_attr_get(attrs_bundle, attr_idx); 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (IS_ERR(attr)) { 76562306a36Sopenharmony_ci *arr = NULL; 76662306a36Sopenharmony_ci return 0; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci *arr = attr->objs_arr_attr.uobjects; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return attr->objs_arr_attr.len; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data); 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic inline void *uverbs_attr_get_alloced_ptr( 78062306a36Sopenharmony_ci const struct uverbs_attr_bundle *attrs_bundle, u16 idx) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (IS_ERR(attr)) 78562306a36Sopenharmony_ci return (void *)attr; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci return uverbs_attr_ptr_is_inline(attr) ? (void *)&attr->ptr_attr.data : 78862306a36Sopenharmony_ci attr->ptr_attr.ptr; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic inline int _uverbs_copy_from(void *to, 79262306a36Sopenharmony_ci const struct uverbs_attr_bundle *attrs_bundle, 79362306a36Sopenharmony_ci size_t idx, 79462306a36Sopenharmony_ci size_t size) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (IS_ERR(attr)) 79962306a36Sopenharmony_ci return PTR_ERR(attr); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* 80262306a36Sopenharmony_ci * Validation ensures attr->ptr_attr.len >= size. If the caller is 80362306a36Sopenharmony_ci * using UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO then it must call 80462306a36Sopenharmony_ci * uverbs_copy_from_or_zero. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci if (unlikely(size < attr->ptr_attr.len)) 80762306a36Sopenharmony_ci return -EINVAL; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (uverbs_attr_ptr_is_inline(attr)) 81062306a36Sopenharmony_ci memcpy(to, &attr->ptr_attr.data, attr->ptr_attr.len); 81162306a36Sopenharmony_ci else if (copy_from_user(to, u64_to_user_ptr(attr->ptr_attr.data), 81262306a36Sopenharmony_ci attr->ptr_attr.len)) 81362306a36Sopenharmony_ci return -EFAULT; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci return 0; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic inline int _uverbs_copy_from_or_zero(void *to, 81962306a36Sopenharmony_ci const struct uverbs_attr_bundle *attrs_bundle, 82062306a36Sopenharmony_ci size_t idx, 82162306a36Sopenharmony_ci size_t size) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); 82462306a36Sopenharmony_ci size_t min_size; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (IS_ERR(attr)) 82762306a36Sopenharmony_ci return PTR_ERR(attr); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci min_size = min_t(size_t, size, attr->ptr_attr.len); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (uverbs_attr_ptr_is_inline(attr)) 83262306a36Sopenharmony_ci memcpy(to, &attr->ptr_attr.data, min_size); 83362306a36Sopenharmony_ci else if (copy_from_user(to, u64_to_user_ptr(attr->ptr_attr.data), 83462306a36Sopenharmony_ci min_size)) 83562306a36Sopenharmony_ci return -EFAULT; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (size > min_size) 83862306a36Sopenharmony_ci memset(to + min_size, 0, size - min_size); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci#define uverbs_copy_from(to, attrs_bundle, idx) \ 84462306a36Sopenharmony_ci _uverbs_copy_from(to, attrs_bundle, idx, sizeof(*to)) 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci#define uverbs_copy_from_or_zero(to, attrs_bundle, idx) \ 84762306a36Sopenharmony_ci _uverbs_copy_from_or_zero(to, attrs_bundle, idx, sizeof(*to)) 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic inline struct ib_ucontext * 85062306a36Sopenharmony_ciib_uverbs_get_ucontext(const struct uverbs_attr_bundle *attrs) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci return ib_uverbs_get_ucontext_file(attrs->ufile); 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS) 85662306a36Sopenharmony_ciint uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle, 85762306a36Sopenharmony_ci size_t idx, u64 allowed_bits); 85862306a36Sopenharmony_ciint uverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, 85962306a36Sopenharmony_ci size_t idx, u64 allowed_bits); 86062306a36Sopenharmony_ciint uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, size_t idx, 86162306a36Sopenharmony_ci const void *from, size_t size); 86262306a36Sopenharmony_ci__malloc void *_uverbs_alloc(struct uverbs_attr_bundle *bundle, size_t size, 86362306a36Sopenharmony_ci gfp_t flags); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic inline __malloc void *uverbs_alloc(struct uverbs_attr_bundle *bundle, 86662306a36Sopenharmony_ci size_t size) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci return _uverbs_alloc(bundle, size, GFP_KERNEL); 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle, 87262306a36Sopenharmony_ci size_t size) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci return _uverbs_alloc(bundle, size, GFP_KERNEL | __GFP_ZERO); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic inline __malloc void *uverbs_kcalloc(struct uverbs_attr_bundle *bundle, 87862306a36Sopenharmony_ci size_t n, size_t size) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci size_t bytes; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (unlikely(check_mul_overflow(n, size, &bytes))) 88362306a36Sopenharmony_ci return ERR_PTR(-EOVERFLOW); 88462306a36Sopenharmony_ci return uverbs_zalloc(bundle, bytes); 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ciint _uverbs_get_const_signed(s64 *to, 88862306a36Sopenharmony_ci const struct uverbs_attr_bundle *attrs_bundle, 88962306a36Sopenharmony_ci size_t idx, s64 lower_bound, u64 upper_bound, 89062306a36Sopenharmony_ci s64 *def_val); 89162306a36Sopenharmony_ciint _uverbs_get_const_unsigned(u64 *to, 89262306a36Sopenharmony_ci const struct uverbs_attr_bundle *attrs_bundle, 89362306a36Sopenharmony_ci size_t idx, u64 upper_bound, u64 *def_val); 89462306a36Sopenharmony_ciint uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle, 89562306a36Sopenharmony_ci size_t idx, const void *from, size_t size); 89662306a36Sopenharmony_ci#else 89762306a36Sopenharmony_cistatic inline int 89862306a36Sopenharmony_ciuverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle, 89962306a36Sopenharmony_ci size_t idx, u64 allowed_bits) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci return -EINVAL; 90262306a36Sopenharmony_ci} 90362306a36Sopenharmony_cistatic inline int 90462306a36Sopenharmony_ciuverbs_get_flags32(u32 *to, const struct uverbs_attr_bundle *attrs_bundle, 90562306a36Sopenharmony_ci size_t idx, u64 allowed_bits) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci return -EINVAL; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_cistatic inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, 91062306a36Sopenharmony_ci size_t idx, const void *from, size_t size) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci return -EINVAL; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_cistatic inline __malloc void *uverbs_alloc(struct uverbs_attr_bundle *bundle, 91562306a36Sopenharmony_ci size_t size) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_cistatic inline __malloc void *uverbs_zalloc(struct uverbs_attr_bundle *bundle, 92062306a36Sopenharmony_ci size_t size) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_cistatic inline int 92562306a36Sopenharmony_ci_uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle, 92662306a36Sopenharmony_ci size_t idx, s64 lower_bound, u64 upper_bound, 92762306a36Sopenharmony_ci s64 *def_val) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci return -EINVAL; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_cistatic inline int 93262306a36Sopenharmony_ciuverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle, 93362306a36Sopenharmony_ci size_t idx, const void *from, size_t size) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci return -EINVAL; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_cistatic inline int 93862306a36Sopenharmony_ci_uverbs_get_const_signed(s64 *to, 93962306a36Sopenharmony_ci const struct uverbs_attr_bundle *attrs_bundle, 94062306a36Sopenharmony_ci size_t idx, s64 lower_bound, u64 upper_bound, 94162306a36Sopenharmony_ci s64 *def_val) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci return -EINVAL; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_cistatic inline int 94662306a36Sopenharmony_ci_uverbs_get_const_unsigned(u64 *to, 94762306a36Sopenharmony_ci const struct uverbs_attr_bundle *attrs_bundle, 94862306a36Sopenharmony_ci size_t idx, u64 upper_bound, u64 *def_val) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci return -EINVAL; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci#endif 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci#define uverbs_get_const_signed(_to, _attrs_bundle, _idx) \ 95562306a36Sopenharmony_ci ({ \ 95662306a36Sopenharmony_ci s64 _val; \ 95762306a36Sopenharmony_ci int _ret = \ 95862306a36Sopenharmony_ci _uverbs_get_const_signed(&_val, _attrs_bundle, _idx, \ 95962306a36Sopenharmony_ci type_min(typeof(*(_to))), \ 96062306a36Sopenharmony_ci type_max(typeof(*(_to))), NULL); \ 96162306a36Sopenharmony_ci (*(_to)) = _val; \ 96262306a36Sopenharmony_ci _ret; \ 96362306a36Sopenharmony_ci }) 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci#define uverbs_get_const_unsigned(_to, _attrs_bundle, _idx) \ 96662306a36Sopenharmony_ci ({ \ 96762306a36Sopenharmony_ci u64 _val; \ 96862306a36Sopenharmony_ci int _ret = \ 96962306a36Sopenharmony_ci _uverbs_get_const_unsigned(&_val, _attrs_bundle, _idx, \ 97062306a36Sopenharmony_ci type_max(typeof(*(_to))), NULL); \ 97162306a36Sopenharmony_ci (*(_to)) = _val; \ 97262306a36Sopenharmony_ci _ret; \ 97362306a36Sopenharmony_ci }) 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci#define uverbs_get_const_default_signed(_to, _attrs_bundle, _idx, _default) \ 97662306a36Sopenharmony_ci ({ \ 97762306a36Sopenharmony_ci s64 _val; \ 97862306a36Sopenharmony_ci s64 _def_val = _default; \ 97962306a36Sopenharmony_ci int _ret = \ 98062306a36Sopenharmony_ci _uverbs_get_const_signed(&_val, _attrs_bundle, _idx, \ 98162306a36Sopenharmony_ci type_min(typeof(*(_to))), \ 98262306a36Sopenharmony_ci type_max(typeof(*(_to))), &_def_val); \ 98362306a36Sopenharmony_ci (*(_to)) = _val; \ 98462306a36Sopenharmony_ci _ret; \ 98562306a36Sopenharmony_ci }) 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci#define uverbs_get_const_default_unsigned(_to, _attrs_bundle, _idx, _default) \ 98862306a36Sopenharmony_ci ({ \ 98962306a36Sopenharmony_ci u64 _val; \ 99062306a36Sopenharmony_ci u64 _def_val = _default; \ 99162306a36Sopenharmony_ci int _ret = \ 99262306a36Sopenharmony_ci _uverbs_get_const_unsigned(&_val, _attrs_bundle, _idx, \ 99362306a36Sopenharmony_ci type_max(typeof(*(_to))), &_def_val); \ 99462306a36Sopenharmony_ci (*(_to)) = _val; \ 99562306a36Sopenharmony_ci _ret; \ 99662306a36Sopenharmony_ci }) 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci#define uverbs_get_const(_to, _attrs_bundle, _idx) \ 99962306a36Sopenharmony_ci (is_signed_type(typeof(*(_to))) ? \ 100062306a36Sopenharmony_ci uverbs_get_const_signed(_to, _attrs_bundle, _idx) : \ 100162306a36Sopenharmony_ci uverbs_get_const_unsigned(_to, _attrs_bundle, _idx)) \ 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci#define uverbs_get_const_default(_to, _attrs_bundle, _idx, _default) \ 100462306a36Sopenharmony_ci (is_signed_type(typeof(*(_to))) ? \ 100562306a36Sopenharmony_ci uverbs_get_const_default_signed(_to, _attrs_bundle, _idx, \ 100662306a36Sopenharmony_ci _default) : \ 100762306a36Sopenharmony_ci uverbs_get_const_default_unsigned(_to, _attrs_bundle, _idx, \ 100862306a36Sopenharmony_ci _default)) 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cistatic inline int 101162306a36Sopenharmony_ciuverbs_get_raw_fd(int *to, const struct uverbs_attr_bundle *attrs_bundle, 101262306a36Sopenharmony_ci size_t idx) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci return uverbs_get_const_signed(to, attrs_bundle, idx); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci#endif 1018