^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Pluggable TCP upper layer protocol support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2016-2017, Dave Watson <davejwatson@fb.com>. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <net/tcp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) static DEFINE_SPINLOCK(tcp_ulp_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static LIST_HEAD(tcp_ulp_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* Simple linear search, don't expect many entries! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static struct tcp_ulp_ops *tcp_ulp_find(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct tcp_ulp_ops *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) list_for_each_entry_rcu(e, &tcp_ulp_list, list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) lockdep_is_held(&tcp_ulp_list_lock)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) if (strcmp(e->name, name) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) const struct tcp_ulp_ops *ulp = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ulp = tcp_ulp_find(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #ifdef CONFIG_MODULES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (!ulp && capable(CAP_NET_ADMIN)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) request_module("tcp-ulp-%s", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) ulp = tcp_ulp_find(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (!ulp || !try_module_get(ulp->owner))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) ulp = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return ulp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /* Attach new upper layer protocol to the list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * of available protocols.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int tcp_register_ulp(struct tcp_ulp_ops *ulp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) spin_lock(&tcp_ulp_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (tcp_ulp_find(ulp->name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ret = -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) list_add_tail_rcu(&ulp->list, &tcp_ulp_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) spin_unlock(&tcp_ulp_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) EXPORT_SYMBOL_GPL(tcp_register_ulp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) void tcp_unregister_ulp(struct tcp_ulp_ops *ulp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) spin_lock(&tcp_ulp_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) list_del_rcu(&ulp->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) spin_unlock(&tcp_ulp_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) synchronize_rcu();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) EXPORT_SYMBOL_GPL(tcp_unregister_ulp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* Build string with list of available upper layer protocl values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) void tcp_get_available_ulp(char *buf, size_t maxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct tcp_ulp_ops *ulp_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) size_t offs = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) *buf = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) list_for_each_entry_rcu(ulp_ops, &tcp_ulp_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) offs += snprintf(buf + offs, maxlen - offs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) "%s%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) offs == 0 ? "" : " ", ulp_ops->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (WARN_ON_ONCE(offs >= maxlen))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) void tcp_update_ulp(struct sock *sk, struct proto *proto,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) void (*write_space)(struct sock *sk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct inet_connection_sock *icsk = inet_csk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (icsk->icsk_ulp_ops->update)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) icsk->icsk_ulp_ops->update(sk, proto, write_space);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) void tcp_cleanup_ulp(struct sock *sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct inet_connection_sock *icsk = inet_csk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* No sock_owned_by_me() check here as at the time the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * stack calls this function, the socket is dead and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * about to be destroyed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (!icsk->icsk_ulp_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (icsk->icsk_ulp_ops->release)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) icsk->icsk_ulp_ops->release(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) module_put(icsk->icsk_ulp_ops->owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) icsk->icsk_ulp_ops = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct inet_connection_sock *icsk = inet_csk(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) err = -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (icsk->icsk_ulp_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) err = ulp_ops->init(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) goto out_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) icsk->icsk_ulp_ops = ulp_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) out_err:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) module_put(ulp_ops->owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) int tcp_set_ulp(struct sock *sk, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) const struct tcp_ulp_ops *ulp_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) sock_owned_by_me(sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) ulp_ops = __tcp_ulp_find_autoload(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (!ulp_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return __tcp_set_ulp(sk, ulp_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }