aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/inet_connection_sock.c22
-rw-r--r--net/ipv4/inet_hashtables.c13
-rw-r--r--net/ipv4/sysctl_net_ipv4.c75
-rw-r--r--net/ipv4/tcp_ipv4.c1
-rw-r--r--net/ipv4/udp.c6
5 files changed, 98 insertions, 19 deletions
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index fbe7714f21d0..3cef12835c4b 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -33,6 +33,19 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
33 * This array holds the first and last local port number. 33 * This array holds the first and last local port number.
34 */ 34 */
35int sysctl_local_port_range[2] = { 32768, 61000 }; 35int sysctl_local_port_range[2] = { 32768, 61000 };
36DEFINE_SEQLOCK(sysctl_port_range_lock);
37
38void inet_get_local_port_range(int *low, int *high)
39{
40 unsigned seq;
41 do {
42 seq = read_seqbegin(&sysctl_port_range_lock);
43
44 *low = sysctl_local_port_range[0];
45 *high = sysctl_local_port_range[1];
46 } while (read_seqretry(&sysctl_port_range_lock, seq));
47}
48EXPORT_SYMBOL(inet_get_local_port_range);
36 49
37int inet_csk_bind_conflict(const struct sock *sk, 50int inet_csk_bind_conflict(const struct sock *sk,
38 const struct inet_bind_bucket *tb) 51 const struct inet_bind_bucket *tb)
@@ -77,10 +90,11 @@ int inet_csk_get_port(struct inet_hashinfo *hashinfo,
77 90
78 local_bh_disable(); 91 local_bh_disable();
79 if (!snum) { 92 if (!snum) {
80 int low = sysctl_local_port_range[0]; 93 int remaining, rover, low, high;
81 int high = sysctl_local_port_range[1]; 94
82 int remaining = (high - low) + 1; 95 inet_get_local_port_range(&low, &high);
83 int rover = net_random() % (high - low) + low; 96 remaining = high - low;
97 rover = net_random() % remaining + low;
84 98
85 do { 99 do {
86 head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)]; 100 head = &hashinfo->bhash[inet_bhashfn(rover, hashinfo->bhash_size)];
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index fb662621c54e..fac6398e4367 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -279,19 +279,18 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row,
279 int ret; 279 int ret;
280 280
281 if (!snum) { 281 if (!snum) {
282 int low = sysctl_local_port_range[0]; 282 int i, remaining, low, high, port;
283 int high = sysctl_local_port_range[1];
284 int range = high - low;
285 int i;
286 int port;
287 static u32 hint; 283 static u32 hint;
288 u32 offset = hint + inet_sk_port_offset(sk); 284 u32 offset = hint + inet_sk_port_offset(sk);
289 struct hlist_node *node; 285 struct hlist_node *node;
290 struct inet_timewait_sock *tw = NULL; 286 struct inet_timewait_sock *tw = NULL;
291 287
288 inet_get_local_port_range(&low, &high);
289 remaining = high - low;
290
292 local_bh_disable(); 291 local_bh_disable();
293 for (i = 1; i <= range; i++) { 292 for (i = 1; i <= remaining; i++) {
294 port = low + (i + offset) % range; 293 port = low + (i + offset) % remaining;
295 head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)]; 294 head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
296 spin_lock(&head->lock); 295 spin_lock(&head->lock);
297 296
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 53ef0f4bbdaa..eb286abcf5dc 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -12,6 +12,7 @@
12#include <linux/sysctl.h> 12#include <linux/sysctl.h>
13#include <linux/igmp.h> 13#include <linux/igmp.h>
14#include <linux/inetdevice.h> 14#include <linux/inetdevice.h>
15#include <linux/seqlock.h>
15#include <net/snmp.h> 16#include <net/snmp.h>
16#include <net/icmp.h> 17#include <net/icmp.h>
17#include <net/ip.h> 18#include <net/ip.h>
@@ -89,6 +90,74 @@ static int ipv4_sysctl_forward_strategy(ctl_table *table,
89 return 1; 90 return 1;
90} 91}
91 92
93extern seqlock_t sysctl_port_range_lock;
94extern int sysctl_local_port_range[2];
95
96/* Update system visible IP port range */
97static void set_local_port_range(int range[2])
98{
99 write_seqlock(&sysctl_port_range_lock);
100 sysctl_local_port_range[0] = range[0];
101 sysctl_local_port_range[1] = range[1];
102 write_sequnlock(&sysctl_port_range_lock);
103}
104
105/* Validate changes from /proc interface. */
106static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp,
107 void __user *buffer,
108 size_t *lenp, loff_t *ppos)
109{
110 int ret;
111 int range[2] = { sysctl_local_port_range[0],
112 sysctl_local_port_range[1] };
113 ctl_table tmp = {
114 .data = &range,
115 .maxlen = sizeof(range),
116 .mode = table->mode,
117 .extra1 = &ip_local_port_range_min,
118 .extra2 = &ip_local_port_range_max,
119 };
120
121 ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos);
122
123 if (write && ret == 0) {
124 if (range[1] <= range[0])
125 ret = -EINVAL;
126 else
127 set_local_port_range(range);
128 }
129
130 return ret;
131}
132
133/* Validate changes from sysctl interface. */
134static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name,
135 int nlen, void __user *oldval,
136 size_t __user *oldlenp,
137 void __user *newval, size_t newlen)
138{
139 int ret;
140 int range[2] = { sysctl_local_port_range[0],
141 sysctl_local_port_range[1] };
142 ctl_table tmp = {
143 .data = &range,
144 .maxlen = sizeof(range),
145 .mode = table->mode,
146 .extra1 = &ip_local_port_range_min,
147 .extra2 = &ip_local_port_range_max,
148 };
149
150 ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen);
151 if (ret == 0 && newval && newlen) {
152 if (range[1] <= range[0])
153 ret = -EINVAL;
154 else
155 set_local_port_range(range);
156 }
157 return ret;
158}
159
160
92static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp, 161static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp,
93 void __user *buffer, size_t *lenp, loff_t *ppos) 162 void __user *buffer, size_t *lenp, loff_t *ppos)
94{ 163{
@@ -427,10 +496,8 @@ ctl_table ipv4_table[] = {
427 .data = &sysctl_local_port_range, 496 .data = &sysctl_local_port_range,
428 .maxlen = sizeof(sysctl_local_port_range), 497 .maxlen = sizeof(sysctl_local_port_range),
429 .mode = 0644, 498 .mode = 0644,
430 .proc_handler = &proc_dointvec_minmax, 499 .proc_handler = &ipv4_local_port_range,
431 .strategy = &sysctl_intvec, 500 .strategy = &ipv4_sysctl_local_port_range,
432 .extra1 = ip_local_port_range_min,
433 .extra2 = ip_local_port_range_max
434 }, 501 },
435 { 502 {
436 .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL, 503 .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 8855e640e958..38cf73a56731 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2470,6 +2470,5 @@ EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
2470EXPORT_SYMBOL(tcp_proc_register); 2470EXPORT_SYMBOL(tcp_proc_register);
2471EXPORT_SYMBOL(tcp_proc_unregister); 2471EXPORT_SYMBOL(tcp_proc_unregister);
2472#endif 2472#endif
2473EXPORT_SYMBOL(sysctl_local_port_range);
2474EXPORT_SYMBOL(sysctl_tcp_low_latency); 2473EXPORT_SYMBOL(sysctl_tcp_low_latency);
2475 2474
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ef4d901ee9ad..cb9fc58efb2f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -147,11 +147,11 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
147 write_lock_bh(&udp_hash_lock); 147 write_lock_bh(&udp_hash_lock);
148 148
149 if (!snum) { 149 if (!snum) {
150 int i; 150 int i, low, high;
151 int low = sysctl_local_port_range[0];
152 int high = sysctl_local_port_range[1];
153 unsigned rover, best, best_size_so_far; 151 unsigned rover, best, best_size_so_far;
154 152
153 inet_get_local_port_range(&low, &high);
154
155 best_size_so_far = UINT_MAX; 155 best_size_so_far = UINT_MAX;
156 best = rover = net_random() % (high - low) + low; 156 best = rover = net_random() % (high - low) + low;
157 157