sysctl.c 12.5 KB
Newer Older
1
/* SCTP kernel implementation
Linus Torvalds's avatar
Linus Torvalds committed
2 3 4
 * (C) Copyright IBM Corp. 2002, 2004
 * Copyright (c) 2002 Intel Corp.
 *
5
 * This file is part of the SCTP kernel implementation
Linus Torvalds's avatar
Linus Torvalds committed
6 7 8
 *
 * Sysctl related interfaces for SCTP.
 *
9
 * This SCTP implementation is free software;
Linus Torvalds's avatar
Linus Torvalds committed
10 11 12 13 14
 * you can redistribute it and/or modify it under the terms of
 * the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
15
 * This SCTP implementation is distributed in the hope that it
Linus Torvalds's avatar
Linus Torvalds committed
16 17 18 19 20 21
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
 *                 ************************
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
22 23
 * along with GNU CC; see the file COPYING.  If not, see
 * <http://www.gnu.org/licenses/>.
Linus Torvalds's avatar
Linus Torvalds committed
24 25 26
 *
 * Please send any bug reports or fixes you make to the
 * email address(es):
27
 *    lksctp developers <linux-sctp@vger.kernel.org>
Linus Torvalds's avatar
Linus Torvalds committed
28 29 30 31 32 33 34 35 36
 *
 * Written or modified by:
 *    Mingqin Liu           <liuming@us.ibm.com>
 *    Jon Grimm             <jgrimm@us.ibm.com>
 *    Ardelle Fan           <ardelle.fan@intel.com>
 *    Ryan Layer            <rmlayer@us.ibm.com>
 *    Sridhar Samudrala     <sri@us.ibm.com>
 */

37 38
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

Linus Torvalds's avatar
Linus Torvalds committed
39
#include <net/sctp/structs.h>
40
#include <net/sctp/sctp.h>
Linus Torvalds's avatar
Linus Torvalds committed
41 42
#include <linux/sysctl.h>

43 44 45 46
static int zero = 0;
static int one = 1;
static int timer_max = 86400000; /* ms in one day */
static int int_max = INT_MAX;
47 48
static int sack_timer_min = 1;
static int sack_timer_max = 500;
49
static int addr_scope_max = SCTP_SCOPE_POLICY_MAX;
50
static int rwnd_scale_max = 16;
51 52 53 54 55
static int rto_alpha_min = 0;
static int rto_beta_min = 0;
static int rto_alpha_max = 1000;
static int rto_beta_max = 1000;

56 57 58 59
static unsigned long max_autoclose_min = 0;
static unsigned long max_autoclose_max =
	(MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX)
	? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ;
Linus Torvalds's avatar
Linus Torvalds committed
60

wangweidong's avatar
wangweidong committed
61
static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write,
62 63
				void __user *buffer, size_t *lenp,
				loff_t *ppos);
64 65 66 67
static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write,
				void __user *buffer, size_t *lenp,
				loff_t *ppos);
static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write,
68 69
				void __user *buffer, size_t *lenp,
				loff_t *ppos);
70 71 72
static int proc_sctp_do_alpha_beta(struct ctl_table *ctl, int write,
				   void __user *buffer, size_t *lenp,
				   loff_t *ppos);
73 74 75
static int proc_sctp_do_auth(struct ctl_table *ctl, int write,
			     void __user *buffer, size_t *lenp,
			     loff_t *ppos);
76

77
static struct ctl_table sctp_table[] = {
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	{
		.procname	= "sctp_mem",
		.data		= &sysctl_sctp_mem,
		.maxlen		= sizeof(sysctl_sctp_mem),
		.mode		= 0644,
		.proc_handler	= proc_doulongvec_minmax
	},
	{
		.procname	= "sctp_rmem",
		.data		= &sysctl_sctp_rmem,
		.maxlen		= sizeof(sysctl_sctp_rmem),
		.mode		= 0644,
		.proc_handler	= proc_dointvec,
	},
	{
		.procname	= "sctp_wmem",
		.data		= &sysctl_sctp_wmem,
		.maxlen		= sizeof(sysctl_sctp_wmem),
		.mode		= 0644,
		.proc_handler	= proc_dointvec,
	},

