Blame view

net/smc/af_smc.c 52.9 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
ac7138746   Ursula Braun   smc: establish ne...
2
3
4
5
6
7
8
9
  /*
   *  Shared Memory Communications over RDMA (SMC-R) and RoCE
   *
   *  AF_SMC protocol family socket handler keeping the AF_INET sock address type
   *  applies to SOCK_STREAM sockets only
   *  offers an alternative communication option for TCP-protocol sockets
   *  applicable with RoCE-cards only
   *
a046d57da   Ursula Braun   smc: CLC handshak...
10
   *  Initial restrictions:
a046d57da   Ursula Braun   smc: CLC handshak...
11
   *    - support for alternate links postponed
a046d57da   Ursula Braun   smc: CLC handshak...
12
   *
aaa4d33f6   Karsten Graul   net/smc: enable i...
13
   *  Copyright IBM Corp. 2016, 2018
ac7138746   Ursula Braun   smc: establish ne...
14
15
16
17
18
19
20
21
22
23
   *
   *  Author(s):  Ursula Braun <ubraun@linux.vnet.ibm.com>
   *              based on prototype from Frank Blaschka
   */
  
  #define KMSG_COMPONENT "smc"
  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  
  #include <linux/module.h>
  #include <linux/socket.h>
a046d57da   Ursula Braun   smc: CLC handshak...
24
  #include <linux/workqueue.h>
5f08318f6   Ursula Braun   smc: connection d...
25
  #include <linux/in.h>
c3edc4010   Ingo Molnar   sched/headers: Mo...
26
  #include <linux/sched/signal.h>
413498440   Hans Wippel   net/smc: add SMC-...
27
  #include <linux/if_vlan.h>
4ead9c96d   Ursula Braun   net/smc: use rcu_...
28
  #include <linux/rcupdate_wait.h>
c3edc4010   Ingo Molnar   sched/headers: Mo...
29

ac7138746   Ursula Braun   smc: establish ne...
30
  #include <net/sock.h>
a046d57da   Ursula Braun   smc: CLC handshak...
31
  #include <net/tcp.h>
f16a7dd5c   Ursula Braun   smc: netlink inte...
32
  #include <net/smc.h>
9b67e26f9   Ursula Braun   net/smc: handle i...
33
  #include <asm/ioctls.h>
ac7138746   Ursula Braun   smc: establish ne...
34

64e28b52c   Hans Wippel   net/smc: add pnet...
35
36
37
  #include <net/net_namespace.h>
  #include <net/netns/generic.h>
  #include "smc_netns.h"
ac7138746   Ursula Braun   smc: establish ne...
38
  #include "smc.h"
a046d57da   Ursula Braun   smc: CLC handshak...
39
  #include "smc_clc.h"
9bf9abead   Ursula Braun   smc: link layer c...
40
  #include "smc_llc.h"
5f08318f6   Ursula Braun   smc: connection d...
41
  #include "smc_cdc.h"
0cfdd8f92   Ursula Braun   smc: connection a...
42
  #include "smc_core.h"
a4cf0443c   Ursula Braun   smc: introduce SM...
43
  #include "smc_ib.h"
413498440   Hans Wippel   net/smc: add SMC-...
44
  #include "smc_ism.h"
6812baabf   Thomas Richter   smc: establish pn...
45
  #include "smc_pnet.h"
e6727f390   Ursula Braun   smc: send data (t...
46
  #include "smc_tx.h"
952310ccf   Ursula Braun   smc: receive data...
47
  #include "smc_rx.h"
b38d73247   Ursula Braun   smc: socket closi...
48
  #include "smc_close.h"
ac7138746   Ursula Braun   smc: establish ne...
49

72a36a8ae   Hans Wippel   net/smc: use clie...
50
51
52
53
54
  static DEFINE_MUTEX(smc_server_lgr_pending);	/* serialize link group
  						 * creation on server
  						 */
  static DEFINE_MUTEX(smc_client_lgr_pending);	/* serialize link group
  						 * creation on client
0cfdd8f92   Ursula Braun   smc: connection a...
55
  						 */
a046d57da   Ursula Braun   smc: CLC handshak...
56
  static void smc_tcp_listen_work(struct work_struct *);
24ac3a08e   Ursula Braun   net/smc: rebuild ...
57
  static void smc_connect_work(struct work_struct *);
a046d57da   Ursula Braun   smc: CLC handshak...
58

ac7138746   Ursula Braun   smc: establish ne...
59
60
61
62
63
64
  static void smc_set_keepalive(struct sock *sk, int val)
  {
  	struct smc_sock *smc = smc_sk(sk);
  
  	smc->clcsock->sk->sk_prot->keepalive(smc->clcsock->sk, val);
  }
f16a7dd5c   Ursula Braun   smc: netlink inte...
65
66
67
  static struct smc_hashinfo smc_v4_hashinfo = {
  	.lock = __RW_LOCK_UNLOCKED(smc_v4_hashinfo.lock),
  };
aaa4d33f6   Karsten Graul   net/smc: enable i...
68
69
70
  static struct smc_hashinfo smc_v6_hashinfo = {
  	.lock = __RW_LOCK_UNLOCKED(smc_v6_hashinfo.lock),
  };
f16a7dd5c   Ursula Braun   smc: netlink inte...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  int smc_hash_sk(struct sock *sk)
  {
  	struct smc_hashinfo *h = sk->sk_prot->h.smc_hash;
  	struct hlist_head *head;
  
  	head = &h->ht;
  
  	write_lock_bh(&h->lock);
  	sk_add_node(sk, head);
  	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
  	write_unlock_bh(&h->lock);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(smc_hash_sk);
  
  void smc_unhash_sk(struct sock *sk)
  {
  	struct smc_hashinfo *h = sk->sk_prot->h.smc_hash;
  
  	write_lock_bh(&h->lock);
  	if (sk_del_node_init(sk))
  		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
  	write_unlock_bh(&h->lock);
  }
  EXPORT_SYMBOL_GPL(smc_unhash_sk);
  
  struct proto smc_proto = {
ac7138746   Ursula Braun   smc: establish ne...
99
100
101
  	.name		= "SMC",
  	.owner		= THIS_MODULE,
  	.keepalive	= smc_set_keepalive,
f16a7dd5c   Ursula Braun   smc: netlink inte...
102
103
  	.hash		= smc_hash_sk,
  	.unhash		= smc_unhash_sk,
ac7138746   Ursula Braun   smc: establish ne...
104
  	.obj_size	= sizeof(struct smc_sock),
f16a7dd5c   Ursula Braun   smc: netlink inte...
105
  	.h.smc_hash	= &smc_v4_hashinfo,
5f0d5a3ae   Paul E. McKenney   mm: Rename SLAB_D...
106
  	.slab_flags	= SLAB_TYPESAFE_BY_RCU,
ac7138746   Ursula Braun   smc: establish ne...
107
  };
f16a7dd5c   Ursula Braun   smc: netlink inte...
108
  EXPORT_SYMBOL_GPL(smc_proto);
ac7138746   Ursula Braun   smc: establish ne...
109

aaa4d33f6   Karsten Graul   net/smc: enable i...
110
111
112
113
114
115
116
117
118
119
120
  struct proto smc_proto6 = {
  	.name		= "SMC6",
  	.owner		= THIS_MODULE,
  	.keepalive	= smc_set_keepalive,
  	.hash		= smc_hash_sk,
  	.unhash		= smc_unhash_sk,
  	.obj_size	= sizeof(struct smc_sock),
  	.h.smc_hash	= &smc_v6_hashinfo,
  	.slab_flags	= SLAB_TYPESAFE_BY_RCU,
  };
  EXPORT_SYMBOL_GPL(smc_proto6);
f536dffc0   Ursula Braun   net/smc: fix clos...
121
122
123
124
125
  static void smc_restore_fallback_changes(struct smc_sock *smc)
  {
  	smc->clcsock->file->private_data = smc->sk.sk_socket;
  	smc->clcsock->file = NULL;
  }
39f41f367   Ursula Braun   net/smc: common r...
126
  static int __smc_release(struct smc_sock *smc)
ac7138746   Ursula Braun   smc: establish ne...
127
  {
39f41f367   Ursula Braun   net/smc: common r...
128
  	struct sock *sk = &smc->sk;
b38d73247   Ursula Braun   smc: socket closi...
129
  	int rc = 0;
ac7138746   Ursula Braun   smc: establish ne...
130

51f1de79a   Ursula Braun   net/smc: replace ...
131
  	if (!smc->use_fallback) {
b38d73247   Ursula Braun   smc: socket closi...
132
133
134
  		rc = smc_close_active(smc);
  		sock_set_flag(sk, SOCK_DEAD);
  		sk->sk_shutdown |= SHUTDOWN_MASK;
b03faa1fa   Ursula Braun   net/smc: postpone...
135
136
137
138
  	} else {
  		if (sk->sk_state != SMC_LISTEN && sk->sk_state != SMC_INIT)
  			sock_put(sk); /* passive closing */
  		if (sk->sk_state == SMC_LISTEN) {
78abe3d0d   Myungho Jung   net/smc: fix TCP ...
139
140
141
  			/* wake up clcsock accept */
  			rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR);
  		}
51f1de79a   Ursula Braun   net/smc: replace ...
142
143
  		sk->sk_state = SMC_CLOSED;
  		sk->sk_state_change(sk);
f536dffc0   Ursula Braun   net/smc: fix clos...
144
  		smc_restore_fallback_changes(smc);
51f1de79a   Ursula Braun   net/smc: replace ...
145
  	}
ac7138746   Ursula Braun   smc: establish ne...
146

b03faa1fa   Ursula Braun   net/smc: postpone...
147
148
149
150
  	sk->sk_prot->unhash(sk);
  
  	if (sk->sk_state == SMC_CLOSED) {
  		if (smc->clcsock) {
fd57770dd   Karsten Graul   net/smc: wait for...
151
152
153
  			release_sock(sk);
  			smc_clcsock_release(smc);
  			lock_sock(sk);
b03faa1fa   Ursula Braun   net/smc: postpone...
154
155
156
157
  		}
  		if (!smc->use_fallback)
  			smc_conn_free(&smc->conn);
  	}
39f41f367   Ursula Braun   net/smc: common r...
158
159
160
161
162
163
164
165
166
167
168
  	return rc;
  }
  
  static int smc_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc = 0;
  
  	if (!sk)
  		goto out;
81cf4f470   Ursula Braun   net/smc: remove c...
169
  	sock_hold(sk); /* sock_put below */
39f41f367   Ursula Braun   net/smc: common r...
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  	smc = smc_sk(sk);
  
  	/* cleanup for a dangling non-blocking connect */
  	if (smc->connect_nonblock && sk->sk_state == SMC_INIT)
  		tcp_abort(smc->clcsock->sk, ECONNABORTED);
  	flush_work(&smc->connect_work);
  
  	if (sk->sk_state == SMC_LISTEN)
  		/* smc_close_non_accepted() is called and acquires
  		 * sock lock for child sockets again
  		 */
  		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
  	else
  		lock_sock(sk);
  
  	rc = __smc_release(smc);
ac7138746   Ursula Braun   smc: establish ne...
186
187
188
189
  	/* detach socket */
  	sock_orphan(sk);
  	sock->sk = NULL;
  	release_sock(sk);
81cf4f470   Ursula Braun   net/smc: remove c...
190
  	sock_put(sk); /* sock_hold above */
51f1de79a   Ursula Braun   net/smc: replace ...
191
  	sock_put(sk); /* final sock_put */
ac7138746   Ursula Braun   smc: establish ne...
192
  out:
b38d73247   Ursula Braun   smc: socket closi...
193
  	return rc;
ac7138746   Ursula Braun   smc: establish ne...
194
195
196
197
198
199
200
201
202
203
204
  }
  
  static void smc_destruct(struct sock *sk)
  {
  	if (sk->sk_state != SMC_CLOSED)
  		return;
  	if (!sock_flag(sk, SOCK_DEAD))
  		return;
  
  	sk_refcnt_debug_dec(sk);
  }
aaa4d33f6   Karsten Graul   net/smc: enable i...
205
206
  static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
  				   int protocol)
ac7138746   Ursula Braun   smc: establish ne...
207
208
  {
  	struct smc_sock *smc;
aaa4d33f6   Karsten Graul   net/smc: enable i...
209
  	struct proto *prot;
ac7138746   Ursula Braun   smc: establish ne...
210
  	struct sock *sk;
aaa4d33f6   Karsten Graul   net/smc: enable i...
211
212
  	prot = (protocol == SMCPROTO_SMC6) ? &smc_proto6 : &smc_proto;
  	sk = sk_alloc(net, PF_SMC, GFP_KERNEL, prot, 0);
ac7138746   Ursula Braun   smc: establish ne...
213
214
215
216
217
218
  	if (!sk)
  		return NULL;
  
  	sock_init_data(sock, sk); /* sets sk_refcnt to 1 */
  	sk->sk_state = SMC_INIT;
  	sk->sk_destruct = smc_destruct;
aaa4d33f6   Karsten Graul   net/smc: enable i...
219
  	sk->sk_protocol = protocol;
ac7138746   Ursula Braun   smc: establish ne...
220
  	smc = smc_sk(sk);
a046d57da   Ursula Braun   smc: CLC handshak...
221
  	INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work);
24ac3a08e   Ursula Braun   net/smc: rebuild ...
222
  	INIT_WORK(&smc->connect_work, smc_connect_work);
be7f3e599   Eric Dumazet   net/smc: init con...
223
  	INIT_DELAYED_WORK(&smc->conn.tx_work, smc_tx_work);
a046d57da   Ursula Braun   smc: CLC handshak...
224
225
  	INIT_LIST_HEAD(&smc->accept_q);
  	spin_lock_init(&smc->accept_q_lock);
be7f3e599   Eric Dumazet   net/smc: init con...
226
  	spin_lock_init(&smc->conn.send_lock);
f16a7dd5c   Ursula Braun   smc: netlink inte...
227
  	sk->sk_prot->hash(sk);
a046d57da   Ursula Braun   smc: CLC handshak...
228
  	sk_refcnt_debug_inc(sk);
78abe3d0d   Myungho Jung   net/smc: fix TCP ...
229
  	mutex_init(&smc->clcsock_release_lock);
ac7138746   Ursula Braun   smc: establish ne...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  
  	return sk;
  }
  
  static int smc_bind(struct socket *sock, struct sockaddr *uaddr,
  		    int addr_len)
  {
  	struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc;
  
  	smc = smc_sk(sk);
  
  	/* replicate tests from inet_bind(), to be safe wrt. future changes */
  	rc = -EINVAL;
  	if (addr_len < sizeof(struct sockaddr_in))
  		goto out;
  
  	rc = -EAFNOSUPPORT;
aaa4d33f6   Karsten Graul   net/smc: enable i...
250
251
252
253
  	if (addr->sin_family != AF_INET &&
  	    addr->sin_family != AF_INET6 &&
  	    addr->sin_family != AF_UNSPEC)
  		goto out;
ac7138746   Ursula Braun   smc: establish ne...
254
  	/* accept AF_UNSPEC (mapped to AF_INET) only if s_addr is INADDR_ANY */
aaa4d33f6   Karsten Graul   net/smc: enable i...
255
256
  	if (addr->sin_family == AF_UNSPEC &&
  	    addr->sin_addr.s_addr != htonl(INADDR_ANY))
ac7138746   Ursula Braun   smc: establish ne...
257
258
259
260
261
262
  		goto out;
  
  	lock_sock(sk);
  
  	/* Check if socket is already active */
  	rc = -EINVAL;
cd2063604   Ursula Braun   net/smc: avoid fa...
263
  	if (sk->sk_state != SMC_INIT || smc->connect_nonblock)
ac7138746   Ursula Braun   smc: establish ne...
264
265
266
267
268
269
270
271
272
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
301
302
303
304
305
306
  		goto out_rel;
  
  	smc->clcsock->sk->sk_reuse = sk->sk_reuse;
  	rc = kernel_bind(smc->clcsock, uaddr, addr_len);
  
  out_rel:
  	release_sock(sk);
  out:
  	return rc;
  }
  
  static void smc_copy_sock_settings(struct sock *nsk, struct sock *osk,
  				   unsigned long mask)
  {
  	/* options we don't get control via setsockopt for */
  	nsk->sk_type = osk->sk_type;
  	nsk->sk_sndbuf = osk->sk_sndbuf;
  	nsk->sk_rcvbuf = osk->sk_rcvbuf;
  	nsk->sk_sndtimeo = osk->sk_sndtimeo;
  	nsk->sk_rcvtimeo = osk->sk_rcvtimeo;
  	nsk->sk_mark = osk->sk_mark;
  	nsk->sk_priority = osk->sk_priority;
  	nsk->sk_rcvlowat = osk->sk_rcvlowat;
  	nsk->sk_bound_dev_if = osk->sk_bound_dev_if;
  	nsk->sk_err = osk->sk_err;
  
  	nsk->sk_flags &= ~mask;
  	nsk->sk_flags |= osk->sk_flags & mask;
  }
  
  #define SK_FLAGS_SMC_TO_CLC ((1UL << SOCK_URGINLINE) | \
  			     (1UL << SOCK_KEEPOPEN) | \
  			     (1UL << SOCK_LINGER) | \
  			     (1UL << SOCK_BROADCAST) | \
  			     (1UL << SOCK_TIMESTAMP) | \
  			     (1UL << SOCK_DBG) | \
  			     (1UL << SOCK_RCVTSTAMP) | \
  			     (1UL << SOCK_RCVTSTAMPNS) | \
  			     (1UL << SOCK_LOCALROUTE) | \
  			     (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE) | \
  			     (1UL << SOCK_RXQ_OVFL) | \
  			     (1UL << SOCK_WIFI_STATUS) | \
  			     (1UL << SOCK_NOFCS) | \
