aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ipv4.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp/ipv4.c')
-rw-r--r--net/dccp/ipv4.c160
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
55EXPORT_SYMBOL_GPL(dccp_unhash); 55EXPORT_SYMBOL_GPL(dccp_unhash);
56 56
57/* called with local bh disabled */
58static 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
114not_unique:
115 write_unlock(&head->lock);
116 return -EADDRNOTAVAIL;
117}
118
119/*
120 * Bind a port for a connect operation and hash it.
121 */
122static 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
179ok:
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);
209out:
210 local_bh_enable();
211 return ret;
212 }
213}
214
215int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) 57int 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