	{ /* sentinel */ }
};

103
static struct ctl_table sctp_net_table[] = {
Linus Torvalds's avatar
Linus Torvalds committed
104 105
	{
		.procname	= "rto_initial",
106
		.data		= &init_net.sctp.rto_initial,
107
		.maxlen		= sizeof(unsigned int),
Linus Torvalds's avatar
Linus Torvalds committed
108
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
109
		.proc_handler	= proc_dointvec_minmax,
110 111
		.extra1         = &one,
		.extra2         = &timer_max
Linus Torvalds's avatar
Linus Torvalds committed
112 113 114
	},
	{
		.procname	= "rto_min",
115
		.data		= &init_net.sctp.rto_min,
116
		.maxlen		= sizeof(unsigned int),
Linus Torvalds's avatar
Linus Torvalds committed
117
		.mode		= 0644,
118
		.proc_handler	= proc_sctp_do_rto_min,
119
		.extra1         = &one,
120
		.extra2         = &init_net.sctp.rto_max
Linus Torvalds's avatar
Linus Torvalds committed
121 122 123
	},
	{
		.procname	= "rto_max",
124
		.data		= &init_net.sctp.rto_max,
125
		.maxlen		= sizeof(unsigned int),
Linus Torvalds's avatar
Linus Torvalds committed
126
		.mode		= 0644,
127 128
		.proc_handler	= proc_sctp_do_rto_max,
		.extra1         = &init_net.sctp.rto_min,
129
		.extra2         = &timer_max
Linus Torvalds's avatar
Linus Torvalds committed
130 131
	},
	{
132 133 134
		.procname	= "rto_alpha_exp_divisor",
		.data		= &init_net.sctp.rto_alpha,
		.maxlen		= sizeof(int),
135 136 137 138
		.mode		= 0644,
		.proc_handler	= proc_sctp_do_alpha_beta,
		.extra1		= &rto_alpha_min,
		.extra2		= &rto_alpha_max,
139 140 141 142 143
	},
	{
		.procname	= "rto_beta_exp_divisor",
		.data		= &init_net.sctp.rto_beta,
		.maxlen		= sizeof(int),
144 145 146 147
		.mode		= 0644,
		.proc_handler	= proc_sctp_do_alpha_beta,
		.extra1		= &rto_beta_min,
		.extra2		= &rto_beta_max,
Linus Torvalds's avatar
Linus Torvalds committed
148 149 150
	},
	{
		.procname	= "max_burst",
151
		.data		= &init_net.sctp.max_burst,
Linus Torvalds's avatar
Linus Torvalds committed
152 153
		.maxlen		= sizeof(int),
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
154
		.proc_handler	= proc_dointvec_minmax,
155 156
		.extra1		= &zero,
		.extra2		= &int_max
Linus Torvalds's avatar
Linus Torvalds committed
157 158
	},
	{
159 160
		.procname	= "cookie_preserve_enable",
		.data		= &init_net.sctp.cookie_preserve_enable,
Linus Torvalds's avatar
Linus Torvalds committed
161 162
		.maxlen		= sizeof(int),
		.mode		= 0644,
163 164
		.proc_handler	= proc_dointvec,
	},
165 166
	{
		.procname	= "cookie_hmac_alg",
167
		.data		= &init_net.sctp.sctp_hmac_alg,
168 169 170 171
		.maxlen		= 8,
		.mode		= 0644,
		.proc_handler	= proc_sctp_do_hmac_alg,
	},
172 173 174 175 176
	{
		.procname	= "valid_cookie_life",
		.data		= &init_net.sctp.valid_cookie_life,
		.maxlen		= sizeof(unsigned int),
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
177
		.proc_handler	= proc_dointvec_minmax,
178 179
		.extra1         = &one,
		.extra2         = &timer_max
Linus Torvalds's avatar
Linus Torvalds committed
180
	},
181
	{
182 183
		.procname	= "sack_timeout",
		.data		= &init_net.sctp.sack_timeout,
184 185
		.maxlen		= sizeof(int),
		.mode		= 0644,
186 187 188
		.proc_handler	= proc_dointvec_minmax,
		.extra1         = &sack_timer_min,
		.extra2         = &sack_timer_max,
189
	},
190
	{
191 192 193
		.procname	= "hb_interval",
		.data		= &init_net.sctp.hb_interval,
		.maxlen		= sizeof(unsigned int),
194
		.mode		= 0644,
195 196 197
		.proc_handler	= proc_dointvec_minmax,
		.extra1         = &one,
		.extra2         = &timer_max
198
	},
Linus Torvalds's avatar
Linus Torvalds committed
199
	{
200 201
		.procname	= "association_max_retrans",
		.data		= &init_net.sctp.max_retrans_association,
Linus Torvalds's avatar
Linus Torvalds committed
202 203
		.maxlen		= sizeof(int),
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
204
		.proc_handler	= proc_dointvec_minmax,
205 206
		.extra1		= &one,
		.extra2		= &int_max
Linus Torvalds's avatar
Linus Torvalds committed
207
	},
208
	{
209 210
		.procname	= "path_max_retrans",
		.data		= &init_net.sctp.max_retrans_path,
211 212 213
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec_minmax,
214
		.extra1		= &one,
215 216
		.extra2		= &int_max
	},
Linus Torvalds's avatar
Linus Torvalds committed
217 218
	{
		.procname	= "max_init_retransmits",
219
		.data		= &init_net.sctp.max_retrans_init,
Linus Torvalds's avatar
Linus Torvalds committed
220 221
		.maxlen		= sizeof(int),
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
222
		.proc_handler	= proc_dointvec_minmax,
223 224
		.extra1		= &one,
		.extra2		= &int_max
Linus Torvalds's avatar
Linus Torvalds committed
225 226
	},
	{
227 228 229
		.procname	= "pf_retrans",
		.data		= &init_net.sctp.pf_retrans,
		.maxlen		= sizeof(int),
Linus Torvalds's avatar
Linus Torvalds committed
230
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
231
		.proc_handler	= proc_dointvec_minmax,
232 233
		.extra1		= &zero,
		.extra2		= &int_max
Linus Torvalds's avatar
Linus Torvalds committed
234 235
	},
	{
236 237
		.procname	= "sndbuf_policy",
		.data		= &init_net.sctp.sndbuf_policy,
238
		.maxlen		= sizeof(int),
Linus Torvalds's avatar
Linus Torvalds committed
239
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
240
		.proc_handler	= proc_dointvec,
Linus Torvalds's avatar
Linus Torvalds committed
241 242
	},
	{
243 244
		.procname	= "rcvbuf_policy",
		.data		= &init_net.sctp.rcvbuf_policy,
245 246 247 248 249 250
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec,
	},
	{
		.procname	= "default_auto_asconf",
251
		.data		= &init_net.sctp.default_auto_asconf,
Linus Torvalds's avatar
Linus Torvalds committed
252 253
		.maxlen		= sizeof(int),
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
254
		.proc_handler	= proc_dointvec,
Linus Torvalds's avatar
Linus Torvalds committed
255 256
	},
	{
257 258
		.procname	= "addip_enable",
		.data		= &init_net.sctp.addip_enable,
Linus Torvalds's avatar
Linus Torvalds committed
259 260
		.maxlen		= sizeof(int),
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
261
		.proc_handler	= proc_dointvec,
Linus Torvalds's avatar
Linus Torvalds committed
262
	},
263
	{
264 265
		.procname	= "addip_noauth_enable",
		.data		= &init_net.sctp.addip_noauth,
266
		.maxlen		= sizeof(int),
267
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
268
		.proc_handler	= proc_dointvec,
269 270
	},
	{
271 272
		.procname	= "prsctp_enable",
		.data		= &init_net.sctp.prsctp_enable,
273 274
		.maxlen		= sizeof(int),
		.mode		= 0644,
Alexey Dobriyan's avatar
Alexey Dobriyan committed
275
		.proc_handler	= proc_dointvec,
276
	},
277 278 279 280 281 282 283
	{
		.procname	= "reconf_enable",
		.data		= &init_net.sctp.reconf_enable,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec,
	},
284
	{
285 286
		.procname	= "auth_enable",
		.data		= &init_net.sctp.auth_enable,
287 288
		.maxlen		= sizeof(int),
		.mode		= 0644,
289
		.proc_handler	= proc_sctp_do_auth,
290
	},
291 292
	{
		.procname	= "addr_scope_policy",
293
		.data		= &init_net.sctp.scope_policy,
294 295
		.maxlen		= sizeof(int),
		.mode		= 0644,
296
		.proc_handler	= proc_dointvec_minmax,
297 298 299
		.extra1		= &zero,
		.extra2		= &addr_scope_max,
	},
300 301
	{
		.procname	= "rwnd_update_shift",
302
		.data		= &init_net.sctp.rwnd_upd_shift,
303 304 305 306 307 308
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= &proc_dointvec_minmax,
		.extra1		= &one,
		.extra2		= &rwnd_scale_max,
	},
309 310
	{
		.procname	= "max_autoclose",
311
		.data		= &init_net.sctp.max_autoclose,
312 313 314 315 316 317
		.maxlen		= sizeof(unsigned long),
		.mode		= 0644,
		.proc_handler	= &proc_doulongvec_minmax,
		.extra1		= &max_autoclose_min,
		.extra2		= &max_autoclose_max,
	},
318 319 320 321 322 323 324
	{
		.procname	= "pf_enable",
		.data		= &init_net.sctp.pf_enable,
		.maxlen		= sizeof(int),
		.mode		= 0644,
		.proc_handler	= proc_dointvec,
	},
325

326
	{ /* sentinel */ }
Linus Torvalds's avatar
Linus Torvalds committed
327 328
};