9718475e6   Deepa Dinamani   socket: Add SO_TI...
307
308
  			     (1UL << SOCK_FILTER_LOCKED) | \
  			     (1UL << SOCK_TSTAMP_NEW))
ac7138746   Ursula Braun   smc: establish ne...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  /* copy only relevant settings and flags of SOL_SOCKET level from smc to
   * clc socket (since smc is not called for these options from net/core)
   */
  static void smc_copy_sock_settings_to_clc(struct smc_sock *smc)
  {
  	smc_copy_sock_settings(smc->clcsock->sk, &smc->sk, SK_FLAGS_SMC_TO_CLC);
  }
  
  #define SK_FLAGS_CLC_TO_SMC ((1UL << SOCK_URGINLINE) | \
  			     (1UL << SOCK_KEEPOPEN) | \
  			     (1UL << SOCK_LINGER) | \
  			     (1UL << SOCK_DBG))
  /* copy only settings and flags relevant for smc from clc to smc socket */
  static void smc_copy_sock_settings_to_smc(struct smc_sock *smc)
  {
  	smc_copy_sock_settings(&smc->sk, smc->clcsock->sk, SK_FLAGS_CLC_TO_SMC);
  }
c7674c001   Karsten Graul   net/smc: unregist...
326
  /* register a new rmb, send confirm_rkey msg to register with peer */
44aa81ce9   Karsten Graul   net/smc: register...
327
328
  static int smc_reg_rmb(struct smc_link *link, struct smc_buf_desc *rmb_desc,
  		       bool conf_rkey)
e63a5f8c1   Karsten Graul   net/smc: call con...
329
  {
c7674c001   Karsten Graul   net/smc: unregist...
330
331
332
333
334
335
336
  	if (!rmb_desc->wr_reg) {
  		/* register memory region for new rmb */
  		if (smc_wr_reg_send(link, rmb_desc->mr_rx[SMC_SINGLE_LINK])) {
  			rmb_desc->regerr = 1;
  			return -EFAULT;
  		}
  		rmb_desc->wr_reg = 1;
a6920d1d1   Karsten Graul   net/smc: handle u...
337
  	}
44aa81ce9   Karsten Graul   net/smc: register...
338
339
340
341
342
343
344
  	if (!conf_rkey)
  		return 0;
  	/* exchange confirm_rkey msg with peer */
  	if (smc_llc_do_confirm_rkey(link, rmb_desc)) {
  		rmb_desc->regerr = 1;
  		return -EFAULT;
  	}
e63a5f8c1   Karsten Graul   net/smc: call con...
345
346
  	return 0;
  }
0f6271264   Stefan Raspl   net/smc: cleanup ...
347
  static int smc_clnt_conf_first_link(struct smc_sock *smc)
9bf9abead   Ursula Braun   smc: link layer c...
348
  {
877ae5be4   Karsten Graul   net/smc: periodic...
349
  	struct net *net = sock_net(smc->clcsock->sk);
9bf9abead   Ursula Braun   smc: link layer c...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  	struct smc_link_group *lgr = smc->conn.lgr;
  	struct smc_link *link;
  	int rest;
  	int rc;
  
  	link = &lgr->lnk[SMC_SINGLE_LINK];
  	/* receive CONFIRM LINK request from server over RoCE fabric */
  	rest = wait_for_completion_interruptible_timeout(
  		&link->llc_confirm,
  		SMC_LLC_WAIT_FIRST_TIME);
  	if (rest <= 0) {
  		struct smc_clc_msg_decline dclc;
  
  		rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
2b59f58e3   Ursula Braun   net/smc: short wa...
364
  				      SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT);
9ed28556a   Ursula Braun   net/smc: allow fa...
365
  		return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_CL : rc;
9bf9abead   Ursula Braun   smc: link layer c...
366
  	}
75d320d61   Karsten Graul   net/smc: do not a...
367
368
  	if (link->llc_confirm_rc)
  		return SMC_CLC_DECL_RMBE_EC;
9bf9abead   Ursula Braun   smc: link layer c...
369
370
  	rc = smc_ib_modify_qp_rts(link);
  	if (rc)
603cc1498   Karsten Graul   net/smc: provide ...
371
  		return SMC_CLC_DECL_ERR_RDYLNK;
9bf9abead   Ursula Braun   smc: link layer c...
372
373
  
  	smc_wr_remember_qp_attr(link);
652a1e41e   Ursula Braun   net/smc: register...
374

44aa81ce9   Karsten Graul   net/smc: register...
375
  	if (smc_reg_rmb(link, smc->conn.rmb_desc, false))
603cc1498   Karsten Graul   net/smc: provide ...
376
  		return SMC_CLC_DECL_ERR_REGRMB;
652a1e41e   Ursula Braun   net/smc: register...
377

9bf9abead   Ursula Braun   smc: link layer c...
378
  	/* send CONFIRM LINK response over RoCE fabric */
947541f36   Ursula Braun   net/smc: fewer pa...
379
  	rc = smc_llc_send_confirm_link(link, SMC_LLC_RESP);
9bf9abead   Ursula Braun   smc: link layer c...
380
  	if (rc < 0)
603cc1498   Karsten Graul   net/smc: provide ...
381
  		return SMC_CLC_DECL_TIMEOUT_CL;
9bf9abead   Ursula Braun   smc: link layer c...
382

52bedf37b   Karsten Graul   net/smc: process ...
383
384
385
386
387
388
389
  	/* receive ADD LINK request from server over RoCE fabric */
  	rest = wait_for_completion_interruptible_timeout(&link->llc_add,
  							 SMC_LLC_WAIT_TIME);
  	if (rest <= 0) {
  		struct smc_clc_msg_decline dclc;
  
  		rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
2b59f58e3   Ursula Braun   net/smc: short wa...
390
  				      SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT);
9ed28556a   Ursula Braun   net/smc: allow fa...
391
  		return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_AL : rc;
52bedf37b   Karsten Graul   net/smc: process ...
392
393
394
395
396
  	}
  
  	/* send add link reject message, only one link supported for now */
  	rc = smc_llc_send_add_link(link,
  				   link->smcibdev->mac[link->ibport - 1],
7005ada68   Ursula Braun   net/smc: use corr...
397
  				   link->gid, SMC_LLC_RESP);
52bedf37b   Karsten Graul   net/smc: process ...
398
  	if (rc < 0)
603cc1498   Karsten Graul   net/smc: provide ...
399
  		return SMC_CLC_DECL_TIMEOUT_AL;
52bedf37b   Karsten Graul   net/smc: process ...
400

877ae5be4   Karsten Graul   net/smc: periodic...
401
  	smc_llc_link_active(link, net->ipv4.sysctl_tcp_keepalive_time);
52bedf37b   Karsten Graul   net/smc: process ...
402

75d320d61   Karsten Graul   net/smc: do not a...
403
  	return 0;
9bf9abead   Ursula Braun   smc: link layer c...
404
  }
413498440   Hans Wippel   net/smc: add SMC-...
405
406
  static void smcr_conn_save_peer_info(struct smc_sock *smc,
  				     struct smc_clc_msg_accept_confirm *clc)
0cfdd8f92   Ursula Braun   smc: connection a...
407
  {
95d8d2630   Hans Wippel   net/smc: calculat...
408
  	int bufsize = smc_uncompress_bufsize(clc->rmbe_size);
92a138e33   Hans Wippel   net/smc: rename c...
409
  	smc->conn.peer_rmbe_idx = clc->rmbe_idx;
5f08318f6   Ursula Braun   smc: connection d...
410
  	smc->conn.local_tx_ctrl.token = ntohl(clc->rmbe_alert_token);
95d8d2630   Hans Wippel   net/smc: calculat...
411
  	smc->conn.peer_rmbe_size = bufsize;
cd6851f30   Ursula Braun   smc: remote memor...
412
  	atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size);
95d8d2630   Hans Wippel   net/smc: calculat...
413
  	smc->conn.tx_off = bufsize * (smc->conn.peer_rmbe_idx - 1);
0cfdd8f92   Ursula Braun   smc: connection a...
414
  }
413498440   Hans Wippel   net/smc: add SMC-...
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  static void smcd_conn_save_peer_info(struct smc_sock *smc,
  				     struct smc_clc_msg_accept_confirm *clc)
  {
  	int bufsize = smc_uncompress_bufsize(clc->dmbe_size);
  
  	smc->conn.peer_rmbe_idx = clc->dmbe_idx;
  	smc->conn.peer_token = clc->token;
  	/* msg header takes up space in the buffer */
  	smc->conn.peer_rmbe_size = bufsize - sizeof(struct smcd_cdc_msg);
  	atomic_set(&smc->conn.peer_rmbe_space, smc->conn.peer_rmbe_size);
  	smc->conn.tx_off = bufsize * smc->conn.peer_rmbe_idx;
  }
  
  static void smc_conn_save_peer_info(struct smc_sock *smc,
  				    struct smc_clc_msg_accept_confirm *clc)
  {
  	if (smc->conn.lgr->is_smcd)
  		smcd_conn_save_peer_info(smc, clc);
  	else
  		smcr_conn_save_peer_info(smc, clc);
  }
0cfdd8f92   Ursula Braun   smc: connection a...
436
437
438
439
440
441
442
443
444
  static void smc_link_save_peer_info(struct smc_link *link,
  				    struct smc_clc_msg_accept_confirm *clc)
  {
  	link->peer_qpn = ntoh24(clc->qpn);
  	memcpy(link->peer_gid, clc->lcl.gid, SMC_GID_SIZE);
  	memcpy(link->peer_mac, clc->lcl.mac, sizeof(link->peer_mac));
  	link->peer_psn = ntoh24(clc->psn);
  	link->peer_mtu = clc->qp_mtu;
  }
07603b230   Ursula Braun   net/smc: propagat...
445
446
447
448
449
450
  static void smc_switch_to_fallback(struct smc_sock *smc)
  {
  	smc->use_fallback = true;
  	if (smc->sk.sk_socket && smc->sk.sk_socket->file) {
  		smc->clcsock->file = smc->sk.sk_socket->file;
  		smc->clcsock->file->private_data = smc->clcsock;
67f562e3e   Ursula Braun   net/smc: transfer...
451
452
  		smc->clcsock->wq.fasync_list =
  			smc->sk.sk_socket->wq.fasync_list;
07603b230   Ursula Braun   net/smc: propagat...
453
454
  	}
  }
3b2dec260   Hans Wippel   net/smc: restruct...
455
  /* fall back during connect */
603cc1498   Karsten Graul   net/smc: provide ...
456
  static int smc_connect_fallback(struct smc_sock *smc, int reason_code)
a046d57da   Ursula Braun   smc: CLC handshak...
457
  {
07603b230   Ursula Braun   net/smc: propagat...
458
  	smc_switch_to_fallback(smc);
603cc1498   Karsten Graul   net/smc: provide ...
459
  	smc->fallback_rsn = reason_code;
3b2dec260   Hans Wippel   net/smc: restruct...
460
  	smc_copy_sock_settings_to_clc(smc);
50717a37d   Ursula Braun   net/smc: nonblock...
461
  	smc->connect_nonblock = 0;
3b2dec260   Hans Wippel   net/smc: restruct...
462
463
464
465
  	if (smc->sk.sk_state == SMC_INIT)
  		smc->sk.sk_state = SMC_ACTIVE;
  	return 0;
  }
51f1de79a   Ursula Braun   net/smc: replace ...
466

3b2dec260   Hans Wippel   net/smc: restruct...
467
468
469
470
  /* decline and fall back during connect */
  static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code)
  {
  	int rc;
ee9dfbef0   Ursula Braun   net/smc: handle s...
471

e1bbdd570   Ursula Braun   net/smc: reduce s...
472
473
474
  	if (reason_code < 0) { /* error, fallback is not possible */
  		if (smc->sk.sk_state == SMC_INIT)
  			sock_put(&smc->sk); /* passive closing */
3b2dec260   Hans Wippel   net/smc: restruct...
475
  		return reason_code;
e1bbdd570   Ursula Braun   net/smc: reduce s...
476
  	}
603cc1498   Karsten Graul   net/smc: provide ...
477
  	if (reason_code != SMC_CLC_DECL_PEERDECL) {
3b2dec260   Hans Wippel   net/smc: restruct...
478
  		rc = smc_clc_send_decline(smc, reason_code);
e1bbdd570   Ursula Braun   net/smc: reduce s...
479
480
481
  		if (rc < 0) {
  			if (smc->sk.sk_state == SMC_INIT)
  				sock_put(&smc->sk); /* passive closing */
3b2dec260   Hans Wippel   net/smc: restruct...
482
  			return rc;
e1bbdd570   Ursula Braun   net/smc: reduce s...
483
  		}
c5c1cc9c5   Ursula Braun   smc: add SMC rend...
484
  	}
603cc1498   Karsten Graul   net/smc: provide ...
485
  	return smc_connect_fallback(smc, reason_code);
3b2dec260   Hans Wippel   net/smc: restruct...
486
  }
c5c1cc9c5   Ursula Braun   smc: add SMC rend...
487

3b2dec260   Hans Wippel   net/smc: restruct...
488
489
490
491
  /* abort connecting */
  static int smc_connect_abort(struct smc_sock *smc, int reason_code,
  			     int local_contact)
  {
51e3dfa89   Ursula Braun   net/smc: fix clea...
492
  	bool is_smcd = smc->conn.lgr->is_smcd;
3b2dec260   Hans Wippel   net/smc: restruct...
493
  	if (local_contact == SMC_FIRST_CONTACT)
51e3dfa89   Ursula Braun   net/smc: fix clea...
494
495
496
497
  		smc_lgr_cleanup_early(&smc->conn);
  	else
  		smc_conn_free(&smc->conn);
  	if (is_smcd)
72a36a8ae   Hans Wippel   net/smc: use clie...
498
499
500
501
  		/* there is only one lgr role for SMC-D; use server lock */
  		mutex_unlock(&smc_server_lgr_pending);
  	else
  		mutex_unlock(&smc_client_lgr_pending);
50717a37d   Ursula Braun   net/smc: nonblock...
502
  	smc->connect_nonblock = 0;
3b2dec260   Hans Wippel   net/smc: restruct...
503
504
505
506
507
  	return reason_code;
  }
  
  /* check if there is a rdma device available for this connection. */
  /* called for connect and listen */
228bae05b   Karsten Graul   net/smc: code cle...
508
  static int smc_find_rdma_device(struct smc_sock *smc, struct smc_init_info *ini)
3b2dec260   Hans Wippel   net/smc: restruct...
509
  {
a046d57da   Ursula Braun   smc: CLC handshak...
510
511
512
513
  	/* PNET table look up: search active ib_device and port
  	 * within same PNETID that also contains the ethernet device
  	 * used for the internal TCP socket
  	 */
bc36d2fc9   Karsten Graul   net/smc: consolid...
514
  	smc_pnet_find_roce_resource(smc->clcsock->sk, ini);
9aa68d298   Karsten Graul   net/smc: improve ...
515
516
  	if (!ini->ib_dev)
  		return SMC_CLC_DECL_NOSMCRDEV;
bc36d2fc9   Karsten Graul   net/smc: consolid...
517
  	return 0;
3b2dec260   Hans Wippel   net/smc: restruct...
518
  }
413498440   Hans Wippel   net/smc: add SMC-...
519
520
  /* check if there is an ISM device available for this connection. */
  /* called for connect and listen */
228bae05b   Karsten Graul   net/smc: code cle...
521
  static int smc_find_ism_device(struct smc_sock *smc, struct smc_init_info *ini)
413498440   Hans Wippel   net/smc: add SMC-...
522
523
  {
  	/* Find ISM device with same PNETID as connecting interface  */
bc36d2fc9   Karsten Graul   net/smc: consolid...
524
525
  	smc_pnet_find_ism_resource(smc->clcsock->sk, ini);
  	if (!ini->ism_dev)
9aa68d298   Karsten Graul   net/smc: improve ...
526
  		return SMC_CLC_DECL_NOSMCDDEV;
413498440   Hans Wippel   net/smc: add SMC-...
527
528
529
530
531
  	return 0;
  }
  
  /* Check for VLAN ID and register it on ISM device just for CLC handshake */
  static int smc_connect_ism_vlan_setup(struct smc_sock *smc,
bc36d2fc9   Karsten Graul   net/smc: consolid...
532
  				      struct smc_init_info *ini)
