Blame view
net/ipv4/inet_connection_sock.c
30.6 KB
3f421baa4 [NET]: Just move ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * * Support for INET connection oriented protocols. * * Authors: See the TCP sources * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or(at your option) any later version. */ |
3f421baa4 [NET]: Just move ... |
15 16 17 18 19 20 21 22 23 |
#include <linux/module.h> #include <linux/jhash.h> #include <net/inet_connection_sock.h> #include <net/inet_hashtables.h> #include <net/inet_timewait_sock.h> #include <net/ip.h> #include <net/route.h> #include <net/tcp_states.h> |
a019d6fe2 [ICSK]: Move gene... |
24 |
#include <net/xfrm.h> |
fa76ce732 inet: get rid of ... |
25 |
#include <net/tcp.h> |
c125e80b8 soreuseport: fast... |
26 |
#include <net/sock_reuseport.h> |
9691724e5 inet: fix warning... |
27 |
#include <net/addrconf.h> |
3f421baa4 [NET]: Just move ... |
28 29 30 31 32 33 |
#ifdef INET_CSK_DEBUG const char inet_csk_timer_bug_msg[] = "inet_csk BUG: unknown timer value "; EXPORT_SYMBOL(inet_csk_timer_bug_msg); #endif |
fe38d2a1c inet: collapse ip... |
34 35 36 37 38 39 40 |
#if IS_ENABLED(CONFIG_IPV6) /* match_wildcard == true: IPV6_ADDR_ANY equals to any IPv6 addresses if IPv6 * only, and any IPv4 addresses if not IPv6 only * match_wildcard == false: addresses must be exactly the same, i.e. * IPV6_ADDR_ANY only equals to IPV6_ADDR_ANY, * and 0.0.0.0 equals to 0.0.0.0 only */ |
637bc8bbe inet: reset tb->f... |
41 42 43 44 |
static int ipv6_rcv_saddr_equal(const struct in6_addr *sk1_rcv_saddr6, const struct in6_addr *sk2_rcv_saddr6, __be32 sk1_rcv_saddr, __be32 sk2_rcv_saddr, bool sk1_ipv6only, bool sk2_ipv6only, |
fe38d2a1c inet: collapse ip... |
45 46 |
bool match_wildcard) { |
637bc8bbe inet: reset tb->f... |
47 |
int addr_type = ipv6_addr_type(sk1_rcv_saddr6); |
fe38d2a1c inet: collapse ip... |
48 49 50 51 52 |
int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; /* if both are mapped, treat as IPv4 */ if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) { if (!sk2_ipv6only) { |
637bc8bbe inet: reset tb->f... |
53 |
if (sk1_rcv_saddr == sk2_rcv_saddr) |
fe38d2a1c inet: collapse ip... |
54 |
return 1; |
637bc8bbe inet: reset tb->f... |
55 |
if (!sk1_rcv_saddr || !sk2_rcv_saddr) |
fe38d2a1c inet: collapse ip... |
56 57 58 59 60 61 62 63 64 65 66 67 68 |
return match_wildcard; } return 0; } if (addr_type == IPV6_ADDR_ANY && addr_type2 == IPV6_ADDR_ANY) return 1; if (addr_type2 == IPV6_ADDR_ANY && match_wildcard && !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) return 1; if (addr_type == IPV6_ADDR_ANY && match_wildcard && |
637bc8bbe inet: reset tb->f... |
69 |
!(sk1_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) |
fe38d2a1c inet: collapse ip... |
70 71 72 |
return 1; if (sk2_rcv_saddr6 && |
637bc8bbe inet: reset tb->f... |
73 |
ipv6_addr_equal(sk1_rcv_saddr6, sk2_rcv_saddr6)) |
fe38d2a1c inet: collapse ip... |
74 75 76 77 78 79 80 81 82 83 |
return 1; return 0; } #endif /* match_wildcard == true: 0.0.0.0 equals to any IPv4 addresses * match_wildcard == false: addresses must be exactly the same, i.e. * 0.0.0.0 only equals to 0.0.0.0 */ |
637bc8bbe inet: reset tb->f... |
84 85 |
static int ipv4_rcv_saddr_equal(__be32 sk1_rcv_saddr, __be32 sk2_rcv_saddr, bool sk2_ipv6only, bool match_wildcard) |
fe38d2a1c inet: collapse ip... |
86 |
{ |
637bc8bbe inet: reset tb->f... |
87 88 |
if (!sk2_ipv6only) { if (sk1_rcv_saddr == sk2_rcv_saddr) |
fe38d2a1c inet: collapse ip... |
89 |
return 1; |
637bc8bbe inet: reset tb->f... |
90 |
if (!sk1_rcv_saddr || !sk2_rcv_saddr) |
fe38d2a1c inet: collapse ip... |
91 92 93 94 95 96 97 98 99 100 |
return match_wildcard; } return 0; } int inet_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2, bool match_wildcard) { #if IS_ENABLED(CONFIG_IPV6) if (sk->sk_family == AF_INET6) |
637bc8bbe inet: reset tb->f... |
101 |
return ipv6_rcv_saddr_equal(&sk->sk_v6_rcv_saddr, |
319554f28 inet: don't use s... |
102 |
inet6_rcv_saddr(sk2), |
637bc8bbe inet: reset tb->f... |
103 104 105 106 107 |
sk->sk_rcv_saddr, sk2->sk_rcv_saddr, ipv6_only_sock(sk), ipv6_only_sock(sk2), match_wildcard); |
fe38d2a1c inet: collapse ip... |
108 |
#endif |
637bc8bbe inet: reset tb->f... |
109 110 |
return ipv4_rcv_saddr_equal(sk->sk_rcv_saddr, sk2->sk_rcv_saddr, ipv6_only_sock(sk2), match_wildcard); |
fe38d2a1c inet: collapse ip... |
111 112 |
} EXPORT_SYMBOL(inet_rcv_saddr_equal); |
0bbf87d85 net ipv4: Convert... |
113 |
void inet_get_local_port_range(struct net *net, int *low, int *high) |
227b60f51 [INET]: local por... |
114 |
{ |
95c961747 net: cleanup unsi... |
115 |
unsigned int seq; |
227b60f51 [INET]: local por... |
116 |
do { |
c9d8f1a64 ipv4: move local_... |
117 |
seq = read_seqbegin(&net->ipv4.ip_local_ports.lock); |
227b60f51 [INET]: local por... |
118 |
|
c9d8f1a64 ipv4: move local_... |
119 120 121 |
*low = net->ipv4.ip_local_ports.range[0]; *high = net->ipv4.ip_local_ports.range[1]; } while (read_seqretry(&net->ipv4.ip_local_ports.lock, seq)); |
227b60f51 [INET]: local por... |
122 123 |
} EXPORT_SYMBOL(inet_get_local_port_range); |
3f421baa4 [NET]: Just move ... |
124 |
|
aa078842b inet: drop ->bind... |
125 126 127 |
static int inet_csk_bind_conflict(const struct sock *sk, const struct inet_bind_bucket *tb, bool relax, bool reuseport_ok) |
3f421baa4 [NET]: Just move ... |
128 |
{ |
3f421baa4 [NET]: Just move ... |
129 |
struct sock *sk2; |
0643ee4fd inet: Fix get por... |
130 131 |
bool reuse = sk->sk_reuse; bool reuseport = !!sk->sk_reuseport && reuseport_ok; |
da5e36308 soreuseport: TCP/... |
132 |
kuid_t uid = sock_i_uid((struct sock *)sk); |
3f421baa4 [NET]: Just move ... |
133 |
|
7477fd2e6 [SOCK]: Add some ... |
134 135 136 137 138 139 |
/* * Unlike other sk lookup places we do not check * for sk_net here, since _all_ the socks listed * in tb->owners list belong to the same net - the * one this bucket belongs to. */ |
b67bfe0d4 hlist: drop the n... |
140 |
sk_for_each_bound(sk2, &tb->owners) { |
3f421baa4 [NET]: Just move ... |
141 |
if (sk != sk2 && |
3f421baa4 [NET]: Just move ... |
142 143 144 |
(!sk->sk_bound_dev_if || !sk2->sk_bound_dev_if || sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { |
da5e36308 soreuseport: TCP/... |
145 146 147 |
if ((!reuse || !sk2->sk_reuse || sk2->sk_state == TCP_LISTEN) && (!reuseport || !sk2->sk_reuseport || |
c125e80b8 soreuseport: fast... |
148 149 |
rcu_access_pointer(sk->sk_reuseport_cb) || (sk2->sk_state != TCP_TIME_WAIT && |
da5e36308 soreuseport: TCP/... |
150 |
!uid_eq(uid, sock_i_uid(sk2))))) { |
aa078842b inet: drop ->bind... |
151 |
if (inet_rcv_saddr_equal(sk, sk2, true)) |
3f421baa4 [NET]: Just move ... |
152 |
break; |
8d238b25b Revert "tcp: bind... |
153 |
} |
aacd9289a tcp: bind() use s... |
154 155 |
if (!relax && reuse && sk2->sk_reuse && sk2->sk_state != TCP_LISTEN) { |
aa078842b inet: drop ->bind... |
156 |
if (inet_rcv_saddr_equal(sk, sk2, true)) |
aacd9289a tcp: bind() use s... |
157 158 |
break; } |
3f421baa4 [NET]: Just move ... |
159 160 |
} } |
b67bfe0d4 hlist: drop the n... |
161 |
return sk2 != NULL; |
3f421baa4 [NET]: Just move ... |
162 |
} |
971af18bb [IPV6]: Reuse ine... |
163 |
|
289141b76 inet: split inet_... |
164 165 166 |
/* * Find an open port number for the socket. Returns with the * inet_bind_hashbucket lock held. |
3f421baa4 [NET]: Just move ... |
167 |
*/ |
289141b76 inet: split inet_... |
168 169 |
static struct inet_bind_hashbucket * inet_csk_find_open_port(struct sock *sk, struct inet_bind_bucket **tb_ret, int *port_ret) |
3f421baa4 [NET]: Just move ... |
170 |
{ |
ea8add2b1 tcp/dccp: better ... |
171 |
struct inet_hashinfo *hinfo = sk->sk_prot->h.hashinfo; |
289141b76 inet: split inet_... |
172 |
int port = 0; |
3f421baa4 [NET]: Just move ... |
173 |
struct inet_bind_hashbucket *head; |
3b1e0a655 [NET] NETNS: Omit... |
174 |
struct net *net = sock_net(sk); |
ea8add2b1 tcp/dccp: better ... |
175 176 |
int i, low, high, attempt_half; struct inet_bind_bucket *tb; |
ea8add2b1 tcp/dccp: better ... |
177 |
u32 remaining, offset; |
3f421baa4 [NET]: Just move ... |
178 |
|
ea8add2b1 tcp/dccp: better ... |
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
attempt_half = (sk->sk_reuse == SK_CAN_REUSE) ? 1 : 0; other_half_scan: inet_get_local_port_range(net, &low, &high); high++; /* [32768, 60999] -> [32768, 61000[ */ if (high - low < 4) attempt_half = 0; if (attempt_half) { int half = low + (((high - low) >> 2) << 1); if (attempt_half == 1) high = half; else low = half; } remaining = high - low; if (likely(remaining > 1)) remaining &= ~1U; |
3f421baa4 [NET]: Just move ... |
196 |
|
ea8add2b1 tcp/dccp: better ... |
197 198 199 200 201 |
offset = prandom_u32() % remaining; /* __inet_hash_connect() favors ports having @low parity * We do the opposite to not pollute connect() users. */ offset |= 1U; |
ea8add2b1 tcp/dccp: better ... |
202 203 204 205 206 207 208 209 210 211 212 213 214 |
other_parity_scan: port = low + offset; for (i = 0; i < remaining; i += 2, port += 2) { if (unlikely(port >= high)) port -= remaining; if (inet_is_local_reserved_port(net, port)) continue; head = &hinfo->bhash[inet_bhashfn(net, port, hinfo->bhash_size)]; spin_lock_bh(&head->lock); inet_bind_bucket_for_each(tb, &head->chain) if (net_eq(ib_net(tb), net) && tb->port == port) { |
289141b76 inet: split inet_... |
215 |
if (!inet_csk_bind_conflict(sk, tb, false, false)) |
6cd666168 inet: don't check... |
216 |
goto success; |
ea8add2b1 tcp/dccp: better ... |
217 |
goto next_port; |
946f9eb22 tcp: improve REUS... |
218 |
} |
289141b76 inet: split inet_... |
219 220 |
tb = NULL; goto success; |
ea8add2b1 tcp/dccp: better ... |
221 222 223 224 |
next_port: spin_unlock_bh(&head->lock); cond_resched(); } |
ea8add2b1 tcp/dccp: better ... |
225 226 227 228 229 230 231 232 233 |
offset--; if (!(offset & 1)) goto other_parity_scan; if (attempt_half == 1) { /* OK we now try the upper half of the range */ attempt_half = 2; goto other_half_scan; } |
289141b76 inet: split inet_... |
234 235 236 237 238 239 |
return NULL; success: *port_ret = port; *tb_ret = tb; return head; } |
ea8add2b1 tcp/dccp: better ... |
240 |
|
637bc8bbe inet: reset tb->f... |
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
static inline int sk_reuseport_match(struct inet_bind_bucket *tb, struct sock *sk) { kuid_t uid = sock_i_uid(sk); if (tb->fastreuseport <= 0) return 0; if (!sk->sk_reuseport) return 0; if (rcu_access_pointer(sk->sk_reuseport_cb)) return 0; if (!uid_eq(tb->fastuid, uid)) return 0; /* We only need to check the rcv_saddr if this tb was once marked * without fastreuseport and then was reset, as we can only know that * the fast_*rcv_saddr doesn't have any conflicts with the socks on the * owners list. */ if (tb->fastreuseport == FASTREUSEPORT_ANY) return 1; #if IS_ENABLED(CONFIG_IPV6) if (tb->fast_sk_family == AF_INET6) return ipv6_rcv_saddr_equal(&tb->fast_v6_rcv_saddr, |
7a56673b5 net: use inet6_rc... |
264 |
inet6_rcv_saddr(sk), |
637bc8bbe inet: reset tb->f... |
265 266 267 268 269 270 271 272 |
tb->fast_rcv_saddr, sk->sk_rcv_saddr, tb->fast_ipv6_only, ipv6_only_sock(sk), true); #endif return ipv4_rcv_saddr_equal(tb->fast_rcv_saddr, sk->sk_rcv_saddr, ipv6_only_sock(sk), true); } |
289141b76 inet: split inet_... |
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
/* Obtain a reference to a local port for the given sock, * if snum is zero it means select any available local port. * We try to allocate an odd port (and leave even ports for connect()) */ int inet_csk_get_port(struct sock *sk, unsigned short snum) { bool reuse = sk->sk_reuse && sk->sk_state != TCP_LISTEN; struct inet_hashinfo *hinfo = sk->sk_prot->h.hashinfo; int ret = 1, port = snum; struct inet_bind_hashbucket *head; struct net *net = sock_net(sk); struct inet_bind_bucket *tb = NULL; kuid_t uid = sock_i_uid(sk); if (!port) { head = inet_csk_find_open_port(sk, &tb, &port); if (!head) return ret; if (!tb) goto tb_not_found; goto success; } head = &hinfo->bhash[inet_bhashfn(net, port, hinfo->bhash_size)]; spin_lock_bh(&head->lock); inet_bind_bucket_for_each(tb, &head->chain) if (net_eq(ib_net(tb), net) && tb->port == port) goto tb_found; |
ea8add2b1 tcp/dccp: better ... |
301 302 303 304 305 |
tb_not_found: tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, net, head, port); if (!tb) goto fail_unlock; |
3f421baa4 [NET]: Just move ... |
306 307 |
tb_found: if (!hlist_empty(&tb->owners)) { |
4a17fd522 sock: Introduce n... |
308 309 |
if (sk->sk_reuse == SK_FORCE_REUSE) goto success; |
b9470c276 inet: kill smalle... |
310 |
if ((tb->fastreuse > 0 && reuse) || |
637bc8bbe inet: reset tb->f... |
311 |
sk_reuseport_match(tb, sk)) |
3f421baa4 [NET]: Just move ... |
312 |
goto success; |
289141b76 inet: split inet_... |
313 |
if (inet_csk_bind_conflict(sk, tb, true, true)) |
ea8add2b1 tcp/dccp: better ... |
314 |
goto fail_unlock; |
6cd666168 inet: don't check... |
315 316 |
} success: |
fbed24bcc inet: fix imprope... |
317 |
if (hlist_empty(&tb->owners)) { |
ea8add2b1 tcp/dccp: better ... |
318 |
tb->fastreuse = reuse; |
da5e36308 soreuseport: TCP/... |
319 |
if (sk->sk_reuseport) { |
637bc8bbe inet: reset tb->f... |
320 |
tb->fastreuseport = FASTREUSEPORT_ANY; |
da5e36308 soreuseport: TCP/... |
321 |
tb->fastuid = uid; |
637bc8bbe inet: reset tb->f... |
322 323 |
tb->fast_rcv_saddr = sk->sk_rcv_saddr; tb->fast_ipv6_only = ipv6_only_sock(sk); |
cbb2fb5c7 net: set tb->fast... |
324 |
tb->fast_sk_family = sk->sk_family; |
637bc8bbe inet: reset tb->f... |
325 326 327 |
#if IS_ENABLED(CONFIG_IPV6) tb->fast_v6_rcv_saddr = sk->sk_v6_rcv_saddr; #endif |
ea8add2b1 tcp/dccp: better ... |
328 |
} else { |
da5e36308 soreuseport: TCP/... |
329 |
tb->fastreuseport = 0; |
ea8add2b1 tcp/dccp: better ... |
330 |
} |
6cd666168 inet: don't check... |
331 332 333 |
} else { if (!reuse) tb->fastreuse = 0; |
637bc8bbe inet: reset tb->f... |
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
if (sk->sk_reuseport) { /* We didn't match or we don't have fastreuseport set on * the tb, but we have sk_reuseport set on this socket * and we know that there are no bind conflicts with * this socket in this tb, so reset our tb's reuseport * settings so that any subsequent sockets that match * our current socket will be put on the fast path. * * If we reset we need to set FASTREUSEPORT_STRICT so we * do extra checking for all subsequent sk_reuseport * socks. */ if (!sk_reuseport_match(tb, sk)) { tb->fastreuseport = FASTREUSEPORT_STRICT; tb->fastuid = uid; tb->fast_rcv_saddr = sk->sk_rcv_saddr; tb->fast_ipv6_only = ipv6_only_sock(sk); |
cbb2fb5c7 net: set tb->fast... |
351 |
tb->fast_sk_family = sk->sk_family; |
637bc8bbe inet: reset tb->f... |
352 353 354 355 356 |
#if IS_ENABLED(CONFIG_IPV6) tb->fast_v6_rcv_saddr = sk->sk_v6_rcv_saddr; #endif } } else { |
6cd666168 inet: don't check... |
357 |
tb->fastreuseport = 0; |
637bc8bbe inet: reset tb->f... |
358 |
} |
da5e36308 soreuseport: TCP/... |
359 |
} |
3f421baa4 [NET]: Just move ... |
360 |
if (!inet_csk(sk)->icsk_bind_hash) |
ea8add2b1 tcp/dccp: better ... |
361 |
inet_bind_hash(sk, tb, port); |
547b792ca net: convert BUG_... |
362 |
WARN_ON(inet_csk(sk)->icsk_bind_hash != tb); |
e905a9eda [NET] IPV4: Fix w... |
363 |
ret = 0; |
3f421baa4 [NET]: Just move ... |
364 365 |
fail_unlock: |
ea8add2b1 tcp/dccp: better ... |
366 |
spin_unlock_bh(&head->lock); |
3f421baa4 [NET]: Just move ... |
367 368 |
return ret; } |
3f421baa4 [NET]: Just move ... |
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
EXPORT_SYMBOL_GPL(inet_csk_get_port); /* * Wait for an incoming connection, avoid race conditions. This must be called * with the socket locked. */ static int inet_csk_wait_for_connect(struct sock *sk, long timeo) { struct inet_connection_sock *icsk = inet_csk(sk); DEFINE_WAIT(wait); int err; /* * True wake-one mechanism for incoming connections: only * one process gets woken up, not the 'whole herd'. * Since we do not 'race & poll' for established sockets * anymore, the common case will execute the loop only once. * * Subtle issue: "add_wait_queue_exclusive()" will be added * after any current non-exclusive waiters, and we know that * it will always _stay_ after any new non-exclusive waiters * because all non-exclusive waiters are added at the * beginning of the wait-queue. As such, it's ok to "drop" * our exclusiveness temporarily when we get woken up without * having to remove and re-insert us on the wait queue. */ for (;;) { |
aa3951451 net: sk_sleep() h... |
396 |
prepare_to_wait_exclusive(sk_sleep(sk), &wait, |
3f421baa4 [NET]: Just move ... |
397 398 399 400 |
TASK_INTERRUPTIBLE); release_sock(sk); if (reqsk_queue_empty(&icsk->icsk_accept_queue)) timeo = schedule_timeout(timeo); |
cb7cf8a33 inet: Clean up in... |
401 |
sched_annotate_sleep(); |
3f421baa4 [NET]: Just move ... |
402 403 404 405 406 407 408 409 410 411 412 413 414 415 |
lock_sock(sk); err = 0; if (!reqsk_queue_empty(&icsk->icsk_accept_queue)) break; err = -EINVAL; if (sk->sk_state != TCP_LISTEN) break; err = sock_intr_errno(timeo); if (signal_pending(current)) break; err = -EAGAIN; if (!timeo) break; } |
aa3951451 net: sk_sleep() h... |
416 |
finish_wait(sk_sleep(sk), &wait); |
3f421baa4 [NET]: Just move ... |
417 418 419 420 421 422 |
return err; } /* * This will accept the next outstanding connection. */ |
cdfbabfb2 net: Work around ... |
423 |
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern) |
3f421baa4 [NET]: Just move ... |
424 425 |
{ struct inet_connection_sock *icsk = inet_csk(sk); |
8336886f7 tcp: TCP Fast Ope... |
426 |
struct request_sock_queue *queue = &icsk->icsk_accept_queue; |
8336886f7 tcp: TCP Fast Ope... |
427 |
struct request_sock *req; |
e3d95ad7d inet: avoid fasto... |
428 |
struct sock *newsk; |
3f421baa4 [NET]: Just move ... |
429 430 431 432 433 434 435 436 437 438 439 440 |
int error; lock_sock(sk); /* We need to make sure that this socket is listening, * and that it has something pending. */ error = -EINVAL; if (sk->sk_state != TCP_LISTEN) goto out_err; /* Find already established connection */ |
8336886f7 tcp: TCP Fast Ope... |
441 |
if (reqsk_queue_empty(queue)) { |
3f421baa4 [NET]: Just move ... |
442 443 444 445 446 447 448 449 450 451 452 |
long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); /* If this is a non blocking socket don't sleep */ error = -EAGAIN; if (!timeo) goto out_err; error = inet_csk_wait_for_connect(sk, timeo); if (error) goto out_err; } |
fff1f3001 tcp: add a spinlo... |
453 |
req = reqsk_queue_remove(queue, sk); |
8336886f7 tcp: TCP Fast Ope... |
454 |
newsk = req->sk; |
e3d95ad7d inet: avoid fasto... |
455 |
if (sk->sk_protocol == IPPROTO_TCP && |
0536fcc03 tcp: prepare fast... |
456 457 |
tcp_rsk(req)->tfo_listener) { spin_lock_bh(&queue->fastopenq.lock); |
9439ce00f tcp: rename struc... |
458 |
if (tcp_rsk(req)->tfo_listener) { |
8336886f7 tcp: TCP Fast Ope... |
459 460 461 462 463 464 465 466 467 |
/* We are still waiting for the final ACK from 3WHS * so can't free req now. Instead, we set req->sk to * NULL to signify that the child socket is taken * so reqsk_fastopen_remove() will free the req * when 3WHS finishes (or is aborted). */ req->sk = NULL; req = NULL; } |
0536fcc03 tcp: prepare fast... |
468 |
spin_unlock_bh(&queue->fastopenq.lock); |
8336886f7 tcp: TCP Fast Ope... |
469 |
} |
3f421baa4 [NET]: Just move ... |
470 471 |
out: release_sock(sk); |
8336886f7 tcp: TCP Fast Ope... |
472 |
if (req) |
13854e5a6 inet: add proper ... |
473 |
reqsk_put(req); |
3f421baa4 [NET]: Just move ... |
474 475 476 |
return newsk; out_err: newsk = NULL; |
8336886f7 tcp: TCP Fast Ope... |
477 |
req = NULL; |
3f421baa4 [NET]: Just move ... |
478 479 480 |
*err = error; goto out; } |
3f421baa4 [NET]: Just move ... |
481 482 483 484 |
EXPORT_SYMBOL(inet_csk_accept); /* * Using different timers for retransmit, delayed acks and probes |
e905a9eda [NET] IPV4: Fix w... |
485 |
* We may wish use just one timer maintaining a list of expire jiffies |
3f421baa4 [NET]: Just move ... |
486 487 488 489 490 491 492 493 |
* to optimize. */ void inet_csk_init_xmit_timers(struct sock *sk, void (*retransmit_handler)(unsigned long), void (*delack_handler)(unsigned long), void (*keepalive_handler)(unsigned long)) { struct inet_connection_sock *icsk = inet_csk(sk); |
b24b8a247 [NET]: Convert in... |
494 495 496 497 498 |
setup_timer(&icsk->icsk_retransmit_timer, retransmit_handler, (unsigned long)sk); setup_timer(&icsk->icsk_delack_timer, delack_handler, (unsigned long)sk); setup_timer(&sk->sk_timer, keepalive_handler, (unsigned long)sk); |
3f421baa4 [NET]: Just move ... |
499 500 |
icsk->icsk_pending = icsk->icsk_ack.pending = 0; } |
3f421baa4 [NET]: Just move ... |
501 502 503 504 505 506 507 508 509 510 511 512 |
EXPORT_SYMBOL(inet_csk_init_xmit_timers); void inet_csk_clear_xmit_timers(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); icsk->icsk_pending = icsk->icsk_ack.pending = icsk->icsk_ack.blocked = 0; sk_stop_timer(sk, &icsk->icsk_retransmit_timer); sk_stop_timer(sk, &icsk->icsk_delack_timer); sk_stop_timer(sk, &sk->sk_timer); } |
3f421baa4 [NET]: Just move ... |
513 514 515 516 517 518 |
EXPORT_SYMBOL(inet_csk_clear_xmit_timers); void inet_csk_delete_keepalive_timer(struct sock *sk) { sk_stop_timer(sk, &sk->sk_timer); } |
3f421baa4 [NET]: Just move ... |
519 520 521 522 523 524 |
EXPORT_SYMBOL(inet_csk_delete_keepalive_timer); void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len) { sk_reset_timer(sk, &sk->sk_timer, jiffies + len); } |
3f421baa4 [NET]: Just move ... |
525 |
EXPORT_SYMBOL(inet_csk_reset_keepalive_timer); |
e5895bc60 inet: constify in... |
526 |
struct dst_entry *inet_csk_route_req(const struct sock *sk, |
6bd023f3d ipv4: Make caller... |
527 |
struct flowi4 *fl4, |
ba3f7f04e ipv4: Kill FLOWI_... |
528 |
const struct request_sock *req) |
3f421baa4 [NET]: Just move ... |
529 |
{ |
3f421baa4 [NET]: Just move ... |
530 |
const struct inet_request_sock *ireq = inet_rsk(req); |
8b929ab12 inet: remove some... |
531 |
struct net *net = read_pnet(&ireq->ireq_net); |
c92e8c02f tcp/dccp: fix ire... |
532 |
struct ip_options_rcu *opt; |
8b929ab12 inet: remove some... |
533 |
struct rtable *rt; |
3f421baa4 [NET]: Just move ... |
534 |
|
c5df58138 inet: make sure t... |
535 536 |
rcu_read_lock(); opt = rcu_dereference(ireq->ireq_opt); |
06f877d61 tcp/dccp: fix oth... |
537 |
|
8b929ab12 inet: remove some... |
538 |
flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, |
e79d9bc7e ipv4: Use flowi4_... |
539 |
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, |
8b929ab12 inet: remove some... |
540 |
sk->sk_protocol, inet_sk_flowi_flags(sk), |
634fb979e inet: includes a ... |
541 |
(opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, |
8b929ab12 inet: remove some... |
542 |
ireq->ir_loc_addr, ireq->ir_rmt_port, |
e2d118a1c net: inet: Suppor... |
543 |
htons(ireq->ir_num), sk->sk_uid); |
6bd023f3d ipv4: Make caller... |
544 545 |
security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); |
b23dd4fe4 ipv4: Make output... |
546 |
if (IS_ERR(rt)) |
857a6e0a4 icsk: join error ... |
547 |
goto no_route; |
155e8336c ipv4: introduce r... |
548 |
if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) |
857a6e0a4 icsk: join error ... |
549 |
goto route_err; |
c5df58138 inet: make sure t... |
550 |
rcu_read_unlock(); |
d8d1f30b9 net-next: remove ... |
551 |
return &rt->dst; |
857a6e0a4 icsk: join error ... |
552 553 554 555 |
route_err: ip_rt_put(rt); no_route: |
c5df58138 inet: make sure t... |
556 |
rcu_read_unlock(); |
b45386efa net: rename IP_IN... |
557 |
__IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); |
857a6e0a4 icsk: join error ... |
558 |
return NULL; |
3f421baa4 [NET]: Just move ... |
559 |
} |
3f421baa4 [NET]: Just move ... |
560 |
EXPORT_SYMBOL_GPL(inet_csk_route_req); |
a2432c4fa inet: constify in... |
561 |
struct dst_entry *inet_csk_route_child_sock(const struct sock *sk, |
77357a955 ipv4: Create inet... |
562 563 564 565 |
struct sock *newsk, const struct request_sock *req) { const struct inet_request_sock *ireq = inet_rsk(req); |
8b929ab12 inet: remove some... |
566 |
struct net *net = read_pnet(&ireq->ireq_net); |
77357a955 ipv4: Create inet... |
567 |
struct inet_sock *newinet = inet_sk(newsk); |
1a7b27c97 ipv4: Use newinet... |
568 |
struct ip_options_rcu *opt; |
77357a955 ipv4: Create inet... |
569 570 |
struct flowi4 *fl4; struct rtable *rt; |
c92e8c02f tcp/dccp: fix ire... |
571 |
opt = rcu_dereference(ireq->ireq_opt); |
77357a955 ipv4: Create inet... |
572 |
fl4 = &newinet->cork.fl.u.ip4; |
1a7b27c97 ipv4: Use newinet... |
573 |
|
8b929ab12 inet: remove some... |
574 |
flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, |
77357a955 ipv4: Create inet... |
575 576 |
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, sk->sk_protocol, inet_sk_flowi_flags(sk), |
634fb979e inet: includes a ... |
577 |
(opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, |
8b929ab12 inet: remove some... |
578 |
ireq->ir_loc_addr, ireq->ir_rmt_port, |
e2d118a1c net: inet: Suppor... |
579 |
htons(ireq->ir_num), sk->sk_uid); |
77357a955 ipv4: Create inet... |
580 581 582 583 |
security_req_classify_flow(req, flowi4_to_flowi(fl4)); rt = ip_route_output_flow(net, fl4, sk); if (IS_ERR(rt)) goto no_route; |
155e8336c ipv4: introduce r... |
584 |
if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) |
77357a955 ipv4: Create inet... |
585 586 587 588 589 590 |
goto route_err; return &rt->dst; route_err: ip_rt_put(rt); no_route: |
b45386efa net: rename IP_IN... |
591 |
__IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); |
77357a955 ipv4: Create inet... |
592 593 594 |
return NULL; } EXPORT_SYMBOL_GPL(inet_csk_route_child_sock); |
dfd56b8b3 net: use IS_ENABL... |
595 |
#if IS_ENABLED(CONFIG_IPV6) |
3f421baa4 [NET]: Just move ... |
596 597 |
#define AF_INET_FAMILY(fam) ((fam) == AF_INET) #else |
fa76ce732 inet: get rid of ... |
598 |
#define AF_INET_FAMILY(fam) true |
3f421baa4 [NET]: Just move ... |
599 |
#endif |
0c3d79bce tcp: reduce SYN-A... |
600 601 602 603 604 605 606 |
/* Decide when to expire the request and when to resend SYN-ACK */ static inline void syn_ack_recalc(struct request_sock *req, const int thresh, const int max_retries, const u8 rskq_defer_accept, int *expire, int *resend) { if (!rskq_defer_accept) { |
e6c022a4f tcp: better retra... |
607 |
*expire = req->num_timeout >= thresh; |
0c3d79bce tcp: reduce SYN-A... |
608 609 610 |
*resend = 1; return; } |
e6c022a4f tcp: better retra... |
611 612 |
*expire = req->num_timeout >= thresh && (!inet_rsk(req)->acked || req->num_timeout >= max_retries); |
0c3d79bce tcp: reduce SYN-A... |
613 614 615 616 617 618 |
/* * Do not resend while waiting for data after ACK, * start to resend on end of deferring period to give * last chance for data or ACK to create established socket. */ *resend = !inet_rsk(req)->acked || |
e6c022a4f tcp: better retra... |
619 |
req->num_timeout >= rskq_defer_accept - 1; |
0c3d79bce tcp: reduce SYN-A... |
620 |
} |
1b70e977c inet: constify in... |
621 |
int inet_rtx_syn_ack(const struct sock *parent, struct request_sock *req) |
e6c022a4f tcp: better retra... |
622 |
{ |
1a2c6181c tcp: Remove TCPCT |
623 |
int err = req->rsk_ops->rtx_syn_ack(parent, req); |
e6c022a4f tcp: better retra... |
624 625 626 627 628 629 |
if (!err) req->num_retrans++; return err; } EXPORT_SYMBOL(inet_rtx_syn_ack); |
079096f10 tcp/dccp: install... |
630 |
/* return true if req was found in the ehash table */ |
b357a364c inet: fix possibl... |
631 632 633 |
static bool reqsk_queue_unlink(struct request_sock_queue *queue, struct request_sock *req) { |
079096f10 tcp/dccp: install... |
634 |
struct inet_hashinfo *hashinfo = req_to_sk(req)->sk_prot->h.hashinfo; |
5e0724d02 tcp/dccp: fix has... |
635 |
bool found = false; |
b357a364c inet: fix possibl... |
636 |
|
5e0724d02 tcp/dccp: fix has... |
637 638 |
if (sk_hashed(req_to_sk(req))) { spinlock_t *lock = inet_ehash_lockp(hashinfo, req->rsk_hash); |
b357a364c inet: fix possibl... |
639 |
|
5e0724d02 tcp/dccp: fix has... |
640 641 642 643 |
spin_lock(lock); found = __sk_nulls_del_node_init_rcu(req_to_sk(req)); spin_unlock(lock); } |
83fccfc39 inet: fix potenti... |
644 |
if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer)) |
b357a364c inet: fix possibl... |
645 646 647 648 649 650 651 652 653 654 655 656 |
reqsk_put(req); return found; } void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req) { if (reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req)) { reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); reqsk_put(req); } } EXPORT_SYMBOL(inet_csk_reqsk_queue_drop); |
f03f2e154 tcp/dccp: add ine... |
657 658 659 660 661 662 |
void inet_csk_reqsk_queue_drop_and_put(struct sock *sk, struct request_sock *req) { inet_csk_reqsk_queue_drop(sk, req); reqsk_put(req); } EXPORT_SYMBOL(inet_csk_reqsk_queue_drop_and_put); |
fa76ce732 inet: get rid of ... |
663 |
static void reqsk_timer_handler(unsigned long data) |
a019d6fe2 [ICSK]: Move gene... |
664 |
{ |
fa76ce732 inet: get rid of ... |
665 666 |
struct request_sock *req = (struct request_sock *)data; struct sock *sk_listener = req->rsk_listener; |
7c083ecb3 ipv4: Namespaceif... |
667 |
struct net *net = sock_net(sk_listener); |
fa76ce732 inet: get rid of ... |
668 |
struct inet_connection_sock *icsk = inet_csk(sk_listener); |
a019d6fe2 [ICSK]: Move gene... |
669 |
struct request_sock_queue *queue = &icsk->icsk_accept_queue; |
2b41fab70 inet: cache liste... |
670 |
int qlen, expire = 0, resend = 0; |
fa76ce732 inet: get rid of ... |
671 |
int max_retries, thresh; |
2b41fab70 inet: cache liste... |
672 |
u8 defer_accept; |
a019d6fe2 [ICSK]: Move gene... |
673 |
|
00fd38d93 tcp: ensure prope... |
674 |
if (sk_state_load(sk_listener) != TCP_LISTEN) |
079096f10 tcp/dccp: install... |
675 |
goto drop; |
a019d6fe2 [ICSK]: Move gene... |
676 |
|
7c083ecb3 ipv4: Namespaceif... |
677 |
max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; |
fa76ce732 inet: get rid of ... |
678 |
thresh = max_retries; |
a019d6fe2 [ICSK]: Move gene... |
679 680 |
/* Normally all the openreqs are young and become mature * (i.e. converted to established socket) for first timeout. |
fd4f2cead tcp: RFC6298 supe... |
681 |
* If synack was not acknowledged for 1 second, it means |
a019d6fe2 [ICSK]: Move gene... |
682 683 684 685 686 687 688 689 690 691 692 693 694 695 |
* one of the following things: synack was lost, ack was lost, * rtt is high or nobody planned to ack (i.e. synflood). * When server is a bit loaded, queue is populated with old * open requests, reducing effective size of queue. * When server is well loaded, queue size reduces to zero * after several minutes of work. It is not synflood, * it is normal operation. The solution is pruning * too old entries overriding normal timeout, when * situation becomes dangerous. * * Essentially, we reserve half of room for young * embrions; and abort old ones without pity, if old * ones are about to clog our table. */ |
aac065c50 tcp: move qlen/yo... |
696 |
qlen = reqsk_queue_len(queue); |
acb4a6bfc tcp: ensure prior... |
697 |
if ((qlen << 1) > max(8U, sk_listener->sk_max_ack_backlog)) { |
aac065c50 tcp: move qlen/yo... |
698 |
int young = reqsk_queue_len_young(queue) << 1; |
a019d6fe2 [ICSK]: Move gene... |
699 700 |
while (thresh > 2) { |
2b41fab70 inet: cache liste... |
701 |
if (qlen < young) |
a019d6fe2 [ICSK]: Move gene... |
702 703 704 705 706 |
break; thresh--; young <<= 1; } } |
2b41fab70 inet: cache liste... |
707 708 709 710 |
defer_accept = READ_ONCE(queue->rskq_defer_accept); if (defer_accept) max_retries = defer_accept; syn_ack_recalc(req, thresh, max_retries, defer_accept, |
fa76ce732 inet: get rid of ... |
711 |
&expire, &resend); |
42cb80a23 inet: remove sk_l... |
712 |
req->rsk_ops->syn_ack_timeout(req); |
fa76ce732 inet: get rid of ... |
713 714 715 716 717 718 719 |
if (!expire && (!resend || !inet_rtx_syn_ack(sk_listener, req) || inet_rsk(req)->acked)) { unsigned long timeo; if (req->num_timeout++ == 0) |
aac065c50 tcp: move qlen/yo... |
720 |
atomic_dec(&queue->young); |
fa76ce732 inet: get rid of ... |
721 |
timeo = min(TCP_TIMEOUT_INIT << req->num_timeout, TCP_RTO_MAX); |
f3438bc78 timers, net/ipv4/... |
722 |
mod_timer(&req->rsk_timer, jiffies + timeo); |
fa76ce732 inet: get rid of ... |
723 724 |
return; } |
079096f10 tcp/dccp: install... |
725 |
drop: |
f03f2e154 tcp/dccp: add ine... |
726 |
inet_csk_reqsk_queue_drop_and_put(sk_listener, req); |
fa76ce732 inet: get rid of ... |
727 |
} |
ec0a19662 tcp: Revert 'proc... |
728 |
|
079096f10 tcp/dccp: install... |
729 730 |
static void reqsk_queue_hash_req(struct request_sock *req, unsigned long timeout) |
fa76ce732 inet: get rid of ... |
731 |
{ |
fa76ce732 inet: get rid of ... |
732 733 734 |
req->num_retrans = 0; req->num_timeout = 0; req->sk = NULL; |
a019d6fe2 [ICSK]: Move gene... |
735 |
|
f3438bc78 timers, net/ipv4/... |
736 737 738 |
setup_pinned_timer(&req->rsk_timer, reqsk_timer_handler, (unsigned long)req); mod_timer(&req->rsk_timer, jiffies + timeout); |
29c685260 inet: fix races i... |
739 |
|
079096f10 tcp/dccp: install... |
740 |
inet_ehash_insert(req_to_sk(req), NULL); |
fa76ce732 inet: get rid of ... |
741 742 743 744 |
/* before letting lookups find us, make sure all req fields * are committed to memory and refcnt initialized. */ smp_wmb(); |
41c6d650f net: convert sock... |
745 |
refcount_set(&req->rsk_refcnt, 2 + 1); |
079096f10 tcp/dccp: install... |
746 |
} |
a019d6fe2 [ICSK]: Move gene... |
747 |
|
079096f10 tcp/dccp: install... |
748 749 750 751 752 |
void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, unsigned long timeout) { reqsk_queue_hash_req(req, timeout); inet_csk_reqsk_queue_added(sk); |
a019d6fe2 [ICSK]: Move gene... |
753 |
} |
079096f10 tcp/dccp: install... |
754 |
EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add); |
a019d6fe2 [ICSK]: Move gene... |
755 |
|
e56c57d0d net: rename sk_cl... |
756 757 758 759 760 761 762 763 764 765 766 |
/** * inet_csk_clone_lock - clone an inet socket, and lock its clone * @sk: the socket to clone * @req: request_sock * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) * * Caller must unlock socket even in error path (bh_unlock_sock(newsk)) */ struct sock *inet_csk_clone_lock(const struct sock *sk, const struct request_sock *req, const gfp_t priority) |
9f1d2604c [ICSK]: Introduce... |
767 |
{ |
e56c57d0d net: rename sk_cl... |
768 |
struct sock *newsk = sk_clone_lock(sk, priority); |
9f1d2604c [ICSK]: Introduce... |
769 |
|
00db41243 ipv4: coding styl... |
770 |
if (newsk) { |
9f1d2604c [ICSK]: Introduce... |
771 772 773 774 |
struct inet_connection_sock *newicsk = inet_csk(newsk); newsk->sk_state = TCP_SYN_RECV; newicsk->icsk_bind_hash = NULL; |
634fb979e inet: includes a ... |
775 |
inet_sk(newsk)->inet_dport = inet_rsk(req)->ir_rmt_port; |
b44084c2c inet: rename ir_l... |
776 777 |
inet_sk(newsk)->inet_num = inet_rsk(req)->ir_num; inet_sk(newsk)->inet_sport = htons(inet_rsk(req)->ir_num); |
9f1d2604c [ICSK]: Introduce... |
778 |
|
850178692 tcp/dccp: fix ine... |
779 780 |
/* listeners have SOCK_RCU_FREE, not the children */ sock_reset_flag(newsk, SOCK_RCU_FREE); |
657831ffc dccp/tcp: do not ... |
781 |
inet_sk(newsk)->mc_list = NULL; |
84f39b08d net: support mark... |
782 |
newsk->sk_mark = inet_rsk(req)->ir_mark; |
33cf7c90f net: add real soc... |
783 784 |
atomic64_set(&newsk->sk_cookie, atomic64_read(&inet_rsk(req)->ir_cookie)); |
84f39b08d net: support mark... |
785 |
|
9f1d2604c [ICSK]: Introduce... |
786 |
newicsk->icsk_retransmits = 0; |
6687e988d [ICSK]: Move TCP ... |
787 788 |
newicsk->icsk_backoff = 0; newicsk->icsk_probes_out = 0; |
9f1d2604c [ICSK]: Introduce... |
789 790 791 |
/* Deinitialize accept_queue to trap illegal accesses. */ memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue)); |
4237c75c0 [MLSXFRM]: Auto-l... |
792 793 |
security_inet_csk_clone(newsk, req); |
9f1d2604c [ICSK]: Introduce... |
794 795 796 |
} return newsk; } |
e56c57d0d net: rename sk_cl... |
797 |
EXPORT_SYMBOL_GPL(inet_csk_clone_lock); |
a019d6fe2 [ICSK]: Move gene... |
798 799 800 801 802 803 804 805 806 |
/* * At this point, there should be no process reference to this * socket, and thus no user references at all. Therefore we * can assume the socket waitqueue is inactive and nobody will * try to jump onto it. */ void inet_csk_destroy_sock(struct sock *sk) { |
547b792ca net: convert BUG_... |
807 808 |
WARN_ON(sk->sk_state != TCP_CLOSE); WARN_ON(!sock_flag(sk, SOCK_DEAD)); |
a019d6fe2 [ICSK]: Move gene... |
809 810 |
/* It cannot be in hash table! */ |
547b792ca net: convert BUG_... |
811 |
WARN_ON(!sk_unhashed(sk)); |
a019d6fe2 [ICSK]: Move gene... |
812 |
|
c720c7e83 inet: rename some... |
813 814 |
/* If it has not 0 inet_sk(sk)->inet_num, it must be bound */ WARN_ON(inet_sk(sk)->inet_num && !inet_csk(sk)->icsk_bind_hash); |
a019d6fe2 [ICSK]: Move gene... |
815 816 817 818 819 820 821 822 |
sk->sk_prot->destroy(sk); sk_stream_kill_queues(sk); xfrm_sk_free_policy(sk); sk_refcnt_debug_release(sk); |
dd24c0019 net: Use a percpu... |
823 |
percpu_counter_dec(sk->sk_prot->orphan_count); |
c2a2efbbf net: remove bh di... |
824 |
|
a019d6fe2 [ICSK]: Move gene... |
825 826 |
sock_put(sk); } |
a019d6fe2 [ICSK]: Move gene... |
827 |
EXPORT_SYMBOL(inet_csk_destroy_sock); |
e337e24d6 inet: Fix kmemlea... |
828 829 830 831 |
/* This function allows to force a closure of a socket after the call to * tcp/dccp_create_openreq_child(). */ void inet_csk_prepare_forced_close(struct sock *sk) |
c10cb5fc0 Fix: sparse warni... |
832 |
__releases(&sk->sk_lock.slock) |
e337e24d6 inet: Fix kmemlea... |
833 834 835 836 837 838 839 840 841 842 843 |
{ /* sk_clone_lock locked the socket and set refcnt to 2 */ bh_unlock_sock(sk); sock_put(sk); /* The below has to be done to allow calling inet_csk_destroy_sock */ sock_set_flag(sk, SOCK_DEAD); percpu_counter_inc(sk->sk_prot->orphan_count); inet_sk(sk)->inet_num = 0; } EXPORT_SYMBOL(inet_csk_prepare_forced_close); |
f985c65c9 tcp: avoid spurio... |
844 |
int inet_csk_listen_start(struct sock *sk, int backlog) |
a019d6fe2 [ICSK]: Move gene... |
845 |
{ |
a019d6fe2 [ICSK]: Move gene... |
846 |
struct inet_connection_sock *icsk = inet_csk(sk); |
10cbc8f17 tcp/dccp: remove ... |
847 |
struct inet_sock *inet = inet_sk(sk); |
086c653f5 sock: struct prot... |
848 |
int err = -EADDRINUSE; |
a019d6fe2 [ICSK]: Move gene... |
849 |
|
ef547f2ac tcp: remove max_q... |
850 |
reqsk_queue_alloc(&icsk->icsk_accept_queue); |
a019d6fe2 [ICSK]: Move gene... |
851 |
|
f985c65c9 tcp: avoid spurio... |
852 |
sk->sk_max_ack_backlog = backlog; |
a019d6fe2 [ICSK]: Move gene... |
853 854 855 856 857 858 859 860 |
sk->sk_ack_backlog = 0; inet_csk_delack_init(sk); /* There is race window here: we announce ourselves listening, * but this transition is still not validated by get_port(). * It is OK, because this socket enters to hash table only * after validation is complete. */ |
00fd38d93 tcp: ensure prope... |
861 |
sk_state_store(sk, TCP_LISTEN); |
c720c7e83 inet: rename some... |
862 863 |
if (!sk->sk_prot->get_port(sk, inet->inet_num)) { inet->inet_sport = htons(inet->inet_num); |
a019d6fe2 [ICSK]: Move gene... |
864 865 |
sk_dst_reset(sk); |
086c653f5 sock: struct prot... |
866 |
err = sk->sk_prot->hash(sk); |
a019d6fe2 [ICSK]: Move gene... |
867 |
|
086c653f5 sock: struct prot... |
868 869 |
if (likely(!err)) return 0; |
a019d6fe2 [ICSK]: Move gene... |
870 871 872 |
} sk->sk_state = TCP_CLOSE; |
086c653f5 sock: struct prot... |
873 |
return err; |
a019d6fe2 [ICSK]: Move gene... |
874 |
} |
a019d6fe2 [ICSK]: Move gene... |
875 |
EXPORT_SYMBOL_GPL(inet_csk_listen_start); |
ebb516af6 tcp/dccp: fix rac... |
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 |
static void inet_child_forget(struct sock *sk, struct request_sock *req, struct sock *child) { sk->sk_prot->disconnect(child, O_NONBLOCK); sock_orphan(child); percpu_counter_inc(sk->sk_prot->orphan_count); if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->tfo_listener) { BUG_ON(tcp_sk(child)->fastopen_rsk != req); BUG_ON(sk != req->rsk_listener); /* Paranoid, to prevent race condition if * an inbound pkt destined for child is * blocked by sock lock in tcp_v4_rcv(). * Also to satisfy an assertion in * tcp_v4_destroy_sock(). */ tcp_sk(child)->fastopen_rsk = NULL; } inet_csk_destroy_sock(child); |
ebb516af6 tcp/dccp: fix rac... |
898 |
} |
7716682cc tcp/dccp: fix ano... |
899 900 901 |
struct sock *inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req, struct sock *child) |
ebb516af6 tcp/dccp: fix rac... |
902 903 904 905 906 907 |
{ struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; spin_lock(&queue->rskq_lock); if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_child_forget(sk, req, child); |
7716682cc tcp/dccp: fix ano... |
908 |
child = NULL; |
ebb516af6 tcp/dccp: fix rac... |
909 910 911 912 913 914 915 916 917 918 919 |
} else { req->sk = child; req->dl_next = NULL; if (queue->rskq_accept_head == NULL) queue->rskq_accept_head = req; else queue->rskq_accept_tail->dl_next = req; queue->rskq_accept_tail = req; sk_acceptq_added(sk); } spin_unlock(&queue->rskq_lock); |
7716682cc tcp/dccp: fix ano... |
920 |
return child; |
ebb516af6 tcp/dccp: fix rac... |
921 922 |
} EXPORT_SYMBOL(inet_csk_reqsk_queue_add); |
5e0724d02 tcp/dccp: fix has... |
923 924 925 926 927 928 |
struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child, struct request_sock *req, bool own_req) { if (own_req) { inet_csk_reqsk_queue_drop(sk, req); reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); |
7716682cc tcp/dccp: fix ano... |
929 930 |
if (inet_csk_reqsk_queue_add(sk, req, child)) return child; |
5e0724d02 tcp/dccp: fix has... |
931 932 933 934 935 936 937 |
} /* Too bad, another child took ownership of the request, undo. */ bh_unlock_sock(child); sock_put(child); return NULL; } EXPORT_SYMBOL(inet_csk_complete_hashdance); |
a019d6fe2 [ICSK]: Move gene... |
938 939 940 941 942 943 944 |
/* * This routine closes sockets which have been at least partially * opened, but not yet accepted. */ void inet_csk_listen_stop(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); |
8336886f7 tcp: TCP Fast Ope... |
945 |
struct request_sock_queue *queue = &icsk->icsk_accept_queue; |
fff1f3001 tcp: add a spinlo... |
946 |
struct request_sock *next, *req; |
a019d6fe2 [ICSK]: Move gene... |
947 948 949 950 951 952 953 954 955 |
/* Following specs, it would be better either to send FIN * (and enter FIN-WAIT-1, it is normal close) * or to send active reset (abort). * Certainly, it is pretty dangerous while synflood, but it is * bad justification for our negligence 8) * To be honest, we are not able to make either * of the variants now. --ANK */ |
fff1f3001 tcp: add a spinlo... |
956 |
while ((req = reqsk_queue_remove(queue, sk)) != NULL) { |
a019d6fe2 [ICSK]: Move gene... |
957 |
struct sock *child = req->sk; |
a019d6fe2 [ICSK]: Move gene... |
958 959 |
local_bh_disable(); bh_lock_sock(child); |
547b792ca net: convert BUG_... |
960 |
WARN_ON(sock_owned_by_user(child)); |
a019d6fe2 [ICSK]: Move gene... |
961 |
sock_hold(child); |
ebb516af6 tcp/dccp: fix rac... |
962 |
inet_child_forget(sk, req, child); |
da8ab5786 tcp/dccp: remove ... |
963 |
reqsk_put(req); |
a019d6fe2 [ICSK]: Move gene... |
964 965 966 |
bh_unlock_sock(child); local_bh_enable(); sock_put(child); |
92d6f176f tcp/dccp: add a r... |
967 |
cond_resched(); |
a019d6fe2 [ICSK]: Move gene... |
968 |
} |
0536fcc03 tcp: prepare fast... |
969 |
if (queue->fastopenq.rskq_rst_head) { |
8336886f7 tcp: TCP Fast Ope... |
970 |
/* Free all the reqs queued in rskq_rst_head. */ |
0536fcc03 tcp: prepare fast... |
971 |
spin_lock_bh(&queue->fastopenq.lock); |
fff1f3001 tcp: add a spinlo... |
972 |
req = queue->fastopenq.rskq_rst_head; |
0536fcc03 tcp: prepare fast... |
973 974 |
queue->fastopenq.rskq_rst_head = NULL; spin_unlock_bh(&queue->fastopenq.lock); |
fff1f3001 tcp: add a spinlo... |
975 976 |
while (req != NULL) { next = req->dl_next; |
13854e5a6 inet: add proper ... |
977 |
reqsk_put(req); |
fff1f3001 tcp: add a spinlo... |
978 |
req = next; |
8336886f7 tcp: TCP Fast Ope... |
979 980 |
} } |
ebb516af6 tcp/dccp: fix rac... |
981 |
WARN_ON_ONCE(sk->sk_ack_backlog); |
a019d6fe2 [ICSK]: Move gene... |
982 |
} |
a019d6fe2 [ICSK]: Move gene... |
983 |
EXPORT_SYMBOL_GPL(inet_csk_listen_stop); |
af05dc939 [ICSK]: Move v4_a... |
984 985 986 987 988 989 990 |
void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr) { struct sockaddr_in *sin = (struct sockaddr_in *)uaddr; const struct inet_sock *inet = inet_sk(sk); sin->sin_family = AF_INET; |
c720c7e83 inet: rename some... |
991 992 |
sin->sin_addr.s_addr = inet->inet_daddr; sin->sin_port = inet->inet_dport; |
af05dc939 [ICSK]: Move v4_a... |
993 |
} |
af05dc939 [ICSK]: Move v4_a... |
994 |
EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr); |
c4d939094 [ICSK]: Introduce... |
995 |
|
dec73ff02 [ICSK] compat: In... |
996 997 998 999 |
#ifdef CONFIG_COMPAT int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { |
dbeff12b4 [INET]: Fix typo ... |
1000 |
const struct inet_connection_sock *icsk = inet_csk(sk); |
dec73ff02 [ICSK] compat: In... |
1001 |
|
00db41243 ipv4: coding styl... |
1002 |
if (icsk->icsk_af_ops->compat_getsockopt) |
dec73ff02 [ICSK] compat: In... |
1003 1004 1005 1006 1007 |
return icsk->icsk_af_ops->compat_getsockopt(sk, level, optname, optval, optlen); return icsk->icsk_af_ops->getsockopt(sk, level, optname, optval, optlen); } |
dec73ff02 [ICSK] compat: In... |
1008 1009 1010 |
EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt); int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, |
b7058842c net: Make setsock... |
1011 |
char __user *optval, unsigned int optlen) |
dec73ff02 [ICSK] compat: In... |
1012 |
{ |
dbeff12b4 [INET]: Fix typo ... |
1013 |
const struct inet_connection_sock *icsk = inet_csk(sk); |
dec73ff02 [ICSK] compat: In... |
1014 |
|
00db41243 ipv4: coding styl... |
1015 |
if (icsk->icsk_af_ops->compat_setsockopt) |
dec73ff02 [ICSK] compat: In... |
1016 1017 1018 1019 1020 |
return icsk->icsk_af_ops->compat_setsockopt(sk, level, optname, optval, optlen); return icsk->icsk_af_ops->setsockopt(sk, level, optname, optval, optlen); } |
dec73ff02 [ICSK] compat: In... |
1021 1022 |
EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt); #endif |
80d0a69fc ipv4: Add helper ... |
1023 1024 1025 |
static struct dst_entry *inet_csk_rebuild_route(struct sock *sk, struct flowi *fl) { |
5abf7f7e0 ipv4: fix rcu splat |
1026 1027 |
const struct inet_sock *inet = inet_sk(sk); const struct ip_options_rcu *inet_opt; |
80d0a69fc ipv4: Add helper ... |
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 |
__be32 daddr = inet->inet_daddr; struct flowi4 *fl4; struct rtable *rt; rcu_read_lock(); inet_opt = rcu_dereference(inet->inet_opt); if (inet_opt && inet_opt->opt.srr) daddr = inet_opt->opt.faddr; fl4 = &fl->u.ip4; rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, RT_CONN_FLAGS(sk), sk->sk_bound_dev_if); if (IS_ERR(rt)) rt = NULL; if (rt) sk_setup_caps(sk, &rt->dst); rcu_read_unlock(); return &rt->dst; } struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu) { struct dst_entry *dst = __sk_dst_check(sk, 0); struct inet_sock *inet = inet_sk(sk); if (!dst) { dst = inet_csk_rebuild_route(sk, &inet->cork.fl); if (!dst) goto out; } |
6700c2709 net: Pass optiona... |
1060 |
dst->ops->update_pmtu(dst, sk, NULL, mtu); |
80d0a69fc ipv4: Add helper ... |
1061 1062 1063 1064 1065 1066 1067 1068 |
dst = __sk_dst_check(sk, 0); if (!dst) dst = inet_csk_rebuild_route(sk, &inet->cork.fl); out: return dst; } EXPORT_SYMBOL_GPL(inet_csk_update_pmtu); |