]>
Commit | Line | Data |
---|---|---|
a0aa309c MB |
1 | /* |
2 | * Copyright (c) 2017, Mellanox Technologies inc. All rights reserved. | |
3 | * | |
4 | * This software is available to you under a choice of one of two | |
5 | * licenses. You may choose to be licensed under the terms of the GNU | |
6 | * General Public License (GPL) Version 2, available from the file | |
7 | * COPYING in the main directory of this source tree, or the | |
8 | * OpenIB.org BSD license below: | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or | |
11 | * without modification, are permitted provided that the following | |
12 | * conditions are met: | |
13 | * | |
14 | * - Redistributions of source code must retain the above | |
15 | * copyright notice, this list of conditions and the following | |
16 | * disclaimer. | |
17 | * | |
18 | * - Redistributions in binary form must reproduce the above | |
19 | * copyright notice, this list of conditions and the following | |
20 | * disclaimer in the documentation and/or other materials | |
21 | * provided with the distribution. | |
22 | * | |
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | |
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | |
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
30 | * SOFTWARE. | |
31 | */ | |
32 | ||
33 | #ifndef _UVERBS_IOCTL_ | |
34 | #define _UVERBS_IOCTL_ | |
35 | ||
36 | #include <rdma/uverbs_types.h> | |
35410306 MB |
37 | #include <linux/uaccess.h> |
38 | #include <rdma/rdma_user_ioctl.h> | |
d70724f1 | 39 | #include <rdma/ib_user_ioctl_verbs.h> |
1f7ff9d5 | 40 | #include <rdma/ib_user_ioctl_cmds.h> |
a0aa309c MB |
41 | |
42 | /* | |
43 | * ======================================= | |
44 | * Verbs action specifications | |
45 | * ======================================= | |
46 | */ | |
47 | ||
f43dbebf MB |
48 | enum uverbs_attr_type { |
49 | UVERBS_ATTR_TYPE_NA, | |
fac9658c MB |
50 | UVERBS_ATTR_TYPE_PTR_IN, |
51 | UVERBS_ATTR_TYPE_PTR_OUT, | |
f43dbebf MB |
52 | UVERBS_ATTR_TYPE_IDR, |
53 | UVERBS_ATTR_TYPE_FD, | |
494c5580 | 54 | UVERBS_ATTR_TYPE_ENUM_IN, |
f43dbebf MB |
55 | }; |
56 | ||
a0aa309c MB |
57 | enum uverbs_obj_access { |
58 | UVERBS_ACCESS_READ, | |
59 | UVERBS_ACCESS_WRITE, | |
60 | UVERBS_ACCESS_NEW, | |
61 | UVERBS_ACCESS_DESTROY | |
62 | }; | |
63 | ||
fac9658c MB |
64 | enum { |
65 | UVERBS_ATTR_SPEC_F_MANDATORY = 1U << 0, | |
c66db311 MB |
66 | /* Support extending attributes by length, validate all unknown size == zero */ |
67 | UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO = 1U << 1, | |
8762d149 MB |
68 | /* |
69 | * Valid only for PTR_IN. Allocate and copy the data inside the parser | |
70 | */ | |
71 | UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY = 1U << 2, | |
fac9658c MB |
72 | }; |
73 | ||
1f07e08f | 74 | /* Specification of a single attribute inside the ioctl message */ |
f43dbebf | 75 | struct uverbs_attr_spec { |
fac9658c | 76 | union { |
1f07e08f | 77 | /* Header shared by all following union members - to reduce space. */ |
fac9658c | 78 | struct { |
1f07e08f MB |
79 | enum uverbs_attr_type type; |
80 | /* Combination of bits from enum UVERBS_ATTR_SPEC_F_XXXX */ | |
81 | u8 flags; | |
82 | }; | |
83 | struct { | |
84 | enum uverbs_attr_type type; | |
85 | /* Combination of bits from enum UVERBS_ATTR_SPEC_F_XXXX */ | |
86 | u8 flags; | |
c66db311 | 87 | /* Current known size to kernel */ |
1f07e08f | 88 | u16 len; |
c66db311 MB |
89 | /* User isn't allowed to provide something < min_len */ |
90 | u16 min_len; | |
1f07e08f MB |
91 | } ptr; |
92 | struct { | |
93 | enum uverbs_attr_type type; | |
94 | /* Combination of bits from enum UVERBS_ATTR_SPEC_F_XXXX */ | |
95 | u8 flags; | |
fac9658c MB |
96 | /* |
97 | * higher bits mean the namespace and lower bits mean | |
98 | * the type id within the namespace. | |
99 | */ | |
100 | u16 obj_type; | |
101 | u8 access; | |
102 | } obj; | |
494c5580 MB |
103 | struct { |
104 | enum uverbs_attr_type type; | |
105 | /* Combination of bits from enum UVERBS_ATTR_SPEC_F_XXXX */ | |
106 | u8 flags; | |
107 | u8 num_elems; | |
108 | /* | |
109 | * The enum attribute can select one of the attributes | |
110 | * contained in the ids array. Currently only PTR_IN | |
111 | * attributes are supported in the ids array. | |
112 | */ | |
113 | const struct uverbs_attr_spec *ids; | |
114 | } enum_def; | |
fac9658c | 115 | }; |
f43dbebf MB |
116 | }; |
117 | ||
118 | struct uverbs_attr_spec_hash { | |
119 | size_t num_attrs; | |
fac9658c | 120 | unsigned long *mandatory_attrs_bitmask; |
f43dbebf MB |
121 | struct uverbs_attr_spec attrs[0]; |
122 | }; | |
123 | ||
fac9658c MB |
124 | struct uverbs_attr_bundle; |
125 | struct ib_uverbs_file; | |
126 | ||
127 | enum { | |
128 | /* | |
129 | * Action marked with this flag creates a context (or root for all | |
130 | * objects). | |
131 | */ | |
132 | UVERBS_ACTION_FLAG_CREATE_ROOT = 1U << 0, | |
133 | }; | |
134 | ||
135 | struct uverbs_method_spec { | |
136 | /* Combination of bits from enum UVERBS_ACTION_FLAG_XXXX */ | |
137 | u32 flags; | |
138 | size_t num_buckets; | |
139 | size_t num_child_attrs; | |
140 | int (*handler)(struct ib_device *ib_dev, struct ib_uverbs_file *ufile, | |
141 | struct uverbs_attr_bundle *ctx); | |
142 | struct uverbs_attr_spec_hash *attr_buckets[0]; | |
143 | }; | |
144 | ||
145 | struct uverbs_method_spec_hash { | |
146 | size_t num_methods; | |
147 | struct uverbs_method_spec *methods[0]; | |
148 | }; | |
149 | ||
150 | struct uverbs_object_spec { | |
151 | const struct uverbs_obj_type *type_attrs; | |
152 | size_t num_buckets; | |
153 | struct uverbs_method_spec_hash *method_buckets[0]; | |
154 | }; | |
155 | ||
156 | struct uverbs_object_spec_hash { | |
157 | size_t num_objects; | |
158 | struct uverbs_object_spec *objects[0]; | |
159 | }; | |
160 | ||
161 | struct uverbs_root_spec { | |
162 | size_t num_buckets; | |
163 | struct uverbs_object_spec_hash *object_buckets[0]; | |
164 | }; | |
165 | ||
5009010f MB |
166 | /* |
167 | * ======================================= | |
168 | * Verbs definitions | |
169 | * ======================================= | |
170 | */ | |
171 | ||
09e3ebf8 MB |
172 | struct uverbs_attr_def { |
173 | u16 id; | |
174 | struct uverbs_attr_spec attr; | |
175 | }; | |
176 | ||
177 | struct uverbs_method_def { | |
178 | u16 id; | |
179 | /* Combination of bits from enum UVERBS_ACTION_FLAG_XXXX */ | |
180 | u32 flags; | |
181 | size_t num_attrs; | |
182 | const struct uverbs_attr_def * const (*attrs)[]; | |
183 | int (*handler)(struct ib_device *ib_dev, struct ib_uverbs_file *ufile, | |
184 | struct uverbs_attr_bundle *ctx); | |
185 | }; | |
186 | ||
5009010f | 187 | struct uverbs_object_def { |
09e3ebf8 | 188 | u16 id; |
5009010f | 189 | const struct uverbs_obj_type *type_attrs; |
09e3ebf8 MB |
190 | size_t num_methods; |
191 | const struct uverbs_method_def * const (*methods)[]; | |
192 | }; | |
193 | ||
194 | struct uverbs_object_tree_def { | |
195 | size_t num_objects; | |
196 | const struct uverbs_object_def * const (*objects)[]; | |
5009010f MB |
197 | }; |
198 | ||
35410306 | 199 | #define UA_FLAGS(_flags) .flags = _flags |
c66db311 | 200 | #define __UVERBS_ATTR0(_id, _type, _fld, _attr, ...) \ |
35410306 | 201 | ((const struct uverbs_attr_def) \ |
c66db311 MB |
202 | {.id = _id, .attr = {{._fld = {.type = _type, _attr, .flags = 0, } }, } }) |
203 | #define __UVERBS_ATTR1(_id, _type, _fld, _attr, _extra1, ...) \ | |
35410306 | 204 | ((const struct uverbs_attr_def) \ |
c66db311 MB |
205 | {.id = _id, .attr = {{._fld = {.type = _type, _attr, _extra1 } },} }) |
206 | #define __UVERBS_ATTR2(_id, _type, _fld, _attr, _extra1, _extra2) \ | |
207 | ((const struct uverbs_attr_def) \ | |
208 | {.id = _id, .attr = {{._fld = {.type = _type, _attr, _extra1, _extra2 } },} }) | |
209 | #define __UVERBS_ATTR(_id, _type, _fld, _attr, _extra1, _extra2, _n, ...) \ | |
210 | __UVERBS_ATTR##_n(_id, _type, _fld, _attr, _extra1, _extra2) | |
211 | ||
212 | #define UVERBS_ATTR_TYPE(_type) \ | |
213 | .min_len = sizeof(_type), .len = sizeof(_type) | |
214 | #define UVERBS_ATTR_STRUCT(_type, _last) \ | |
215 | .min_len = ((uintptr_t)(&((_type *)0)->_last + 1)), .len = sizeof(_type) | |
216 | #define UVERBS_ATTR_SIZE(_min_len, _len) \ | |
217 | .min_len = _min_len, .len = _len | |
2d9c1bd7 MB |
218 | #define UVERBS_ATTR_MIN_SIZE(_min_len) \ |
219 | UVERBS_ATTR_SIZE(_min_len, USHRT_MAX) | |
c66db311 | 220 | |
35410306 MB |
221 | /* |
222 | * In new compiler, UVERBS_ATTR could be simplified by declaring it as | |
223 | * [_id] = {.type = _type, .len = _len, ##__VA_ARGS__} | |
224 | * But since we support older compilers too, we need the more complex code. | |
225 | */ | |
c66db311 MB |
226 | #define UVERBS_ATTR(_id, _type, _fld, _attr, ...) \ |
227 | __UVERBS_ATTR(_id, _type, _fld, _attr, ##__VA_ARGS__, 2, 1, 0) | |
35410306 | 228 | #define UVERBS_ATTR_PTR_IN_SZ(_id, _len, ...) \ |
c66db311 | 229 | UVERBS_ATTR(_id, UVERBS_ATTR_TYPE_PTR_IN, ptr, _len, ##__VA_ARGS__) |
35410306 MB |
230 | /* If sizeof(_type) <= sizeof(u64), this will be inlined rather than a pointer */ |
231 | #define UVERBS_ATTR_PTR_IN(_id, _type, ...) \ | |
c66db311 | 232 | UVERBS_ATTR_PTR_IN_SZ(_id, _type, ##__VA_ARGS__) |
35410306 | 233 | #define UVERBS_ATTR_PTR_OUT_SZ(_id, _len, ...) \ |
c66db311 | 234 | UVERBS_ATTR(_id, UVERBS_ATTR_TYPE_PTR_OUT, ptr, _len, ##__VA_ARGS__) |
35410306 | 235 | #define UVERBS_ATTR_PTR_OUT(_id, _type, ...) \ |
c66db311 | 236 | UVERBS_ATTR_PTR_OUT_SZ(_id, _type, ##__VA_ARGS__) |
494c5580 MB |
237 | #define UVERBS_ATTR_ENUM_IN(_id, _enum_arr, ...) \ |
238 | UVERBS_ATTR(_id, UVERBS_ATTR_TYPE_ENUM_IN, enum_def, \ | |
239 | .ids = (_enum_arr), \ | |
240 | .num_elems = ARRAY_SIZE(_enum_arr), ##__VA_ARGS__) | |
35410306 MB |
241 | |
242 | /* | |
243 | * In new compiler, UVERBS_ATTR_IDR (and FD) could be simplified by declaring | |
244 | * it as | |
245 | * {.id = _id, \ | |
246 | * .attr {.type = __obj_class, \ | |
247 | * .obj = {.obj_type = _idr_type, \ | |
248 | * .access = _access \ | |
249 | * }, ##__VA_ARGS__ } } | |
250 | * But since we support older compilers too, we need the more complex code. | |
251 | */ | |
252 | #define ___UVERBS_ATTR_OBJ0(_id, _obj_class, _obj_type, _access, ...)\ | |
253 | ((const struct uverbs_attr_def) \ | |
254 | {.id = _id, \ | |
1f07e08f MB |
255 | .attr = { {.obj = {.type = _obj_class, .obj_type = _obj_type, \ |
256 | .access = _access, .flags = 0 } }, } }) | |
35410306 MB |
257 | #define ___UVERBS_ATTR_OBJ1(_id, _obj_class, _obj_type, _access, _flags)\ |
258 | ((const struct uverbs_attr_def) \ | |
259 | {.id = _id, \ | |
1f07e08f MB |
260 | .attr = { {.obj = {.type = _obj_class, .obj_type = _obj_type, \ |
261 | .access = _access, _flags} }, } }) | |
35410306 MB |
262 | #define ___UVERBS_ATTR_OBJ(_id, _obj_class, _obj_type, _access, _flags, \ |
263 | _n, ...) \ | |
264 | ___UVERBS_ATTR_OBJ##_n(_id, _obj_class, _obj_type, _access, _flags) | |
265 | #define __UVERBS_ATTR_OBJ(_id, _obj_class, _obj_type, _access, ...) \ | |
266 | ___UVERBS_ATTR_OBJ(_id, _obj_class, _obj_type, _access, \ | |
267 | ##__VA_ARGS__, 1, 0) | |
268 | #define UVERBS_ATTR_IDR(_id, _idr_type, _access, ...) \ | |
269 | __UVERBS_ATTR_OBJ(_id, UVERBS_ATTR_TYPE_IDR, _idr_type, _access,\ | |
270 | ##__VA_ARGS__) | |
271 | #define UVERBS_ATTR_FD(_id, _fd_type, _access, ...) \ | |
272 | __UVERBS_ATTR_OBJ(_id, UVERBS_ATTR_TYPE_FD, _fd_type, \ | |
273 | (_access) + BUILD_BUG_ON_ZERO( \ | |
274 | (_access) != UVERBS_ACCESS_NEW && \ | |
275 | (_access) != UVERBS_ACCESS_READ), \ | |
276 | ##__VA_ARGS__) | |
277 | #define DECLARE_UVERBS_ATTR_SPEC(_name, ...) \ | |
278 | const struct uverbs_attr_def _name = __VA_ARGS__ | |
279 | ||
494c5580 MB |
280 | #define DECLARE_UVERBS_ENUM(_name, ...) \ |
281 | const struct uverbs_enum_spec _name = { \ | |
282 | .len = ARRAY_SIZE(((struct uverbs_attr_spec[]){__VA_ARGS__})),\ | |
283 | .ids = {__VA_ARGS__}, \ | |
284 | } | |
35410306 MB |
285 | #define _UVERBS_METHOD_ATTRS_SZ(...) \ |
286 | (sizeof((const struct uverbs_attr_def * const []){__VA_ARGS__}) /\ | |
287 | sizeof(const struct uverbs_attr_def *)) | |
288 | #define _UVERBS_METHOD(_id, _handler, _flags, ...) \ | |
289 | ((const struct uverbs_method_def) { \ | |
290 | .id = _id, \ | |
291 | .flags = _flags, \ | |
292 | .handler = _handler, \ | |
293 | .num_attrs = _UVERBS_METHOD_ATTRS_SZ(__VA_ARGS__), \ | |
294 | .attrs = &(const struct uverbs_attr_def * const []){__VA_ARGS__} }) | |
295 | #define DECLARE_UVERBS_METHOD(_name, _id, _handler, ...) \ | |
296 | const struct uverbs_method_def _name = \ | |
297 | _UVERBS_METHOD(_id, _handler, 0, ##__VA_ARGS__) | |
298 | #define DECLARE_UVERBS_CTX_METHOD(_name, _id, _handler, _flags, ...) \ | |
299 | const struct uverbs_method_def _name = \ | |
300 | _UVERBS_METHOD(_id, _handler, \ | |
301 | UVERBS_ACTION_FLAG_CREATE_ROOT, \ | |
302 | ##__VA_ARGS__) | |
303 | #define _UVERBS_OBJECT_METHODS_SZ(...) \ | |
304 | (sizeof((const struct uverbs_method_def * const []){__VA_ARGS__}) / \ | |
305 | sizeof(const struct uverbs_method_def *)) | |
5009010f MB |
306 | #define _UVERBS_OBJECT(_id, _type_attrs, ...) \ |
307 | ((const struct uverbs_object_def) { \ | |
09e3ebf8 | 308 | .id = _id, \ |
35410306 MB |
309 | .type_attrs = _type_attrs, \ |
310 | .num_methods = _UVERBS_OBJECT_METHODS_SZ(__VA_ARGS__), \ | |
311 | .methods = &(const struct uverbs_method_def * const []){__VA_ARGS__} }) | |
5009010f MB |
312 | #define DECLARE_UVERBS_OBJECT(_name, _id, _type_attrs, ...) \ |
313 | const struct uverbs_object_def _name = \ | |
314 | _UVERBS_OBJECT(_id, _type_attrs, ##__VA_ARGS__) | |
09e3ebf8 MB |
315 | #define _UVERBS_TREE_OBJECTS_SZ(...) \ |
316 | (sizeof((const struct uverbs_object_def * const []){__VA_ARGS__}) / \ | |
317 | sizeof(const struct uverbs_object_def *)) | |
318 | #define _UVERBS_OBJECT_TREE(...) \ | |
319 | ((const struct uverbs_object_tree_def) { \ | |
320 | .num_objects = _UVERBS_TREE_OBJECTS_SZ(__VA_ARGS__), \ | |
321 | .objects = &(const struct uverbs_object_def * const []){__VA_ARGS__} }) | |
322 | #define DECLARE_UVERBS_OBJECT_TREE(_name, ...) \ | |
323 | const struct uverbs_object_tree_def _name = \ | |
324 | _UVERBS_OBJECT_TREE(__VA_ARGS__) | |
325 | ||
fac9658c MB |
326 | /* ================================================= |
327 | * Parsing infrastructure | |
328 | * ================================================= | |
329 | */ | |
330 | ||
331 | struct uverbs_ptr_attr { | |
8762d149 MB |
332 | /* |
333 | * If UVERBS_ATTR_SPEC_F_ALLOC_AND_COPY is set then the 'ptr' is | |
334 | * used. | |
335 | */ | |
336 | union { | |
337 | void *ptr; | |
338 | u64 data; | |
339 | }; | |
fac9658c MB |
340 | u16 len; |
341 | /* Combination of bits from enum UVERBS_ATTR_F_XXXX */ | |
342 | u16 flags; | |
494c5580 | 343 | u8 enum_id; |
fac9658c MB |
344 | }; |
345 | ||
f43dbebf MB |
346 | struct uverbs_obj_attr { |
347 | struct ib_uobject *uobject; | |
348 | }; | |
349 | ||
350 | struct uverbs_attr { | |
fac9658c MB |
351 | /* |
352 | * pointer to the user-space given attribute, in order to write the | |
353 | * new uobject's id or update flags. | |
354 | */ | |
355 | struct ib_uverbs_attr __user *uattr; | |
356 | union { | |
357 | struct uverbs_ptr_attr ptr_attr; | |
358 | struct uverbs_obj_attr obj_attr; | |
359 | }; | |
f43dbebf MB |
360 | }; |
361 | ||
362 | struct uverbs_attr_bundle_hash { | |
363 | /* if bit i is set, it means attrs[i] contains valid information */ | |
364 | unsigned long *valid_bitmap; | |
365 | size_t num_attrs; | |
366 | /* | |
367 | * arrays of attributes, each element corresponds to the specification | |
368 | * of the attribute in the same index. | |
369 | */ | |
370 | struct uverbs_attr *attrs; | |
371 | }; | |
372 | ||
373 | struct uverbs_attr_bundle { | |
374 | size_t num_buckets; | |
375 | struct uverbs_attr_bundle_hash hash[]; | |
376 | }; | |
377 | ||
378 | static inline bool uverbs_attr_is_valid_in_hash(const struct uverbs_attr_bundle_hash *attrs_hash, | |
379 | unsigned int idx) | |
380 | { | |
381 | return test_bit(idx, attrs_hash->valid_bitmap); | |
382 | } | |
383 | ||
35410306 MB |
384 | static inline bool uverbs_attr_is_valid(const struct uverbs_attr_bundle *attrs_bundle, |
385 | unsigned int idx) | |
386 | { | |
387 | u16 idx_bucket = idx >> UVERBS_ID_NS_SHIFT; | |
388 | ||
389 | if (attrs_bundle->num_buckets <= idx_bucket) | |
390 | return false; | |
391 | ||
392 | return uverbs_attr_is_valid_in_hash(&attrs_bundle->hash[idx_bucket], | |
393 | idx & ~UVERBS_ID_NS_MASK); | |
394 | } | |
395 | ||
41b2a71f MB |
396 | #define IS_UVERBS_COPY_ERR(_ret) ((_ret) && (_ret) != -ENOENT) |
397 | ||
d70724f1 MB |
398 | static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr_bundle *attrs_bundle, |
399 | u16 idx) | |
400 | { | |
401 | u16 idx_bucket = idx >> UVERBS_ID_NS_SHIFT; | |
402 | ||
403 | if (!uverbs_attr_is_valid(attrs_bundle, idx)) | |
404 | return ERR_PTR(-ENOENT); | |
405 | ||
406 | return &attrs_bundle->hash[idx_bucket].attrs[idx & ~UVERBS_ID_NS_MASK]; | |
407 | } | |
408 | ||
494c5580 MB |
409 | static inline int uverbs_attr_get_enum_id(const struct uverbs_attr_bundle *attrs_bundle, |
410 | u16 idx) | |
411 | { | |
412 | const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); | |
413 | ||
414 | if (IS_ERR(attr)) | |
415 | return PTR_ERR(attr); | |
416 | ||
417 | return attr->ptr_attr.enum_id; | |
418 | } | |
419 | ||
be934cca AL |
420 | static inline void *uverbs_attr_get_obj(const struct uverbs_attr_bundle *attrs_bundle, |
421 | u16 idx) | |
422 | { | |
f4602cbb | 423 | const struct uverbs_attr *attr; |
be934cca | 424 | |
f4602cbb JG |
425 | attr = uverbs_attr_get(attrs_bundle, idx); |
426 | if (IS_ERR(attr)) | |
427 | return ERR_CAST(attr); | |
be934cca | 428 | |
f4602cbb | 429 | return attr->obj_attr.uobject->object; |
be934cca AL |
430 | } |
431 | ||
3efa3812 MB |
432 | static inline struct ib_uobject *uverbs_attr_get_uobject(const struct uverbs_attr_bundle *attrs_bundle, |
433 | u16 idx) | |
434 | { | |
435 | const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); | |
436 | ||
437 | if (IS_ERR(attr)) | |
438 | return ERR_CAST(attr); | |
439 | ||
440 | return attr->obj_attr.uobject; | |
441 | } | |
442 | ||
8762d149 MB |
443 | static inline int |
444 | uverbs_attr_get_len(const struct uverbs_attr_bundle *attrs_bundle, u16 idx) | |
445 | { | |
446 | const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); | |
447 | ||
448 | if (IS_ERR(attr)) | |
449 | return PTR_ERR(attr); | |
450 | ||
451 | return attr->ptr_attr.len; | |
452 | } | |
453 | ||
d70724f1 | 454 | static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle, |
89d9e8d3 | 455 | size_t idx, const void *from, size_t size) |
d70724f1 MB |
456 | { |
457 | const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); | |
458 | u16 flags; | |
89d9e8d3 | 459 | size_t min_size; |
d70724f1 MB |
460 | |
461 | if (IS_ERR(attr)) | |
462 | return PTR_ERR(attr); | |
463 | ||
89d9e8d3 | 464 | min_size = min_t(size_t, attr->ptr_attr.len, size); |
2f36028c | 465 | if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size)) |
89d9e8d3 MB |
466 | return -EFAULT; |
467 | ||
d70724f1 | 468 | flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT; |
89d9e8d3 MB |
469 | if (put_user(flags, &attr->uattr->flags)) |
470 | return -EFAULT; | |
471 | ||
472 | return 0; | |
d70724f1 MB |
473 | } |
474 | ||
89d9e8d3 MB |
475 | static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr) |
476 | { | |
477 | return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data); | |
478 | } | |
479 | ||
8762d149 MB |
480 | static inline void *uverbs_attr_get_alloced_ptr( |
481 | const struct uverbs_attr_bundle *attrs_bundle, u16 idx) | |
482 | { | |
483 | const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); | |
484 | ||
485 | if (IS_ERR(attr)) | |
486 | return (void *)attr; | |
487 | ||
488 | return uverbs_attr_ptr_is_inline(attr) ? (void *)&attr->ptr_attr.data : | |
489 | attr->ptr_attr.ptr; | |
490 | } | |
491 | ||
89d9e8d3 | 492 | static inline int _uverbs_copy_from(void *to, |
d70724f1 | 493 | const struct uverbs_attr_bundle *attrs_bundle, |
89d9e8d3 MB |
494 | size_t idx, |
495 | size_t size) | |
d70724f1 MB |
496 | { |
497 | const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); | |
498 | ||
499 | if (IS_ERR(attr)) | |
500 | return PTR_ERR(attr); | |
501 | ||
89d9e8d3 MB |
502 | /* |
503 | * Validation ensures attr->ptr_attr.len >= size. If the caller is | |
c66db311 MB |
504 | * using UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO then it must call |
505 | * uverbs_copy_from_or_zero. | |
89d9e8d3 MB |
506 | */ |
507 | if (unlikely(size < attr->ptr_attr.len)) | |
508 | return -EINVAL; | |
509 | ||
510 | if (uverbs_attr_ptr_is_inline(attr)) | |
d70724f1 | 511 | memcpy(to, &attr->ptr_attr.data, attr->ptr_attr.len); |
2f36028c JG |
512 | else if (copy_from_user(to, u64_to_user_ptr(attr->ptr_attr.data), |
513 | attr->ptr_attr.len)) | |
d70724f1 MB |
514 | return -EFAULT; |
515 | ||
516 | return 0; | |
517 | } | |
518 | ||
c66db311 MB |
519 | static inline int _uverbs_copy_from_or_zero(void *to, |
520 | const struct uverbs_attr_bundle *attrs_bundle, | |
521 | size_t idx, | |
522 | size_t size) | |
523 | { | |
524 | const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx); | |
525 | size_t min_size; | |
526 | ||
527 | if (IS_ERR(attr)) | |
528 | return PTR_ERR(attr); | |
529 | ||
530 | min_size = min_t(size_t, size, attr->ptr_attr.len); | |
531 | ||
532 | if (uverbs_attr_ptr_is_inline(attr)) | |
533 | memcpy(to, &attr->ptr_attr.data, min_size); | |
534 | else if (copy_from_user(to, u64_to_user_ptr(attr->ptr_attr.data), | |
535 | min_size)) | |
536 | return -EFAULT; | |
537 | ||
538 | if (size > min_size) | |
539 | memset(to + min_size, 0, size - min_size); | |
540 | ||
541 | return 0; | |
542 | } | |
543 | ||
d70724f1 | 544 | #define uverbs_copy_from(to, attrs_bundle, idx) \ |
89d9e8d3 | 545 | _uverbs_copy_from(to, attrs_bundle, idx, sizeof(*to)) |
d70724f1 | 546 | |
c66db311 MB |
547 | #define uverbs_copy_from_or_zero(to, attrs_bundle, idx) \ |
548 | _uverbs_copy_from_or_zero(to, attrs_bundle, idx, sizeof(*to)) | |
549 | ||
118620d3 MB |
550 | /* ================================================= |
551 | * Definitions -> Specs infrastructure | |
552 | * ================================================= | |
553 | */ | |
554 | ||
555 | /* | |
556 | * uverbs_alloc_spec_tree - Merges different common and driver specific feature | |
557 | * into one parsing tree that every uverbs command will be parsed upon. | |
558 | * | |
559 | * @num_trees: Number of trees in the array @trees. | |
560 | * @trees: Array of pointers to tree root definitions to merge. Each such tree | |
561 | * possibly contains objects, methods and attributes definitions. | |
562 | * | |
563 | * Returns: | |
564 | * uverbs_root_spec *: The root of the merged parsing tree. | |
565 | * On error, we return an error code. Error is checked via IS_ERR. | |
566 | * | |
567 | * The following merges could take place: | |
568 | * a. Two trees representing the same method with different handler | |
569 | * -> We take the handler of the tree that its handler != NULL | |
570 | * and its index in the trees array is greater. The incentive for that | |
571 | * is that developers are expected to first merge common trees and then | |
572 | * merge trees that gives specialized the behaviour. | |
573 | * b. Two trees representing the same object with different | |
574 | * type_attrs (struct uverbs_obj_type): | |
575 | * -> We take the type_attrs of the tree that its type_attr != NULL | |
576 | * and its index in the trees array is greater. This could be used | |
577 | * in order to override the free function, allocation size, etc. | |
578 | * c. Two trees representing the same method attribute (same id but possibly | |
579 | * different attributes): | |
580 | * -> ERROR (-ENOENT), we believe that's not the programmer's intent. | |
581 | * | |
582 | * An object without any methods is considered invalid and will abort the | |
583 | * function with -ENOENT error. | |
584 | */ | |
52427112 | 585 | #if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS) |
118620d3 MB |
586 | struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, |
587 | const struct uverbs_object_tree_def **trees); | |
588 | void uverbs_free_spec_tree(struct uverbs_root_spec *root); | |
52427112 MB |
589 | #else |
590 | static inline struct uverbs_root_spec *uverbs_alloc_spec_tree(unsigned int num_trees, | |
591 | const struct uverbs_object_tree_def **trees) | |
592 | { | |
593 | return NULL; | |
594 | } | |
595 | ||
596 | static inline void uverbs_free_spec_tree(struct uverbs_root_spec *root) | |
597 | { | |
598 | } | |
599 | #endif | |
a0aa309c | 600 | |
118620d3 | 601 | #endif |