413498440   Hans Wippel   net/smc: add SMC-...
533
  {
bc36d2fc9   Karsten Graul   net/smc: consolid...
534
  	if (ini->vlan_id && smc_ism_get_vlan(ini->ism_dev, ini->vlan_id))
7a62725a5   Karsten Graul   net/smc: improve ...
535
  		return SMC_CLC_DECL_ISMVLANERR;
413498440   Hans Wippel   net/smc: add SMC-...
536
537
538
539
540
541
542
  	return 0;
  }
  
  /* cleanup temporary VLAN ID registration used for CLC handshake. If ISM is
   * used, the VLAN ID will be registered again during the connection setup.
   */
  static int smc_connect_ism_vlan_cleanup(struct smc_sock *smc, bool is_smcd,
bc36d2fc9   Karsten Graul   net/smc: consolid...
543
  					struct smc_init_info *ini)
413498440   Hans Wippel   net/smc: add SMC-...
544
545
546
  {
  	if (!is_smcd)
  		return 0;
bc36d2fc9   Karsten Graul   net/smc: consolid...
547
  	if (ini->vlan_id && smc_ism_put_vlan(ini->ism_dev, ini->vlan_id))
413498440   Hans Wippel   net/smc: add SMC-...
548
549
550
  		return SMC_CLC_DECL_CNFERR;
  	return 0;
  }
3b2dec260   Hans Wippel   net/smc: restruct...
551
  /* CLC handshake during connect */
c758dfddc   Hans Wippel   net/smc: add SMC-...
552
  static int smc_connect_clc(struct smc_sock *smc, int smc_type,
3b2dec260   Hans Wippel   net/smc: restruct...
553
  			   struct smc_clc_msg_accept_confirm *aclc,
bc36d2fc9   Karsten Graul   net/smc: consolid...
554
  			   struct smc_init_info *ini)
3b2dec260   Hans Wippel   net/smc: restruct...
555
556
  {
  	int rc = 0;
a046d57da   Ursula Braun   smc: CLC handshak...
557
558
  
  	/* do inband token exchange */
bc36d2fc9   Karsten Graul   net/smc: consolid...
559
  	rc = smc_clc_send_proposal(smc, smc_type, ini);
3b2dec260   Hans Wippel   net/smc: restruct...
560
561
  	if (rc)
  		return rc;
a046d57da   Ursula Braun   smc: CLC handshak...
562
  	/* receive SMC Accept CLC message */
2b59f58e3   Ursula Braun   net/smc: short wa...
563
564
  	return smc_clc_wait_msg(smc, aclc, sizeof(*aclc), SMC_CLC_ACCEPT,
  				CLC_WAIT_TIME);
3b2dec260   Hans Wippel   net/smc: restruct...
565
566
567
568
569
  }
  
  /* setup for RDMA connection of client */
  static int smc_connect_rdma(struct smc_sock *smc,
  			    struct smc_clc_msg_accept_confirm *aclc,
bc36d2fc9   Karsten Graul   net/smc: consolid...
570
  			    struct smc_init_info *ini)
3b2dec260   Hans Wippel   net/smc: restruct...
571
  {
3b2dec260   Hans Wippel   net/smc: restruct...
572
573
  	struct smc_link *link;
  	int reason_code = 0;
a046d57da   Ursula Braun   smc: CLC handshak...
574

bc36d2fc9   Karsten Graul   net/smc: consolid...
575
576
577
578
  	ini->is_smcd = false;
  	ini->ib_lcl = &aclc->lcl;
  	ini->ib_clcqpn = ntoh24(aclc->qpn);
  	ini->srv_first_contact = aclc->hdr.flag;
72a36a8ae   Hans Wippel   net/smc: use clie...
579
  	mutex_lock(&smc_client_lgr_pending);
7a62725a5   Karsten Graul   net/smc: improve ...
580
581
  	reason_code = smc_conn_create(smc, ini);
  	if (reason_code) {
72a36a8ae   Hans Wippel   net/smc: use clie...
582
583
  		mutex_unlock(&smc_client_lgr_pending);
  		return reason_code;
0cfdd8f92   Ursula Braun   smc: connection a...
584
585
  	}
  	link = &smc->conn.lgr->lnk[SMC_SINGLE_LINK];
a046d57da   Ursula Braun   smc: CLC handshak...
586

3b2dec260   Hans Wippel   net/smc: restruct...
587
  	smc_conn_save_peer_info(smc, aclc);
cd6851f30   Ursula Braun   smc: remote memor...
588

3e034725c   Ursula Braun   net/smc: common f...
589
  	/* create send buffer and rmb */
c6ba7c9ba   Hans Wippel   net/smc: add base...
590
  	if (smc_buf_create(smc, false))
7a62725a5   Karsten Graul   net/smc: improve ...
591
592
  		return smc_connect_abort(smc, SMC_CLC_DECL_MEM,
  					 ini->cln_first_contact);
cd6851f30   Ursula Braun   smc: remote memor...
593

7a62725a5   Karsten Graul   net/smc: improve ...
594
  	if (ini->cln_first_contact == SMC_FIRST_CONTACT)
3b2dec260   Hans Wippel   net/smc: restruct...
595
  		smc_link_save_peer_info(link, aclc);
bd4ad5771   Ursula Braun   smc: initialize I...
596

3b2dec260   Hans Wippel   net/smc: restruct...
597
  	if (smc_rmb_rtoken_handling(&smc->conn, aclc))
603cc1498   Karsten Graul   net/smc: provide ...
598
  		return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RTOK,
7a62725a5   Karsten Graul   net/smc: improve ...
599
  					 ini->cln_first_contact);
bd4ad5771   Ursula Braun   smc: initialize I...
600

46c28dbd4   Ursula Braun   net/smc: no socke...
601
602
  	smc_close_init(smc);
  	smc_rx_init(smc);
7a62725a5   Karsten Graul   net/smc: improve ...
603
  	if (ini->cln_first_contact == SMC_FIRST_CONTACT) {
3b2dec260   Hans Wippel   net/smc: restruct...
604
  		if (smc_ib_ready_link(link))
603cc1498   Karsten Graul   net/smc: provide ...
605
  			return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RDYLNK,
7a62725a5   Karsten Graul   net/smc: improve ...
606
  						 ini->cln_first_contact);
652a1e41e   Ursula Braun   net/smc: register...
607
  	} else {
c7674c001   Karsten Graul   net/smc: unregist...
608
  		if (smc_reg_rmb(link, smc->conn.rmb_desc, true))
603cc1498   Karsten Graul   net/smc: provide ...
609
  			return smc_connect_abort(smc, SMC_CLC_DECL_ERR_REGRMB,
7a62725a5   Karsten Graul   net/smc: improve ...
610
  						 ini->cln_first_contact);
bd4ad5771   Ursula Braun   smc: initialize I...
611
  	}
10428dd83   Ursula Braun   net/smc: synchron...
612
  	smc_rmb_sync_sg_for_device(&smc->conn);
a046d57da   Ursula Braun   smc: CLC handshak...
613

3b2dec260   Hans Wippel   net/smc: restruct...
614
615
  	reason_code = smc_clc_send_confirm(smc);
  	if (reason_code)
7a62725a5   Karsten Graul   net/smc: improve ...
616
617
  		return smc_connect_abort(smc, reason_code,
  					 ini->cln_first_contact);
3b2dec260   Hans Wippel   net/smc: restruct...
618
619
  
  	smc_tx_init(smc);
a046d57da   Ursula Braun   smc: CLC handshak...
620

7a62725a5   Karsten Graul   net/smc: improve ...
621
  	if (ini->cln_first_contact == SMC_FIRST_CONTACT) {
9bf9abead   Ursula Braun   smc: link layer c...
622
  		/* QP confirmation over RoCE fabric */
0f6271264   Stefan Raspl   net/smc: cleanup ...
623
  		reason_code = smc_clnt_conf_first_link(smc);
3b2dec260   Hans Wippel   net/smc: restruct...
624
625
  		if (reason_code)
  			return smc_connect_abort(smc, reason_code,
7a62725a5   Karsten Graul   net/smc: improve ...
626
  						 ini->cln_first_contact);
9bf9abead   Ursula Braun   smc: link layer c...
627
  	}
72a36a8ae   Hans Wippel   net/smc: use clie...
628
  	mutex_unlock(&smc_client_lgr_pending);
e6727f390   Ursula Braun   smc: send data (t...
629

a046d57da   Ursula Braun   smc: CLC handshak...
630
  	smc_copy_sock_settings_to_clc(smc);
50717a37d   Ursula Braun   net/smc: nonblock...
631
  	smc->connect_nonblock = 0;
b38d73247   Ursula Braun   smc: socket closi...
632
633
  	if (smc->sk.sk_state == SMC_INIT)
  		smc->sk.sk_state = SMC_ACTIVE;
a046d57da   Ursula Braun   smc: CLC handshak...
634

3b2dec260   Hans Wippel   net/smc: restruct...
635
636
  	return 0;
  }
a046d57da   Ursula Braun   smc: CLC handshak...
637

413498440   Hans Wippel   net/smc: add SMC-...
638
639
640
  /* setup for ISM connection of client */
  static int smc_connect_ism(struct smc_sock *smc,
  			   struct smc_clc_msg_accept_confirm *aclc,
bc36d2fc9   Karsten Graul   net/smc: consolid...
641
  			   struct smc_init_info *ini)
413498440   Hans Wippel   net/smc: add SMC-...
642
  {
413498440   Hans Wippel   net/smc: add SMC-...
643
  	int rc = 0;
bc36d2fc9   Karsten Graul   net/smc: consolid...
644
645
646
  	ini->is_smcd = true;
  	ini->ism_gid = aclc->gid;
  	ini->srv_first_contact = aclc->hdr.flag;
72a36a8ae   Hans Wippel   net/smc: use clie...
647
648
  	/* there is only one lgr role for SMC-D; use server lock */
  	mutex_lock(&smc_server_lgr_pending);
7a62725a5   Karsten Graul   net/smc: improve ...
649
650
  	rc = smc_conn_create(smc, ini);
  	if (rc) {
72a36a8ae   Hans Wippel   net/smc: use clie...
651
  		mutex_unlock(&smc_server_lgr_pending);
7a62725a5   Karsten Graul   net/smc: improve ...
652
  		return rc;
72a36a8ae   Hans Wippel   net/smc: use clie...
653
  	}
413498440   Hans Wippel   net/smc: add SMC-...
654
655
656
  
  	/* Create send and receive buffers */
  	if (smc_buf_create(smc, true))
7a62725a5   Karsten Graul   net/smc: improve ...
657
658
  		return smc_connect_abort(smc, SMC_CLC_DECL_MEM,
  					 ini->cln_first_contact);
413498440   Hans Wippel   net/smc: add SMC-...
659
660
661
662
663
664
665
666
  
  	smc_conn_save_peer_info(smc, aclc);
  	smc_close_init(smc);
  	smc_rx_init(smc);
  	smc_tx_init(smc);
  
  	rc = smc_clc_send_confirm(smc);
  	if (rc)
7a62725a5   Karsten Graul   net/smc: improve ...
667
  		return smc_connect_abort(smc, rc, ini->cln_first_contact);
72a36a8ae   Hans Wippel   net/smc: use clie...
668
  	mutex_unlock(&smc_server_lgr_pending);
413498440   Hans Wippel   net/smc: add SMC-...
669
670
  
  	smc_copy_sock_settings_to_clc(smc);
50717a37d   Ursula Braun   net/smc: nonblock...
671
  	smc->connect_nonblock = 0;
413498440   Hans Wippel   net/smc: add SMC-...
672
673
674
675
676
  	if (smc->sk.sk_state == SMC_INIT)
  		smc->sk.sk_state = SMC_ACTIVE;
  
  	return 0;
  }
3b2dec260   Hans Wippel   net/smc: restruct...
677
678
679
  /* perform steps before actually connecting */
  static int __smc_connect(struct smc_sock *smc)
  {
413498440   Hans Wippel   net/smc: add SMC-...
680
  	bool ism_supported = false, rdma_supported = false;
3b2dec260   Hans Wippel   net/smc: restruct...
681
  	struct smc_clc_msg_accept_confirm aclc;
bc36d2fc9   Karsten Graul   net/smc: consolid...
682
  	struct smc_init_info ini = {0};
413498440   Hans Wippel   net/smc: add SMC-...
683
  	int smc_type;
3b2dec260   Hans Wippel   net/smc: restruct...
684
  	int rc = 0;
a046d57da   Ursula Braun   smc: CLC handshak...
685

3b2dec260   Hans Wippel   net/smc: restruct...
686
  	if (smc->use_fallback)
603cc1498   Karsten Graul   net/smc: provide ...
687
  		return smc_connect_fallback(smc, smc->fallback_rsn);
3b2dec260   Hans Wippel   net/smc: restruct...
688
689
690
  
  	/* if peer has not signalled SMC-capability, fall back */
  	if (!tcp_sk(smc->clcsock->sk)->syn_smc)
603cc1498   Karsten Graul   net/smc: provide ...
691
  		return smc_connect_fallback(smc, SMC_CLC_DECL_PEERNOSMC);
3b2dec260   Hans Wippel   net/smc: restruct...
692
693
694
695
  
  	/* IPSec connections opt out of SMC-R optimizations */
  	if (using_ipsec(smc))
  		return smc_connect_decline_fallback(smc, SMC_CLC_DECL_IPSEC);
fba7e8ef5   Karsten Graul   net/smc: cleanup ...
696
  	/* get vlan id from IP device */
bc36d2fc9   Karsten Graul   net/smc: consolid...
697
  	if (smc_vlan_by_tcpsk(smc->clcsock, &ini))
fba7e8ef5   Karsten Graul   net/smc: cleanup ...
698
699
  		return smc_connect_decline_fallback(smc,
  						    SMC_CLC_DECL_GETVLANERR);
413498440   Hans Wippel   net/smc: add SMC-...
700
701
  
  	/* check if there is an ism device available */
228bae05b   Karsten Graul   net/smc: code cle...
702
  	if (!smc_find_ism_device(smc, &ini) &&
bc36d2fc9   Karsten Graul   net/smc: consolid...
703
  	    !smc_connect_ism_vlan_setup(smc, &ini)) {
413498440   Hans Wippel   net/smc: add SMC-...
704
705
706
707
708
709
  		/* ISM is supported for this connection */
  		ism_supported = true;
  		smc_type = SMC_TYPE_D;
  	}
  
  	/* check if there is a rdma device available */
228bae05b   Karsten Graul   net/smc: code cle...
710
  	if (!smc_find_rdma_device(smc, &ini)) {
413498440   Hans Wippel   net/smc: add SMC-...
711
712
713
714
715
716
717
718
719
720
  		/* RDMA is supported for this connection */
  		rdma_supported = true;
  		if (ism_supported)
  			smc_type = SMC_TYPE_B; /* both */
  		else
  			smc_type = SMC_TYPE_R; /* only RDMA */
  	}
  
  	/* if neither ISM nor RDMA are supported, fallback */
  	if (!rdma_supported && !ism_supported)
603cc1498   Karsten Graul   net/smc: provide ...
721
  		return smc_connect_decline_fallback(smc, SMC_CLC_DECL_NOSMCDEV);
3b2dec260   Hans Wippel   net/smc: restruct...
722
723
  
  	/* perform CLC handshake */
bc36d2fc9   Karsten Graul   net/smc: consolid...
724
  	rc = smc_connect_clc(smc, smc_type, &aclc, &ini);
413498440   Hans Wippel   net/smc: add SMC-...
725
  	if (rc) {
bc36d2fc9   Karsten Graul   net/smc: consolid...
726
  		smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini);
3b2dec260   Hans Wippel   net/smc: restruct...
727
  		return smc_connect_decline_fallback(smc, rc);
413498440   Hans Wippel   net/smc: add SMC-...
728
  	}
3b2dec260   Hans Wippel   net/smc: restruct...
729

413498440   Hans Wippel   net/smc: add SMC-...
730
731
  	/* depending on previous steps, connect using rdma or ism */
  	if (rdma_supported && aclc.hdr.path == SMC_TYPE_R)
bc36d2fc9   Karsten Graul   net/smc: consolid...
732
  		rc = smc_connect_rdma(smc, &aclc, &ini);
413498440   Hans Wippel   net/smc: add SMC-...
733
  	else if (ism_supported && aclc.hdr.path == SMC_TYPE_D)
bc36d2fc9   Karsten Graul   net/smc: consolid...
734
  		rc = smc_connect_ism(smc, &aclc, &ini);
413498440   Hans Wippel   net/smc: add SMC-...
735
  	else
603cc1498   Karsten Graul   net/smc: provide ...
736
  		rc = SMC_CLC_DECL_MODEUNSUPP;
413498440   Hans Wippel   net/smc: add SMC-...
737
  	if (rc) {
bc36d2fc9   Karsten Graul   net/smc: consolid...
738
  		smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini);
3b2dec260   Hans Wippel   net/smc: restruct...
739
  		return smc_connect_decline_fallback(smc, rc);
413498440   Hans Wippel   net/smc: add SMC-...
740
  	}
3b2dec260   Hans Wippel   net/smc: restruct...
741

