1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2734942ccSDave Watson /* 3734942ccSDave Watson * Pluggable TCP upper layer protocol support. 4734942ccSDave Watson * 5734942ccSDave Watson * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved. 6734942ccSDave Watson * Copyright (c) 2016-2017, Dave Watson <davejwatson@fb.com>. All rights reserved. 7734942ccSDave Watson * 8734942ccSDave Watson */ 9734942ccSDave Watson 10734942ccSDave Watson #include <linux/module.h> 11734942ccSDave Watson #include <linux/mm.h> 12734942ccSDave Watson #include <linux/types.h> 13734942ccSDave Watson #include <linux/list.h> 14734942ccSDave Watson #include <linux/gfp.h> 15734942ccSDave Watson #include <net/tcp.h> 16734942ccSDave Watson 17734942ccSDave Watson static DEFINE_SPINLOCK(tcp_ulp_list_lock); 18734942ccSDave Watson static LIST_HEAD(tcp_ulp_list); 19734942ccSDave Watson 20734942ccSDave Watson /* Simple linear search, don't expect many entries! */ 21734942ccSDave Watson static struct tcp_ulp_ops *tcp_ulp_find(const char *name) 22734942ccSDave Watson { 23734942ccSDave Watson struct tcp_ulp_ops *e; 24734942ccSDave Watson 25958a93c1SAmol Grover list_for_each_entry_rcu(e, &tcp_ulp_list, list, 26958a93c1SAmol Grover lockdep_is_held(&tcp_ulp_list_lock)) { 27734942ccSDave Watson if (strcmp(e->name, name) == 0) 28734942ccSDave Watson return e; 29734942ccSDave Watson } 30734942ccSDave Watson 31734942ccSDave Watson return NULL; 32734942ccSDave Watson } 33734942ccSDave Watson 34734942ccSDave Watson static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) 35734942ccSDave Watson { 36734942ccSDave Watson const struct tcp_ulp_ops *ulp = NULL; 37734942ccSDave Watson 38734942ccSDave Watson rcu_read_lock(); 39734942ccSDave Watson ulp = tcp_ulp_find(name); 40734942ccSDave Watson 41734942ccSDave Watson #ifdef CONFIG_MODULES 42734942ccSDave Watson if (!ulp && capable(CAP_NET_ADMIN)) { 43734942ccSDave Watson rcu_read_unlock(); 44037b0b86SDaniel Borkmann request_module("tcp-ulp-%s", name); 45734942ccSDave Watson rcu_read_lock(); 46734942ccSDave Watson ulp = tcp_ulp_find(name); 47734942ccSDave Watson } 48734942ccSDave Watson #endif 49734942ccSDave Watson if (!ulp || !try_module_get(ulp->owner)) 50734942ccSDave Watson ulp = NULL; 51734942ccSDave Watson 52734942ccSDave Watson rcu_read_unlock(); 53734942ccSDave Watson return ulp; 54734942ccSDave Watson } 55734942ccSDave Watson 56734942ccSDave Watson /* Attach new upper layer protocol to the list 57734942ccSDave Watson * of available protocols. 58734942ccSDave Watson */ 59734942ccSDave Watson int tcp_register_ulp(struct tcp_ulp_ops *ulp) 60734942ccSDave Watson { 61734942ccSDave Watson int ret = 0; 62734942ccSDave Watson 63734942ccSDave Watson spin_lock(&tcp_ulp_list_lock); 64b11a632cSJohn Fastabend if (tcp_ulp_find(ulp->name)) 65734942ccSDave Watson ret = -EEXIST; 66b11a632cSJohn Fastabend else 67734942ccSDave Watson list_add_tail_rcu(&ulp->list, &tcp_ulp_list); 68734942ccSDave Watson spin_unlock(&tcp_ulp_list_lock); 69734942ccSDave Watson 70734942ccSDave Watson return ret; 71734942ccSDave Watson } 72734942ccSDave Watson EXPORT_SYMBOL_GPL(tcp_register_ulp); 73734942ccSDave Watson 74734942ccSDave Watson void tcp_unregister_ulp(struct tcp_ulp_ops *ulp) 75734942ccSDave Watson { 76734942ccSDave Watson spin_lock(&tcp_ulp_list_lock); 77734942ccSDave Watson list_del_rcu(&ulp->list); 78734942ccSDave Watson spin_unlock(&tcp_ulp_list_lock); 79734942ccSDave Watson 80734942ccSDave Watson synchronize_rcu(); 81734942ccSDave Watson } 82734942ccSDave Watson EXPORT_SYMBOL_GPL(tcp_unregister_ulp); 83734942ccSDave Watson 84734942ccSDave Watson /* Build string with list of available upper layer protocl values */ 85734942ccSDave Watson void tcp_get_available_ulp(char *buf, size_t maxlen) 86734942ccSDave Watson { 87734942ccSDave Watson struct tcp_ulp_ops *ulp_ops; 88734942ccSDave Watson size_t offs = 0; 89734942ccSDave Watson 90926f38e9SJakub Kicinski *buf = '\0'; 91734942ccSDave Watson rcu_read_lock(); 92734942ccSDave Watson list_for_each_entry_rcu(ulp_ops, &tcp_ulp_list, list) { 93734942ccSDave Watson offs += snprintf(buf + offs, maxlen - offs, 94734942ccSDave Watson "%s%s", 95734942ccSDave Watson offs == 0 ? "" : " ", ulp_ops->name); 969bb59a21SHangbin Liu 979bb59a21SHangbin Liu if (WARN_ON_ONCE(offs >= maxlen)) 989bb59a21SHangbin Liu break; 99734942ccSDave Watson } 100734942ccSDave Watson rcu_read_unlock(); 101734942ccSDave Watson } 102734942ccSDave Watson 10333bfe20dSJohn Fastabend void tcp_update_ulp(struct sock *sk, struct proto *proto, 10433bfe20dSJohn Fastabend void (*write_space)(struct sock *sk)) 10595fa1454SJohn Fastabend { 10695fa1454SJohn Fastabend struct inet_connection_sock *icsk = inet_csk(sk); 10795fa1454SJohn Fastabend 10895fa1454SJohn Fastabend if (icsk->icsk_ulp_ops->update) 10933bfe20dSJohn Fastabend icsk->icsk_ulp_ops->update(sk, proto, write_space); 11095fa1454SJohn Fastabend } 11195fa1454SJohn Fastabend 112734942ccSDave Watson void tcp_cleanup_ulp(struct sock *sk) 113734942ccSDave Watson { 114734942ccSDave Watson struct inet_connection_sock *icsk = inet_csk(sk); 115734942ccSDave Watson 116aadd4355SDaniel Borkmann /* No sock_owned_by_me() check here as at the time the 117aadd4355SDaniel Borkmann * stack calls this function, the socket is dead and 118aadd4355SDaniel Borkmann * about to be destroyed. 119aadd4355SDaniel Borkmann */ 120734942ccSDave Watson if (!icsk->icsk_ulp_ops) 121734942ccSDave Watson return; 122734942ccSDave Watson 123734942ccSDave Watson if (icsk->icsk_ulp_ops->release) 124734942ccSDave Watson icsk->icsk_ulp_ops->release(sk); 125734942ccSDave Watson module_put(icsk->icsk_ulp_ops->owner); 12690545cdcSDaniel Borkmann 12790545cdcSDaniel Borkmann icsk->icsk_ulp_ops = NULL; 128734942ccSDave Watson } 129734942ccSDave Watson 1301243a51fSDaniel Borkmann static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops) 131734942ccSDave Watson { 132734942ccSDave Watson struct inet_connection_sock *icsk = inet_csk(sk); 1331243a51fSDaniel Borkmann int err; 1341243a51fSDaniel Borkmann 1351243a51fSDaniel Borkmann err = -EEXIST; 1361243a51fSDaniel Borkmann if (icsk->icsk_ulp_ops) 1371243a51fSDaniel Borkmann goto out_err; 1381243a51fSDaniel Borkmann 139*e276d62dSPavel Begunkov if (sk->sk_socket) 140*e276d62dSPavel Begunkov clear_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags); 141*e276d62dSPavel Begunkov 1421243a51fSDaniel Borkmann err = ulp_ops->init(sk); 1431243a51fSDaniel Borkmann if (err) 1441243a51fSDaniel Borkmann goto out_err; 1451243a51fSDaniel Borkmann 1461243a51fSDaniel Borkmann icsk->icsk_ulp_ops = ulp_ops; 1471243a51fSDaniel Borkmann return 0; 1481243a51fSDaniel Borkmann out_err: 1491243a51fSDaniel Borkmann module_put(ulp_ops->owner); 1501243a51fSDaniel Borkmann return err; 1511243a51fSDaniel Borkmann } 1521243a51fSDaniel Borkmann 1531243a51fSDaniel Borkmann int tcp_set_ulp(struct sock *sk, const char *name) 1541243a51fSDaniel Borkmann { 155734942ccSDave Watson const struct tcp_ulp_ops *ulp_ops; 156734942ccSDave Watson 1578b9088f8SDaniel Borkmann sock_owned_by_me(sk); 158734942ccSDave Watson 159734942ccSDave Watson ulp_ops = __tcp_ulp_find_autoload(name); 160734942ccSDave Watson if (!ulp_ops) 161539a06baSSabrina Dubroca return -ENOENT; 162734942ccSDave Watson 1631243a51fSDaniel Borkmann return __tcp_set_ulp(sk, ulp_ops); 164734942ccSDave Watson } 165