Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Pluggable TCP upper layer protocol support.
0004  *
0005  * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved.
0006  * Copyright (c) 2016-2017, Dave Watson <davejwatson@fb.com>. All rights reserved.
0007  *
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/mm.h>
0012 #include <linux/types.h>
0013 #include <linux/list.h>
0014 #include <linux/gfp.h>
0015 #include <net/tcp.h>
0016 
0017 static DEFINE_SPINLOCK(tcp_ulp_list_lock);
0018 static LIST_HEAD(tcp_ulp_list);
0019 
0020 /* Simple linear search, don't expect many entries! */
0021 static struct tcp_ulp_ops *tcp_ulp_find(const char *name)
0022 {
0023     struct tcp_ulp_ops *e;
0024 
0025     list_for_each_entry_rcu(e, &tcp_ulp_list, list,
0026                 lockdep_is_held(&tcp_ulp_list_lock)) {
0027         if (strcmp(e->name, name) == 0)
0028             return e;
0029     }
0030 
0031     return NULL;
0032 }
0033 
0034 static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name)
0035 {
0036     const struct tcp_ulp_ops *ulp = NULL;
0037 
0038     rcu_read_lock();
0039     ulp = tcp_ulp_find(name);
0040 
0041 #ifdef CONFIG_MODULES
0042     if (!ulp && capable(CAP_NET_ADMIN)) {
0043         rcu_read_unlock();
0044         request_module("tcp-ulp-%s", name);
0045         rcu_read_lock();
0046         ulp = tcp_ulp_find(name);
0047     }
0048 #endif
0049     if (!ulp || !try_module_get(ulp->owner))
0050         ulp = NULL;
0051 
0052     rcu_read_unlock();
0053     return ulp;
0054 }
0055 
0056 /* Attach new upper layer protocol to the list
0057  * of available protocols.
0058  */
0059 int tcp_register_ulp(struct tcp_ulp_ops *ulp)
0060 {
0061     int ret = 0;
0062 
0063     spin_lock(&tcp_ulp_list_lock);
0064     if (tcp_ulp_find(ulp->name))
0065         ret = -EEXIST;
0066     else
0067         list_add_tail_rcu(&ulp->list, &tcp_ulp_list);
0068     spin_unlock(&tcp_ulp_list_lock);
0069 
0070     return ret;
0071 }
0072 EXPORT_SYMBOL_GPL(tcp_register_ulp);
0073 
0074 void tcp_unregister_ulp(struct tcp_ulp_ops *ulp)
0075 {
0076     spin_lock(&tcp_ulp_list_lock);
0077     list_del_rcu(&ulp->list);
0078     spin_unlock(&tcp_ulp_list_lock);
0079 
0080     synchronize_rcu();
0081 }
0082 EXPORT_SYMBOL_GPL(tcp_unregister_ulp);
0083 
0084 /* Build string with list of available upper layer protocl values */
0085 void tcp_get_available_ulp(char *buf, size_t maxlen)
0086 {
0087     struct tcp_ulp_ops *ulp_ops;
0088     size_t offs = 0;
0089 
0090     *buf = '\0';
0091     rcu_read_lock();
0092     list_for_each_entry_rcu(ulp_ops, &tcp_ulp_list, list) {
0093         offs += snprintf(buf + offs, maxlen - offs,
0094                  "%s%s",
0095                  offs == 0 ? "" : " ", ulp_ops->name);
0096 
0097         if (WARN_ON_ONCE(offs >= maxlen))
0098             break;
0099     }
0100     rcu_read_unlock();
0101 }
0102 
0103 void tcp_update_ulp(struct sock *sk, struct proto *proto,
0104             void (*write_space)(struct sock *sk))
0105 {
0106     struct inet_connection_sock *icsk = inet_csk(sk);
0107 
0108     if (icsk->icsk_ulp_ops->update)
0109         icsk->icsk_ulp_ops->update(sk, proto, write_space);
0110 }
0111 
0112 void tcp_cleanup_ulp(struct sock *sk)
0113 {
0114     struct inet_connection_sock *icsk = inet_csk(sk);
0115 
0116     /* No sock_owned_by_me() check here as at the time the
0117      * stack calls this function, the socket is dead and
0118      * about to be destroyed.
0119      */
0120     if (!icsk->icsk_ulp_ops)
0121         return;
0122 
0123     if (icsk->icsk_ulp_ops->release)
0124         icsk->icsk_ulp_ops->release(sk);
0125     module_put(icsk->icsk_ulp_ops->owner);
0126 
0127     icsk->icsk_ulp_ops = NULL;
0128 }
0129 
0130 static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops)
0131 {
0132     struct inet_connection_sock *icsk = inet_csk(sk);
0133     int err;
0134 
0135     err = -EEXIST;
0136     if (icsk->icsk_ulp_ops)
0137         goto out_err;
0138 
0139     err = ulp_ops->init(sk);
0140     if (err)
0141         goto out_err;
0142 
0143     icsk->icsk_ulp_ops = ulp_ops;
0144     return 0;
0145 out_err:
0146     module_put(ulp_ops->owner);
0147     return err;
0148 }
0149 
0150 int tcp_set_ulp(struct sock *sk, const char *name)
0151 {
0152     const struct tcp_ulp_ops *ulp_ops;
0153 
0154     sock_owned_by_me(sk);
0155 
0156     ulp_ops = __tcp_ulp_find_autoload(name);
0157     if (!ulp_ops)
0158         return -ENOENT;
0159 
0160     return __tcp_set_ulp(sk, ulp_ops);
0161 }