bc36d2fc9   Karsten Graul   net/smc: consolid...
742
  	smc_connect_ism_vlan_cleanup(smc, ism_supported, &ini);
3b2dec260   Hans Wippel   net/smc: restruct...
743
  	return 0;
a046d57da   Ursula Braun   smc: CLC handshak...
744
  }
24ac3a08e   Ursula Braun   net/smc: rebuild ...
745
746
747
748
  static void smc_connect_work(struct work_struct *work)
  {
  	struct smc_sock *smc = container_of(work, struct smc_sock,
  					    connect_work);
50717a37d   Ursula Braun   net/smc: nonblock...
749
750
  	long timeo = smc->sk.sk_sndtimeo;
  	int rc = 0;
24ac3a08e   Ursula Braun   net/smc: rebuild ...
751

50717a37d   Ursula Braun   net/smc: nonblock...
752
753
754
  	if (!timeo)
  		timeo = MAX_SCHEDULE_TIMEOUT;
  	lock_sock(smc->clcsock->sk);
24ac3a08e   Ursula Braun   net/smc: rebuild ...
755
756
  	if (smc->clcsock->sk->sk_err) {
  		smc->sk.sk_err = smc->clcsock->sk->sk_err;
50717a37d   Ursula Braun   net/smc: nonblock...
757
758
759
760
761
762
763
  	} else if ((1 << smc->clcsock->sk->sk_state) &
  					(TCPF_SYN_SENT | TCP_SYN_RECV)) {
  		rc = sk_stream_wait_connect(smc->clcsock->sk, &timeo);
  		if ((rc == -EPIPE) &&
  		    ((1 << smc->clcsock->sk->sk_state) &
  					(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)))
  			rc = 0;
24ac3a08e   Ursula Braun   net/smc: rebuild ...
764
  	}
50717a37d   Ursula Braun   net/smc: nonblock...
765
766
767
768
769
770
771
772
  	release_sock(smc->clcsock->sk);
  	lock_sock(&smc->sk);
  	if (rc != 0 || smc->sk.sk_err) {
  		smc->sk.sk_state = SMC_CLOSED;
  		if (rc == -EPIPE || rc == -EAGAIN)
  			smc->sk.sk_err = EPIPE;
  		else if (signal_pending(current))
  			smc->sk.sk_err = -sock_intr_errno(timeo);
6d6dd528d   Ursula Braun   net/smc: fix refc...
773
  		sock_put(&smc->sk); /* passive closing */
24ac3a08e   Ursula Braun   net/smc: rebuild ...
774
775
776
777
778
779
780
781
  		goto out;
  	}
  
  	rc = __smc_connect(smc);
  	if (rc < 0)
  		smc->sk.sk_err = -rc;
  
  out:
07603b230   Ursula Braun   net/smc: propagat...
782
783
784
785
786
787
788
789
  	if (!sock_flag(&smc->sk, SOCK_DEAD)) {
  		if (smc->sk.sk_err) {
  			smc->sk.sk_state_change(&smc->sk);
  		} else { /* allow polling before and after fallback decision */
  			smc->clcsock->sk->sk_write_space(smc->clcsock->sk);
  			smc->sk.sk_write_space(&smc->sk);
  		}
  	}
24ac3a08e   Ursula Braun   net/smc: rebuild ...
790
791
  	release_sock(&smc->sk);
  }
ac7138746   Ursula Braun   smc: establish ne...
792
793
794
795
796
797
798
799
800
801
802
803
  static int smc_connect(struct socket *sock, struct sockaddr *addr,
  		       int alen, int flags)
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc = -EINVAL;
  
  	smc = smc_sk(sk);
  
  	/* separate smc parameter checking to be safe */
  	if (alen < sizeof(addr->sa_family))
  		goto out_err;
aaa4d33f6   Karsten Graul   net/smc: enable i...
804
  	if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
ac7138746   Ursula Braun   smc: establish ne...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
  		goto out_err;
  
  	lock_sock(sk);
  	switch (sk->sk_state) {
  	default:
  		goto out;
  	case SMC_ACTIVE:
  		rc = -EISCONN;
  		goto out;
  	case SMC_INIT:
  		rc = 0;
  		break;
  	}
  
  	smc_copy_sock_settings_to_clc(smc);
c5c1cc9c5   Ursula Braun   smc: add SMC rend...
820
  	tcp_sk(smc->clcsock->sk)->syn_smc = 1;
50717a37d   Ursula Braun   net/smc: nonblock...
821
822
823
824
825
826
827
  	if (smc->connect_nonblock) {
  		rc = -EALREADY;
  		goto out;
  	}
  	rc = kernel_connect(smc->clcsock, addr, alen, flags);
  	if (rc && rc != -EINPROGRESS)
  		goto out;
301428ea3   Ursula Braun   net/smc: fix refc...
828
829
  
  	sock_hold(&smc->sk); /* sock put in passive closing */
86434744f   Ursula Braun   net/smc: add fall...
830
831
  	if (smc->use_fallback)
  		goto out;
24ac3a08e   Ursula Braun   net/smc: rebuild ...
832
  	if (flags & O_NONBLOCK) {
50717a37d   Ursula Braun   net/smc: nonblock...
833
834
  		if (schedule_work(&smc->connect_work))
  			smc->connect_nonblock = 1;
24ac3a08e   Ursula Braun   net/smc: rebuild ...
835
836
  		rc = -EINPROGRESS;
  	} else {
24ac3a08e   Ursula Braun   net/smc: rebuild ...
837
838
839
840
841
842
  		rc = __smc_connect(smc);
  		if (rc < 0)
  			goto out;
  		else
  			rc = 0; /* success cases including fallback */
  	}
ac7138746   Ursula Braun   smc: establish ne...
843
844
845
846
847
848
849
850
851
  
  out:
  	release_sock(sk);
  out_err:
  	return rc;
  }
  
  static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc)
  {
3163c5071   Ursula Braun   net/smc: use loca...
852
853
  	struct socket *new_clcsock = NULL;
  	struct sock *lsk = &lsmc->sk;
ac7138746   Ursula Braun   smc: establish ne...
854
  	struct sock *new_sk;
78abe3d0d   Myungho Jung   net/smc: fix TCP ...
855
  	int rc = -EINVAL;
ac7138746   Ursula Braun   smc: establish ne...
856

3163c5071   Ursula Braun   net/smc: use loca...
857
  	release_sock(lsk);
aaa4d33f6   Karsten Graul   net/smc: enable i...
858
  	new_sk = smc_sock_alloc(sock_net(lsk), NULL, lsk->sk_protocol);
ac7138746   Ursula Braun   smc: establish ne...
859
860
  	if (!new_sk) {
  		rc = -ENOMEM;
3163c5071   Ursula Braun   net/smc: use loca...
861
  		lsk->sk_err = ENOMEM;
ac7138746   Ursula Braun   smc: establish ne...
862
  		*new_smc = NULL;
3163c5071   Ursula Braun   net/smc: use loca...
863
  		lock_sock(lsk);
ac7138746   Ursula Braun   smc: establish ne...
864
865
866
  		goto out;
  	}
  	*new_smc = smc_sk(new_sk);
78abe3d0d   Myungho Jung   net/smc: fix TCP ...
867
868
869
870
  	mutex_lock(&lsmc->clcsock_release_lock);
  	if (lsmc->clcsock)
  		rc = kernel_accept(lsmc->clcsock, &new_clcsock, 0);
  	mutex_unlock(&lsmc->clcsock_release_lock);
3163c5071   Ursula Braun   net/smc: use loca...
871
  	lock_sock(lsk);
35a6b1784   Ursula Braun   net/smc: simplify...
872
  	if  (rc < 0)
3163c5071   Ursula Braun   net/smc: use loca...
873
  		lsk->sk_err = -rc;
35a6b1784   Ursula Braun   net/smc: simplify...
874
  	if (rc < 0 || lsk->sk_state == SMC_CLOSED) {
f61bca58f   Ursula Braun   net/smc: move unh...
875
  		new_sk->sk_prot->unhash(new_sk);
a046d57da   Ursula Braun   smc: CLC handshak...
876
877
878
879
  		if (new_clcsock)
  			sock_release(new_clcsock);
  		new_sk->sk_state = SMC_CLOSED;
  		sock_set_flag(new_sk, SOCK_DEAD);
51f1de79a   Ursula Braun   net/smc: replace ...
880
  		sock_put(new_sk); /* final */
ac7138746   Ursula Braun   smc: establish ne...
881
882
883
884
885
886
887
888
  		*new_smc = NULL;
  		goto out;
  	}
  
  	(*new_smc)->clcsock = new_clcsock;
  out:
  	return rc;
  }
a046d57da   Ursula Braun   smc: CLC handshak...
889
890
891
892
893
894
  /* add a just created sock to the accept queue of the listen sock as
   * candidate for a following socket accept call from user space
   */
  static void smc_accept_enqueue(struct sock *parent, struct sock *sk)
  {
  	struct smc_sock *par = smc_sk(parent);
51f1de79a   Ursula Braun   net/smc: replace ...
895
  	sock_hold(sk); /* sock_put in smc_accept_unlink () */
a046d57da   Ursula Braun   smc: CLC handshak...
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
  	spin_lock(&par->accept_q_lock);
  	list_add_tail(&smc_sk(sk)->accept_q, &par->accept_q);
  	spin_unlock(&par->accept_q_lock);
  	sk_acceptq_added(parent);
  }
  
  /* remove a socket from the accept queue of its parental listening socket */
  static void smc_accept_unlink(struct sock *sk)
  {
  	struct smc_sock *par = smc_sk(sk)->listen_smc;
  
  	spin_lock(&par->accept_q_lock);
  	list_del_init(&smc_sk(sk)->accept_q);
  	spin_unlock(&par->accept_q_lock);
  	sk_acceptq_removed(&smc_sk(sk)->listen_smc->sk);
51f1de79a   Ursula Braun   net/smc: replace ...
911
  	sock_put(sk); /* sock_hold in smc_accept_enqueue */
a046d57da   Ursula Braun   smc: CLC handshak...
912
913
914
915
916
  }
  
  /* remove a sock from the accept queue to bind it to a new socket created
   * for a socket accept call from user space
   */
b38d73247   Ursula Braun   smc: socket closi...
917
918
  struct sock *smc_accept_dequeue(struct sock *parent,
  				struct socket *new_sock)
a046d57da   Ursula Braun   smc: CLC handshak...
919
920
921
922
923
924
925
926
927
  {
  	struct smc_sock *isk, *n;
  	struct sock *new_sk;
  
  	list_for_each_entry_safe(isk, n, &smc_sk(parent)->accept_q, accept_q) {
  		new_sk = (struct sock *)isk;
  
  		smc_accept_unlink(new_sk);
  		if (new_sk->sk_state == SMC_CLOSED) {
f61bca58f   Ursula Braun   net/smc: move unh...
928
  			new_sk->sk_prot->unhash(new_sk);
127f49705   Ursula Braun   net/smc: release ...
929
930
931
932
  			if (isk->clcsock) {
  				sock_release(isk->clcsock);
  				isk->clcsock = NULL;
  			}
51f1de79a   Ursula Braun   net/smc: replace ...
933
  			sock_put(new_sk); /* final */
a046d57da   Ursula Braun   smc: CLC handshak...
934
935
  			continue;
  		}
07603b230   Ursula Braun   net/smc: propagat...
936
  		if (new_sock) {
a046d57da   Ursula Braun   smc: CLC handshak...
937
  			sock_graft(new_sk, new_sock);
07603b230   Ursula Braun   net/smc: propagat...
938
939
940
941
942
  			if (isk->use_fallback) {
  				smc_sk(new_sk)->clcsock->file = new_sock->file;
  				isk->clcsock->file->private_data = isk->clcsock;
  			}
  		}
a046d57da   Ursula Braun   smc: CLC handshak...
943
944
945
946
947
948
  		return new_sk;
  	}
  	return NULL;
  }
  
  /* clean up for a created but never accepted sock */
b38d73247   Ursula Braun   smc: socket closi...
949
  void smc_close_non_accepted(struct sock *sk)
a046d57da   Ursula Braun   smc: CLC handshak...
950
951
  {
  	struct smc_sock *smc = smc_sk(sk);
81cf4f470   Ursula Braun   net/smc: remove c...
952
  	sock_hold(sk); /* sock_put below */
b38d73247   Ursula Braun   smc: socket closi...
953
954
955
956
  	lock_sock(sk);
  	if (!sk->sk_lingertime)
  		/* wait for peer closing */
  		sk->sk_lingertime = SMC_MAX_STREAM_WAIT_TIMEOUT;
39f41f367   Ursula Braun   net/smc: common r...
957
  	__smc_release(smc);
b38d73247   Ursula Braun   smc: socket closi...
958
  	release_sock(sk);
81cf4f470   Ursula Braun   net/smc: remove c...
959
  	sock_put(sk); /* sock_hold above */
51f1de79a   Ursula Braun   net/smc: replace ...
960
  	sock_put(sk); /* final sock_put */
a046d57da   Ursula Braun   smc: CLC handshak...
961
  }
9bf9abead   Ursula Braun   smc: link layer c...
962
963
  static int smc_serv_conf_first_link(struct smc_sock *smc)
  {
877ae5be4   Karsten Graul   net/smc: periodic...
964
  	struct net *net = sock_net(smc->clcsock->sk);
9bf9abead   Ursula Braun   smc: link layer c...
965
966
967
968
969
970
  	struct smc_link_group *lgr = smc->conn.lgr;
  	struct smc_link *link;
  	int rest;
  	int rc;
  
  	link = &lgr->lnk[SMC_SINGLE_LINK];
652a1e41e   Ursula Braun   net/smc: register...
971

44aa81ce9   Karsten Graul   net/smc: register...
972
  	if (smc_reg_rmb(link, smc->conn.rmb_desc, false))
603cc1498   Karsten Graul   net/smc: provide ...
973
  		return SMC_CLC_DECL_ERR_REGRMB;
652a1e41e   Ursula Braun   net/smc: register...
974

9bf9abead   Ursula Braun   smc: link layer c...
975
  	/* send CONFIRM LINK request to client over the RoCE fabric */
947541f36   Ursula Braun   net/smc: fewer pa...
976
  	rc = smc_llc_send_confirm_link(link, SMC_LLC_REQ);
9bf9abead   Ursula Braun   smc: link layer c...
977
  	if (rc < 0)
603cc1498   Karsten Graul   net/smc: provide ...
978
  		return SMC_CLC_DECL_TIMEOUT_CL;
9bf9abead   Ursula Braun   smc: link layer c...
979
980
981
982
983
984
985
986
987
  
  	/* receive CONFIRM LINK response from client over the RoCE fabric */
  	rest = wait_for_completion_interruptible_timeout(
  		&link->llc_confirm_resp,
  		SMC_LLC_WAIT_FIRST_TIME);
  	if (rest <= 0) {
  		struct smc_clc_msg_decline dclc;
  
  		rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
2b59f58e3   Ursula Braun   net/smc: short wa...
988
  				      SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT);
9ed28556a   Ursula Braun   net/smc: allow fa...
989
  		return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_CL : rc;
9bf9abead   Ursula Braun   smc: link layer c...
990
  	}
75d320d61   Karsten Graul   net/smc: do not a...
991
992
  	if (link->llc_confirm_resp_rc)
  		return SMC_CLC_DECL_RMBE_EC;
52bedf37b   Karsten Graul   net/smc: process ...
993
994
995
  	/* send ADD LINK request to client over the RoCE fabric */
  	rc = smc_llc_send_add_link(link,
  				   link->smcibdev->mac[link->ibport - 1],
7005ada68   Ursula Braun   net/smc: use corr...
996
  				   link->gid, SMC_LLC_REQ);
52bedf37b   Karsten Graul   net/smc: process ...
997
  	if (rc < 0)
603cc1498   Karsten Graul   net/smc: provide ...
998
  		return SMC_CLC_DECL_TIMEOUT_AL;
52bedf37b   Karsten Graul   net/smc: process ...
999
1000
1001
1002
1003
1004
1005
1006
  
  	/* receive ADD LINK response from client over the RoCE fabric */
  	rest = wait_for_completion_interruptible_timeout(&link->llc_add_resp,
  							 SMC_LLC_WAIT_TIME);
  	if (rest <= 0) {
  		struct smc_clc_msg_decline dclc;
  
  		rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
2b59f58e3   Ursula Braun   net/smc: short wa...
1007
  				      SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT);
9ed28556a   Ursula Braun   net/smc: allow fa...
1008
  		return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_AL : rc;
52bedf37b   Karsten Graul   net/smc: process ...
1009
  	}
877ae5be4   Karsten Graul   net/smc: periodic...
1010
  	smc_llc_link_active(link, net->ipv4.sysctl_tcp_keepalive_time);
52bedf37b   Karsten Graul   net/smc: process ...
1011

75d320d61   Karsten Graul   net/smc: do not a...
1012
  	return 0;
9bf9abead   Ursula Braun   smc: link layer c...
1013
  }
3b2dec260   Hans Wippel   net/smc: restruct...
1014
1015
  /* listen worker: finish */
  static void smc_listen_out(struct smc_sock *new_smc)
