diff options
Diffstat (limited to 'net/sctp/sysctl.c')
| -rw-r--r-- | net/sctp/sysctl.c | 178 | 
1 files changed, 150 insertions, 28 deletions
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 6b36561a1b3..12c7e01c267 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -19,9 +19,8 @@   * See the GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING.  If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING.  If not, see + * <http://www.gnu.org/licenses/>.   *   * Please send any bug reports or fixes you make to the   * email address(es): @@ -35,6 +34,8 @@   *    Sridhar Samudrala     <sri@us.ibm.com>   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <net/sctp/structs.h>  #include <net/sctp/sctp.h>  #include <linux/sysctl.h> @@ -47,6 +48,11 @@ static int sack_timer_min = 1;  static int sack_timer_max = 500;  static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */  static int rwnd_scale_max = 16; +static int rto_alpha_min = 0; +static int rto_beta_min = 0; +static int rto_alpha_max = 1000; +static int rto_beta_max = 1000; +  static unsigned long max_autoclose_min = 0;  static unsigned long max_autoclose_max =  	(MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX) @@ -56,11 +62,22 @@ extern long sysctl_sctp_mem[3];  extern int sysctl_sctp_rmem[3];  extern int sysctl_sctp_wmem[3]; -static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, -				int write, +static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write, +				void __user *buffer, size_t *lenp, +				loff_t *ppos); +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, +				void __user *buffer, size_t *lenp, +				loff_t *ppos); +static int proc_sctp_do_alpha_beta(struct ctl_table *ctl, int write, +				   void __user *buffer, size_t *lenp, +				   loff_t *ppos); +static int proc_sctp_do_auth(struct ctl_table *ctl, int write, +			     void __user *buffer, size_t *lenp, +			     loff_t *ppos); +  static struct ctl_table sctp_table[] = {  	{  		.procname	= "sctp_mem", @@ -102,32 +119,36 @@ static struct ctl_table sctp_net_table[] = {  		.data		= &init_net.sctp.rto_min,  		.maxlen		= sizeof(unsigned int),  		.mode		= 0644, -		.proc_handler	= proc_dointvec_minmax, +		.proc_handler	= proc_sctp_do_rto_min,  		.extra1         = &one, -		.extra2         = &timer_max +		.extra2         = &init_net.sctp.rto_max  	},  	{  		.procname	= "rto_max",  		.data		= &init_net.sctp.rto_max,  		.maxlen		= sizeof(unsigned int),  		.mode		= 0644, -		.proc_handler	= proc_dointvec_minmax, -		.extra1         = &one, +		.proc_handler	= proc_sctp_do_rto_max, +		.extra1         = &init_net.sctp.rto_min,  		.extra2         = &timer_max  	},  	{  		.procname	= "rto_alpha_exp_divisor",  		.data		= &init_net.sctp.rto_alpha,  		.maxlen		= sizeof(int), -		.mode		= 0444, -		.proc_handler	= proc_dointvec, +		.mode		= 0644, +		.proc_handler	= proc_sctp_do_alpha_beta, +		.extra1		= &rto_alpha_min, +		.extra2		= &rto_alpha_max,  	},  	{  		.procname	= "rto_beta_exp_divisor",  		.data		= &init_net.sctp.rto_beta,  		.maxlen		= sizeof(int), -		.mode		= 0444, -		.proc_handler	= proc_dointvec, +		.mode		= 0644, +		.proc_handler	= proc_sctp_do_alpha_beta, +		.extra1		= &rto_beta_min, +		.extra2		= &rto_beta_max,  	},  	{  		.procname	= "max_burst", @@ -147,6 +168,7 @@ static struct ctl_table sctp_net_table[] = {  	},  	{  		.procname	= "cookie_hmac_alg", +		.data		= &init_net.sctp.sctp_hmac_alg,  		.maxlen		= 8,  		.mode		= 0644,  		.proc_handler	= proc_sctp_do_hmac_alg, @@ -261,7 +283,7 @@ static struct ctl_table sctp_net_table[] = {  		.data		= &init_net.sctp.auth_enable,  		.maxlen		= sizeof(int),  		.mode		= 0644, -		.proc_handler	= proc_dointvec, +		.proc_handler	= proc_sctp_do_auth,  	},  	{  		.procname	= "addr_scope_policy", @@ -294,47 +316,45 @@ static struct ctl_table sctp_net_table[] = {  	{ /* sentinel */ }  }; -static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, -				int write, +static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write,  				void __user *buffer, size_t *lenp,  				loff_t *ppos)  {  	struct net *net = current->nsproxy->net_ns; -	char tmp[8];  	struct ctl_table tbl; -	int ret; -	int changed = 0; +	bool changed = false;  	char *none = "none"; +	char tmp[8]; +	int ret;  	memset(&tbl, 0, sizeof(struct ctl_table));  	if (write) {  		tbl.data = tmp; -		tbl.maxlen = 8; +		tbl.maxlen = sizeof(tmp);  	} else {  		tbl.data = net->sctp.sctp_hmac_alg ? : none;  		tbl.maxlen = strlen(tbl.data);  	} -		ret = proc_dostring(&tbl, write, buffer, lenp, ppos); -	if (write) { +	ret = proc_dostring(&tbl, write, buffer, lenp, ppos); +	if (write && ret == 0) {  #ifdef CONFIG_CRYPTO_MD5  		if (!strncmp(tmp, "md5", 3)) {  			net->sctp.sctp_hmac_alg = "md5"; -			changed = 1; +			changed = true;  		}  #endif  #ifdef CONFIG_CRYPTO_SHA1  		if (!strncmp(tmp, "sha1", 4)) {  			net->sctp.sctp_hmac_alg = "sha1"; -			changed = 1; +			changed = true;  		}  #endif  		if (!strncmp(tmp, "none", 4)) {  			net->sctp.sctp_hmac_alg = NULL; -			changed = 1; +			changed = true;  		} -  		if (!changed)  			ret = -EINVAL;  	} @@ -342,6 +362,104 @@ static int proc_sctp_do_hmac_alg(struct ctl_table *ctl,  	return ret;  } +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; +	struct ctl_table tbl; +	int ret, new_value; + +	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; + +	ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); +	if (write && ret == 0) { +		if (new_value > max || new_value < min) +			return -EINVAL; + +		net->sctp.rto_min = new_value; +	} + +	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; +	struct ctl_table tbl; +	int ret, new_value; + +	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; + +	ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); +	if (write && ret == 0) { +		if (new_value > max || new_value < min) +			return -EINVAL; + +		net->sctp.rto_max = new_value; +	} + +	return ret; +} + +static int proc_sctp_do_alpha_beta(struct ctl_table *ctl, int write, +				   void __user *buffer, size_t *lenp, +				   loff_t *ppos) +{ +	pr_warn_once("Changing rto_alpha or rto_beta may lead to " +		     "suboptimal rtt/srtt estimations!\n"); + +	return proc_dointvec_minmax(ctl, write, buffer, lenp, ppos); +} + +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); +	if (write && ret == 0) { +		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; +} +  int sctp_sysctl_net_register(struct net *net)  {  	struct ctl_table *table; @@ -355,6 +473,10 @@ int sctp_sysctl_net_register(struct net *net)  		table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp;  	net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table); +	if (net->sctp.sysctl_header == NULL) { +		kfree(table); +		return -ENOMEM; +	}  	return 0;  } @@ -367,7 +489,7 @@ void sctp_sysctl_net_unregister(struct net *net)  	kfree(table);  } -static struct ctl_table_header * sctp_sysctl_header; +static struct ctl_table_header *sctp_sysctl_header;  /* Sysctl registration.  */  void sctp_sysctl_register(void)  | 
