diff options
Diffstat (limited to 'net/ipv4/sysctl_net_ipv4.c')
| -rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 75 | 
1 files changed, 71 insertions, 4 deletions
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 53ef0f4bbda..eb286abcf5d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -12,6 +12,7 @@  #include <linux/sysctl.h>  #include <linux/igmp.h>  #include <linux/inetdevice.h> +#include <linux/seqlock.h>  #include <net/snmp.h>  #include <net/icmp.h>  #include <net/ip.h> @@ -89,6 +90,74 @@ static int ipv4_sysctl_forward_strategy(ctl_table *table,  	return 1;  } +extern seqlock_t sysctl_port_range_lock; +extern int sysctl_local_port_range[2]; + +/* Update system visible IP port range */ +static void set_local_port_range(int range[2]) +{ +	write_seqlock(&sysctl_port_range_lock); +	sysctl_local_port_range[0] = range[0]; +	sysctl_local_port_range[1] = range[1]; +	write_sequnlock(&sysctl_port_range_lock); +} + +/* Validate changes from /proc interface. */ +static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp, +				 void __user *buffer, +				 size_t *lenp, loff_t *ppos) +{ +	int ret; +	int range[2] = { sysctl_local_port_range[0], +			 sysctl_local_port_range[1] }; +	ctl_table tmp = { +		.data = &range, +		.maxlen = sizeof(range), +		.mode = table->mode, +		.extra1 = &ip_local_port_range_min, +		.extra2 = &ip_local_port_range_max, +	}; + +	ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos); + +	if (write && ret == 0) { +		if (range[1] <= range[0]) +			ret = -EINVAL; +		else +			set_local_port_range(range); +	} + +	return ret; +} + +/* Validate changes from sysctl interface. */ +static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name, +					 int nlen, void __user *oldval, +					 size_t __user *oldlenp, +					void __user *newval, size_t newlen) +{ +	int ret; +	int range[2] = { sysctl_local_port_range[0], +			 sysctl_local_port_range[1] }; +	ctl_table tmp = { +		.data = &range, +		.maxlen = sizeof(range), +		.mode = table->mode, +		.extra1 = &ip_local_port_range_min, +		.extra2 = &ip_local_port_range_max, +	}; + +	ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen); +	if (ret == 0 && newval && newlen) { +		if (range[1] <= range[0]) +			ret = -EINVAL; +		else +			set_local_port_range(range); +	} +	return ret; +} + +  static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp,  				       void __user *buffer, size_t *lenp, loff_t *ppos)  { @@ -427,10 +496,8 @@ ctl_table ipv4_table[] = {  		.data		= &sysctl_local_port_range,  		.maxlen		= sizeof(sysctl_local_port_range),  		.mode		= 0644, -		.proc_handler	= &proc_dointvec_minmax, -		.strategy	= &sysctl_intvec, -		.extra1		= ip_local_port_range_min, -		.extra2		= ip_local_port_range_max +		.proc_handler	= &ipv4_local_port_range, +		.strategy	= &ipv4_sysctl_local_port_range,  	},  	{  		.ctl_name	= NET_IPV4_ICMP_ECHO_IGNORE_ALL,  |