a046d57da   Ursula Braun   smc: CLC handshak...
1016
  {
a046d57da   Ursula Braun   smc: CLC handshak...
1017
  	struct smc_sock *lsmc = new_smc->listen_smc;
a046d57da   Ursula Braun   smc: CLC handshak...
1018
  	struct sock *newsmcsk = &new_smc->sk;
a046d57da   Ursula Braun   smc: CLC handshak...
1019

3b2dec260   Hans Wippel   net/smc: restruct...
1020
  	if (lsmc->sk.sk_state == SMC_LISTEN) {
fd57770dd   Karsten Graul   net/smc: wait for...
1021
  		lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING);
3b2dec260   Hans Wippel   net/smc: restruct...
1022
  		smc_accept_enqueue(&lsmc->sk, newsmcsk);
fd57770dd   Karsten Graul   net/smc: wait for...
1023
  		release_sock(&lsmc->sk);
3b2dec260   Hans Wippel   net/smc: restruct...
1024
1025
  	} else { /* no longer listening */
  		smc_close_non_accepted(newsmcsk);
c5c1cc9c5   Ursula Braun   smc: add SMC rend...
1026
  	}
3b2dec260   Hans Wippel   net/smc: restruct...
1027
1028
1029
1030
  	/* Wake up accept */
  	lsmc->sk.sk_data_ready(&lsmc->sk);
  	sock_put(&lsmc->sk); /* sock_hold in smc_tcp_listen_work */
  }
a046d57da   Ursula Braun   smc: CLC handshak...
1031

3b2dec260   Hans Wippel   net/smc: restruct...
1032
1033
1034
1035
  /* listen worker: finish in state connected */
  static void smc_listen_out_connected(struct smc_sock *new_smc)
  {
  	struct sock *newsmcsk = &new_smc->sk;
a046d57da   Ursula Braun   smc: CLC handshak...
1036

3b2dec260   Hans Wippel   net/smc: restruct...
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
  	sk_refcnt_debug_inc(newsmcsk);
  	if (newsmcsk->sk_state == SMC_INIT)
  		newsmcsk->sk_state = SMC_ACTIVE;
  
  	smc_listen_out(new_smc);
  }
  
  /* listen worker: finish in error state */
  static void smc_listen_out_err(struct smc_sock *new_smc)
  {
  	struct sock *newsmcsk = &new_smc->sk;
  
  	if (newsmcsk->sk_state == SMC_INIT)
  		sock_put(&new_smc->sk); /* passive closing */
  	newsmcsk->sk_state = SMC_CLOSED;
3b2dec260   Hans Wippel   net/smc: restruct...
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
  
  	smc_listen_out(new_smc);
  }
  
  /* listen worker: decline and fall back if possible */
  static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
  			       int local_contact)
  {
  	/* RDMA setup failed, switch back to TCP */
  	if (local_contact == SMC_FIRST_CONTACT)
51e3dfa89   Ursula Braun   net/smc: fix clea...
1062
1063
1064
  		smc_lgr_cleanup_early(&new_smc->conn);
  	else
  		smc_conn_free(&new_smc->conn);
3b2dec260   Hans Wippel   net/smc: restruct...
1065
1066
1067
1068
  	if (reason_code < 0) { /* error, no fallback possible */
  		smc_listen_out_err(new_smc);
  		return;
  	}
07603b230   Ursula Braun   net/smc: propagat...
1069
  	smc_switch_to_fallback(new_smc);
603cc1498   Karsten Graul   net/smc: provide ...
1070
1071
  	new_smc->fallback_rsn = reason_code;
  	if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) {
3b2dec260   Hans Wippel   net/smc: restruct...
1072
1073
1074
1075
  		if (smc_clc_send_decline(new_smc, reason_code) < 0) {
  			smc_listen_out_err(new_smc);
  			return;
  		}
a046d57da   Ursula Braun   smc: CLC handshak...
1076
  	}
3b2dec260   Hans Wippel   net/smc: restruct...
1077
1078
1079
1080
  	smc_listen_out_connected(new_smc);
  }
  
  /* listen worker: check prefixes */
598866974   Karsten Graul   net/smc: check fo...
1081
  static int smc_listen_prfx_check(struct smc_sock *new_smc,
3b2dec260   Hans Wippel   net/smc: restruct...
1082
1083
1084
1085
  				 struct smc_clc_msg_proposal *pclc)
  {
  	struct smc_clc_msg_proposal_prefix *pclc_prfx;
  	struct socket *newclcsock = new_smc->clcsock;
a046d57da   Ursula Braun   smc: CLC handshak...
1086

e7b7a64a8   Ursula Braun   smc: support vari...
1087
  	pclc_prfx = smc_clc_proposal_get_prefix(pclc);
3b2dec260   Hans Wippel   net/smc: restruct...
1088
  	if (smc_clc_prfx_match(newclcsock, pclc_prfx))
598866974   Karsten Graul   net/smc: check fo...
1089
  		return SMC_CLC_DECL_DIFFPREFIX;
c246d942e   Karsten Graul   net/smc: restruct...
1090

3b2dec260   Hans Wippel   net/smc: restruct...
1091
1092
  	return 0;
  }
a046d57da   Ursula Braun   smc: CLC handshak...
1093

3b2dec260   Hans Wippel   net/smc: restruct...
1094
1095
  /* listen worker: initialize connection and buffers */
  static int smc_listen_rdma_init(struct smc_sock *new_smc,
7a62725a5   Karsten Graul   net/smc: improve ...
1096
  				struct smc_init_info *ini)
3b2dec260   Hans Wippel   net/smc: restruct...
1097
  {
7a62725a5   Karsten Graul   net/smc: improve ...
1098
  	int rc;
0cfdd8f92   Ursula Braun   smc: connection a...
1099
  	/* allocate connection / link group */
7a62725a5   Karsten Graul   net/smc: improve ...
1100
1101
1102
  	rc = smc_conn_create(new_smc, ini);
  	if (rc)
  		return rc;
a046d57da   Ursula Braun   smc: CLC handshak...
1103

3e034725c   Ursula Braun   net/smc: common f...
1104
  	/* create send buffer and rmb */
c6ba7c9ba   Hans Wippel   net/smc: add base...
1105
  	if (smc_buf_create(new_smc, false))
3b2dec260   Hans Wippel   net/smc: restruct...
1106
  		return SMC_CLC_DECL_MEM;
a046d57da   Ursula Braun   smc: CLC handshak...
1107

3b2dec260   Hans Wippel   net/smc: restruct...
1108
1109
  	return 0;
  }
413498440   Hans Wippel   net/smc: add SMC-...
1110
1111
1112
  /* listen worker: initialize connection and buffers for SMC-D */
  static int smc_listen_ism_init(struct smc_sock *new_smc,
  			       struct smc_clc_msg_proposal *pclc,
7a62725a5   Karsten Graul   net/smc: improve ...
1113
  			       struct smc_init_info *ini)
413498440   Hans Wippel   net/smc: add SMC-...
1114
1115
  {
  	struct smc_clc_msg_smcd *pclc_smcd;
7a62725a5   Karsten Graul   net/smc: improve ...
1116
  	int rc;
413498440   Hans Wippel   net/smc: add SMC-...
1117
1118
  
  	pclc_smcd = smc_get_clc_msg_smcd(pclc);
bc36d2fc9   Karsten Graul   net/smc: consolid...
1119
  	ini->ism_gid = pclc_smcd->gid;
7a62725a5   Karsten Graul   net/smc: improve ...
1120
1121
1122
  	rc = smc_conn_create(new_smc, ini);
  	if (rc)
  		return rc;
413498440   Hans Wippel   net/smc: add SMC-...
1123
1124
1125
1126
1127
  
  	/* Check if peer can be reached via ISM device */
  	if (smc_ism_cantalk(new_smc->conn.lgr->peer_gid,
  			    new_smc->conn.lgr->vlan_id,
  			    new_smc->conn.lgr->smcd)) {
7a62725a5   Karsten Graul   net/smc: improve ...
1128
  		if (ini->cln_first_contact == SMC_FIRST_CONTACT)
51e3dfa89   Ursula Braun   net/smc: fix clea...
1129
1130
1131
  			smc_lgr_cleanup_early(&new_smc->conn);
  		else
  			smc_conn_free(&new_smc->conn);
9aa68d298   Karsten Graul   net/smc: improve ...
1132
  		return SMC_CLC_DECL_SMCDNOTALK;
413498440   Hans Wippel   net/smc: add SMC-...
1133
1134
1135
1136
  	}
  
  	/* Create send and receive buffers */
  	if (smc_buf_create(new_smc, true)) {
7a62725a5   Karsten Graul   net/smc: improve ...
1137
  		if (ini->cln_first_contact == SMC_FIRST_CONTACT)
51e3dfa89   Ursula Braun   net/smc: fix clea...
1138
1139
1140
  			smc_lgr_cleanup_early(&new_smc->conn);
  		else
  			smc_conn_free(&new_smc->conn);
413498440   Hans Wippel   net/smc: add SMC-...
1141
1142
1143
1144
1145
  		return SMC_CLC_DECL_MEM;
  	}
  
  	return 0;
  }
3b2dec260   Hans Wippel   net/smc: restruct...
1146
1147
1148
1149
  /* listen worker: register buffers */
  static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact)
  {
  	struct smc_link *link = &new_smc->conn.lgr->lnk[SMC_SINGLE_LINK];
46c28dbd4   Ursula Braun   net/smc: no socke...
1150

652a1e41e   Ursula Braun   net/smc: register...
1151
  	if (local_contact != SMC_FIRST_CONTACT) {
c7674c001   Karsten Graul   net/smc: unregist...
1152
1153
  		if (smc_reg_rmb(link, new_smc->conn.rmb_desc, true))
  			return SMC_CLC_DECL_ERR_REGRMB;
652a1e41e   Ursula Braun   net/smc: register...
1154
  	}
10428dd83   Ursula Braun   net/smc: synchron...
1155
  	smc_rmb_sync_sg_for_device(&new_smc->conn);
652a1e41e   Ursula Braun   net/smc: register...
1156

3b2dec260   Hans Wippel   net/smc: restruct...
1157
1158
1159
1160
  	return 0;
  }
  
  /* listen worker: finish RDMA setup */
1ca52fcfa   Ursula Braun   net/smc: remove d...
1161
1162
1163
  static int smc_listen_rdma_finish(struct smc_sock *new_smc,
  				  struct smc_clc_msg_accept_confirm *cclc,
  				  int local_contact)
3b2dec260   Hans Wippel   net/smc: restruct...
1164
1165
1166
  {
  	struct smc_link *link = &new_smc->conn.lgr->lnk[SMC_SINGLE_LINK];
  	int reason_code = 0;
a046d57da   Ursula Braun   smc: CLC handshak...
1167

0cfdd8f92   Ursula Braun   smc: connection a...
1168
  	if (local_contact == SMC_FIRST_CONTACT)
3b2dec260   Hans Wippel   net/smc: restruct...
1169
  		smc_link_save_peer_info(link, cclc);
a046d57da   Ursula Braun   smc: CLC handshak...
1170

3b2dec260   Hans Wippel   net/smc: restruct...
1171
  	if (smc_rmb_rtoken_handling(&new_smc->conn, cclc)) {
603cc1498   Karsten Graul   net/smc: provide ...
1172
  		reason_code = SMC_CLC_DECL_ERR_RTOK;
3b2dec260   Hans Wippel   net/smc: restruct...
1173
  		goto decline;
bd4ad5771   Ursula Braun   smc: initialize I...
1174
  	}
bd4ad5771   Ursula Braun   smc: initialize I...
1175
  	if (local_contact == SMC_FIRST_CONTACT) {
3b2dec260   Hans Wippel   net/smc: restruct...
1176
  		if (smc_ib_ready_link(link)) {
603cc1498   Karsten Graul   net/smc: provide ...
1177
  			reason_code = SMC_CLC_DECL_ERR_RDYLNK;
3b2dec260   Hans Wippel   net/smc: restruct...
1178
  			goto decline;
bd4ad5771   Ursula Braun   smc: initialize I...
1179
  		}
9bf9abead   Ursula Braun   smc: link layer c...
1180
1181
  		/* QP confirmation over RoCE fabric */
  		reason_code = smc_serv_conf_first_link(new_smc);
3b2dec260   Hans Wippel   net/smc: restruct...
1182
1183
  		if (reason_code)
  			goto decline;
bd4ad5771   Ursula Braun   smc: initialize I...
1184
  	}
1ca52fcfa   Ursula Braun   net/smc: remove d...
1185
  	return 0;
a046d57da   Ursula Braun   smc: CLC handshak...
1186

3b2dec260   Hans Wippel   net/smc: restruct...
1187
  decline:
3b2dec260   Hans Wippel   net/smc: restruct...
1188
  	smc_listen_decline(new_smc, reason_code, local_contact);
1ca52fcfa   Ursula Braun   net/smc: remove d...
1189
  	return reason_code;
3b2dec260   Hans Wippel   net/smc: restruct...
1190
  }
