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
uverbs_free_flow_action(struct ib_uobject * uobject,enum rdma_remove_reason why,struct uverbs_attr_bundle * attrs)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
43 if (atomic_read(&action->usecnt))
44 return -EBUSY;
45
46 return action->device->ops.destroy_flow_action(action);
47 }
48
esp_flags_uverbs_to_verbs(struct uverbs_attr_bundle * attrs,u32 flags,bool is_modify)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
validate_flow_action_esp_keymat_aes_gcm(struct ib_flow_action_attrs_esp_keymats * keymat)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
flow_action_esp_replay_none(struct ib_flow_action_attrs_esp_replays * replay,bool is_modify)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
flow_action_esp_replay_def_ok(struct ib_flow_action_attrs_esp_replays * replay,bool is_modify)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
parse_esp_ip(enum ib_flow_spec_type proto,const void __user * val_ptr,size_t len,union ib_flow_spec * out)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
flow_action_esp_get_encap(struct ib_flow_spec_list * out,struct uverbs_attr_bundle * attrs)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
parse_flow_action_esp(struct ib_device * ib_dev,struct uverbs_attr_bundle * attrs,struct ib_flow_action_esp_attr * esp_attr,bool is_modify)225 static int parse_flow_action_esp(struct ib_device *ib_dev,
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
UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)306 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE)(
307 struct uverbs_attr_bundle *attrs)
308 {
309 struct ib_uobject *uobj = uverbs_attr_get_uobject(
310 attrs, UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE);
311 struct ib_device *ib_dev = attrs->context->device;
312 int ret;
313 struct ib_flow_action *action;
314 struct ib_flow_action_esp_attr esp_attr = {};
315
316 if (!ib_dev->ops.create_flow_action_esp)
317 return -EOPNOTSUPP;
318
319 ret = parse_flow_action_esp(ib_dev, attrs, &esp_attr, false);
320 if (ret)
321 return ret;
322
323 /* No need to check as this attribute is marked as MANDATORY */
324 action = ib_dev->ops.create_flow_action_esp(ib_dev, &esp_attr.hdr,
325 attrs);
326 if (IS_ERR(action))
327 return PTR_ERR(action);
328
329 uverbs_flow_action_fill_action(action, uobj, ib_dev,
330 IB_FLOW_ACTION_ESP);
331
332 return 0;
333 }
334
UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY)335 static int UVERBS_HANDLER(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY)(
336 struct uverbs_attr_bundle *attrs)
337 {
338 struct ib_uobject *uobj = uverbs_attr_get_uobject(
339 attrs, UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE);
340 struct ib_flow_action *action = uobj->object;
341 int ret;
342 struct ib_flow_action_esp_attr esp_attr = {};
343
344 if (!action->device->ops.modify_flow_action_esp)
345 return -EOPNOTSUPP;
346
347 ret = parse_flow_action_esp(action->device, attrs, &esp_attr, true);
348 if (ret)
349 return ret;
350
351 if (action->type != IB_FLOW_ACTION_ESP)
352 return -EINVAL;
353
354 return action->device->ops.modify_flow_action_esp(action,
355 &esp_attr.hdr,
356 attrs);
357 }
358
359 static const struct uverbs_attr_spec uverbs_flow_action_esp_keymat[] = {
360 [IB_UVERBS_FLOW_ACTION_ESP_KEYMAT_AES_GCM] = {
361 .type = UVERBS_ATTR_TYPE_PTR_IN,
362 UVERBS_ATTR_STRUCT(
363 struct ib_uverbs_flow_action_esp_keymat_aes_gcm,
364 aes_key),
365 },
366 };
367
368 static const struct uverbs_attr_spec uverbs_flow_action_esp_replay[] = {
369 [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_NONE] = {
370 .type = UVERBS_ATTR_TYPE_PTR_IN,
371 UVERBS_ATTR_NO_DATA(),
372 },
373 [IB_UVERBS_FLOW_ACTION_ESP_REPLAY_BMP] = {
374 .type = UVERBS_ATTR_TYPE_PTR_IN,
375 UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp_replay_bmp,
376 size),
377 },
378 };
379
380 DECLARE_UVERBS_NAMED_METHOD(
381 UVERBS_METHOD_FLOW_ACTION_ESP_CREATE,
382 UVERBS_ATTR_IDR(UVERBS_ATTR_CREATE_FLOW_ACTION_ESP_HANDLE,
383 UVERBS_OBJECT_FLOW_ACTION,
384 UVERBS_ACCESS_NEW,
385 UA_MANDATORY),
386 UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
387 UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
388 hard_limit_pkts),
389 UA_MANDATORY),
390 UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
391 UVERBS_ATTR_TYPE(__u32),
392 UA_OPTIONAL),
393 UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
394 uverbs_flow_action_esp_keymat,
395 UA_MANDATORY),
396 UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
397 uverbs_flow_action_esp_replay,
398 UA_OPTIONAL),
399 UVERBS_ATTR_PTR_IN(
400 UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
401 UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
402 UA_OPTIONAL));
403
404 DECLARE_UVERBS_NAMED_METHOD(
405 UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY,
406 UVERBS_ATTR_IDR(UVERBS_ATTR_MODIFY_FLOW_ACTION_ESP_HANDLE,
407 UVERBS_OBJECT_FLOW_ACTION,
408 UVERBS_ACCESS_WRITE,
409 UA_MANDATORY),
410 UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ATTRS,
411 UVERBS_ATTR_STRUCT(struct ib_uverbs_flow_action_esp,
412 hard_limit_pkts),
413 UA_OPTIONAL),
414 UVERBS_ATTR_PTR_IN(UVERBS_ATTR_FLOW_ACTION_ESP_ESN,
415 UVERBS_ATTR_TYPE(__u32),
416 UA_OPTIONAL),
417 UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_KEYMAT,
418 uverbs_flow_action_esp_keymat,
419 UA_OPTIONAL),
420 UVERBS_ATTR_ENUM_IN(UVERBS_ATTR_FLOW_ACTION_ESP_REPLAY,
421 uverbs_flow_action_esp_replay,
422 UA_OPTIONAL),
423 UVERBS_ATTR_PTR_IN(
424 UVERBS_ATTR_FLOW_ACTION_ESP_ENCAP,
425 UVERBS_ATTR_TYPE(struct ib_uverbs_flow_action_esp_encap),
426 UA_OPTIONAL));
427
428 DECLARE_UVERBS_NAMED_METHOD_DESTROY(
429 UVERBS_METHOD_FLOW_ACTION_DESTROY,
430 UVERBS_ATTR_IDR(UVERBS_ATTR_DESTROY_FLOW_ACTION_HANDLE,
431 UVERBS_OBJECT_FLOW_ACTION,
432 UVERBS_ACCESS_DESTROY,
433 UA_MANDATORY));
434
435 DECLARE_UVERBS_NAMED_OBJECT(
436 UVERBS_OBJECT_FLOW_ACTION,
437 UVERBS_TYPE_ALLOC_IDR(uverbs_free_flow_action),
438 &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_CREATE),
439 &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_DESTROY),
440 &UVERBS_METHOD(UVERBS_METHOD_FLOW_ACTION_ESP_MODIFY));
441
442 const struct uapi_definition uverbs_def_obj_flow_action[] = {
443 UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
444 UVERBS_OBJECT_FLOW_ACTION,
445 UAPI_DEF_OBJ_NEEDS_FN(destroy_flow_action)),
446 {}
447 };
448