Blame view

net/ipv4/inet_connection_sock.c 30.6 KB
3f421baa4   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
24
  #include <net/xfrm.h>
fa76ce732   Eric Dumazet   inet: get rid of ...
25
  #include <net/tcp.h>
c125e80b8   Craig Gallek   soreuseport: fast...
26
  #include <net/sock_reuseport.h>
9691724e5   stephen hemminger   inet: fix warning...
27
  #include <net/addrconf.h>
3f421baa4   Arnaldo Carvalho de Melo   [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   Josef Bacik   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   Josef Bacik   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   Josef Bacik   inet: collapse ip...
45
46
  				bool match_wildcard)
  {
637bc8bbe   Josef Bacik   inet: reset tb->f...
47
  	int addr_type = ipv6_addr_type(sk1_rcv_saddr6);
fe38d2a1c   Josef Bacik   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   Josef Bacik   inet: reset tb->f...
53
  			if (sk1_rcv_saddr == sk2_rcv_saddr)
fe38d2a1c   Josef Bacik   inet: collapse ip...
54
  				return 1;
637bc8bbe   Josef Bacik   inet: reset tb->f...
55
  			if (!sk1_rcv_saddr || !sk2_rcv_saddr)
fe38d2a1c   Josef Bacik   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   Josef Bacik   inet: reset tb->f...
69
  	    !(sk1_ipv6only && addr_type2 == IPV6_ADDR_MAPPED))
fe38d2a1c   Josef Bacik   inet: collapse ip...
70
71
72
  		return 1;
  
  	if (sk2_rcv_saddr6 &&
637bc8bbe   Josef Bacik   inet: reset tb->f...
73
  	    ipv6_addr_equal(sk1_rcv_saddr6, sk2_rcv_saddr6))