e6727f390   Ursula Braun   smc: send data (t...
1191

3b2dec260   Hans Wippel   net/smc: restruct...
1192
1193
1194
1195
1196
1197
1198
1199
  /* setup for RDMA connection of server */
  static void smc_listen_work(struct work_struct *work)
  {
  	struct smc_sock *new_smc = container_of(work, struct smc_sock,
  						smc_listen_work);
  	struct socket *newclcsock = new_smc->clcsock;
  	struct smc_clc_msg_accept_confirm cclc;
  	struct smc_clc_msg_proposal *pclc;
bc36d2fc9   Karsten Graul   net/smc: consolid...
1200
  	struct smc_init_info ini = {0};
413498440   Hans Wippel   net/smc: add SMC-...
1201
  	bool ism_supported = false;
3b2dec260   Hans Wippel   net/smc: restruct...
1202
  	u8 buf[SMC_CLC_MAX_LEN];
3b2dec260   Hans Wippel   net/smc: restruct...
1203
  	int rc = 0;
3b2dec260   Hans Wippel   net/smc: restruct...
1204

fd57770dd   Karsten Graul   net/smc: wait for...
1205
1206
  	if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN)
  		return smc_listen_out_err(new_smc);
3b2dec260   Hans Wippel   net/smc: restruct...
1207
1208
1209
  	if (new_smc->use_fallback) {
  		smc_listen_out_connected(new_smc);
  		return;
a046d57da   Ursula Braun   smc: CLC handshak...
1210
  	}
a046d57da   Ursula Braun   smc: CLC handshak...
1211

3b2dec260   Hans Wippel   net/smc: restruct...
1212
1213
  	/* check if peer is smc capable */
  	if (!tcp_sk(newclcsock->sk)->syn_smc) {
07603b230   Ursula Braun   net/smc: propagat...
1214
  		smc_switch_to_fallback(new_smc);
603cc1498   Karsten Graul   net/smc: provide ...
1215
  		new_smc->fallback_rsn = SMC_CLC_DECL_PEERNOSMC;
3b2dec260   Hans Wippel   net/smc: restruct...
1216
1217
1218
  		smc_listen_out_connected(new_smc);
  		return;
  	}
a046d57da   Ursula Braun   smc: CLC handshak...
1219

3b2dec260   Hans Wippel   net/smc: restruct...
1220
1221
1222
1223
  	/* do inband token exchange -
  	 * wait for and receive SMC Proposal CLC message
  	 */
  	pclc = (struct smc_clc_msg_proposal *)&buf;
228bae05b   Karsten Graul   net/smc: code cle...
1224
1225
  	rc = smc_clc_wait_msg(new_smc, pclc, SMC_CLC_MAX_LEN,
  			      SMC_CLC_PROPOSAL, CLC_WAIT_TIME);
9aa68d298   Karsten Graul   net/smc: improve ...
1226
1227
  	if (rc)
  		goto out_decl;
a046d57da   Ursula Braun   smc: CLC handshak...
1228

3b2dec260   Hans Wippel   net/smc: restruct...
1229
1230
  	/* IPSec connections opt out of SMC-R optimizations */
  	if (using_ipsec(new_smc)) {
9aa68d298   Karsten Graul   net/smc: improve ...
1231
1232
  		rc = SMC_CLC_DECL_IPSEC;
  		goto out_decl;
3b2dec260   Hans Wippel   net/smc: restruct...
1233
  	}
598866974   Karsten Graul   net/smc: check fo...
1234
1235
  	/* check for matching IP prefix and subnet length */
  	rc = smc_listen_prfx_check(new_smc, pclc);
9aa68d298   Karsten Graul   net/smc: improve ...
1236
1237
  	if (rc)
  		goto out_decl;
598866974   Karsten Graul   net/smc: check fo...
1238

fba7e8ef5   Karsten Graul   net/smc: cleanup ...
1239
1240
  	/* get vlan id from IP device */
  	if (smc_vlan_by_tcpsk(new_smc->clcsock, &ini)) {
9aa68d298   Karsten Graul   net/smc: improve ...
1241
1242
  		rc = SMC_CLC_DECL_GETVLANERR;
  		goto out_decl;
fba7e8ef5   Karsten Graul   net/smc: cleanup ...
1243
  	}
72a36a8ae   Hans Wippel   net/smc: use clie...
1244
  	mutex_lock(&smc_server_lgr_pending);
3b2dec260   Hans Wippel   net/smc: restruct...
1245
1246
1247
  	smc_close_init(new_smc);
  	smc_rx_init(new_smc);
  	smc_tx_init(new_smc);
413498440   Hans Wippel   net/smc: add SMC-...
1248
  	/* check if ISM is available */
9aa68d298   Karsten Graul   net/smc: improve ...
1249
1250
1251
1252
  	if (pclc->hdr.path == SMC_TYPE_D || pclc->hdr.path == SMC_TYPE_B) {
  		ini.is_smcd = true; /* prepare ISM check */
  		rc = smc_find_ism_device(new_smc, &ini);
  		if (!rc)
7a62725a5   Karsten Graul   net/smc: improve ...
1253
  			rc = smc_listen_ism_init(new_smc, pclc, &ini);
9aa68d298   Karsten Graul   net/smc: improve ...
1254
1255
1256
1257
1258
1259
1260
1261
  		if (!rc)
  			ism_supported = true;
  		else if (pclc->hdr.path == SMC_TYPE_D)
  			goto out_unlock; /* skip RDMA and decline */
  	}
  
  	/* check if RDMA is available */
  	if (!ism_supported) { /* SMC_TYPE_R or SMC_TYPE_B */
bc36d2fc9   Karsten Graul   net/smc: consolid...
1262
  		/* prepare RDMA check */
bc36d2fc9   Karsten Graul   net/smc: consolid...
1263
  		ini.is_smcd = false;
ca5f8d2dd   Ursula Braun   net/smc: keep vla...
1264
  		ini.ism_dev = NULL;
bc36d2fc9   Karsten Graul   net/smc: consolid...
1265
  		ini.ib_lcl = &pclc->lcl;
9aa68d298   Karsten Graul   net/smc: improve ...
1266
1267
1268
1269
1270
1271
1272
1273
  		rc = smc_find_rdma_device(new_smc, &ini);
  		if (rc) {
  			/* no RDMA device found */
  			if (pclc->hdr.path == SMC_TYPE_B)
  				/* neither ISM nor RDMA device found */
  				rc = SMC_CLC_DECL_NOSMCDEV;
  			goto out_unlock;
  		}
7a62725a5   Karsten Graul   net/smc: improve ...
1274
  		rc = smc_listen_rdma_init(new_smc, &ini);
9aa68d298   Karsten Graul   net/smc: improve ...
1275
1276
  		if (rc)
  			goto out_unlock;
7a62725a5   Karsten Graul   net/smc: improve ...
1277
  		rc = smc_listen_rdma_reg(new_smc, ini.cln_first_contact);
9aa68d298   Karsten Graul   net/smc: improve ...
1278
1279
  		if (rc)
  			goto out_unlock;
3b2dec260   Hans Wippel   net/smc: restruct...
1280
1281
1282
  	}
  
  	/* send SMC Accept CLC message */
7a62725a5   Karsten Graul   net/smc: improve ...
1283
  	rc = smc_clc_send_accept(new_smc, ini.cln_first_contact);
9aa68d298   Karsten Graul   net/smc: improve ...
1284
1285
  	if (rc)
  		goto out_unlock;
3b2dec260   Hans Wippel   net/smc: restruct...
1286

62c7139f3   Hans Wippel   net/smc: unlock L...
1287
1288
  	/* SMC-D does not need this lock any more */
  	if (ism_supported)
72a36a8ae   Hans Wippel   net/smc: use clie...
1289
  		mutex_unlock(&smc_server_lgr_pending);
62c7139f3   Hans Wippel   net/smc: unlock L...
1290

3b2dec260   Hans Wippel   net/smc: restruct...
1291
  	/* receive SMC Confirm CLC message */
228bae05b   Karsten Graul   net/smc: code cle...
1292
1293
1294
  	rc = smc_clc_wait_msg(new_smc, &cclc, sizeof(cclc),
  			      SMC_CLC_CONFIRM, CLC_WAIT_TIME);
  	if (rc) {
62c7139f3   Hans Wippel   net/smc: unlock L...
1295
  		if (!ism_supported)
9aa68d298   Karsten Graul   net/smc: improve ...
1296
1297
  			goto out_unlock;
  		goto out_decl;
3b2dec260   Hans Wippel   net/smc: restruct...
1298
1299
1300
  	}
  
  	/* finish worker */
1ca52fcfa   Ursula Braun   net/smc: remove d...
1301
  	if (!ism_supported) {
7a62725a5   Karsten Graul   net/smc: improve ...
1302
1303
  		rc = smc_listen_rdma_finish(new_smc, &cclc,
  					    ini.cln_first_contact);
72a36a8ae   Hans Wippel   net/smc: use clie...
1304
  		mutex_unlock(&smc_server_lgr_pending);
62c7139f3   Hans Wippel   net/smc: unlock L...
1305
  		if (rc)
1ca52fcfa   Ursula Braun   net/smc: remove d...
1306
1307
  			return;
  	}
3b2dec260   Hans Wippel   net/smc: restruct...
1308
  	smc_conn_save_peer_info(new_smc, &cclc);
3b2dec260   Hans Wippel   net/smc: restruct...
1309
  	smc_listen_out_connected(new_smc);
9aa68d298   Karsten Graul   net/smc: improve ...
1310
1311
1312
1313
1314
  	return;
  
  out_unlock:
  	mutex_unlock(&smc_server_lgr_pending);
  out_decl:
7a62725a5   Karsten Graul   net/smc: improve ...
1315
  	smc_listen_decline(new_smc, rc, ini.cln_first_contact);
a046d57da   Ursula Braun   smc: CLC handshak...
1316
1317
1318
1319
1320
1321
  }
  
  static void smc_tcp_listen_work(struct work_struct *work)
  {
  	struct smc_sock *lsmc = container_of(work, struct smc_sock,
  					     tcp_listen_work);
3163c5071   Ursula Braun   net/smc: use loca...
1322
  	struct sock *lsk = &lsmc->sk;
a046d57da   Ursula Braun   smc: CLC handshak...
1323
1324
  	struct smc_sock *new_smc;
  	int rc = 0;
3163c5071   Ursula Braun   net/smc: use loca...
1325
1326
  	lock_sock(lsk);
  	while (lsk->sk_state == SMC_LISTEN) {
a046d57da   Ursula Braun   smc: CLC handshak...
1327
1328
1329
1330
1331
1332
1333
  		rc = smc_clcsock_accept(lsmc, &new_smc);
  		if (rc)
  			goto out;
  		if (!new_smc)
  			continue;
  
  		new_smc->listen_smc = lsmc;
ee9dfbef0   Ursula Braun   net/smc: handle s...
1334
  		new_smc->use_fallback = lsmc->use_fallback;
603cc1498   Karsten Graul   net/smc: provide ...
1335
  		new_smc->fallback_rsn = lsmc->fallback_rsn;
3163c5071   Ursula Braun   net/smc: use loca...
1336
  		sock_hold(lsk); /* sock_put in smc_listen_work */
a046d57da   Ursula Braun   smc: CLC handshak...
1337
1338
  		INIT_WORK(&new_smc->smc_listen_work, smc_listen_work);
  		smc_copy_sock_settings_to_smc(new_smc);
bd58c7e08   Ursula Braun   net/smc: allow sy...
1339
1340
  		new_smc->sk.sk_sndbuf = lsmc->sk.sk_sndbuf;
  		new_smc->sk.sk_rcvbuf = lsmc->sk.sk_rcvbuf;
51f1de79a   Ursula Braun   net/smc: replace ...
1341
1342
1343
  		sock_hold(&new_smc->sk); /* sock_put in passive closing */
  		if (!schedule_work(&new_smc->smc_listen_work))
  			sock_put(&new_smc->sk);
a046d57da   Ursula Braun   smc: CLC handshak...
1344
1345
1346
  	}
  
  out:
3163c5071   Ursula Braun   net/smc: use loca...
1347
  	release_sock(lsk);
51f1de79a   Ursula Braun   net/smc: replace ...
1348
  	sock_put(&lsmc->sk); /* sock_hold in smc_listen */
a046d57da   Ursula Braun   smc: CLC handshak...
1349
  }
ac7138746   Ursula Braun   smc: establish ne...
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
  static int smc_listen(struct socket *sock, int backlog)
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc;
  
  	smc = smc_sk(sk);
  	lock_sock(sk);
  
  	rc = -EINVAL;
cd2063604   Ursula Braun   net/smc: avoid fa...
1360
1361
  	if ((sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) ||
  	    smc->connect_nonblock)
ac7138746   Ursula Braun   smc: establish ne...
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
  		goto out;
  
  	rc = 0;
  	if (sk->sk_state == SMC_LISTEN) {
  		sk->sk_max_ack_backlog = backlog;
  		goto out;
  	}
  	/* some socket options are handled in core, so we could not apply
  	 * them to the clc socket -- copy smc socket options to clc socket
  	 */
  	smc_copy_sock_settings_to_clc(smc);
ee9dfbef0   Ursula Braun   net/smc: handle s...
1373
1374
  	if (!smc->use_fallback)
  		tcp_sk(smc->clcsock->sk)->syn_smc = 1;
ac7138746   Ursula Braun   smc: establish ne...
1375
1376
1377
1378
1379
1380
1381
  
  	rc = kernel_listen(smc->clcsock, backlog);
  	if (rc)
  		goto out;
  	sk->sk_max_ack_backlog = backlog;
  	sk->sk_ack_backlog = 0;
  	sk->sk_state = SMC_LISTEN;
51f1de79a   Ursula Braun   net/smc: replace ...
1382
1383
1384
  	sock_hold(sk); /* sock_hold in tcp_listen_worker */
  	if (!schedule_work(&smc->tcp_listen_work))
  		sock_put(sk);
ac7138746   Ursula Braun   smc: establish ne...
1385
1386
1387
1388
1389
1390
1391
  
  out:
  	release_sock(sk);
  	return rc;
  }
  
  static int smc_accept(struct socket *sock, struct socket *new_sock,
cdfbabfb2   David Howells   net: Work around ...
1392
  		      int flags, bool kern)
ac7138746   Ursula Braun   smc: establish ne...
1393
  {
a046d57da   Ursula Braun   smc: CLC handshak...
1394
1395
  	struct sock *sk = sock->sk, *nsk;
  	DECLARE_WAITQUEUE(wait, current);
ac7138746   Ursula Braun   smc: establish ne...
1396
  	struct smc_sock *lsmc;
a046d57da   Ursula Braun   smc: CLC handshak...
1397
1398
  	long timeo;
  	int rc = 0;
ac7138746   Ursula Braun   smc: establish ne...
1399
1400
  
  	lsmc = smc_sk(sk);
51f1de79a   Ursula Braun   net/smc: replace ...
1401
  	sock_hold(sk); /* sock_put below */
ac7138746   Ursula Braun   smc: establish ne...
1402
1403
1404
1405
  	lock_sock(sk);
  
  	if (lsmc->sk.sk_state != SMC_LISTEN) {
  		rc = -EINVAL;
abb190f19   Ursula Braun   net/smc: handle s...
1406
  		release_sock(sk);
ac7138746   Ursula Braun   smc: establish ne...
1407
1408
  		goto out;
  	}
a046d57da   Ursula Braun   smc: CLC handshak...
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
  	/* Wait for an incoming connection */
  	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
  	add_wait_queue_exclusive(sk_sleep(sk), &wait);
  	while (!(nsk = smc_accept_dequeue(sk, new_sock))) {
  		set_current_state(TASK_INTERRUPTIBLE);
  		if (!timeo) {
  			rc = -EAGAIN;
  			break;
  		}
  		release_sock(sk);
  		timeo = schedule_timeout(timeo);
  		/* wakeup by sk_data_ready in smc_listen_work() */
  		sched_annotate_sleep();
  		lock_sock(sk);
  		if (signal_pending(current)) {
  			rc = sock_intr_errno(timeo);
  			break;
  		}
  	}
  	set_current_state(TASK_RUNNING);
  	remove_wait_queue(sk_sleep(sk), &wait);
ac7138746   Ursula Braun   smc: establish ne...
1430

a046d57da   Ursula Braun   smc: CLC handshak...
1431
1432
  	if (!rc)
  		rc = sock_error(nsk);
abb190f19   Ursula Braun   net/smc: handle s...
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
  	release_sock(sk);
  	if (rc)
  		goto out;
  
  	if (lsmc->sockopt_defer_accept && !(flags & O_NONBLOCK)) {
  		/* wait till data arrives on the socket */
  		timeo = msecs_to_jiffies(lsmc->sockopt_defer_accept *
  								MSEC_PER_SEC);
  		if (smc_sk(nsk)->use_fallback) {
  			struct sock *clcsk = smc_sk(nsk)->clcsock->sk;
  
  			lock_sock(clcsk);
  			if (skb_queue_empty(&clcsk->sk_receive_queue))
  				sk_wait_data(clcsk, &timeo, NULL);
  			release_sock(clcsk);
  		} else if (!atomic_read(&smc_sk(nsk)->conn.bytes_to_rcv)) {
  			lock_sock(nsk);
b51fa1b13   Stefan Raspl   smc: make smc_rx_...
1450
  			smc_rx_wait(smc_sk(nsk), &timeo, smc_rx_data_available);
abb190f19   Ursula Braun   net/smc: handle s...
1451
1452
1453
  			release_sock(nsk);
  		}
  	}
ac7138746   Ursula Braun   smc: establish ne...
1454
1455
  
  out:
51f1de79a   Ursula Braun   net/smc: replace ...
1456
  	sock_put(sk); /* sock_hold above */
ac7138746   Ursula Braun   smc: establish ne...
1457
1458
1459
1460
  	return rc;
  }
  
  static int smc_getname(struct socket *sock, struct sockaddr *addr,
9b2c45d47   Denys Vlasenko   net: make getname...
1461
  		       int peer)
ac7138746   Ursula Braun   smc: establish ne...
1462
1463
  {
  	struct smc_sock *smc;
b38d73247   Ursula Braun   smc: socket closi...
1464
1465
  	if (peer && (sock->sk->sk_state != SMC_ACTIVE) &&
  	    (sock->sk->sk_state != SMC_APPCLOSEWAIT1))
ac7138746   Ursula Braun   smc: establish ne...
1466
1467
1468
  		return -ENOTCONN;
  
  	smc = smc_sk(sock->sk);
9b2c45d47   Denys Vlasenko   net: make getname...
1469
  	return smc->clcsock->ops->getname(smc->clcsock, addr, peer);
ac7138746   Ursula Braun   smc: establish ne...
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
  }
  
  static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc = -EPIPE;
  
  	smc = smc_sk(sk);
  	lock_sock(sk);
b38d73247   Ursula Braun   smc: socket closi...
1480
1481
1482
  	if ((sk->sk_state != SMC_ACTIVE) &&
  	    (sk->sk_state != SMC_APPCLOSEWAIT1) &&
  	    (sk->sk_state != SMC_INIT))
ac7138746   Ursula Braun   smc: establish ne...
1483
  		goto out;
ee9dfbef0   Ursula Braun   net/smc: handle s...
1484
1485
  
  	if (msg->msg_flags & MSG_FASTOPEN) {
cd2063604   Ursula Braun   net/smc: avoid fa...
1486
  		if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
07603b230   Ursula Braun   net/smc: propagat...
1487
  			smc_switch_to_fallback(smc);
603cc1498   Karsten Graul   net/smc: provide ...
1488
  			smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP;
ee9dfbef0   Ursula Braun   net/smc: handle s...
1489
1490
1491
1492
1493
  		} else {
  			rc = -EINVAL;
  			goto out;
  		}
  	}
ac7138746   Ursula Braun   smc: establish ne...
1494
1495
1496
  	if (smc->use_fallback)
  		rc = smc->clcsock->ops->sendmsg(smc->clcsock, msg, len);
  	else
e6727f390   Ursula Braun   smc: send data (t...
1497
  		rc = smc_tx_sendmsg(smc, msg, len);
ac7138746   Ursula Braun   smc: establish ne...
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
  out:
  	release_sock(sk);
  	return rc;
  }
  
  static int smc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
  		       int flags)
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc = -ENOTCONN;
  
  	smc = smc_sk(sk);
  	lock_sock(sk);
51c5aba3b   Karsten Graul   net/smc: recvmsg ...
1512
1513
1514
1515
1516
  	if (sk->sk_state == SMC_CLOSED && (sk->sk_shutdown & RCV_SHUTDOWN)) {
  		/* socket was connected before, no more data to read */
  		rc = 0;
  		goto out;
  	}
b38d73247   Ursula Braun   smc: socket closi...
1517
1518
1519
  	if ((sk->sk_state == SMC_INIT) ||
  	    (sk->sk_state == SMC_LISTEN) ||
  	    (sk->sk_state == SMC_CLOSED))
ac7138746   Ursula Braun   smc: establish ne...
1520
  		goto out;