wangweidong's avatar
wangweidong committed
329
static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write,
330 331 332 333
				void __user *buffer, size_t *lenp,
				loff_t *ppos)
{
	struct net *net = current->nsproxy->net_ns;
334
	struct ctl_table tbl;
335
	bool changed = false;
336
	char *none = "none";
337
	char tmp[8] = {0};
338
	int ret;
339 340 341 342 343

	memset(&tbl, 0, sizeof(struct ctl_table));

	if (write) {
		tbl.data = tmp;
344
		tbl.maxlen = sizeof(tmp);
345 346 347 348 349
	} else {
		tbl.data = net->sctp.sctp_hmac_alg ? : none;
		tbl.maxlen = strlen(tbl.data);
	}

350 351
	ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
	if (write && ret == 0) {
352 353 354
#ifdef CONFIG_CRYPTO_MD5
		if (!strncmp(tmp, "md5", 3)) {
			net->sctp.sctp_hmac_alg = "md5";
355
			changed = true;
356 357 358 359 360
		}
#endif
#ifdef CONFIG_CRYPTO_SHA1
		if (!strncmp(tmp, "sha1", 4)) {
			net->sctp.sctp_hmac_alg = "sha1";
361
			changed = true;
362 363 364 365
		}
#endif
		if (!strncmp(tmp, "none", 4)) {
			net->sctp.sctp_hmac_alg = NULL;
366
			changed = true;
367 368 369 370 371 372 373 374
		}
		if (!changed)
			ret = -EINVAL;
	}

	return ret;
}