fe38d2a1c   Josef Bacik   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   Josef Bacik   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   Josef Bacik   inet: collapse ip...
86
  {
637bc8bbe   Josef Bacik   inet: reset tb->f...
87
88
  	if (!sk2_ipv6only) {
  		if (sk1_rcv_saddr == sk2_rcv_saddr)
fe38d2a1c   Josef Bacik   inet: collapse ip...
89
  			return 1;
637bc8bbe   Josef Bacik   inet: reset tb->f...
90
  		if (!sk1_rcv_saddr || !sk2_rcv_saddr)
fe38d2a1c   Josef Bacik   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   Josef Bacik   inet: reset tb->f...
101
  		return ipv6_rcv_saddr_equal(&sk->sk_v6_rcv_saddr,
319554f28   Josef Bacik   inet: don't use s...
102
  					    inet6_rcv_saddr(sk2),
637bc8bbe   Josef Bacik   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   Josef Bacik   inet: collapse ip...
108
  #endif
637bc8bbe   Josef Bacik   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   Josef Bacik   inet: collapse ip...
111
112
  }
  EXPORT_SYMBOL(inet_rcv_saddr_equal);
0bbf87d85   Eric W. Biederman   net ipv4: Convert...
113
  void inet_get_local_port_range(struct net *net, int *low, int *high)
227b60f51   Stephen Hemminger   [INET]: local por...
114
  {
95c961747   Eric Dumazet   net: cleanup unsi...
115
  	unsigned int seq;
227b60f51   Stephen Hemminger   [INET]: local por...
116
  	do {
c9d8f1a64   Cong Wang   ipv4: move local_...
117
  		seq = read_seqbegin(&net->ipv4.ip_local_ports.lock);
227b60f51   Stephen Hemminger   [INET]: local por...
118

c9d8f1a64   Cong Wang   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   Stephen Hemminger   [INET]: local por...
122
123
  }
  EXPORT_SYMBOL(inet_get_local_port_range);
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
124

aa078842b   Josef Bacik   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   Arnaldo Carvalho de Melo   [NET]: Just move ...
128
  {
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
129
  	struct sock *sk2;
0643ee4fd   Tom Herbert   inet: Fix get por...
130
131
  	bool reuse = sk->sk_reuse;
  	bool reuseport = !!sk->sk_reuseport && reuseport_ok;
da5e36308   Tom Herbert   soreuseport: TCP/...
132
  	kuid_t uid = sock_i_uid((struct sock *)sk);
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
133

7477fd2e6   Pavel Emelyanov   [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   Sasha Levin   hlist: drop the n...
140
  	sk_for_each_bound(sk2, &tb->owners) {
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
141
  		if (sk != sk2 &&
3f421baa4   Arnaldo Carvalho de Melo   [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   Tom Herbert   soreuseport: TCP/...
145
146
147
  			if ((!reuse || !sk2->sk_reuse ||
  			    sk2->sk_state == TCP_LISTEN) &&
  			    (!reuseport || !sk2->sk_reuseport ||
c125e80b8   Craig Gallek   soreuseport: fast...
148
149
  			     rcu_access_pointer(sk->sk_reuseport_cb) ||
  			     (sk2->sk_state != TCP_TIME_WAIT &&
da5e36308   Tom Herbert   soreuseport: TCP/...
150
  			     !uid_eq(uid, sock_i_uid(sk2))))) {
aa078842b   Josef Bacik   inet: drop ->bind...
151
  				if (inet_rcv_saddr_equal(sk, sk2, true))
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
152
  					break;
8d238b25b   David S. Miller   Revert "tcp: bind...
153
  			}
aacd9289a   Alex Copot   tcp: bind() use s...
154
155
  			if (!relax && reuse && sk2->sk_reuse &&
  			    sk2->sk_state != TCP_LISTEN) {
aa078842b   Josef Bacik   inet: drop ->bind...
156
  				if (inet_rcv_saddr_equal(sk, sk2, true))
aacd9289a   Alex Copot   tcp: bind() use s...
157
158
  					break;
  			}
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
159
160
  		}
  	}
b67bfe0d4   Sasha Levin   hlist: drop the n...
161
  	return sk2 != NULL;
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
162
  }
971af18bb   Arnaldo Carvalho de Melo   [IPV6]: Reuse ine...
163

289141b76   Josef Bacik   inet: split inet_...
164
165
166
  /*
   * Find an open port number for the socket.  Returns with the
   * inet_bind_hashbucket lock held.
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
167
   */
289141b76   Josef Bacik   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   Arnaldo Carvalho de Melo   [NET]: Just move ...
170
  {
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
171
  	struct inet_hashinfo *hinfo = sk->sk_prot->h.hashinfo;
289141b76   Josef Bacik   inet: split inet_...
172
  	int port = 0;
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
173
  	struct inet_bind_hashbucket *head;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
174
  	struct net *net = sock_net(sk);
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
175
176
  	int i, low, high, attempt_half;
  	struct inet_bind_bucket *tb;
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
177
  	u32 remaining, offset;
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
178

ea8add2b1   Eric Dumazet   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   Arnaldo Carvalho de Melo   [NET]: Just move ...
196

ea8add2b1   Eric Dumazet   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   Eric Dumazet   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   Josef Bacik   inet: split inet_...
215
  				if (!inet_csk_bind_conflict(sk, tb, false, false))
6cd666168   Josef Bacik   inet: don't check...
216
  					goto success;
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
217
  				goto next_port;
946f9eb22   Eric Dumazet   tcp: improve REUS...
218
  			}
289141b76   Josef Bacik   inet: split inet_...
219
220
  		tb = NULL;
  		goto success;
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
221
222
223
224
  next_port:
  		spin_unlock_bh(&head->lock);
  		cond_resched();
  	}
ea8add2b1   Eric Dumazet   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   Josef Bacik   inet: split inet_...
234
235
236
237
238
239
  	return NULL;
  success:
  	*port_ret = port;
  	*tb_ret = tb;
  	return head;
  }
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
240

637bc8bbe   Josef Bacik   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   Josef Bacik   net: use inet6_rc...
264
  					    inet6_rcv_saddr(sk),
637bc8bbe   Josef Bacik   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   Josef Bacik   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   Eric Dumazet   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   Arnaldo Carvalho de Melo   [NET]: Just move ...
306
307
  tb_found:
  	if (!hlist_empty(&tb->owners)) {
4a17fd522   Pavel Emelyanov   sock: Introduce n...
308
309
  		if (sk->sk_reuse == SK_FORCE_REUSE)
  			goto success;
b9470c276   Josef Bacik   inet: kill smalle...
310
  		if ((tb->fastreuse > 0 && reuse) ||
637bc8bbe   Josef Bacik   inet: reset tb->f...
311
  		    sk_reuseport_match(tb, sk))
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
312
  			goto success;
289141b76   Josef Bacik   inet: split inet_...
313
  		if (inet_csk_bind_conflict(sk, tb, true, true))
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
314
  			goto fail_unlock;
6cd666168   Josef Bacik   inet: don't check...
315
316
  	}
  success:
fbed24bcc   Josef Bacik   inet: fix imprope...
317
  	if (hlist_empty(&tb->owners)) {
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
318
  		tb->fastreuse = reuse;
da5e36308   Tom Herbert   soreuseport: TCP/...
319
  		if (sk->sk_reuseport) {
637bc8bbe   Josef Bacik   inet: reset tb->f...
320
  			tb->fastreuseport = FASTREUSEPORT_ANY;
da5e36308   Tom Herbert   soreuseport: TCP/...
321
  			tb->fastuid = uid;
637bc8bbe   Josef Bacik   inet: reset tb->f...
322
323
  			tb->fast_rcv_saddr = sk->sk_rcv_saddr;
  			tb->fast_ipv6_only = ipv6_only_sock(sk);
cbb2fb5c7   Josef Bacik   net: set tb->fast...
324
  			tb->fast_sk_family = sk->sk_family;
637bc8bbe   Josef Bacik   inet: reset tb->f...
325
326
327
  #if IS_ENABLED(CONFIG_IPV6)
  			tb->fast_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
  #endif
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
328
  		} else {
da5e36308   Tom Herbert   soreuseport: TCP/...
329
  			tb->fastreuseport = 0;
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
330
  		}
6cd666168   Josef Bacik   inet: don't check...
331
332
333
  	} else {
  		if (!reuse)
  			tb->fastreuse = 0;
637bc8bbe   Josef Bacik   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   Josef Bacik   net: set tb->fast...
351
  				tb->fast_sk_family = sk->sk_family;
637bc8bbe   Josef Bacik   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   Josef Bacik   inet: don't check...
357
  			tb->fastreuseport = 0;
637bc8bbe   Josef Bacik   inet: reset tb->f...
358
  		}
da5e36308   Tom Herbert   soreuseport: TCP/...
359
  	}
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
360
  	if (!inet_csk(sk)->icsk_bind_hash)
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
361
  		inet_bind_hash(sk, tb, port);
547b792ca   Ilpo Järvinen   net: convert BUG_...
362
  	WARN_ON(inet_csk(sk)->icsk_bind_hash != tb);
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
363
  	ret = 0;
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
364
365
  
  fail_unlock:
ea8add2b1   Eric Dumazet   tcp/dccp: better ...
366
  	spin_unlock_bh(&head->lock);
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
367
368
  	return ret;
  }
3f421baa4   Arnaldo Carvalho de Melo   [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   Eric Dumazet   net: sk_sleep() h...
396
  		prepare_to_wait_exclusive(sk_sleep(sk), &wait,
3f421baa4   Arnaldo Carvalho de Melo   [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   Eric Dumazet   inet: Clean up in...
401
  		sched_annotate_sleep();
3f421baa4   Arnaldo Carvalho de Melo   [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   Eric Dumazet   net: sk_sleep() h...
416
  	finish_wait(sk_sleep(sk), &wait);
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
417
418
419
420
421
422
  	return err;
  }
  
  /*
   * This will accept the next outstanding connection.
   */
cdfbabfb2   David Howells   net: Work around ...
423
  struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern)
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
424
425
  {
  	struct inet_connection_sock *icsk = inet_csk(sk);
8336886f7   Jerry Chu   tcp: TCP Fast Ope...
426
  	struct request_sock_queue *queue = &icsk->icsk_accept_queue;
8336886f7   Jerry Chu   tcp: TCP Fast Ope...
427
  	struct request_sock *req;
e3d95ad7d   Eric Dumazet   inet: avoid fasto...
428
  	struct sock *newsk;
3f421baa4   Arnaldo Carvalho de Melo   [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   Jerry Chu   tcp: TCP Fast Ope...
441
  	if (reqsk_queue_empty(queue)) {
3f421baa4   Arnaldo Carvalho de Melo   [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   Eric Dumazet   tcp: add a spinlo...
453
  	req = reqsk_queue_remove(queue, sk);
8336886f7   Jerry Chu   tcp: TCP Fast Ope...
454
  	newsk = req->sk;
e3d95ad7d   Eric Dumazet   inet: avoid fasto...
455
  	if (sk->sk_protocol == IPPROTO_TCP &&
0536fcc03   Eric Dumazet   tcp: prepare fast...
456
457
  	    tcp_rsk(req)->tfo_listener) {
  		spin_lock_bh(&queue->fastopenq.lock);
9439ce00f   Eric Dumazet   tcp: rename struc...
458
  		if (tcp_rsk(req)->tfo_listener) {
8336886f7   Jerry Chu   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   Eric Dumazet   tcp: prepare fast...
468
  		spin_unlock_bh(&queue->fastopenq.lock);
8336886f7   Jerry Chu   tcp: TCP Fast Ope...
469
  	}
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
470
471
  out:
  	release_sock(sk);
8336886f7   Jerry Chu   tcp: TCP Fast Ope...
472
  	if (req)
13854e5a6   Eric Dumazet   inet: add proper ...
473
  		reqsk_put(req);
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
474
475
476
  	return newsk;
  out_err:
  	newsk = NULL;
8336886f7   Jerry Chu   tcp: TCP Fast Ope...
477
  	req = NULL;
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
478
479
480
  	*err = error;
  	goto out;
  }
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
481
482
483
484
  EXPORT_SYMBOL(inet_csk_accept);
  
  /*
   * Using different timers for retransmit, delayed acks and probes
e905a9eda   YOSHIFUJI Hideaki   [NET] IPV4: Fix w...
485
   * We may wish use just one timer maintaining a list of expire jiffies
3f421baa4   Arnaldo Carvalho de Melo   [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   Pavel Emelyanov   [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   Arnaldo Carvalho de Melo   [NET]: Just move ...
499
500
  	icsk->icsk_pending = icsk->icsk_ack.pending = 0;
  }
3f421baa4   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [NET]: Just move ...
525
  EXPORT_SYMBOL(inet_csk_reset_keepalive_timer);
e5895bc60   Eric Dumazet   inet: constify in...
526
  struct dst_entry *inet_csk_route_req(const struct sock *sk,
6bd023f3d   David S. Miller   ipv4: Make caller...
527
  				     struct flowi4 *fl4,
ba3f7f04e   David S. Miller   ipv4: Kill FLOWI_...
528
  				     const struct request_sock *req)
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
529
  {
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
530
  	const struct inet_request_sock *ireq = inet_rsk(req);
8b929ab12   Eric Dumazet   inet: remove some...
531
  	struct net *net = read_pnet(&ireq->ireq_net);
c92e8c02f   Eric Dumazet   tcp/dccp: fix ire...
532
  	struct ip_options_rcu *opt;
8b929ab12   Eric Dumazet   inet: remove some...
533
  	struct rtable *rt;
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
534

c5df58138   Eric Dumazet   inet: make sure t...
535
536
  	rcu_read_lock();
  	opt = rcu_dereference(ireq->ireq_opt);
06f877d61   Eric Dumazet   tcp/dccp: fix oth...
537

8b929ab12   Eric Dumazet   inet: remove some...
538
  	flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark,
e79d9bc7e   David S. Miller   ipv4: Use flowi4_...
539
  			   RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
8b929ab12   Eric Dumazet   inet: remove some...
540
  			   sk->sk_protocol, inet_sk_flowi_flags(sk),
634fb979e   Eric Dumazet   inet: includes a ...
541
  			   (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr,
8b929ab12   Eric Dumazet   inet: remove some...
542
  			   ireq->ir_loc_addr, ireq->ir_rmt_port,
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
543
  			   htons(ireq->ir_num), sk->sk_uid);
6bd023f3d   David S. Miller   ipv4: Make caller...
544
545
  	security_req_classify_flow(req, flowi4_to_flowi(fl4));
  	rt = ip_route_output_flow(net, fl4, sk);
b23dd4fe4   David S. Miller   ipv4: Make output...
546
  	if (IS_ERR(rt))
857a6e0a4   Ilpo Järvinen   icsk: join error ...
547
  		goto no_route;
155e8336c   Julian Anastasov   ipv4: introduce r...
548
  	if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
857a6e0a4   Ilpo Järvinen   icsk: join error ...
549
  		goto route_err;
c5df58138   Eric Dumazet   inet: make sure t...
550
  	rcu_read_unlock();
d8d1f30b9   Changli Gao   net-next: remove ...
551
  	return &rt->dst;
857a6e0a4   Ilpo Järvinen   icsk: join error ...
552
553
554
555
  
  route_err:
  	ip_rt_put(rt);
  no_route:
c5df58138   Eric Dumazet   inet: make sure t...
556
  	rcu_read_unlock();
b45386efa   Eric Dumazet   net: rename IP_IN...
557
  	__IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);
857a6e0a4   Ilpo Järvinen   icsk: join error ...
558
  	return NULL;
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
559
  }
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
560
  EXPORT_SYMBOL_GPL(inet_csk_route_req);
a2432c4fa   Eric Dumazet   inet: constify in...
561
  struct dst_entry *inet_csk_route_child_sock(const struct sock *sk,
77357a955   David S. Miller   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   Eric Dumazet   inet: remove some...
566
  	struct net *net = read_pnet(&ireq->ireq_net);
77357a955   David S. Miller   ipv4: Create inet...
567
  	struct inet_sock *newinet = inet_sk(newsk);
1a7b27c97   Christoph Paasch   ipv4: Use newinet...
568
  	struct ip_options_rcu *opt;
77357a955   David S. Miller   ipv4: Create inet...
569
570
  	struct flowi4 *fl4;
  	struct rtable *rt;
c92e8c02f   Eric Dumazet   tcp/dccp: fix ire...
571
  	opt = rcu_dereference(ireq->ireq_opt);
77357a955   David S. Miller   ipv4: Create inet...
572
  	fl4 = &newinet->cork.fl.u.ip4;
1a7b27c97   Christoph Paasch   ipv4: Use newinet...
573

8b929ab12   Eric Dumazet   inet: remove some...
574
  	flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark,
77357a955   David S. Miller   ipv4: Create inet...
575
576
  			   RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
  			   sk->sk_protocol, inet_sk_flowi_flags(sk),
634fb979e   Eric Dumazet   inet: includes a ...
577
  			   (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr,
8b929ab12   Eric Dumazet   inet: remove some...
578
  			   ireq->ir_loc_addr, ireq->ir_rmt_port,
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
579
  			   htons(ireq->ir_num), sk->sk_uid);
77357a955   David S. Miller   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   Julian Anastasov   ipv4: introduce r...
584
  	if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway)
77357a955   David S. Miller   ipv4: Create inet...
585
586
587
588
589
590
  		goto route_err;
  	return &rt->dst;
  
  route_err:
  	ip_rt_put(rt);
  no_route:
b45386efa   Eric Dumazet   net: rename IP_IN...
591
  	__IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES);
77357a955   David S. Miller   ipv4: Create inet...
592
593
594
  	return NULL;
  }
  EXPORT_SYMBOL_GPL(inet_csk_route_child_sock);
dfd56b8b3   Eric Dumazet   net: use IS_ENABL...
595
  #if IS_ENABLED(CONFIG_IPV6)
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
596
597
  #define AF_INET_FAMILY(fam) ((fam) == AF_INET)
  #else
fa76ce732   Eric Dumazet   inet: get rid of ...
598
  #define AF_INET_FAMILY(fam) true
3f421baa4   Arnaldo Carvalho de Melo   [NET]: Just move ...
599
  #endif
0c3d79bce   Julian Anastasov   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   Eric Dumazet   tcp: better retra...
607
  		*expire = req->num_timeout >= thresh;
0c3d79bce   Julian Anastasov   tcp: reduce SYN-A...
608
609
610
  		*resend = 1;
  		return;
  	}
e6c022a4f   Eric Dumazet   tcp: better retra...
611
612
  	*expire = req->num_timeout >= thresh &&
  		  (!inet_rsk(req)->acked || req->num_timeout >= max_retries);
0c3d79bce   Julian Anastasov   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   Eric Dumazet   tcp: better retra...
619
  		  req->num_timeout >= rskq_defer_accept - 1;
0c3d79bce   Julian Anastasov   tcp: reduce SYN-A...
620
  }
1b70e977c   Eric Dumazet   inet: constify in...
621
  int inet_rtx_syn_ack(const struct sock *parent, struct request_sock *req)
e6c022a4f   Eric Dumazet   tcp: better retra...
622
  {
1a2c6181c   Christoph Paasch   tcp: Remove TCPCT
623
  	int err = req->rsk_ops->rtx_syn_ack(parent, req);
e6c022a4f   Eric Dumazet   tcp: better retra...
624
625
626
627
628
629
  
  	if (!err)
  		req->num_retrans++;
  	return err;
  }
  EXPORT_SYMBOL(inet_rtx_syn_ack);
079096f10   Eric Dumazet   tcp/dccp: install...
630
  /* return true if req was found in the ehash table */
b357a364c   Eric Dumazet   inet: fix possibl...
631
632
633
  static bool reqsk_queue_unlink(struct request_sock_queue *queue,
  			       struct request_sock *req)
  {
079096f10   Eric Dumazet   tcp/dccp: install...
634
  	struct inet_hashinfo *hashinfo = req_to_sk(req)->sk_prot->h.hashinfo;
5e0724d02   Eric Dumazet   tcp/dccp: fix has...
635
  	bool found = false;
b357a364c   Eric Dumazet   inet: fix possibl...
636

5e0724d02   Eric Dumazet   tcp/dccp: fix has...
637
638
  	if (sk_hashed(req_to_sk(req))) {
  		spinlock_t *lock = inet_ehash_lockp(hashinfo, req->rsk_hash);
b357a364c   Eric Dumazet   inet: fix possibl...
639

5e0724d02   Eric Dumazet   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   Eric Dumazet   inet: fix potenti...
644
  	if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer))
b357a364c   Eric Dumazet   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   Eric Dumazet   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   Eric Dumazet   inet: get rid of ...
663
  static void reqsk_timer_handler(unsigned long data)
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
664
  {
fa76ce732   Eric Dumazet   inet: get rid of ...
665
666
  	struct request_sock *req = (struct request_sock *)data;
  	struct sock *sk_listener = req->rsk_listener;
7c083ecb3   Nikolay Borisov   ipv4: Namespaceif...
667
  	struct net *net = sock_net(sk_listener);
fa76ce732   Eric Dumazet   inet: get rid of ...
668
  	struct inet_connection_sock *icsk = inet_csk(sk_listener);
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
669
  	struct request_sock_queue *queue = &icsk->icsk_accept_queue;
2b41fab70   Eric Dumazet   inet: cache liste...
670
  	int qlen, expire = 0, resend = 0;
fa76ce732   Eric Dumazet   inet: get rid of ...
671
  	int max_retries, thresh;
2b41fab70   Eric Dumazet   inet: cache liste...
672
  	u8 defer_accept;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
673

00fd38d93   Eric Dumazet   tcp: ensure prope...
674
  	if (sk_state_load(sk_listener) != TCP_LISTEN)
079096f10   Eric Dumazet   tcp/dccp: install...
675
  		goto drop;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
676

7c083ecb3   Nikolay Borisov   ipv4: Namespaceif...
677
  	max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries;
fa76ce732   Eric Dumazet   inet: get rid of ...
678
  	thresh = max_retries;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
679
680
  	/* Normally all the openreqs are young and become mature
  	 * (i.e. converted to established socket) for first timeout.
fd4f2cead   Eric Dumazet   tcp: RFC6298 supe...
681
  	 * If synack was not acknowledged for 1 second, it means
a019d6fe2   Arnaldo Carvalho de Melo   [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   Eric Dumazet   tcp: move qlen/yo...
696
  	qlen = reqsk_queue_len(queue);
acb4a6bfc   Eric Dumazet   tcp: ensure prior...
697
  	if ((qlen << 1) > max(8U, sk_listener->sk_max_ack_backlog)) {
aac065c50   Eric Dumazet   tcp: move qlen/yo...
698
  		int young = reqsk_queue_len_young(queue) << 1;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
699
700
  
  		while (thresh > 2) {
2b41fab70   Eric Dumazet   inet: cache liste...
701
  			if (qlen < young)
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
702
703
704
705
706
  				break;
  			thresh--;
  			young <<= 1;
  		}
  	}
2b41fab70   Eric Dumazet   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   Eric Dumazet   inet: get rid of ...
711
  		       &expire, &resend);
42cb80a23   Eric Dumazet   inet: remove sk_l...
712
  	req->rsk_ops->syn_ack_timeout(req);
fa76ce732   Eric Dumazet   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   Eric Dumazet   tcp: move qlen/yo...
720
  			atomic_dec(&queue->young);
fa76ce732   Eric Dumazet   inet: get rid of ...
721
  		timeo = min(TCP_TIMEOUT_INIT << req->num_timeout, TCP_RTO_MAX);
f3438bc78   Thomas Gleixner   timers, net/ipv4/...
722
  		mod_timer(&req->rsk_timer, jiffies + timeo);
fa76ce732   Eric Dumazet   inet: get rid of ...
723
724
  		return;
  	}
079096f10   Eric Dumazet   tcp/dccp: install...
725
  drop:
f03f2e154   Eric Dumazet   tcp/dccp: add ine...
726
  	inet_csk_reqsk_queue_drop_and_put(sk_listener, req);
fa76ce732   Eric Dumazet   inet: get rid of ...
727
  }
ec0a19662   David S. Miller   tcp: Revert 'proc...
728

079096f10   Eric Dumazet   tcp/dccp: install...
729
730
  static void reqsk_queue_hash_req(struct request_sock *req,
  				 unsigned long timeout)
fa76ce732   Eric Dumazet   inet: get rid of ...
731
  {
fa76ce732   Eric Dumazet   inet: get rid of ...
732
733
734
  	req->num_retrans = 0;
  	req->num_timeout = 0;
  	req->sk = NULL;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
735

f3438bc78   Thomas Gleixner   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   Eric Dumazet   inet: fix races i...
739

079096f10   Eric Dumazet   tcp/dccp: install...
740
  	inet_ehash_insert(req_to_sk(req), NULL);
fa76ce732   Eric Dumazet   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   Reshetova, Elena   net: convert sock...
745
  	refcount_set(&req->rsk_refcnt, 2 + 1);
079096f10   Eric Dumazet   tcp/dccp: install...
746
  }
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
747

079096f10   Eric Dumazet   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   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
753
  }
079096f10   Eric Dumazet   tcp/dccp: install...
754
  EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add);
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
755

e56c57d0d   Eric Dumazet   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   Arnaldo Carvalho de Melo   [ICSK]: Introduce...
767
  {
e56c57d0d   Eric Dumazet   net: rename sk_cl...
768
  	struct sock *newsk = sk_clone_lock(sk, priority);
9f1d2604c   Arnaldo Carvalho de Melo   [ICSK]: Introduce...
769

00db41243   Ian Morris   ipv4: coding styl...
770
  	if (newsk) {
9f1d2604c   Arnaldo Carvalho de Melo   [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   Eric Dumazet   inet: includes a ...
775
  		inet_sk(newsk)->inet_dport = inet_rsk(req)->ir_rmt_port;
b44084c2c   Eric Dumazet   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   Arnaldo Carvalho de Melo   [ICSK]: Introduce...
778

850178692   Eric Dumazet   tcp/dccp: fix ine...
779
780
  		/* listeners have SOCK_RCU_FREE, not the children */
  		sock_reset_flag(newsk, SOCK_RCU_FREE);
657831ffc   Eric Dumazet   dccp/tcp: do not ...
781
  		inet_sk(newsk)->mc_list = NULL;
84f39b08d   Lorenzo Colitti   net: support mark...
782
  		newsk->sk_mark = inet_rsk(req)->ir_mark;
33cf7c90f   Eric Dumazet   net: add real soc...
783
784
  		atomic64_set(&newsk->sk_cookie,
  			     atomic64_read(&inet_rsk(req)->ir_cookie));
84f39b08d   Lorenzo Colitti   net: support mark...
785

9f1d2604c   Arnaldo Carvalho de Melo   [ICSK]: Introduce...
786
  		newicsk->icsk_retransmits = 0;
6687e988d   Arnaldo Carvalho de Melo   [ICSK]: Move TCP ...
787
788
  		newicsk->icsk_backoff	  = 0;
  		newicsk->icsk_probes_out  = 0;
9f1d2604c   Arnaldo Carvalho de Melo   [ICSK]: Introduce...
789
790
791
  
  		/* Deinitialize accept_queue to trap illegal accesses. */
  		memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue));
4237c75c0   Venkat Yekkirala   [MLSXFRM]: Auto-l...
792
793
  
  		security_inet_csk_clone(newsk, req);
9f1d2604c   Arnaldo Carvalho de Melo   [ICSK]: Introduce...
794
795
796
  	}
  	return newsk;
  }
e56c57d0d   Eric Dumazet   net: rename sk_cl...
797
  EXPORT_SYMBOL_GPL(inet_csk_clone_lock);
a019d6fe2   Arnaldo Carvalho de Melo   [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   Ilpo Järvinen   net: convert BUG_...
807
808
  	WARN_ON(sk->sk_state != TCP_CLOSE);
  	WARN_ON(!sock_flag(sk, SOCK_DEAD));
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
809
810
  
  	/* It cannot be in hash table! */
547b792ca   Ilpo Järvinen   net: convert BUG_...
811
  	WARN_ON(!sk_unhashed(sk));
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
812

c720c7e83   Eric Dumazet   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   Arnaldo Carvalho de Melo   [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   Eric Dumazet   net: Use a percpu...
823
  	percpu_counter_dec(sk->sk_prot->orphan_count);
c2a2efbbf   Eric Dumazet   net: remove bh di...
824

a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
825
826
  	sock_put(sk);
  }
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
827
  EXPORT_SYMBOL(inet_csk_destroy_sock);
e337e24d6   Christoph Paasch   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   Christoph Paasch   Fix: sparse warni...
832
  	__releases(&sk->sk_lock.slock)
e337e24d6   Christoph Paasch   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   Eric Dumazet   tcp: avoid spurio...
844
  int inet_csk_listen_start(struct sock *sk, int backlog)
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
845
  {
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
846
  	struct inet_connection_sock *icsk = inet_csk(sk);
10cbc8f17   Eric Dumazet   tcp/dccp: remove ...
847
  	struct inet_sock *inet = inet_sk(sk);
086c653f5   Craig Gallek   sock: struct prot...
848
  	int err = -EADDRINUSE;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
849

ef547f2ac   Eric Dumazet   tcp: remove max_q...
850
  	reqsk_queue_alloc(&icsk->icsk_accept_queue);
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
851

f985c65c9   Eric Dumazet   tcp: avoid spurio...
852
  	sk->sk_max_ack_backlog = backlog;
a019d6fe2   Arnaldo Carvalho de Melo   [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   Eric Dumazet   tcp: ensure prope...
861
  	sk_state_store(sk, TCP_LISTEN);
c720c7e83   Eric Dumazet   inet: rename some...
862
863
  	if (!sk->sk_prot->get_port(sk, inet->inet_num)) {
  		inet->inet_sport = htons(inet->inet_num);
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
864
865
  
  		sk_dst_reset(sk);
086c653f5   Craig Gallek   sock: struct prot...
866
  		err = sk->sk_prot->hash(sk);
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
867

086c653f5   Craig Gallek   sock: struct prot...
868
869
  		if (likely(!err))
  			return 0;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
870
871
872
  	}
  
  	sk->sk_state = TCP_CLOSE;
086c653f5   Craig Gallek   sock: struct prot...
873
  	return err;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
874
  }
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
875
  EXPORT_SYMBOL_GPL(inet_csk_listen_start);
ebb516af6   Eric Dumazet   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   Eric Dumazet   tcp/dccp: fix rac...
898
  }
7716682cc   Eric Dumazet   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   Eric Dumazet   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   Eric Dumazet   tcp/dccp: fix ano...
908
  		child = NULL;
ebb516af6   Eric Dumazet   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   Eric Dumazet   tcp/dccp: fix ano...
920
  	return child;
ebb516af6   Eric Dumazet   tcp/dccp: fix rac...
921
922
  }
  EXPORT_SYMBOL(inet_csk_reqsk_queue_add);
5e0724d02   Eric Dumazet   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   Eric Dumazet   tcp/dccp: fix ano...
929
930
  		if (inet_csk_reqsk_queue_add(sk, req, child))
  			return child;
5e0724d02   Eric Dumazet   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   Arnaldo Carvalho de Melo   [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   Jerry Chu   tcp: TCP Fast Ope...
945
  	struct request_sock_queue *queue = &icsk->icsk_accept_queue;
fff1f3001   Eric Dumazet   tcp: add a spinlo...
946
  	struct request_sock *next, *req;
a019d6fe2   Arnaldo Carvalho de Melo   [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   Eric Dumazet   tcp: add a spinlo...
956
  	while ((req = reqsk_queue_remove(queue, sk)) != NULL) {
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
957
  		struct sock *child = req->sk;
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
958
959
  		local_bh_disable();
  		bh_lock_sock(child);
547b792ca   Ilpo Järvinen   net: convert BUG_...
960
  		WARN_ON(sock_owned_by_user(child));
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
961
  		sock_hold(child);
ebb516af6   Eric Dumazet   tcp/dccp: fix rac...
962
  		inet_child_forget(sk, req, child);
da8ab5786   Eric Dumazet   tcp/dccp: remove ...
963
  		reqsk_put(req);
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
964
965
966
  		bh_unlock_sock(child);
  		local_bh_enable();
  		sock_put(child);
92d6f176f   Eric Dumazet   tcp/dccp: add a r...
967
  		cond_resched();
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
968
  	}
0536fcc03   Eric Dumazet   tcp: prepare fast...
969
  	if (queue->fastopenq.rskq_rst_head) {
8336886f7   Jerry Chu   tcp: TCP Fast Ope...
970
  		/* Free all the reqs queued in rskq_rst_head. */
0536fcc03   Eric Dumazet   tcp: prepare fast...
971
  		spin_lock_bh(&queue->fastopenq.lock);
fff1f3001   Eric Dumazet   tcp: add a spinlo...
972
  		req = queue->fastopenq.rskq_rst_head;
0536fcc03   Eric Dumazet   tcp: prepare fast...
973
974
  		queue->fastopenq.rskq_rst_head = NULL;
  		spin_unlock_bh(&queue->fastopenq.lock);
fff1f3001   Eric Dumazet   tcp: add a spinlo...
975
976
  		while (req != NULL) {
  			next = req->dl_next;
13854e5a6   Eric Dumazet   inet: add proper ...
977
  			reqsk_put(req);
fff1f3001   Eric Dumazet   tcp: add a spinlo...
978
  			req = next;
8336886f7   Jerry Chu   tcp: TCP Fast Ope...
979
980
  		}
  	}
ebb516af6   Eric Dumazet   tcp/dccp: fix rac...
981
  	WARN_ON_ONCE(sk->sk_ack_backlog);
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
982
  }
a019d6fe2   Arnaldo Carvalho de Melo   [ICSK]: Move gene...
983
  EXPORT_SYMBOL_GPL(inet_csk_listen_stop);
af05dc939   Arnaldo Carvalho de Melo   [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   Eric Dumazet   inet: rename some...
991
992
  	sin->sin_addr.s_addr	= inet->inet_daddr;
  	sin->sin_port		= inet->inet_dport;
af05dc939   Arnaldo Carvalho de Melo   [ICSK]: Move v4_a...
993
  }
af05dc939   Arnaldo Carvalho de Melo   [ICSK]: Move v4_a...
994
  EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr);
c4d939094   Arnaldo Carvalho de Melo   [ICSK]: Introduce...
995

dec73ff02   Arnaldo Carvalho de Melo   [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   David S. Miller   [INET]: Fix typo ...
1000
  	const struct inet_connection_sock *icsk = inet_csk(sk);
dec73ff02   Arnaldo Carvalho de Melo   [ICSK] compat: In...
1001

00db41243   Ian Morris   ipv4: coding styl...
1002
  	if (icsk->icsk_af_ops->compat_getsockopt)
dec73ff02   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [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   David S. Miller   net: Make setsock...
1011
  			       char __user *optval, unsigned int optlen)
dec73ff02   Arnaldo Carvalho de Melo   [ICSK] compat: In...
1012
  {
dbeff12b4   David S. Miller   [INET]: Fix typo ...
1013
  	const struct inet_connection_sock *icsk = inet_csk(sk);
dec73ff02   Arnaldo Carvalho de Melo   [ICSK] compat: In...
1014

00db41243   Ian Morris   ipv4: coding styl...
1015
  	if (icsk->icsk_af_ops->compat_setsockopt)
dec73ff02   Arnaldo Carvalho de Melo   [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   Arnaldo Carvalho de Melo   [ICSK] compat: In...
1021
1022
  EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt);
  #endif
80d0a69fc   David S. Miller   ipv4: Add helper ...
1023
1024
1025
  
  static struct dst_entry *inet_csk_rebuild_route(struct sock *sk, struct flowi *fl)
  {
5abf7f7e0   Eric Dumazet   ipv4: fix rcu splat
1026
1027
  	const struct inet_sock *inet = inet_sk(sk);
  	const struct ip_options_rcu *inet_opt;
80d0a69fc   David S. Miller   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   David S. Miller   net: Pass optiona...
1060
  	dst->ops->update_pmtu(dst, sk, NULL, mtu);
80d0a69fc   David S. Miller   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);