b38d73247   Ursula Braun   smc: socket closi...
1521
1522
1523
1524
  	if (sk->sk_state == SMC_PEERFINCLOSEWAIT) {
  		rc = 0;
  		goto out;
  	}
9014db202   Stefan Raspl   smc: add support ...
1525
  	if (smc->use_fallback) {
ac7138746   Ursula Braun   smc: establish ne...
1526
  		rc = smc->clcsock->ops->recvmsg(smc->clcsock, msg, len, flags);
9014db202   Stefan Raspl   smc: add support ...
1527
1528
1529
1530
  	} else {
  		msg->msg_namelen = 0;
  		rc = smc_rx_recvmsg(smc, msg, NULL, len, flags);
  	}
b38d73247   Ursula Braun   smc: socket closi...
1531

ac7138746   Ursula Braun   smc: establish ne...
1532
1533
1534
1535
  out:
  	release_sock(sk);
  	return rc;
  }
ade994f4f   Al Viro   net: annotate ->p...
1536
  static __poll_t smc_accept_poll(struct sock *parent)
a046d57da   Ursula Braun   smc: CLC handshak...
1537
  {
8dce2786a   Ursula Braun   net/smc: smc_poll...
1538
  	struct smc_sock *isk = smc_sk(parent);
63e2480c8   Al Viro   smc: missing poll...
1539
  	__poll_t mask = 0;
a046d57da   Ursula Braun   smc: CLC handshak...
1540

8dce2786a   Ursula Braun   net/smc: smc_poll...
1541
1542
  	spin_lock(&isk->accept_q_lock);
  	if (!list_empty(&isk->accept_q))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1543
  		mask = EPOLLIN | EPOLLRDNORM;
8dce2786a   Ursula Braun   net/smc: smc_poll...
1544
  	spin_unlock(&isk->accept_q_lock);
a046d57da   Ursula Braun   smc: CLC handshak...
1545

8dce2786a   Ursula Braun   net/smc: smc_poll...
1546
  	return mask;
a046d57da   Ursula Braun   smc: CLC handshak...
1547
  }
a11e1d432   Linus Torvalds   Revert changes to...
1548
1549
  static __poll_t smc_poll(struct file *file, struct socket *sock,
  			     poll_table *wait)
ac7138746   Ursula Braun   smc: establish ne...
1550
1551
  {
  	struct sock *sk = sock->sk;
ac7138746   Ursula Braun   smc: establish ne...
1552
  	struct smc_sock *smc;
50717a37d   Ursula Braun   net/smc: nonblock...
1553
  	__poll_t mask = 0;
ac7138746   Ursula Braun   smc: establish ne...
1554

8dce2786a   Ursula Braun   net/smc: smc_poll...
1555
  	if (!sk)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1556
  		return EPOLLNVAL;
8dce2786a   Ursula Braun   net/smc: smc_poll...
1557

ac7138746   Ursula Braun   smc: establish ne...
1558
  	smc = smc_sk(sock->sk);
648a5a7ae   Ursula Braun   net/smc: fix non-...
1559
  	if (smc->use_fallback) {
a046d57da   Ursula Braun   smc: CLC handshak...
1560
  		/* delegate to CLC child sock */
a11e1d432   Linus Torvalds   Revert changes to...
1561
  		mask = smc->clcsock->ops->poll(file, smc->clcsock, wait);
784813aed   Ursula Braun   net/smc: restrict...
1562
  		sk->sk_err = smc->clcsock->sk->sk_err;
ac7138746   Ursula Braun   smc: establish ne...
1563
  	} else {
410da1e12   Linus Torvalds   net/smc: fix up m...
1564
  		if (sk->sk_state != SMC_CLOSED)
89ab066d4   Karsten Graul   Revert "net: simp...
1565
  			sock_poll_wait(file, sock, wait);
a046d57da   Ursula Braun   smc: CLC handshak...
1566
  		if (sk->sk_err)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1567
  			mask |= EPOLLERR;
b38d73247   Ursula Braun   smc: socket closi...
1568
1569
  		if ((sk->sk_shutdown == SHUTDOWN_MASK) ||
  		    (sk->sk_state == SMC_CLOSED))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1570
  			mask |= EPOLLHUP;
8dce2786a   Ursula Braun   net/smc: smc_poll...
1571
1572
  		if (sk->sk_state == SMC_LISTEN) {
  			/* woken up by sk_data_ready in smc_listen_work() */
50717a37d   Ursula Braun   net/smc: nonblock...
1573
1574
1575
1576
1577
  			mask |= smc_accept_poll(sk);
  		} else if (smc->use_fallback) { /* as result of connect_work()*/
  			mask |= smc->clcsock->ops->poll(file, smc->clcsock,
  							   wait);
  			sk->sk_err = smc->clcsock->sk->sk_err;
8dce2786a   Ursula Braun   net/smc: smc_poll...
1578
  		} else {
50717a37d   Ursula Braun   net/smc: nonblock...
1579
1580
  			if ((sk->sk_state != SMC_INIT &&
  			     atomic_read(&smc->conn.sndbuf_space)) ||
8dce2786a   Ursula Braun   net/smc: smc_poll...
1581
  			    sk->sk_shutdown & SEND_SHUTDOWN) {
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1582
  				mask |= EPOLLOUT | EPOLLWRNORM;
8dce2786a   Ursula Braun   net/smc: smc_poll...
1583
1584
1585
1586
1587
  			} else {
  				sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
  				set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
  			}
  			if (atomic_read(&smc->conn.bytes_to_rcv))
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1588
  				mask |= EPOLLIN | EPOLLRDNORM;
8dce2786a   Ursula Braun   net/smc: smc_poll...
1589
  			if (sk->sk_shutdown & RCV_SHUTDOWN)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1590
  				mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
8dce2786a   Ursula Braun   net/smc: smc_poll...
1591
  			if (sk->sk_state == SMC_APPCLOSEWAIT1)
a9a08845e   Linus Torvalds   vfs: do bulk POLL...
1592
  				mask |= EPOLLIN;
71d117f52   Karsten Graul   net/smc: no urgen...
1593
1594
  			if (smc->conn.urg_state == SMC_URG_VALID)
  				mask |= EPOLLPRI;
8dce2786a   Ursula Braun   net/smc: smc_poll...
1595
  		}
ac7138746   Ursula Braun   smc: establish ne...
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
  	}
  
  	return mask;
  }
  
  static int smc_shutdown(struct socket *sock, int how)
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc = -EINVAL;
b38d73247   Ursula Braun   smc: socket closi...
1606
  	int rc1 = 0;
ac7138746   Ursula Braun   smc: establish ne...
1607
1608
1609
1610
  
  	smc = smc_sk(sk);
  
  	if ((how < SHUT_RD) || (how > SHUT_RDWR))
b38d73247   Ursula Braun   smc: socket closi...
1611
  		return rc;
ac7138746   Ursula Braun   smc: establish ne...
1612
1613
1614
1615
  
  	lock_sock(sk);
  
  	rc = -ENOTCONN;
caa21e19e   Ursula Braun   net/smc: no shutd...
1616
  	if ((sk->sk_state != SMC_ACTIVE) &&
b38d73247   Ursula Braun   smc: socket closi...
1617
1618
1619
1620
1621
  	    (sk->sk_state != SMC_PEERCLOSEWAIT1) &&
  	    (sk->sk_state != SMC_PEERCLOSEWAIT2) &&
  	    (sk->sk_state != SMC_APPCLOSEWAIT1) &&
  	    (sk->sk_state != SMC_APPCLOSEWAIT2) &&
  	    (sk->sk_state != SMC_APPFINCLOSEWAIT))
ac7138746   Ursula Braun   smc: establish ne...
1622
1623
1624
1625
1626
1627
  		goto out;
  	if (smc->use_fallback) {
  		rc = kernel_sock_shutdown(smc->clcsock, how);
  		sk->sk_shutdown = smc->clcsock->sk->sk_shutdown;
  		if (sk->sk_shutdown == SHUTDOWN_MASK)
  			sk->sk_state = SMC_CLOSED;
b38d73247   Ursula Braun   smc: socket closi...
1628
  		goto out;
ac7138746   Ursula Braun   smc: establish ne...
1629
  	}
b38d73247   Ursula Braun   smc: socket closi...
1630
1631
1632
1633
1634
1635
1636
1637
  	switch (how) {
  	case SHUT_RDWR:		/* shutdown in both directions */
  		rc = smc_close_active(smc);
  		break;
  	case SHUT_WR:
  		rc = smc_close_shutdown_write(smc);
  		break;
  	case SHUT_RD:
1255fcb2a   Ursula Braun   net/smc: fix shut...
1638
1639
  		rc = 0;
  		/* nothing more to do because peer is not involved */
b38d73247   Ursula Braun   smc: socket closi...
1640
1641
  		break;
  	}
1255fcb2a   Ursula Braun   net/smc: fix shut...
1642
1643
  	if (smc->clcsock)
  		rc1 = kernel_sock_shutdown(smc->clcsock, how);
b38d73247   Ursula Braun   smc: socket closi...
1644
1645
  	/* map sock_shutdown_cmd constants to sk_shutdown value range */
  	sk->sk_shutdown |= how + 1;
ac7138746   Ursula Braun   smc: establish ne...
1646
1647
1648
  
  out:
  	release_sock(sk);
b38d73247   Ursula Braun   smc: socket closi...
1649
  	return rc ? rc : rc1;
ac7138746   Ursula Braun   smc: establish ne...
1650
1651
1652
1653
1654
1655
1656
  }
  
  static int smc_setsockopt(struct socket *sock, int level, int optname,
  			  char __user *optval, unsigned int optlen)
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
01d2f7e2c   Ursula Braun   net/smc: sockopts...
1657
  	int val, rc;
ac7138746   Ursula Braun   smc: establish ne...
1658
1659
1660
1661
1662
1663
  
  	smc = smc_sk(sk);
  
  	/* generic setsockopts reaching us here always apply to the
  	 * CLC socket
  	 */
ee9dfbef0   Ursula Braun   net/smc: handle s...
1664
1665
1666
1667
1668
1669
  	rc = smc->clcsock->ops->setsockopt(smc->clcsock, level, optname,
  					   optval, optlen);
  	if (smc->clcsock->sk->sk_err) {
  		sk->sk_err = smc->clcsock->sk->sk_err;
  		sk->sk_error_report(sk);
  	}
ee9dfbef0   Ursula Braun   net/smc: handle s...
1670

01d2f7e2c   Ursula Braun   net/smc: sockopts...
1671
  	if (optlen < sizeof(int))
3dc9f558c   Wei Yongjun   net/smc: fix erro...
1672
  		return -EINVAL;
ac0107edb   Ursula Braun   net/smc: add erro...
1673
1674
  	if (get_user(val, (int __user *)optval))
  		return -EFAULT;
01d2f7e2c   Ursula Braun   net/smc: sockopts...
1675

ee9dfbef0   Ursula Braun   net/smc: handle s...
1676
  	lock_sock(sk);
86434744f   Ursula Braun   net/smc: add fall...
1677
1678
  	if (rc || smc->use_fallback)
  		goto out;
ee9dfbef0   Ursula Braun   net/smc: handle s...
1679
1680
1681
1682
1683
1684
1685
  	switch (optname) {
  	case TCP_ULP:
  	case TCP_FASTOPEN:
  	case TCP_FASTOPEN_CONNECT:
  	case TCP_FASTOPEN_KEY:
  	case TCP_FASTOPEN_NO_COOKIE:
  		/* option not supported by SMC */
8204df72b   Ursula Braun   net/smc: fix fast...
1686
  		if (sk->sk_state == SMC_INIT && !smc->connect_nonblock) {
07603b230   Ursula Braun   net/smc: propagat...
1687
  			smc_switch_to_fallback(smc);
603cc1498   Karsten Graul   net/smc: provide ...
1688
  			smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP;
ee9dfbef0   Ursula Braun   net/smc: handle s...
1689
  		} else {
86434744f   Ursula Braun   net/smc: add fall...
1690
  			rc = -EINVAL;
ee9dfbef0   Ursula Braun   net/smc: handle s...
1691
1692
  		}
  		break;
01d2f7e2c   Ursula Braun   net/smc: sockopts...
1693
  	case TCP_NODELAY:
f9cedf1a9   Ursula Braun   net/smc: do not s...
1694
1695
1696
  		if (sk->sk_state != SMC_INIT &&
  		    sk->sk_state != SMC_LISTEN &&
  		    sk->sk_state != SMC_CLOSED) {
86434744f   Ursula Braun   net/smc: add fall...
1697
  			if (val)
01d2f7e2c   Ursula Braun   net/smc: sockopts...
1698
1699
1700
1701
1702
  				mod_delayed_work(system_wq, &smc->conn.tx_work,
  						 0);
  		}
  		break;
  	case TCP_CORK:
f9cedf1a9   Ursula Braun   net/smc: do not s...
1703
1704
1705
  		if (sk->sk_state != SMC_INIT &&
  		    sk->sk_state != SMC_LISTEN &&
  		    sk->sk_state != SMC_CLOSED) {
86434744f   Ursula Braun   net/smc: add fall...
1706
  			if (!val)
01d2f7e2c   Ursula Braun   net/smc: sockopts...
1707
1708
1709
1710
  				mod_delayed_work(system_wq, &smc->conn.tx_work,
  						 0);
  		}
  		break;
abb190f19   Ursula Braun   net/smc: handle s...
1711
1712
1713
  	case TCP_DEFER_ACCEPT:
  		smc->sockopt_defer_accept = val;
  		break;
ee9dfbef0   Ursula Braun   net/smc: handle s...
1714
1715
1716
  	default:
  		break;
  	}
86434744f   Ursula Braun   net/smc: add fall...
1717
  out:
ee9dfbef0   Ursula Braun   net/smc: handle s...
1718
1719
1720
  	release_sock(sk);
  
  	return rc;
ac7138746   Ursula Braun   smc: establish ne...
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
  }
  
  static int smc_getsockopt(struct socket *sock, int level, int optname,
  			  char __user *optval, int __user *optlen)
  {
  	struct smc_sock *smc;
  
  	smc = smc_sk(sock->sk);
  	/* socket options apply to the CLC socket */
  	return smc->clcsock->ops->getsockopt(smc->clcsock, level, optname,
  					     optval, optlen);
  }
  
  static int smc_ioctl(struct socket *sock, unsigned int cmd,
  		     unsigned long arg)
  {
de8474eb9   Stefan Raspl   net/smc: urgent d...
1737
1738
  	union smc_host_cursor cons, urg;
  	struct smc_connection *conn;
ac7138746   Ursula Braun   smc: establish ne...
1739
  	struct smc_sock *smc;
9b67e26f9   Ursula Braun   net/smc: handle i...
1740
  	int answ;
ac7138746   Ursula Braun   smc: establish ne...
1741
1742
  
  	smc = smc_sk(sock->sk);
de8474eb9   Stefan Raspl   net/smc: urgent d...
1743
  	conn = &smc->conn;
7311d665c   Ursula Braun   net/smc: move soc...
1744
  	lock_sock(&smc->sk);
9b67e26f9   Ursula Braun   net/smc: handle i...
1745
  	if (smc->use_fallback) {
7311d665c   Ursula Braun   net/smc: move soc...
1746
1747
  		if (!smc->clcsock) {
  			release_sock(&smc->sk);
9b67e26f9   Ursula Braun   net/smc: handle i...
1748
  			return -EBADF;
7311d665c   Ursula Braun   net/smc: move soc...
1749
1750
1751
1752
  		}
  		answ = smc->clcsock->ops->ioctl(smc->clcsock, cmd, arg);
  		release_sock(&smc->sk);
  		return answ;
9b67e26f9   Ursula Braun   net/smc: handle i...
1753
1754
1755
  	}
  	switch (cmd) {
  	case SIOCINQ: /* same as FIONREAD */
1992d9988   Ursula Braun   net/smc: take soc...
1756
1757
  		if (smc->sk.sk_state == SMC_LISTEN) {
  			release_sock(&smc->sk);
9b67e26f9   Ursula Braun   net/smc: handle i...
1758
  			return -EINVAL;
1992d9988   Ursula Braun   net/smc: take soc...
1759
  		}
2351abe6f   Ursula Braun   net/smc: return 0...
1760
1761
1762
1763
1764
  		if (smc->sk.sk_state == SMC_INIT ||
  		    smc->sk.sk_state == SMC_CLOSED)
  			answ = 0;
  		else
  			answ = atomic_read(&smc->conn.bytes_to_rcv);
9b67e26f9   Ursula Braun   net/smc: handle i...
1765
1766
1767
  		break;
  	case SIOCOUTQ:
  		/* output queue size (not send + not acked) */
1992d9988   Ursula Braun   net/smc: take soc...
1768
1769
  		if (smc->sk.sk_state == SMC_LISTEN) {
  			release_sock(&smc->sk);
9b67e26f9   Ursula Braun   net/smc: handle i...
1770
  			return -EINVAL;
1992d9988   Ursula Braun   net/smc: take soc...
1771
  		}
2351abe6f   Ursula Braun   net/smc: return 0...
1772
1773
1774
1775
1776
  		if (smc->sk.sk_state == SMC_INIT ||
  		    smc->sk.sk_state == SMC_CLOSED)
  			answ = 0;
  		else
  			answ = smc->conn.sndbuf_desc->len -
9b67e26f9   Ursula Braun   net/smc: handle i...
1777
1778
1779
1780
  					atomic_read(&smc->conn.sndbuf_space);
  		break;
  	case SIOCOUTQNSD:
  		/* output queue size (not send only) */
1992d9988   Ursula Braun   net/smc: take soc...
1781
1782
  		if (smc->sk.sk_state == SMC_LISTEN) {
  			release_sock(&smc->sk);
9b67e26f9   Ursula Braun   net/smc: handle i...
1783
  			return -EINVAL;
1992d9988   Ursula Braun   net/smc: take soc...
1784
  		}
2351abe6f   Ursula Braun   net/smc: return 0...
1785
1786
1787
1788
1789
  		if (smc->sk.sk_state == SMC_INIT ||
  		    smc->sk.sk_state == SMC_CLOSED)
  			answ = 0;
  		else
  			answ = smc_tx_prepared_sends(&smc->conn);
9b67e26f9   Ursula Braun   net/smc: handle i...
1790
  		break;
de8474eb9   Stefan Raspl   net/smc: urgent d...
1791
  	case SIOCATMARK:
1992d9988   Ursula Braun   net/smc: take soc...
1792
1793
  		if (smc->sk.sk_state == SMC_LISTEN) {
  			release_sock(&smc->sk);
de8474eb9   Stefan Raspl   net/smc: urgent d...
1794
  			return -EINVAL;
1992d9988   Ursula Braun   net/smc: take soc...
1795
  		}
de8474eb9   Stefan Raspl   net/smc: urgent d...
1796
1797
1798
1799
  		if (smc->sk.sk_state == SMC_INIT ||
  		    smc->sk.sk_state == SMC_CLOSED) {
  			answ = 0;
  		} else {
bac6de7b6   Stefan Raspl   net/smc: eliminat...
1800
1801
  			smc_curs_copy(&cons, &conn->local_tx_ctrl.cons, conn);
  			smc_curs_copy(&urg, &conn->urg_curs, conn);
de8474eb9   Stefan Raspl   net/smc: urgent d...
1802
1803
1804
1805
  			answ = smc_curs_diff(conn->rmb_desc->len,
  					     &cons, &urg) == 1;
  		}
  		break;
9b67e26f9   Ursula Braun   net/smc: handle i...
1806
  	default:
1992d9988   Ursula Braun   net/smc: take soc...
1807
  		release_sock(&smc->sk);
9b67e26f9   Ursula Braun   net/smc: handle i...
1808
1809
  		return -ENOIOCTLCMD;
  	}
1992d9988   Ursula Braun   net/smc: take soc...
1810
  	release_sock(&smc->sk);
9b67e26f9   Ursula Braun   net/smc: handle i...
1811
1812
  
  	return put_user(answ, (int __user *)arg);
ac7138746   Ursula Braun   smc: establish ne...
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
  }
  
  static ssize_t smc_sendpage(struct socket *sock, struct page *page,
  			    int offset, size_t size, int flags)
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc = -EPIPE;
  
  	smc = smc_sk(sk);
  	lock_sock(sk);
