diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 22 | ||||
-rw-r--r-- | net/ipv4/inet_hashtables.c | 13 | ||||
-rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 75 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 1 | ||||
-rw-r--r-- | net/ipv4/udp.c | 6 |
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 | */ |
35 | int sysctl_local_port_range[2] = { 32768, 61000 }; | 35 | int sysctl_local_port_range[2] = { 32768, 61000 }; |
36 | DEFINE_SEQLOCK(sysctl_port_range_lock); | ||
37 | |||
38 | void 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 | } | ||
48 | EXPORT_SYMBOL(inet_get_local_port_range); | ||
36 | 49 | ||
37 | int inet_csk_bind_conflict(const struct sock *sk, | 50 | int 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 | ||
93 | extern seqlock_t sysctl_port_range_lock; | ||
94 | extern int sysctl_local_port_range[2]; | ||
95 | |||
96 | /* Update system visible IP port range */ | ||
97 | static 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. */ | ||
106 | static 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. */ | ||
134 | static 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 | |||
92 | static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp, | 161 | static 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); | |||
2470 | EXPORT_SYMBOL(tcp_proc_register); | 2470 | EXPORT_SYMBOL(tcp_proc_register); |
2471 | EXPORT_SYMBOL(tcp_proc_unregister); | 2471 | EXPORT_SYMBOL(tcp_proc_unregister); |
2472 | #endif | 2472 | #endif |
2473 | EXPORT_SYMBOL(sysctl_local_port_range); | ||
2474 | EXPORT_SYMBOL(sysctl_tcp_low_latency); | 2473 | EXPORT_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 | ||