375 376 377 378 379 380 381
static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write,
				void __user *buffer, size_t *lenp,
				loff_t *ppos)
{
	struct net *net = current->nsproxy->net_ns;
	unsigned int min = *(unsigned int *) ctl->extra1;
	unsigned int max = *(unsigned int *) ctl->extra2;
382 383
	struct ctl_table tbl;
	int ret, new_value;
384 385 386 387 388 389 390 391

	memset(&tbl, 0, sizeof(struct ctl_table));
	tbl.maxlen = sizeof(unsigned int);

	if (write)
		tbl.data = &new_value;
	else
		tbl.data = &net->sctp.rto_min;
392

393
	ret = proc_dointvec(&tbl, write, buffer, lenp, ppos);
394 395
	if (write && ret == 0) {
		if (new_value > max || new_value < min)
396
			return -EINVAL;
397

398 399
		net->sctp.rto_min = new_value;
	}
400

401 402 403 404 405 406 407 408 409 410
	return ret;
}

static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write,
				void __user *buffer, size_t *lenp,
				loff_t *ppos)
{
	struct net *net = current->nsproxy->net_ns;
	unsigned int min = *(unsigned int *) ctl->extra1;
	unsigned int max = *(unsigned int *) ctl->extra2;
411 412
	struct ctl_table tbl;
	int ret, new_value;
413 414 415 416 417 418 419 420

	memset(&tbl, 0, sizeof(struct ctl_table));
	tbl.maxlen = sizeof(unsigned int);

	if (write)
		tbl.data = &new_value;
	else
		tbl.data = &net->sctp.rto_max;
421

422
	ret = proc_dointvec(&tbl, write, buffer, lenp, ppos);
423 424
	if (write && ret == 0) {
		if (new_value > max || new_value < min)
425
			return -EINVAL;
426

427 428
		net->sctp.rto_max = new_value;
	}
429

430 431 432
	return ret;
}