bda27ff5c   Stefan Raspl   smc: fix sendpage...
1824
1825
  	if (sk->sk_state != SMC_ACTIVE) {
  		release_sock(sk);
ac7138746   Ursula Braun   smc: establish ne...
1826
  		goto out;
bda27ff5c   Stefan Raspl   smc: fix sendpage...
1827
1828
  	}
  	release_sock(sk);
ac7138746   Ursula Braun   smc: establish ne...
1829
1830
1831
1832
1833
1834
1835
  	if (smc->use_fallback)
  		rc = kernel_sendpage(smc->clcsock, page, offset,
  				     size, flags);
  	else
  		rc = sock_no_sendpage(sock, page, offset, size, flags);
  
  out:
ac7138746   Ursula Braun   smc: establish ne...
1836
1837
  	return rc;
  }
9014db202   Stefan Raspl   smc: add support ...
1838
1839
1840
1841
1842
1843
  /* Map the affected portions of the rmbe into an spd, note the number of bytes
   * to splice in conn->splice_pending, and press 'go'. Delays consumer cursor
   * updates till whenever a respective page has been fully processed.
   * Note that subsequent recv() calls have to wait till all splice() processing
   * completed.
   */
ac7138746   Ursula Braun   smc: establish ne...
1844
1845
  static ssize_t smc_splice_read(struct socket *sock, loff_t *ppos,
  			       struct pipe_inode_info *pipe, size_t len,
9014db202   Stefan Raspl   smc: add support ...
1846
  			       unsigned int flags)
ac7138746   Ursula Braun   smc: establish ne...
1847
1848
1849
1850
1851
1852
1853
  {
  	struct sock *sk = sock->sk;
  	struct smc_sock *smc;
  	int rc = -ENOTCONN;
  
  	smc = smc_sk(sk);
  	lock_sock(sk);
51c5aba3b   Karsten Graul   net/smc: recvmsg ...
1854
1855
1856
1857
1858
  	if (sk->sk_state == SMC_CLOSED && (sk->sk_shutdown & RCV_SHUTDOWN)) {
  		/* socket was connected before, no more data to read */
  		rc = 0;
  		goto out;
  	}
9014db202   Stefan Raspl   smc: add support ...
1859
1860
1861
1862
1863
1864
1865
  	if (sk->sk_state == SMC_INIT ||
  	    sk->sk_state == SMC_LISTEN ||
  	    sk->sk_state == SMC_CLOSED)
  		goto out;
  
  	if (sk->sk_state == SMC_PEERFINCLOSEWAIT) {
  		rc = 0;
ac7138746   Ursula Braun   smc: establish ne...
1866
  		goto out;
9014db202   Stefan Raspl   smc: add support ...
1867
  	}
ac7138746   Ursula Braun   smc: establish ne...
1868
1869
1870
1871
  	if (smc->use_fallback) {
  		rc = smc->clcsock->ops->splice_read(smc->clcsock, ppos,
  						    pipe, len, flags);
  	} else {
9014db202   Stefan Raspl   smc: add support ...
1872
1873
1874
1875
1876
1877
1878
1879
1880
  		if (*ppos) {
  			rc = -ESPIPE;
  			goto out;
  		}
  		if (flags & SPLICE_F_NONBLOCK)
  			flags = MSG_DONTWAIT;
  		else
  			flags = 0;
  		rc = smc_rx_recvmsg(smc, NULL, pipe, len, flags);
ac7138746   Ursula Braun   smc: establish ne...
1881
1882
1883
  	}
  out:
  	release_sock(sk);
9014db202   Stefan Raspl   smc: add support ...
1884

ac7138746   Ursula Braun   smc: establish ne...
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
  	return rc;
  }
  
  /* must look like tcp */
  static const struct proto_ops smc_sock_ops = {
  	.family		= PF_SMC,
  	.owner		= THIS_MODULE,
  	.release	= smc_release,
  	.bind		= smc_bind,
  	.connect	= smc_connect,
  	.socketpair	= sock_no_socketpair,
  	.accept		= smc_accept,
  	.getname	= smc_getname,
a11e1d432   Linus Torvalds   Revert changes to...
1898
  	.poll		= smc_poll,
ac7138746   Ursula Braun   smc: establish ne...
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
  	.ioctl		= smc_ioctl,
  	.listen		= smc_listen,
  	.shutdown	= smc_shutdown,
  	.setsockopt	= smc_setsockopt,
  	.getsockopt	= smc_getsockopt,
  	.sendmsg	= smc_sendmsg,
  	.recvmsg	= smc_recvmsg,
  	.mmap		= sock_no_mmap,
  	.sendpage	= smc_sendpage,
  	.splice_read	= smc_splice_read,
  };
  
  static int smc_create(struct net *net, struct socket *sock, int protocol,
  		      int kern)
  {
aaa4d33f6   Karsten Graul   net/smc: enable i...
1914
  	int family = (protocol == SMCPROTO_SMC6) ? PF_INET6 : PF_INET;
ac7138746   Ursula Braun   smc: establish ne...
1915
1916
1917
1918
1919
1920
1921
1922
1923
  	struct smc_sock *smc;
  	struct sock *sk;
  	int rc;
  
  	rc = -ESOCKTNOSUPPORT;
  	if (sock->type != SOCK_STREAM)
  		goto out;
  
  	rc = -EPROTONOSUPPORT;
aaa4d33f6   Karsten Graul   net/smc: enable i...
1924
  	if (protocol != SMCPROTO_SMC && protocol != SMCPROTO_SMC6)
ac7138746   Ursula Braun   smc: establish ne...
1925
1926
1927
1928
  		goto out;
  
  	rc = -ENOBUFS;
  	sock->ops = &smc_sock_ops;
aaa4d33f6   Karsten Graul   net/smc: enable i...
1929
  	sk = smc_sock_alloc(net, sock, protocol);
ac7138746   Ursula Braun   smc: establish ne...
1930
1931
1932
1933
1934
  	if (!sk)
  		goto out;
  
  	/* create internal TCP socket for CLC handshake and fallback */
  	smc = smc_sk(sk);
a046d57da   Ursula Braun   smc: CLC handshak...
1935
  	smc->use_fallback = false; /* assume rdma capability first */
603cc1498   Karsten Graul   net/smc: provide ...
1936
  	smc->fallback_rsn = 0;
aaa4d33f6   Karsten Graul   net/smc: enable i...
1937
1938
  	rc = sock_create_kern(net, family, SOCK_STREAM, IPPROTO_TCP,
  			      &smc->clcsock);
a5dcb73b9   Davide Caratti   net/smc: fix NULL...
1939
  	if (rc) {
ac7138746   Ursula Braun   smc: establish ne...
1940
  		sk_common_release(sk);
a5dcb73b9   Davide Caratti   net/smc: fix NULL...
1941
1942
  		goto out;
  	}
cd6851f30   Ursula Braun   smc: remote memor...
1943
1944
  	smc->sk.sk_sndbuf = max(smc->clcsock->sk->sk_sndbuf, SMC_BUF_MIN_SIZE);
  	smc->sk.sk_rcvbuf = max(smc->clcsock->sk->sk_rcvbuf, SMC_BUF_MIN_SIZE);
ac7138746   Ursula Braun   smc: establish ne...
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
  
  out:
  	return rc;
  }
  
  static const struct net_proto_family smc_sock_family_ops = {
  	.family	= PF_SMC,
  	.owner	= THIS_MODULE,
  	.create	= smc_create,
  };
64e28b52c   Hans Wippel   net/smc: add pnet...
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
  unsigned int smc_net_id;
  
  static __net_init int smc_net_init(struct net *net)
  {
  	return smc_pnet_net_init(net);
  }
  
  static void __net_exit smc_net_exit(struct net *net)
  {
  	smc_pnet_net_exit(net);
  }
  
  static struct pernet_operations smc_net_ops = {
  	.init = smc_net_init,
  	.exit = smc_net_exit,
  	.id   = &smc_net_id,
  	.size = sizeof(struct smc_net),
  };
ac7138746   Ursula Braun   smc: establish ne...
1973
1974
1975
  static int __init smc_init(void)
  {
  	int rc;
64e28b52c   Hans Wippel   net/smc: add pnet...
1976
1977
1978
  	rc = register_pernet_subsys(&smc_net_ops);
  	if (rc)
  		return rc;
6812baabf   Thomas Richter   smc: establish pn...
1979
1980
  	rc = smc_pnet_init();
  	if (rc)
8c33bf1b0   YueHaibing   net/smc: Fix erro...
1981
  		goto out_pernet_subsys;
6812baabf   Thomas Richter   smc: establish pn...
1982

6dabd4054   Ursula Braun   net/smc: introduc...
1983
1984
1985
1986
1987
1988
  	rc = smc_core_init();
  	if (rc) {
  		pr_err("%s: smc_core_init fails with %d
  ", __func__, rc);
  		goto out_pnet;
  	}
9bf9abead   Ursula Braun   smc: link layer c...
1989
1990
1991
1992
  	rc = smc_llc_init();
  	if (rc) {
  		pr_err("%s: smc_llc_init fails with %d
  ", __func__, rc);
6dabd4054   Ursula Braun   net/smc: introduc...
1993
  		goto out_core;
9bf9abead   Ursula Braun   smc: link layer c...
1994
  	}
5f08318f6   Ursula Braun   smc: connection d...
1995
1996
1997
1998
  	rc = smc_cdc_init();
  	if (rc) {
  		pr_err("%s: smc_cdc_init fails with %d
  ", __func__, rc);
6dabd4054   Ursula Braun   net/smc: introduc...
1999
  		goto out_core;
5f08318f6   Ursula Braun   smc: connection d...
2000
  	}
ac7138746   Ursula Braun   smc: establish ne...
2001
2002
  	rc = proto_register(&smc_proto, 1);
  	if (rc) {
aaa4d33f6   Karsten Graul   net/smc: enable i...
2003
2004
  		pr_err("%s: proto_register(v4) fails with %d
  ", __func__, rc);
6dabd4054   Ursula Braun   net/smc: introduc...
2005
  		goto out_core;
ac7138746   Ursula Braun   smc: establish ne...
2006
  	}
aaa4d33f6   Karsten Graul   net/smc: enable i...
2007
2008
2009
2010
2011
2012
  	rc = proto_register(&smc_proto6, 1);
  	if (rc) {
  		pr_err("%s: proto_register(v6) fails with %d
  ", __func__, rc);
  		goto out_proto;
  	}
ac7138746   Ursula Braun   smc: establish ne...
2013
2014
2015
2016
  	rc = sock_register(&smc_sock_family_ops);
  	if (rc) {
  		pr_err("%s: sock_register fails with %d
  ", __func__, rc);
aaa4d33f6   Karsten Graul   net/smc: enable i...
2017
  		goto out_proto6;
ac7138746   Ursula Braun   smc: establish ne...
2018
  	}
f16a7dd5c   Ursula Braun   smc: netlink inte...
2019
  	INIT_HLIST_HEAD(&smc_v4_hashinfo.ht);
aaa4d33f6   Karsten Graul   net/smc: enable i...
2020
  	INIT_HLIST_HEAD(&smc_v6_hashinfo.ht);
ac7138746   Ursula Braun   smc: establish ne...
2021

a4cf0443c   Ursula Braun   smc: introduce SM...
2022
2023
2024
2025
2026
2027
  	rc = smc_ib_register_client();
  	if (rc) {
  		pr_err("%s: ib_register fails with %d
  ", __func__, rc);
  		goto out_sock;
  	}
c5c1cc9c5   Ursula Braun   smc: add SMC rend...
2028
  	static_branch_enable(&tcp_have_smc);
ac7138746   Ursula Braun   smc: establish ne...
2029
  	return 0;
a4cf0443c   Ursula Braun   smc: introduce SM...
2030
2031
  out_sock:
  	sock_unregister(PF_SMC);
aaa4d33f6   Karsten Graul   net/smc: enable i...
2032
2033
  out_proto6:
  	proto_unregister(&smc_proto6);
ac7138746   Ursula Braun   smc: establish ne...
2034
2035
  out_proto:
  	proto_unregister(&smc_proto);
6dabd4054   Ursula Braun   net/smc: introduc...
2036
2037
  out_core:
  	smc_core_exit();
6812baabf   Thomas Richter   smc: establish pn...
2038
2039
  out_pnet:
  	smc_pnet_exit();
8c33bf1b0   YueHaibing   net/smc: Fix erro...
2040
2041
  out_pernet_subsys:
  	unregister_pernet_subsys(&smc_net_ops);
ac7138746   Ursula Braun   smc: establish ne...
2042
2043
2044
2045
2046
  	return rc;
  }
  
  static void __exit smc_exit(void)
  {
c5c1cc9c5   Ursula Braun   smc: add SMC rend...
2047
  	static_branch_disable(&tcp_have_smc);
ac7138746   Ursula Braun   smc: establish ne...
2048
  	sock_unregister(PF_SMC);
6dabd4054   Ursula Braun   net/smc: introduc...
2049
2050
  	smc_core_exit();
  	smc_ib_unregister_client();
aaa4d33f6   Karsten Graul   net/smc: enable i...
2051
  	proto_unregister(&smc_proto6);
ac7138746   Ursula Braun   smc: establish ne...
2052
  	proto_unregister(&smc_proto);
6812baabf   Thomas Richter   smc: establish pn...
2053
  	smc_pnet_exit();
64e28b52c   Hans Wippel   net/smc: add pnet...
2054
  	unregister_pernet_subsys(&smc_net_ops);
4ead9c96d   Ursula Braun   net/smc: use rcu_...
2055
  	rcu_barrier();
ac7138746   Ursula Braun   smc: establish ne...
2056
2057
2058
2059
2060
2061
2062
2063
2064
  }
  
  module_init(smc_init);
  module_exit(smc_exit);
  
  MODULE_AUTHOR("Ursula Braun <ubraun@linux.vnet.ibm.com>");
  MODULE_DESCRIPTION("smc socket address family");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_NETPROTO(PF_SMC);