aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_ulp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_ulp.c')
-rw-r--r--net/ipv4/tcp_ulp.c59
1 files changed, 54 insertions, 5 deletions
diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c
index 6bb9e14c710a..622caa4039e0 100644
--- a/net/ipv4/tcp_ulp.c
+++ b/net/ipv4/tcp_ulp.c
@@ -29,6 +29,18 @@ static struct tcp_ulp_ops *tcp_ulp_find(const char *name)
29 return NULL; 29 return NULL;
30} 30}
31 31
32static struct tcp_ulp_ops *tcp_ulp_find_id(const int ulp)
33{
34 struct tcp_ulp_ops *e;
35
36 list_for_each_entry_rcu(e, &tcp_ulp_list, list) {
37 if (e->uid == ulp)
38 return e;
39 }
40
41 return NULL;
42}
43
32static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) 44static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name)
33{ 45{
34 const struct tcp_ulp_ops *ulp = NULL; 46 const struct tcp_ulp_ops *ulp = NULL;
@@ -51,6 +63,18 @@ static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name)
51 return ulp; 63 return ulp;
52} 64}
53 65
66static const struct tcp_ulp_ops *__tcp_ulp_lookup(const int uid)
67{
68 const struct tcp_ulp_ops *ulp;
69
70 rcu_read_lock();
71 ulp = tcp_ulp_find_id(uid);
72 if (!ulp || !try_module_get(ulp->owner))
73 ulp = NULL;
74 rcu_read_unlock();
75 return ulp;
76}
77
54/* Attach new upper layer protocol to the list 78/* Attach new upper layer protocol to the list
55 * of available protocols. 79 * of available protocols.
56 */ 80 */
@@ -59,13 +83,10 @@ int tcp_register_ulp(struct tcp_ulp_ops *ulp)
59 int ret = 0; 83 int ret = 0;
60 84
61 spin_lock(&tcp_ulp_list_lock); 85 spin_lock(&tcp_ulp_list_lock);
62 if (tcp_ulp_find(ulp->name)) { 86 if (tcp_ulp_find(ulp->name))
63 pr_notice("%s already registered or non-unique name\n",
64 ulp->name);
65 ret = -EEXIST; 87 ret = -EEXIST;
66 } else { 88 else
67 list_add_tail_rcu(&ulp->list, &tcp_ulp_list); 89 list_add_tail_rcu(&ulp->list, &tcp_ulp_list);
68 }
69 spin_unlock(&tcp_ulp_list_lock); 90 spin_unlock(&tcp_ulp_list_lock);
70 91
71 return ret; 92 return ret;
@@ -124,6 +145,34 @@ int tcp_set_ulp(struct sock *sk, const char *name)
124 if (!ulp_ops) 145 if (!ulp_ops)
125 return -ENOENT; 146 return -ENOENT;
126 147
148 if (!ulp_ops->user_visible) {
149 module_put(ulp_ops->owner);
150 return -ENOENT;
151 }
152
153 err = ulp_ops->init(sk);
154 if (err) {
155 module_put(ulp_ops->owner);
156 return err;
157 }
158
159 icsk->icsk_ulp_ops = ulp_ops;
160 return 0;
161}
162
163int tcp_set_ulp_id(struct sock *sk, int ulp)
164{
165 struct inet_connection_sock *icsk = inet_csk(sk);
166 const struct tcp_ulp_ops *ulp_ops;
167 int err;
168
169 if (icsk->icsk_ulp_ops)
170 return -EEXIST;
171
172 ulp_ops = __tcp_ulp_lookup(ulp);
173 if (!ulp_ops)
174 return -ENOENT;
175
127 err = ulp_ops->init(sk); 176 err = ulp_ops->init(sk);
128 if (err) { 177 if (err) {
129 module_put(ulp_ops->owner); 178 module_put(ulp_ops->owner);