108700dabSJakub Kicinski /*
208700dabSJakub Kicinski * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved.
308700dabSJakub Kicinski * Copyright (c) 2016-2017, Dave Watson <davejwatson@fb.com>. All rights reserved.
408700dabSJakub Kicinski *
508700dabSJakub Kicinski * This software is available to you under a choice of one of two
608700dabSJakub Kicinski * licenses. You may choose to be licensed under the terms of the GNU
708700dabSJakub Kicinski * General Public License (GPL) Version 2, available from the file
808700dabSJakub Kicinski * COPYING in the main directory of this source tree, or the
908700dabSJakub Kicinski * OpenIB.org BSD license below:
1008700dabSJakub Kicinski *
1108700dabSJakub Kicinski * Redistribution and use in source and binary forms, with or
1208700dabSJakub Kicinski * without modification, are permitted provided that the following
1308700dabSJakub Kicinski * conditions are met:
1408700dabSJakub Kicinski *
1508700dabSJakub Kicinski * - Redistributions of source code must retain the above
1608700dabSJakub Kicinski * copyright notice, this list of conditions and the following
1708700dabSJakub Kicinski * disclaimer.
1808700dabSJakub Kicinski *
1908700dabSJakub Kicinski * - Redistributions in binary form must reproduce the above
2008700dabSJakub Kicinski * copyright notice, this list of conditions and the following
2108700dabSJakub Kicinski * disclaimer in the documentation and/or other materials
2208700dabSJakub Kicinski * provided with the distribution.
2308700dabSJakub Kicinski *
2408700dabSJakub Kicinski * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2508700dabSJakub Kicinski * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2608700dabSJakub Kicinski * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2708700dabSJakub Kicinski * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2808700dabSJakub Kicinski * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2908700dabSJakub Kicinski * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3008700dabSJakub Kicinski * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3108700dabSJakub Kicinski * SOFTWARE.
3208700dabSJakub Kicinski */
3308700dabSJakub Kicinski
3408700dabSJakub Kicinski #include <linux/list.h>
3508700dabSJakub Kicinski #include <linux/rcupdate.h>
3608700dabSJakub Kicinski #include <linux/spinlock.h>
3708700dabSJakub Kicinski #include <net/inet_connection_sock.h>
3808700dabSJakub Kicinski #include <net/tls.h>
3908700dabSJakub Kicinski #include <net/tls_toe.h>
4008700dabSJakub Kicinski
41*58790314SJakub Kicinski #include "tls.h"
42*58790314SJakub Kicinski
4308700dabSJakub Kicinski static LIST_HEAD(device_list);
4408700dabSJakub Kicinski static DEFINE_SPINLOCK(device_spinlock);
4508700dabSJakub Kicinski
tls_toe_sk_destruct(struct sock * sk)460eb8745eSJakub Kicinski static void tls_toe_sk_destruct(struct sock *sk)
4708700dabSJakub Kicinski {
4808700dabSJakub Kicinski struct inet_connection_sock *icsk = inet_csk(sk);
4908700dabSJakub Kicinski struct tls_context *ctx = tls_get_ctx(sk);
5008700dabSJakub Kicinski
5108700dabSJakub Kicinski ctx->sk_destruct(sk);
5208700dabSJakub Kicinski /* Free ctx */
5308700dabSJakub Kicinski rcu_assign_pointer(icsk->icsk_ulp_data, NULL);
5408700dabSJakub Kicinski tls_ctx_free(sk, ctx);
5508700dabSJakub Kicinski }
5608700dabSJakub Kicinski
tls_toe_bypass(struct sock * sk)570eb8745eSJakub Kicinski int tls_toe_bypass(struct sock *sk)
5808700dabSJakub Kicinski {
5908700dabSJakub Kicinski struct tls_toe_device *dev;
6008700dabSJakub Kicinski struct tls_context *ctx;
6108700dabSJakub Kicinski int rc = 0;
6208700dabSJakub Kicinski
6308700dabSJakub Kicinski spin_lock_bh(&device_spinlock);
6408700dabSJakub Kicinski list_for_each_entry(dev, &device_list, dev_list) {
6508700dabSJakub Kicinski if (dev->feature && dev->feature(dev)) {
6608700dabSJakub Kicinski ctx = tls_ctx_create(sk);
6708700dabSJakub Kicinski if (!ctx)
6808700dabSJakub Kicinski goto out;
6908700dabSJakub Kicinski
7008700dabSJakub Kicinski ctx->sk_destruct = sk->sk_destruct;
710eb8745eSJakub Kicinski sk->sk_destruct = tls_toe_sk_destruct;
7208700dabSJakub Kicinski ctx->rx_conf = TLS_HW_RECORD;
7308700dabSJakub Kicinski ctx->tx_conf = TLS_HW_RECORD;
7408700dabSJakub Kicinski update_sk_prot(sk, ctx);
7508700dabSJakub Kicinski rc = 1;
7608700dabSJakub Kicinski break;
7708700dabSJakub Kicinski }
7808700dabSJakub Kicinski }
7908700dabSJakub Kicinski out:
8008700dabSJakub Kicinski spin_unlock_bh(&device_spinlock);
8108700dabSJakub Kicinski return rc;
8208700dabSJakub Kicinski }
8308700dabSJakub Kicinski
tls_toe_unhash(struct sock * sk)840eb8745eSJakub Kicinski void tls_toe_unhash(struct sock *sk)
8508700dabSJakub Kicinski {
8608700dabSJakub Kicinski struct tls_context *ctx = tls_get_ctx(sk);
8708700dabSJakub Kicinski struct tls_toe_device *dev;
8808700dabSJakub Kicinski
8908700dabSJakub Kicinski spin_lock_bh(&device_spinlock);
9008700dabSJakub Kicinski list_for_each_entry(dev, &device_list, dev_list) {
9108700dabSJakub Kicinski if (dev->unhash) {
9208700dabSJakub Kicinski kref_get(&dev->kref);
9308700dabSJakub Kicinski spin_unlock_bh(&device_spinlock);
9408700dabSJakub Kicinski dev->unhash(dev, sk);
9508700dabSJakub Kicinski kref_put(&dev->kref, dev->release);
9608700dabSJakub Kicinski spin_lock_bh(&device_spinlock);
9708700dabSJakub Kicinski }
9808700dabSJakub Kicinski }
9908700dabSJakub Kicinski spin_unlock_bh(&device_spinlock);
10008700dabSJakub Kicinski ctx->sk_proto->unhash(sk);
10108700dabSJakub Kicinski }
10208700dabSJakub Kicinski
tls_toe_hash(struct sock * sk)1030eb8745eSJakub Kicinski int tls_toe_hash(struct sock *sk)
10408700dabSJakub Kicinski {
10508700dabSJakub Kicinski struct tls_context *ctx = tls_get_ctx(sk);
10608700dabSJakub Kicinski struct tls_toe_device *dev;
10708700dabSJakub Kicinski int err;
10808700dabSJakub Kicinski
10908700dabSJakub Kicinski err = ctx->sk_proto->hash(sk);
11008700dabSJakub Kicinski spin_lock_bh(&device_spinlock);
11108700dabSJakub Kicinski list_for_each_entry(dev, &device_list, dev_list) {
11208700dabSJakub Kicinski if (dev->hash) {
11308700dabSJakub Kicinski kref_get(&dev->kref);
11408700dabSJakub Kicinski spin_unlock_bh(&device_spinlock);
11508700dabSJakub Kicinski err |= dev->hash(dev, sk);
11608700dabSJakub Kicinski kref_put(&dev->kref, dev->release);
11708700dabSJakub Kicinski spin_lock_bh(&device_spinlock);
11808700dabSJakub Kicinski }
11908700dabSJakub Kicinski }
12008700dabSJakub Kicinski spin_unlock_bh(&device_spinlock);
12108700dabSJakub Kicinski
12208700dabSJakub Kicinski if (err)
1230eb8745eSJakub Kicinski tls_toe_unhash(sk);
12408700dabSJakub Kicinski return err;
12508700dabSJakub Kicinski }
12608700dabSJakub Kicinski
tls_toe_register_device(struct tls_toe_device * device)12708700dabSJakub Kicinski void tls_toe_register_device(struct tls_toe_device *device)
12808700dabSJakub Kicinski {
12908700dabSJakub Kicinski spin_lock_bh(&device_spinlock);
13008700dabSJakub Kicinski list_add_tail(&device->dev_list, &device_list);
13108700dabSJakub Kicinski spin_unlock_bh(&device_spinlock);
13208700dabSJakub Kicinski }
13308700dabSJakub Kicinski EXPORT_SYMBOL(tls_toe_register_device);
13408700dabSJakub Kicinski
tls_toe_unregister_device(struct tls_toe_device * device)13508700dabSJakub Kicinski void tls_toe_unregister_device(struct tls_toe_device *device)
13608700dabSJakub Kicinski {
13708700dabSJakub Kicinski spin_lock_bh(&device_spinlock);
13808700dabSJakub Kicinski list_del(&device->dev_list);
13908700dabSJakub Kicinski spin_unlock_bh(&device_spinlock);
14008700dabSJakub Kicinski }
14108700dabSJakub Kicinski EXPORT_SYMBOL(tls_toe_unregister_device);
142