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