diff options
author | Arnaldo Carvalho de Melo <acme@mandriva.com> | 2005-12-14 02:25:31 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-01-03 16:10:55 -0500 |
commit | a7f5e7f164788a22eb5d3de8e2d3cee1bf58fdca (patch) | |
tree | 809ed01d61aa9548124b9958a5a500068b1db670 /net/dccp/ipv4.c | |
parent | 6d6ee43e0b8b8d4847627fd43739b98ec2b9404f (diff) |
[INET]: Generalise tcp_v4_hash_connect
Renaming it to inet_hash_connect, making it possible to ditch
dccp_v4_hash_connect and share the same code with TCP instead.
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r-- | net/dccp/ipv4.c | 160 |
1 files changed, 1 insertions, 159 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index e11cda0cb6b3..671fbf3b2379 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -54,164 +54,6 @@ void dccp_unhash(struct sock *sk) | |||
54 | 54 | ||
55 | EXPORT_SYMBOL_GPL(dccp_unhash); | 55 | EXPORT_SYMBOL_GPL(dccp_unhash); |
56 | 56 | ||
57 | /* called with local bh disabled */ | ||
58 | static int __dccp_v4_check_established(struct sock *sk, const __u16 lport, | ||
59 | struct inet_timewait_sock **twp) | ||
60 | { | ||
61 | struct inet_sock *inet = inet_sk(sk); | ||
62 | const u32 daddr = inet->rcv_saddr; | ||
63 | const u32 saddr = inet->daddr; | ||
64 | const int dif = sk->sk_bound_dev_if; | ||
65 | INET_ADDR_COOKIE(acookie, saddr, daddr) | ||
66 | const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); | ||
67 | unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport); | ||
68 | struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash); | ||
69 | const struct sock *sk2; | ||
70 | const struct hlist_node *node; | ||
71 | struct inet_timewait_sock *tw; | ||
72 | |||
73 | prefetch(head->chain.first); | ||
74 | write_lock(&head->lock); | ||
75 | |||
76 | /* Check TIME-WAIT sockets first. */ | ||
77 | sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) { | ||
78 | tw = inet_twsk(sk2); | ||
79 | |||
80 | if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) | ||
81 | goto not_unique; | ||
82 | } | ||
83 | tw = NULL; | ||
84 | |||
85 | /* And established part... */ | ||
86 | sk_for_each(sk2, node, &head->chain) { | ||
87 | if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) | ||
88 | goto not_unique; | ||
89 | } | ||
90 | |||
91 | /* Must record num and sport now. Otherwise we will see | ||
92 | * in hash table socket with a funny identity. */ | ||
93 | inet->num = lport; | ||
94 | inet->sport = htons(lport); | ||
95 | sk->sk_hash = hash; | ||
96 | BUG_TRAP(sk_unhashed(sk)); | ||
97 | __sk_add_node(sk, &head->chain); | ||
98 | sock_prot_inc_use(sk->sk_prot); | ||
99 | write_unlock(&head->lock); | ||
100 | |||
101 | if (twp != NULL) { | ||
102 | *twp = tw; | ||
103 | NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); | ||
104 | } else if (tw != NULL) { | ||
105 | /* Silly. Should hash-dance instead... */ | ||
106 | inet_twsk_deschedule(tw, &dccp_death_row); | ||
107 | NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); | ||
108 | |||
109 | inet_twsk_put(tw); | ||
110 | } | ||
111 | |||
112 | return 0; | ||
113 | |||
114 | not_unique: | ||
115 | write_unlock(&head->lock); | ||
116 | return -EADDRNOTAVAIL; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Bind a port for a connect operation and hash it. | ||
121 | */ | ||
122 | static int dccp_v4_hash_connect(struct sock *sk) | ||
123 | { | ||
124 | const unsigned short snum = inet_sk(sk)->num; | ||
125 | struct inet_bind_hashbucket *head; | ||
126 | struct inet_bind_bucket *tb; | ||
127 | int ret; | ||
128 | |||
129 | if (snum == 0) { | ||
130 | int low = sysctl_local_port_range[0]; | ||
131 | int high = sysctl_local_port_range[1]; | ||
132 | int remaining = (high - low) + 1; | ||
133 | int rover = net_random() % (high - low) + low; | ||
134 | struct hlist_node *node; | ||
135 | struct inet_timewait_sock *tw = NULL; | ||
136 | |||
137 | local_bh_disable(); | ||
138 | do { | ||
139 | head = &dccp_hashinfo.bhash[inet_bhashfn(rover, | ||
140 | dccp_hashinfo.bhash_size)]; | ||
141 | spin_lock(&head->lock); | ||
142 | |||
143 | /* Does not bother with rcv_saddr checks, | ||
144 | * because the established check is already | ||
145 | * unique enough. | ||
146 | */ | ||
147 | inet_bind_bucket_for_each(tb, node, &head->chain) { | ||
148 | if (tb->port == rover) { | ||
149 | BUG_TRAP(!hlist_empty(&tb->owners)); | ||
150 | if (tb->fastreuse >= 0) | ||
151 | goto next_port; | ||
152 | if (!__dccp_v4_check_established(sk, | ||
153 | rover, | ||
154 | &tw)) | ||
155 | goto ok; | ||
156 | goto next_port; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep, | ||
161 | head, rover); | ||
162 | if (tb == NULL) { | ||
163 | spin_unlock(&head->lock); | ||
164 | break; | ||
165 | } | ||
166 | tb->fastreuse = -1; | ||
167 | goto ok; | ||
168 | |||
169 | next_port: | ||
170 | spin_unlock(&head->lock); | ||
171 | if (++rover > high) | ||
172 | rover = low; | ||
173 | } while (--remaining > 0); | ||
174 | |||
175 | local_bh_enable(); | ||
176 | |||
177 | return -EADDRNOTAVAIL; | ||
178 | |||
179 | ok: | ||
180 | /* All locks still held and bhs disabled */ | ||
181 | inet_bind_hash(sk, tb, rover); | ||
182 | if (sk_unhashed(sk)) { | ||
183 | inet_sk(sk)->sport = htons(rover); | ||
184 | __inet_hash(&dccp_hashinfo, sk, 0); | ||
185 | } | ||
186 | spin_unlock(&head->lock); | ||
187 | |||
188 | if (tw != NULL) { | ||
189 | inet_twsk_deschedule(tw, &dccp_death_row); | ||
190 | inet_twsk_put(tw); | ||
191 | } | ||
192 | |||
193 | ret = 0; | ||
194 | goto out; | ||
195 | } | ||
196 | |||
197 | head = &dccp_hashinfo.bhash[inet_bhashfn(snum, | ||
198 | dccp_hashinfo.bhash_size)]; | ||
199 | tb = inet_csk(sk)->icsk_bind_hash; | ||
200 | spin_lock_bh(&head->lock); | ||
201 | if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) { | ||
202 | __inet_hash(&dccp_hashinfo, sk, 0); | ||
203 | spin_unlock_bh(&head->lock); | ||
204 | return 0; | ||
205 | } else { | ||
206 | spin_unlock(&head->lock); | ||
207 | /* No definite answer... Walk to established hash table */ | ||
208 | ret = __dccp_v4_check_established(sk, snum, NULL); | ||
209 | out: | ||
210 | local_bh_enable(); | ||
211 | return ret; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 57 | int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
216 | { | 58 | { |
217 | struct inet_sock *inet = inet_sk(sk); | 59 | struct inet_sock *inet = inet_sk(sk); |
@@ -272,7 +114,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
272 | * complete initialization after this. | 114 | * complete initialization after this. |
273 | */ | 115 | */ |
274 | dccp_set_state(sk, DCCP_REQUESTING); | 116 | dccp_set_state(sk, DCCP_REQUESTING); |
275 | err = dccp_v4_hash_connect(sk); | 117 | err = inet_hash_connect(&dccp_death_row, sk); |
276 | if (err != 0) | 118 | if (err != 0) |
277 | goto failure; | 119 | goto failure; |
278 | 120 | ||