diff options
Diffstat (limited to 'net/ipv4/tcp_ulp.c')
-rw-r--r-- | net/ipv4/tcp_ulp.c | 59 |
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 | ||
32 | static 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 | |||
32 | static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) | 44 | static 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 | ||
66 | static 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 | |||
163 | int 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); |