aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_cong.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_cong.c')
-rw-r--r--net/ipv4/tcp_cong.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index d846d7b95e1f..343d6197c92e 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -123,6 +123,7 @@ int tcp_set_default_congestion_control(const char *name)
123#endif 123#endif
124 124
125 if (ca) { 125 if (ca) {
126 ca->non_restricted = 1; /* default is always allowed */
126 list_move(&ca->list, &tcp_cong_list); 127 list_move(&ca->list, &tcp_cong_list);
127 ret = 0; 128 ret = 0;
128 } 129 }
@@ -168,6 +169,64 @@ void tcp_get_default_congestion_control(char *name)
168 rcu_read_unlock(); 169 rcu_read_unlock();
169} 170}
170 171
172/* Built list of non-restricted congestion control values */
173void tcp_get_allowed_congestion_control(char *buf, size_t maxlen)
174{
175 struct tcp_congestion_ops *ca;
176 size_t offs = 0;
177
178 *buf = '\0';
179 rcu_read_lock();
180 list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
181 if (!ca->non_restricted)
182 continue;
183 offs += snprintf(buf + offs, maxlen - offs,
184 "%s%s",
185 offs == 0 ? "" : " ", ca->name);
186
187 }
188 rcu_read_unlock();
189}
190
191/* Change list of non-restricted congestion control */
192int tcp_set_allowed_congestion_control(char *val)
193{
194 struct tcp_congestion_ops *ca;
195 char *clone, *name;
196 int ret = 0;
197
198 clone = kstrdup(val, GFP_USER);
199 if (!clone)
200 return -ENOMEM;
201
202 spin_lock(&tcp_cong_list_lock);
203 /* pass 1 check for bad entries */
204 while ((name = strsep(&clone, " ")) && *name) {
205 ca = tcp_ca_find(name);
206 if (!ca) {
207 ret = -ENOENT;
208 goto out;
209 }
210 }
211
212 /* pass 2 clear */
213 list_for_each_entry_rcu(ca, &tcp_cong_list, list)
214 ca->non_restricted = 0;
215
216 /* pass 3 mark as allowed */
217 while ((name = strsep(&val, " ")) && *name) {
218 ca = tcp_ca_find(name);
219 WARN_ON(!ca);
220 if (ca)
221 ca->non_restricted = 1;
222 }
223out:
224 spin_unlock(&tcp_cong_list_lock);
225
226 return ret;
227}
228
229
171/* Change congestion control for socket */ 230/* Change congestion control for socket */
172int tcp_set_congestion_control(struct sock *sk, const char *name) 231int tcp_set_congestion_control(struct sock *sk, const char *name)
173{ 232{
@@ -183,6 +242,9 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
183 if (!ca) 242 if (!ca)
184 err = -ENOENT; 243 err = -ENOENT;
185 244
245 else if (!(ca->non_restricted || capable(CAP_NET_ADMIN)))
246 err = -EPERM;
247
186 else if (!try_module_get(ca->owner)) 248 else if (!try_module_get(ca->owner))
187 err = -EBUSY; 249 err = -EBUSY;
188 250
@@ -284,6 +346,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd);
284 346
285struct tcp_congestion_ops tcp_reno = { 347struct tcp_congestion_ops tcp_reno = {
286 .name = "reno", 348 .name = "reno",
349 .non_restricted = 1,
287 .owner = THIS_MODULE, 350 .owner = THIS_MODULE,
288 .ssthresh = tcp_reno_ssthresh, 351 .ssthresh = tcp_reno_ssthresh,
289 .cong_avoid = tcp_reno_cong_avoid, 352 .cong_avoid = tcp_reno_cong_avoid,