433 434 435 436
static int proc_sctp_do_alpha_beta(struct ctl_table *ctl, int write,
				   void __user *buffer, size_t *lenp,
				   loff_t *ppos)
{
437 438 439
	if (write)
		pr_warn_once("Changing rto_alpha or rto_beta may lead to "
			     "suboptimal rtt/srtt estimations!\n");
440 441 442 443

	return proc_dointvec_minmax(ctl, write, buffer, lenp, ppos);
}

444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
static int proc_sctp_do_auth(struct ctl_table *ctl, int write,
			     void __user *buffer, size_t *lenp,
			     loff_t *ppos)
{
	struct net *net = current->nsproxy->net_ns;
	struct ctl_table tbl;
	int new_value, ret;

	memset(&tbl, 0, sizeof(struct ctl_table));
	tbl.maxlen = sizeof(unsigned int);

	if (write)
		tbl.data = &new_value;
	else
		tbl.data = &net->sctp.auth_enable;

	ret = proc_dointvec(&tbl, write, buffer, lenp, ppos);
461
	if (write && ret == 0) {
462 463 464 465 466 467 468 469 470 471 472 473
		struct sock *sk = net->sctp.ctl_sock;

		net->sctp.auth_enable = new_value;
		/* Update the value in the control socket */
		lock_sock(sk);
		sctp_sk(sk)->ep->auth_enable = new_value;
		release_sock(sk);
	}

	return ret;
}

474 475
int sctp_sysctl_net_register(struct net *net)
{
476 477
	struct ctl_table *table;
	int i;
478

479 480 481
	table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL);
	if (!table)
		return -ENOMEM;
482

483 484
	for (i = 0; table[i].data; i++)
		table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp;
485

486
	net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table);
487 488 489 490
	if (net->sctp.sysctl_header == NULL) {
		kfree(table);
		return -ENOMEM;
	}
491 492 493 494 495
	return 0;
}

void sctp_sysctl_net_unregister(struct net *net)
{
496 497 498
	struct ctl_table *table;

	table = net->sctp.sysctl_header->ctl_table_arg;
499
	unregister_net_sysctl_table(net->sctp.sysctl_header);
500
	kfree(table);
501 502
}

503
static struct ctl_table_header *sctp_sysctl_header;
Linus Torvalds's avatar
Linus Torvalds committed
504 505 506 507

/* Sysctl registration.  */
void sctp_sysctl_register(void)
{
508
	sctp_sysctl_header = register_net_sysctl(&init_net, "net/sctp", sctp_table);
Linus Torvalds's avatar
Linus Torvalds committed
509 510 511 512 513
}

/* Sysctl deregistration.  */
void sctp_sysctl_unregister(void)
{
514
	unregister_net_sysctl_table(sctp_sysctl_header);
Linus Torvalds's avatar
Linus Torvalds committed
515
}