Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / infiniband / core / uverbs_std_types_flow_action.c
1 /*
2  * Copyright (c) 2018, 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 #include "rdma_core.h"
34 #include "uverbs.h"
35 #include <rdma/uverbs_std_types.h>
36
37 static int uverbs_free_flow_action(struct ib_uobject *uobject,
38                                    enum rdma_remove_reason why,
39                                    struct uverbs_attr_bundle *attrs)
40 {
41         struct ib_flow_action *action = uobject->object;
42         int ret;
43
44         ret = ib_destroy_usecnt(&action->usecnt, why, uobject);
45         if (ret)
46                 return ret;
47
48         return action->device->ops.destroy_flow_action(action);
49 }
50
51 static u64 esp_flags_uverbs_to_verbs(struct uverbs_attr_bundle *attrs,
52                                      u32 flags, bool is_modify)
53 {
54         u64 verbs_flags = flags;
55
56         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ESN))
57                 verbs_flags |= IB_FLOW_ACTION_ESP_FLAGS_ESN_TRIGGERED;
58
59         if (is_modify && uverbs_attr_is_valid(attrs,
60                                               UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS))
61                 verbs_flags |= IB_FLOW_ACTION_ESP_FLAGS_MOD_ESP_ATTRS;
62
63         return verbs_flags;
64 };
65
66 static int validate_flow_action_esp_keymat_aes_gcm(struct ib_flow_action_attrs_esp_keymats *keymat)
67 {
68         struct ib_uverbs_flow_action_esp_keymat_aes_gcm *aes_gcm =
69                 &keymat->keymat.aes_gcm;
70
71         if (aes_gcm->iv_algo > IB_UVERBS_FLOW_ACTION_IV_ALGO_SEQ)
72                 return -EOPNOTSUPP;
73
74         if (aes_gcm->key_len != 32 &&
75             aes_gcm->key_len != 24 &&
76             aes_gcm->key_len != 16)
77                 return -EINVAL;
78
79         if (aes_gcm->icv_len != 16 &&
80             aes_gcm->icv_len != 8 &&
81             aes_gcm->icv_len != 12)
82                 return -EINVAL;
83
84         return 0;
85 }
86
87 static int (* const flow_action_esp_keymat_validate[])(struct ib_flow_action_attrs_esp_keymats *keymat) = {
88         [IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = validate_flow_action_esp_keymat_aes_gcm,
89 };
90
91 static int flow_action_esp_replay_none(struct ib_flow_action_attrs_esp_replays *replay,
92                                        bool is_modify)
93 {
94         /* This is used in order to modify an esp flow action with an enabled
95          * replay protection to a disabled one. This is only supported via
96          * modify, as in create verb we can simply drop the REPLAY attribute and
97          * achieve the same thing.
98          */
99         return is_modify ? 0 : -EINVAL;
100 }
101
102 static int flow_action_esp_replay_def_ok(struct ib_flow_action_attrs_esp_replays *replay,
103                                          bool is_modify)
104 {
105         /* Some replay protections could always be enabled without validating
106          * anything.
107          */
108         return 0;
109 }
110
111 static int (* const flow_action_esp_replay_validate[])(struct ib_flow_action_attrs_esp_replays *replay,
112                                                        bool is_modify) = {
113         [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = flow_action_esp_replay_none,
114         [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = flow_action_esp_replay_def_ok,
115 };
116
117 static int parse_esp_ip(enum ib_flow_spec_type proto,
118                         const void __user *val_ptr,
119                         size_t len, union ib_flow_spec *out)
120 {
121         int ret;
122         const struct ib_uverbs_flow_ipv4_filter ipv4 = {
123                 .src_ip = cpu_to_be32(0xffffffffUL),
124                 .dst_ip = cpu_to_be32(0xffffffffUL),
125                 .proto = 0xff,
126                 .tos = 0xff,
127                 .ttl = 0xff,
128                 .flags = 0xff,
129         };
130         const struct ib_uverbs_flow_ipv6_filter ipv6 = {
131                 .src_ip = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
132                            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
133                 .dst_ip = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
134                            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
135                 .flow_label = cpu_to_be32(0xffffffffUL),
136                 .next_hdr = 0xff,
137                 .traffic_class = 0xff,
138                 .hop_limit = 0xff,
139         };
140         union {
141                 struct ib_uverbs_flow_ipv4_filter ipv4;
142                 struct ib_uverbs_flow_ipv6_filter ipv6;
143         } user_val = {};
144         const void *user_pmask;
145         size_t val_len;
146
147         /* If the flow IPv4/IPv6 flow specifications are extended, the mask
148          * should be changed as well.
149          */
150         BUILD_BUG_ON(offsetof(struct ib_uverbs_flow_ipv4_filter, flags) +
151                      sizeof(ipv4.flags) != sizeof(ipv4));
152         BUILD_BUG_ON(offsetof(struct ib_uverbs_flow_ipv6_filter, reserved) +
153                      sizeof(ipv6.reserved) != sizeof(ipv6));
154
155         switch (proto) {
156         case IB_FLOW_SPEC_IPV4:
157                 if (len > sizeof(user_val.ipv4) &&
158                     !ib_is_buffer_cleared(val_ptr + sizeof(user_val.ipv4),
159                                           len - sizeof(user_val.ipv4)))
160                         return -EOPNOTSUPP;
161
162                 val_len = min_t(size_t, len, sizeof(user_val.ipv4));
163                 ret = copy_from_user(&user_val.ipv4, val_ptr,
164                                      val_len);
165                 if (ret)
166                         return -EFAULT;
167
168                 user_pmask = &ipv4;
169                 break;
170         case IB_FLOW_SPEC_IPV6:
171                 if (len > sizeof(user_val.ipv6) &&
172                     !ib_is_buffer_cleared(val_ptr + sizeof(user_val.ipv6),
173                                           len - sizeof(user_val.ipv6)))
174                         return -EOPNOTSUPP;
175
176                 val_len = min_t(size_t, len, sizeof(user_val.ipv6));
177                 ret = copy_from_user(&user_val.ipv6, val_ptr,
178                                      val_len);
179                 if (ret)
180                         return -EFAULT;
181
182                 user_pmask = &ipv6;
183                 break;
184         default:
185                 return -EOPNOTSUPP;
186         }
187
188         return ib_uverbs_kern_spec_to_ib_spec_filter(proto, user_pmask,
189                                                      &user_val,
190                                                      val_len, out);
191 }
192
193 static int flow_action_esp_get_encap(struct ib_flow_spec_list *out,
194                                      struct uverbs_attr_bundle *attrs)
195 {
196         struct ib_uverbs_flow_action_esp_encap uverbs_encap;
197         int ret;
198
199         ret = uverbs_copy_from(&uverbs_encap, attrs,
200                                UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP);
201         if (ret)
202                 return ret;
203
204         /* We currently support only one encap */
205         if (uverbs_encap.next_ptr)
206                 return -EOPNOTSUPP;
207
208         if (uverbs_encap.type != IB_FLOW_SPEC_IPV4 &&
209             uverbs_encap.type != IB_FLOW_SPEC_IPV6)
210                 return -EOPNOTSUPP;
211
212         return parse_esp_ip(uverbs_encap.type,
213                             u64_to_user_ptr(uverbs_encap.val_ptr),
214                             uverbs_encap.len,
215                             &out->spec);
216 }
217
218 struct ib_flow_action_esp_attr {
219         struct  ib_flow_action_attrs_esp                hdr;
220         struct  ib_flow_action_attrs_esp_keymats        keymat;
221         struct  ib_flow_action_attrs_esp_replays        replay;
222         /* We currently support only one spec */
223         struct  ib_flow_spec_list                       encap;
224 };
225
226 #define ESP_LAST_SUPPORTED_FLAG         IB_UVERBS_FLOW_ACTION_ESP_FLAGS_ESN_NEW_WINDOW
227 static int parse_flow_action_esp(struct ib_device *ib_dev,
228                                  struct uverbs_attr_bundle *attrs,
229                                  struct ib_flow_action_esp_attr *esp_attr,
230                                  bool is_modify)
231 {
232         struct ib_uverbs_flow_action_esp uverbs_esp = {};
233         int ret;
234
235         /* Optional param, if it doesn't exist, we get -ENOENT and skip it */
236         ret = uverbs_copy_from(&esp_attr->hdr.esn, attrs,
237                                UVERBS_ATTR_FLOW_ACTION_ESP_ESN);
238         if (IS_UVERBS_COPY_ERR(ret))
239                 return ret;
240
241         /* This can be called from FLOW_ACTION_ESP_MODIFY where
242          * UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS is optional
243          */
244         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS)) {
245                 ret = uverbs_copy_from_or_zero(&uverbs_esp, attrs,
246                                                UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS);
247                 if (ret)
248                         return ret;
249
250                 if (uverbs_esp.flags & ~((ESP_LAST_SUPPORTED_FLAG << 1) - 1))
251                         return -EOPNOTSUPP;
252
253                 esp_attr->hdr.spi = uverbs_esp.spi;
254                 esp_attr->hdr.seq = uverbs_esp.seq;
255                 esp_attr->hdr.tfc_pad = uverbs_esp.tfc_pad;
256                 esp_attr->hdr.hard_limit_pkts = uverbs_esp.hard_limit_pkts;
257         }
258         esp_attr->hdr.flags = esp_flags_uverbs_to_verbs(attrs, uverbs_esp.flags,
259                                                         is_modify);
260
261         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT)) {
262                 esp_attr->keymat.protocol =
263                         uverbs_attr_get_enum_id(attrs,
264                                                 UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT);
265                 ret = uverbs_copy_from_or_zero(&esp_attr->keymat.keymat,
266                                                attrs,
267                                                UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT);
268                 if (ret)
269                         return ret;
270
271                 ret = flow_action_esp_keymat_validate[esp_attr->keymat.protocol](&esp_attr->keymat);
272                 if (ret)
273                         return ret;
274
275                 esp_attr->hdr.keymat = &esp_attr->keymat;
276         }
277
278         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY)) {
279                 esp_attr->replay.protocol =
280                         uverbs_attr_get_enum_id(attrs,
281                                                 UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY);
282
283                 ret = uverbs_copy_from_or_zero(&esp_attr->replay.replay,
284                                                attrs,
285                                                UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY);
286                 if (ret)
287                         return ret;
288
289                 ret = flow_action_esp_replay_validate[esp_attr->replay.protocol](&esp_attr->replay,
290                                                                                  is_modify);
291                 if (ret)
292                         return ret;
293
294                 esp_attr->hdr.replay = &esp_attr->replay;
295         }
296
297         if (uverbs_attr_is_valid(attrs, UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP)) {
298                 ret = flow_action_esp_get_encap(&esp_attr->encap, attrs);
299                 if (ret)
300                         return ret;
301
302                 esp_attr->hdr.encap = &esp_attr->encap;
303         }
304
305         return 0;
306 }
307
308 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)(
309         struct uverbs_attr_bundle *attrs)
310 {
311         struct ib_uobject *uobj = uverbs_attr_get_uobject(
312                 attrs, UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE);
313         struct ib_device *ib_dev = attrs->context->device;
314         int                               ret;
315         struct ib_flow_action             *action;
316         struct ib_flow_action_esp_attr    esp_attr = {};
317
318         if (!ib_dev->ops.create_flow_action_esp)
319                 return -EOPNOTSUPP;
320
321         ret = parse_flow_action_esp(ib_dev, attrs, &esp_attr, false);
322         if (ret)
323                 return ret;
324
325         /* No need to check as this attribute is marked as MANDATORY */
326         action = ib_dev->ops.create_flow_action_esp(ib_dev, &esp_attr.hdr,
327                                                     attrs);
328         if (IS_ERR(action))
329                 return PTR_ERR(action);
330
331         uverbs_flow_action_fill_action(action, uobj, ib_dev,
332                                        IB_FLOW_ACTION_ESP);
333
334         return 0;
335 }
336
337 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY)(
338         struct uverbs_attr_bundle *attrs)
339 {
340         struct ib_uobject *uobj = uverbs_attr_get_uobject(
341                 attrs, UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE);
342         struct ib_flow_action *action = uobj->object;
343         int                               ret;
344         struct ib_flow_action_esp_attr    esp_attr = {};
345
346         if (!action->device->ops.modify_flow_action_esp)
347                 return -EOPNOTSUPP;
348
349         ret = parse_flow_action_esp(action->device, attrs, &esp_attr, true);
350         if (ret)
351                 return ret;
352
353         if (action->type != IB_FLOW_ACTION_ESP)
354                 return -EINVAL;
355
356         return action->device->ops.modify_flow_action_esp(action,
357                                                           &esp_attr.hdr,
358                                                           attrs);
359 }
360
361 static const struct uverbs_attr_spec uverbs_flow_action_esp_keymat[] = {
362         [IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = {
363                 .type = UVERBS_ATTR_TYPE_PTR_IN,
364                 UVERBS_ATTR_STRUCT(
365                         struct ib_uverbs_flow_action_esp_keymat_aes_gcm,
366                         aes_key),
367         },
368 };
369
370 static const struct uverbs_attr_spec uverbs_flow_action_esp_replay[] = {
371         [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = {
372                 .type = UVERBS_ATTR_TYPE_PTR_IN,
373                 UVERBS_ATTR_NO_DATA(),
374         },
375         [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = {
376                 .type = UVERBS_ATTR_TYPE_PTR_IN,
377                 UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp_replay_bmp,
378                                    size),
379         },
380 };
381
382 DECLARE_UVERBS_NAMED_METHOD(
383         UVERBS_METHOD_FLOW_ACTION_ESP_CREATE,
384         UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE,
385                         UVERBS_OBJECT_FLOW_ACTION,
386                         UVERBS_ACCESS_NEW,
387                         UA_MANDATORY),
388         UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
389                            UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
390                                               hard_limit_pkts),
391                            UA_MANDATORY),
392         UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
393                            UVERBS_ATTR_TYPE(__u32),
394                            UA_OPTIONAL),
395         UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
396                             uverbs_flow_action_esp_keymat,
397                             UA_MANDATORY),
398         UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
399                             uverbs_flow_action_esp_replay,
400                             UA_OPTIONAL),
401         UVERBS_ATTR_PTR_IN(
402                 UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
403                 UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
404                 UA_OPTIONAL));
405
406 DECLARE_UVERBS_NAMED_METHOD(
407         UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY,
408         UVERBS_ATTR_IDR(UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE,
409                         UVERBS_OBJECT_FLOW_ACTION,
410                         UVERBS_ACCESS_WRITE,
411                         UA_MANDATORY),
412         UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
413                            UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
414                                               hard_limit_pkts),
415                            UA_OPTIONAL),
416         UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
417                            UVERBS_ATTR_TYPE(__u32),
418                            UA_OPTIONAL),
419         UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
420                             uverbs_flow_action_esp_keymat,
421                             UA_OPTIONAL),
422         UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
423                             uverbs_flow_action_esp_replay,
424                             UA_OPTIONAL),
425         UVERBS_ATTR_PTR_IN(
426                 UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
427                 UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
428                 UA_OPTIONAL));
429
430 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
431         UVERBS_METHOD_FLOW_ACTION_DESTROY,
432         UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_FLOW_ACTION_HANDLE,
433                         UVERBS_OBJECT_FLOW_ACTION,
434                         UVERBS_ACCESS_DESTROY,
435                         UA_MANDATORY));
436
437 DECLARE_UVERBS_NAMED_OBJECT(
438         UVERBS_OBJECT_FLOW_ACTION,
439         UVERBS_TYPE_ALLOC_IDR(uverbs_free_flow_action),
440         &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE),
441         &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_DESTROY),
442         &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY));
443
444 const struct uapi_definition uverbs_def_obj_flow_action[] = {
445         UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
446                 UVERBS_OBJECT_FLOW_ACTION,
447                 UAPI_DEF_OBJ_NEEDS_FN(destroy_flow_action)),
448         {}
449 };