1 /* 2 * Pluggable TCP upper layer protocol support. 3 * 4 * Copyright (c) 2016-2017, Mellanox Technologies. All rights reserved. 5 * Copyright (c) 2016-2017, Dave Watson <davejwatson@fb.com>. All rights reserved. 6 * 7 */ 8 9 #include<linux/module.h> 10 #include <linux/mm.h> 11 #include <linux/types.h> 12 #include <linux/list.h> 13 #include <linux/gfp.h> 14 #include <net/tcp.h> 15 16 static DEFINE_SPINLOCK(tcp_ulp_list_lock); 17 static LIST_HEAD(tcp_ulp_list); 18 19 /* Simple linear search, don't expect many entries! */ 20 static struct tcp_ulp_ops *tcp_ulp_find(const char *name) 21 { 22 struct tcp_ulp_ops *e; 23 24 list_for_each_entry_rcu(e, &tcp_ulp_list, list) { 25 if (strcmp(e->name, name) == 0) 26 return e; 27 } 28 29 return NULL; 30 } 31 32 static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) 33 { 34 const struct tcp_ulp_ops *ulp = NULL; 35 36 rcu_read_lock(); 37 ulp = tcp_ulp_find(name); 38 39 #ifdef CONFIG_MODULES 40 if (!ulp && capable(CAP_NET_ADMIN)) { 41 rcu_read_unlock(); 42 request_module("%s", name); 43 rcu_read_lock(); 44 ulp = tcp_ulp_find(name); 45 } 46 #endif 47 if (!ulp || !try_module_get(ulp->owner)) 48 ulp = NULL; 49 50 rcu_read_unlock(); 51 return ulp; 52 } 53 54 /* Attach new upper layer protocol to the list 55 * of available protocols. 56 */ 57 int tcp_register_ulp(struct tcp_ulp_ops *ulp) 58 { 59 int ret = 0; 60 61 spin_lock(&tcp_ulp_list_lock); 62 if (tcp_ulp_find(ulp->name)) { 63 pr_notice("%s already registered or non-unique name\n", 64 ulp->name); 65 ret = -EEXIST; 66 } else { 67 list_add_tail_rcu(&ulp->list, &tcp_ulp_list); 68 } 69 spin_unlock(&tcp_ulp_list_lock); 70 71 return ret; 72 } 73 EXPORT_SYMBOL_GPL(tcp_register_ulp); 74 75 void tcp_unregister_ulp(struct tcp_ulp_ops *ulp) 76 { 77 spin_lock(&tcp_ulp_list_lock); 78 list_del_rcu(&ulp->list); 79 spin_unlock(&tcp_ulp_list_lock); 80 81 synchronize_rcu(); 82 } 83 EXPORT_SYMBOL_GPL(tcp_unregister_ulp); 84 85 /* Build string with list of available upper layer protocl values */ 86 void tcp_get_available_ulp(char *buf, size_t maxlen) 87 { 88 struct tcp_ulp_ops *ulp_ops; 89 size_t offs = 0; 90 91 *buf = '\0'; 92 rcu_read_lock(); 93 list_for_each_entry_rcu(ulp_ops, &tcp_ulp_list, list) { 94 offs += snprintf(buf + offs, maxlen - offs, 95 "%s%s", 96 offs == 0 ? "" : " ", ulp_ops->name); 97 } 98 rcu_read_unlock(); 99 } 100 101 void tcp_cleanup_ulp(struct sock *sk) 102 { 103 struct inet_connection_sock *icsk = inet_csk(sk); 104 105 if (!icsk->icsk_ulp_ops) 106 return; 107 108 if (icsk->icsk_ulp_ops->release) 109 icsk->icsk_ulp_ops->release(sk); 110 module_put(icsk->icsk_ulp_ops->owner); 111 } 112 113 /* Change upper layer protocol for socket */ 114 int tcp_set_ulp(struct sock *sk, const char *name) 115 { 116 struct inet_connection_sock *icsk = inet_csk(sk); 117 const struct tcp_ulp_ops *ulp_ops; 118 int err = 0; 119 120 if (icsk->icsk_ulp_ops) 121 return -EEXIST; 122 123 ulp_ops = __tcp_ulp_find_autoload(name); 124 if (!ulp_ops) 125 return -ENOENT; 126 127 err = ulp_ops->init(sk); 128 if (err) { 129 module_put(ulp_ops->owner); 130 return err; 131 } 132 133 icsk->icsk_ulp_ops = ulp_ops; 134 return 0; 135 } 136