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