Blame view

net/vmw_vsock/virtio_transport_common.c 28.4 KB
7a338472f   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
06a8fc783   Asias He   VSOCK: Introduce ...
2
3
4
5
6
7
  /*
   * common code for virtio vsock
   *
   * Copyright (C) 2013-2015 Red Hat, Inc.
   * Author: Asias He <asias@redhat.com>
   *         Stefan Hajnoczi <stefanha@redhat.com>
06a8fc783   Asias He   VSOCK: Introduce ...
8
9
10
   */
  #include <linux/spinlock.h>
  #include <linux/module.h>
174cd4b1e   Ingo Molnar   sched/headers: Pr...
11
  #include <linux/sched/signal.h>
06a8fc783   Asias He   VSOCK: Introduce ...
12
13
  #include <linux/ctype.h>
  #include <linux/list.h>
06a8fc783   Asias He   VSOCK: Introduce ...
14
  #include <linux/virtio_vsock.h>
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
15
  #include <uapi/linux/vsockmon.h>
06a8fc783   Asias He   VSOCK: Introduce ...
16
17
18
19
20
21
22
23
24
  
  #include <net/sock.h>
  #include <net/af_vsock.h>
  
  #define CREATE_TRACE_POINTS
  #include <trace/events/vsock_virtio_transport_common.h>
  
  /* How long to wait for graceful shutdown of a connection */
  #define VSOCK_CLOSE_TIMEOUT (8 * HZ)
473c7391c   Stefano Garzarella   vsock/virtio: lim...
25
26
  /* Threshold for detecting small packets to copy */
  #define GOOD_COPY_LEN  128
daabfbca3   Stefano Garzarella   vsock: add 'struc...
27
28
  static const struct virtio_transport *
  virtio_transport_get_ops(struct vsock_sock *vsk)
06a8fc783   Asias He   VSOCK: Introduce ...
29
  {
daabfbca3   Stefano Garzarella   vsock: add 'struc...
30
  	const struct vsock_transport *t = vsock_core_get_transport(vsk);
06a8fc783   Asias He   VSOCK: Introduce ...
31

4aaf59614   Stefano Garzarella   vsock/virtio: add...
32
33
  	if (WARN_ON(!t))
  		return NULL;
06a8fc783   Asias He   VSOCK: Introduce ...
34
35
  	return container_of(t, struct virtio_transport, transport);
  }
819483d80   Michael S. Tsirkin   vsock/virtio: mar...
36
  static struct virtio_vsock_pkt *
06a8fc783   Asias He   VSOCK: Introduce ...
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  virtio_transport_alloc_pkt(struct virtio_vsock_pkt_info *info,
  			   size_t len,
  			   u32 src_cid,
  			   u32 src_port,
  			   u32 dst_cid,
  			   u32 dst_port)
  {
  	struct virtio_vsock_pkt *pkt;
  	int err;
  
  	pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
  	if (!pkt)
  		return NULL;
  
  	pkt->hdr.type		= cpu_to_le16(info->type);
  	pkt->hdr.op		= cpu_to_le16(info->op);
  	pkt->hdr.src_cid	= cpu_to_le64(src_cid);
  	pkt->hdr.dst_cid	= cpu_to_le64(dst_cid);
  	pkt->hdr.src_port	= cpu_to_le32(src_port);
  	pkt->hdr.dst_port	= cpu_to_le32(dst_port);
  	pkt->hdr.flags		= cpu_to_le32(info->flags);
  	pkt->len		= len;
  	pkt->hdr.len		= cpu_to_le32(len);
  	pkt->reply		= info->reply;
36d277bac   Peng Tao   vsock: track pkt ...
61
  	pkt->vsk		= info->vsk;
06a8fc783   Asias He   VSOCK: Introduce ...
62
63
64
65
66
  
  	if (info->msg && len > 0) {
  		pkt->buf = kmalloc(len, GFP_KERNEL);
  		if (!pkt->buf)
  			goto out_pkt;
473c7391c   Stefano Garzarella   vsock/virtio: lim...
67
68
  
  		pkt->buf_len = len;
06a8fc783   Asias He   VSOCK: Introduce ...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  		err = memcpy_from_msg(pkt->buf, info->msg, len);
  		if (err)
  			goto out;
  	}
  
  	trace_virtio_transport_alloc_pkt(src_cid, src_port,
  					 dst_cid, dst_port,
  					 len,
  					 info->type,
  					 info->op,
  					 info->flags);
  
  	return pkt;
  
  out:
  	kfree(pkt->buf);
  out_pkt:
  	kfree(pkt);
  	return NULL;
  }
06a8fc783   Asias He   VSOCK: Introduce ...
89

82dfb540a   Gerard Garcia   VSOCK: Add virtio...
90
91
92
93
  /* Packet capture */
  static struct sk_buff *virtio_transport_build_skb(void *opaque)
  {
  	struct virtio_vsock_pkt *pkt = opaque;
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
94
95
  	struct af_vsockmon_hdr *hdr;
  	struct sk_buff *skb;
6dbd3e66e   Stefano Garzarella   vhost/vsock: spli...
96
97
  	size_t payload_len;
  	void *payload_buf;
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
98

6dbd3e66e   Stefano Garzarella   vhost/vsock: spli...
99
100
101
102
103
104
105
106
  	/* A packet could be split to fit the RX buffer, so we can retrieve
  	 * the payload length from the header and the buffer pointer taking
  	 * care of the offset in the original packet.
  	 */
  	payload_len = le32_to_cpu(pkt->hdr.len);
  	payload_buf = pkt->buf + pkt->off;
  
  	skb = alloc_skb(sizeof(*hdr) + sizeof(pkt->hdr) + payload_len,
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
107
108
109
  			GFP_ATOMIC);
  	if (!skb)
  		return NULL;
4df864c1d   Johannes Berg   networking: make ...
110
  	hdr = skb_put(skb, sizeof(*hdr));
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  
  	/* pkt->hdr is little-endian so no need to byteswap here */
  	hdr->src_cid = pkt->hdr.src_cid;
  	hdr->src_port = pkt->hdr.src_port;
  	hdr->dst_cid = pkt->hdr.dst_cid;
  	hdr->dst_port = pkt->hdr.dst_port;
  
  	hdr->transport = cpu_to_le16(AF_VSOCK_TRANSPORT_VIRTIO);
  	hdr->len = cpu_to_le16(sizeof(pkt->hdr));
  	memset(hdr->reserved, 0, sizeof(hdr->reserved));
  
  	switch (le16_to_cpu(pkt->hdr.op)) {
  	case VIRTIO_VSOCK_OP_REQUEST:
  	case VIRTIO_VSOCK_OP_RESPONSE:
  		hdr->op = cpu_to_le16(AF_VSOCK_OP_CONNECT);
  		break;
  	case VIRTIO_VSOCK_OP_RST:
  	case VIRTIO_VSOCK_OP_SHUTDOWN:
  		hdr->op = cpu_to_le16(AF_VSOCK_OP_DISCONNECT);
  		break;
  	case VIRTIO_VSOCK_OP_RW:
  		hdr->op = cpu_to_le16(AF_VSOCK_OP_PAYLOAD);
  		break;
  	case VIRTIO_VSOCK_OP_CREDIT_UPDATE:
  	case VIRTIO_VSOCK_OP_CREDIT_REQUEST:
  		hdr->op = cpu_to_le16(AF_VSOCK_OP_CONTROL);
  		break;
  	default:
  		hdr->op = cpu_to_le16(AF_VSOCK_OP_UNKNOWN);
  		break;
  	}
b952f4dff   yuan linyu   net: manual clean...
142
  	skb_put_data(skb, &pkt->hdr, sizeof(pkt->hdr));
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
143

6dbd3e66e   Stefano Garzarella   vhost/vsock: spli...
144
145
  	if (payload_len) {
  		skb_put_data(skb, payload_buf, payload_len);
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
146
147
148
149
150
151
152
  	}
  
  	return skb;
  }
  
  void virtio_transport_deliver_tap_pkt(struct virtio_vsock_pkt *pkt)
  {
a78d16397   Stefano Garzarella   vsock/virtio: fix...
153
154
  	if (pkt->tap_delivered)
  		return;
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
155
  	vsock_deliver_tap(virtio_transport_build_skb, pkt);
a78d16397   Stefano Garzarella   vsock/virtio: fix...
156
  	pkt->tap_delivered = true;
82dfb540a   Gerard Garcia   VSOCK: Add virtio...
157
158
  }
  EXPORT_SYMBOL_GPL(virtio_transport_deliver_tap_pkt);
4aaf59614   Stefano Garzarella   vsock/virtio: add...
159
160
161
162
163
  /* This function can only be used on connecting/connected sockets,
   * since a socket assigned to a transport is required.
   *
   * Do not use on listener sockets!
   */
06a8fc783   Asias He   VSOCK: Introduce ...
164
165
166
167
  static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
  					  struct virtio_vsock_pkt_info *info)
  {
  	u32 src_cid, src_port, dst_cid, dst_port;
4aaf59614   Stefano Garzarella   vsock/virtio: add...
168
  	const struct virtio_transport *t_ops;
06a8fc783   Asias He   VSOCK: Introduce ...
169
170
171
  	struct virtio_vsock_sock *vvs;
  	struct virtio_vsock_pkt *pkt;
  	u32 pkt_len = info->pkt_len;
4aaf59614   Stefano Garzarella   vsock/virtio: add...
172
173
174
175
176
  	t_ops = virtio_transport_get_ops(vsk);
  	if (unlikely(!t_ops))
  		return -EFAULT;
  
  	src_cid = t_ops->transport.get_local_cid();
06a8fc783   Asias He   VSOCK: Introduce ...
177
178
179
180
181
182
183
184
185
186
187
188
  	src_port = vsk->local_addr.svm_port;
  	if (!info->remote_cid) {
  		dst_cid	= vsk->remote_addr.svm_cid;
  		dst_port = vsk->remote_addr.svm_port;
  	} else {
  		dst_cid = info->remote_cid;
  		dst_port = info->remote_port;
  	}
  
  	vvs = vsk->trans;
  
  	/* we can send less than pkt_len bytes */
0038ff357   Stefano Garzarella   vsock/virtio: cha...
189
190
  	if (pkt_len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE)
  		pkt_len = VIRTIO_VSOCK_MAX_PKT_BUF_SIZE;
06a8fc783   Asias He   VSOCK: Introduce ...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  
  	/* virtio_transport_get_credit might return less than pkt_len credit */
  	pkt_len = virtio_transport_get_credit(vvs, pkt_len);
  
  	/* Do not send zero length OP_RW pkt */
  	if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW)
  		return pkt_len;
  
  	pkt = virtio_transport_alloc_pkt(info, pkt_len,
  					 src_cid, src_port,
  					 dst_cid, dst_port);
  	if (!pkt) {
  		virtio_transport_put_credit(vvs, pkt_len);
  		return -ENOMEM;
  	}
  
  	virtio_transport_inc_tx_pkt(vvs, pkt);
4aaf59614   Stefano Garzarella   vsock/virtio: add...
208
  	return t_ops->send_pkt(pkt);
06a8fc783   Asias He   VSOCK: Introduce ...
209
  }
ae6fcfbf5   Stefano Garzarella   vsock/virtio: dis...
210
  static bool virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs,
06a8fc783   Asias He   VSOCK: Introduce ...
211
212
  					struct virtio_vsock_pkt *pkt)
  {
ae6fcfbf5   Stefano Garzarella   vsock/virtio: dis...
213
214
  	if (vvs->rx_bytes + pkt->len > vvs->buf_alloc)
  		return false;
06a8fc783   Asias He   VSOCK: Introduce ...
215
  	vvs->rx_bytes += pkt->len;
ae6fcfbf5   Stefano Garzarella   vsock/virtio: dis...
216
  	return true;
06a8fc783   Asias He   VSOCK: Introduce ...
217
218
219
220
221
222
223
224
225
226
227
  }
  
  static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs,
  					struct virtio_vsock_pkt *pkt)
  {
  	vvs->rx_bytes -= pkt->len;
  	vvs->fwd_cnt += pkt->len;
  }
  
  void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct virtio_vsock_pkt *pkt)
  {
9632e9f61   Stefano Garzarella   vsock/virtio: fix...
228
  	spin_lock_bh(&vvs->rx_lock);
b89d882dc   Stefano Garzarella   vsock/virtio: red...
229
  	vvs->last_fwd_cnt = vvs->fwd_cnt;
06a8fc783   Asias He   VSOCK: Introduce ...
230
231
  	pkt->hdr.fwd_cnt = cpu_to_le32(vvs->fwd_cnt);
  	pkt->hdr.buf_alloc = cpu_to_le32(vvs->buf_alloc);
9632e9f61   Stefano Garzarella   vsock/virtio: fix...
232
  	spin_unlock_bh(&vvs->rx_lock);
06a8fc783   Asias He   VSOCK: Introduce ...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  }
  EXPORT_SYMBOL_GPL(virtio_transport_inc_tx_pkt);
  
  u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit)
  {
  	u32 ret;
  
  	spin_lock_bh(&vvs->tx_lock);
  	ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt);
  	if (ret > credit)
  		ret = credit;
  	vvs->tx_cnt += ret;
  	spin_unlock_bh(&vvs->tx_lock);
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_get_credit);
  
  void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit)
  {
  	spin_lock_bh(&vvs->tx_lock);
  	vvs->tx_cnt -= credit;
  	spin_unlock_bh(&vvs->tx_lock);
  }
  EXPORT_SYMBOL_GPL(virtio_transport_put_credit);
  
  static int virtio_transport_send_credit_update(struct vsock_sock *vsk,
  					       int type,
  					       struct virtio_vsock_hdr *hdr)
  {
  	struct virtio_vsock_pkt_info info = {
  		.op = VIRTIO_VSOCK_OP_CREDIT_UPDATE,
  		.type = type,
36d277bac   Peng Tao   vsock: track pkt ...
266
  		.vsk = vsk,
06a8fc783   Asias He   VSOCK: Introduce ...
267
268
269
270
271
272
  	};
  
  	return virtio_transport_send_pkt_info(vsk, &info);
  }
  
  static ssize_t
a786ab36a   Matias Ezequiel Vara Larsen   vsock/virtio: add...
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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  virtio_transport_stream_do_peek(struct vsock_sock *vsk,
  				struct msghdr *msg,
  				size_t len)
  {
  	struct virtio_vsock_sock *vvs = vsk->trans;
  	struct virtio_vsock_pkt *pkt;
  	size_t bytes, total = 0, off;
  	int err = -EFAULT;
  
  	spin_lock_bh(&vvs->rx_lock);
  
  	list_for_each_entry(pkt, &vvs->rx_queue, list) {
  		off = pkt->off;
  
  		if (total == len)
  			break;
  
  		while (total < len && off < pkt->len) {
  			bytes = len - total;
  			if (bytes > pkt->len - off)
  				bytes = pkt->len - off;
  
  			/* sk_lock is held by caller so no one else can dequeue.
  			 * Unlock rx_lock since memcpy_to_msg() may sleep.
  			 */
  			spin_unlock_bh(&vvs->rx_lock);
  
  			err = memcpy_to_msg(msg, pkt->buf + off, bytes);
  			if (err)
  				goto out;
  
  			spin_lock_bh(&vvs->rx_lock);
  
  			total += bytes;
  			off += bytes;
  		}
  	}
  
  	spin_unlock_bh(&vvs->rx_lock);
  
  	return total;
  
  out:
  	if (total)
  		err = total;
  	return err;
  }
  
  static ssize_t
06a8fc783   Asias He   VSOCK: Introduce ...
322
323
324
325
326
327
328
  virtio_transport_stream_do_dequeue(struct vsock_sock *vsk,
  				   struct msghdr *msg,
  				   size_t len)
  {
  	struct virtio_vsock_sock *vvs = vsk->trans;
  	struct virtio_vsock_pkt *pkt;
  	size_t bytes, total = 0;
b89d882dc   Stefano Garzarella   vsock/virtio: red...
329
  	u32 free_space;
06a8fc783   Asias He   VSOCK: Introduce ...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  	int err = -EFAULT;
  
  	spin_lock_bh(&vvs->rx_lock);
  	while (total < len && !list_empty(&vvs->rx_queue)) {
  		pkt = list_first_entry(&vvs->rx_queue,
  				       struct virtio_vsock_pkt, list);
  
  		bytes = len - total;
  		if (bytes > pkt->len - pkt->off)
  			bytes = pkt->len - pkt->off;
  
  		/* sk_lock is held by caller so no one else can dequeue.
  		 * Unlock rx_lock since memcpy_to_msg() may sleep.
  		 */
  		spin_unlock_bh(&vvs->rx_lock);
  
  		err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes);
  		if (err)
  			goto out;
  
  		spin_lock_bh(&vvs->rx_lock);
  
  		total += bytes;
  		pkt->off += bytes;
  		if (pkt->off == pkt->len) {
  			virtio_transport_dec_rx_pkt(vvs, pkt);
  			list_del(&pkt->list);
  			virtio_transport_free_pkt(pkt);
  		}
  	}
b89d882dc   Stefano Garzarella   vsock/virtio: red...
360
361
  
  	free_space = vvs->buf_alloc - (vvs->fwd_cnt - vvs->last_fwd_cnt);
06a8fc783   Asias He   VSOCK: Introduce ...
362
  	spin_unlock_bh(&vvs->rx_lock);
f4d7c8e3d   Michael S. Tsirkin   vsock/virtio: a b...
363
364
365
366
367
368
369
  	/* To reduce the number of credit update messages,
  	 * don't update credits as long as lots of space is available.
  	 * Note: the limit chosen here is arbitrary. Setting the limit
  	 * too high causes extra messages. Too low causes transmitter
  	 * stalls. As stalls are in theory more expensive than extra
  	 * messages, we set the limit to a high value. TODO: experiment
  	 * with different values.
b89d882dc   Stefano Garzarella   vsock/virtio: red...
370
371
372
373
374
375
  	 */
  	if (free_space < VIRTIO_VSOCK_MAX_PKT_BUF_SIZE) {
  		virtio_transport_send_credit_update(vsk,
  						    VIRTIO_VSOCK_TYPE_STREAM,
  						    NULL);
  	}
06a8fc783   Asias He   VSOCK: Introduce ...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  
  	return total;
  
  out:
  	if (total)
  		err = total;
  	return err;
  }
  
  ssize_t
  virtio_transport_stream_dequeue(struct vsock_sock *vsk,
  				struct msghdr *msg,
  				size_t len, int flags)
  {
  	if (flags & MSG_PEEK)
a786ab36a   Matias Ezequiel Vara Larsen   vsock/virtio: add...
391
392
393
  		return virtio_transport_stream_do_peek(vsk, msg, len);
  	else
  		return virtio_transport_stream_do_dequeue(vsk, msg, len);
06a8fc783   Asias He   VSOCK: Introduce ...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
  }
  EXPORT_SYMBOL_GPL(virtio_transport_stream_dequeue);
  
  int
  virtio_transport_dgram_dequeue(struct vsock_sock *vsk,
  			       struct msghdr *msg,
  			       size_t len, int flags)
  {
  	return -EOPNOTSUPP;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_dgram_dequeue);
  
  s64 virtio_transport_stream_has_data(struct vsock_sock *vsk)
  {
  	struct virtio_vsock_sock *vvs = vsk->trans;
  	s64 bytes;
  
  	spin_lock_bh(&vvs->rx_lock);
  	bytes = vvs->rx_bytes;
  	spin_unlock_bh(&vvs->rx_lock);
  
  	return bytes;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_stream_has_data);
  
  static s64 virtio_transport_has_space(struct vsock_sock *vsk)
  {
  	struct virtio_vsock_sock *vvs = vsk->trans;
  	s64 bytes;
  
  	bytes = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt);
  	if (bytes < 0)
  		bytes = 0;
  
  	return bytes;
  }
  
  s64 virtio_transport_stream_has_space(struct vsock_sock *vsk)
  {
  	struct virtio_vsock_sock *vvs = vsk->trans;
  	s64 bytes;
  
  	spin_lock_bh(&vvs->tx_lock);
  	bytes = virtio_transport_has_space(vsk);
  	spin_unlock_bh(&vvs->tx_lock);
  
  	return bytes;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_stream_has_space);
  
  int virtio_transport_do_socket_init(struct vsock_sock *vsk,
  				    struct vsock_sock *psk)
  {
  	struct virtio_vsock_sock *vvs;
  
  	vvs = kzalloc(sizeof(*vvs), GFP_KERNEL);
  	if (!vvs)
  		return -ENOMEM;
  
  	vsk->trans = vvs;
  	vvs->vsk = vsk;
c0cfa2d8a   Stefano Garzarella   vsock: add multi-...
455
  	if (psk && psk->trans) {
06a8fc783   Asias He   VSOCK: Introduce ...
456
  		struct virtio_vsock_sock *ptrans = psk->trans;
06a8fc783   Asias He   VSOCK: Introduce ...
457
  		vvs->peer_buf_alloc = ptrans->peer_buf_alloc;
06a8fc783   Asias He   VSOCK: Introduce ...
458
  	}
b9f2b0ffd   Stefano Garzarella   vsock: handle buf...
459
460
461
462
  	if (vsk->buffer_size > VIRTIO_VSOCK_MAX_BUF_SIZE)
  		vsk->buffer_size = VIRTIO_VSOCK_MAX_BUF_SIZE;
  
  	vvs->buf_alloc = vsk->buffer_size;
06a8fc783   Asias He   VSOCK: Introduce ...
463
464
465
466
467
468
469
470
  
  	spin_lock_init(&vvs->rx_lock);
  	spin_lock_init(&vvs->tx_lock);
  	INIT_LIST_HEAD(&vvs->rx_queue);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_do_socket_init);
b9f2b0ffd   Stefano Garzarella   vsock: handle buf...
471
472
  /* sk_lock held by the caller */
  void virtio_transport_notify_buffer_size(struct vsock_sock *vsk, u64 *val)
06a8fc783   Asias He   VSOCK: Introduce ...
473
474
  {
  	struct virtio_vsock_sock *vvs = vsk->trans;
b9f2b0ffd   Stefano Garzarella   vsock: handle buf...
475
476
  	if (*val > VIRTIO_VSOCK_MAX_BUF_SIZE)
  		*val = VIRTIO_VSOCK_MAX_BUF_SIZE;
06a8fc783   Asias He   VSOCK: Introduce ...
477

b9f2b0ffd   Stefano Garzarella   vsock: handle buf...
478
  	vvs->buf_alloc = *val;
ec3359b68   Stefano Garzarella   vsock/virtio: sen...
479
480
481
  
  	virtio_transport_send_credit_update(vsk, VIRTIO_VSOCK_TYPE_STREAM,
  					    NULL);
06a8fc783   Asias He   VSOCK: Introduce ...
482
  }
b9f2b0ffd   Stefano Garzarella   vsock: handle buf...
483
  EXPORT_SYMBOL_GPL(virtio_transport_notify_buffer_size);
06a8fc783   Asias He   VSOCK: Introduce ...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  
  int
  virtio_transport_notify_poll_in(struct vsock_sock *vsk,
  				size_t target,
  				bool *data_ready_now)
  {
  	if (vsock_stream_has_data(vsk))
  		*data_ready_now = true;
  	else
  		*data_ready_now = false;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_in);
  
  int
  virtio_transport_notify_poll_out(struct vsock_sock *vsk,
  				 size_t target,
  				 bool *space_avail_now)
  {
  	s64 free_space;
  
  	free_space = vsock_stream_has_space(vsk);
  	if (free_space > 0)
  		*space_avail_now = true;
  	else if (free_space == 0)
  		*space_avail_now = false;
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_out);
  
  int virtio_transport_notify_recv_init(struct vsock_sock *vsk,
  	size_t target, struct vsock_transport_recv_notify_data *data)
  {
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_init);
  
  int virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk,
  	size_t target, struct vsock_transport_recv_notify_data *data)
  {
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_block);
  
  int virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk,
  	size_t target, struct vsock_transport_recv_notify_data *data)
  {
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_dequeue);
  
  int virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk,
  	size_t target, ssize_t copied, bool data_read,
  	struct vsock_transport_recv_notify_data *data)
  {
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_post_dequeue);
  
  int virtio_transport_notify_send_init(struct vsock_sock *vsk,
  	struct vsock_transport_send_notify_data *data)
  {
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_send_init);
  
  int virtio_transport_notify_send_pre_block(struct vsock_sock *vsk,
  	struct vsock_transport_send_notify_data *data)
  {
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_block);
  
  int virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk,
  	struct vsock_transport_send_notify_data *data)
  {
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_enqueue);
  
  int virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk,
  	ssize_t written, struct vsock_transport_send_notify_data *data)
  {
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_notify_send_post_enqueue);
  
  u64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk)
  {
b9f2b0ffd   Stefano Garzarella   vsock: handle buf...
575
  	return vsk->buffer_size;
06a8fc783   Asias He   VSOCK: Introduce ...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
  }
  EXPORT_SYMBOL_GPL(virtio_transport_stream_rcvhiwat);
  
  bool virtio_transport_stream_is_active(struct vsock_sock *vsk)
  {
  	return true;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_stream_is_active);
  
  bool virtio_transport_stream_allow(u32 cid, u32 port)
  {
  	return true;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_stream_allow);
  
  int virtio_transport_dgram_bind(struct vsock_sock *vsk,
  				struct sockaddr_vm *addr)
  {
  	return -EOPNOTSUPP;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_dgram_bind);
  
  bool virtio_transport_dgram_allow(u32 cid, u32 port)
  {
  	return false;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_dgram_allow);
  
  int virtio_transport_connect(struct vsock_sock *vsk)
  {
  	struct virtio_vsock_pkt_info info = {
  		.op = VIRTIO_VSOCK_OP_REQUEST,
  		.type = VIRTIO_VSOCK_TYPE_STREAM,
36d277bac   Peng Tao   vsock: track pkt ...
609
  		.vsk = vsk,
06a8fc783   Asias He   VSOCK: Introduce ...
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
  	};
  
  	return virtio_transport_send_pkt_info(vsk, &info);
  }
  EXPORT_SYMBOL_GPL(virtio_transport_connect);
  
  int virtio_transport_shutdown(struct vsock_sock *vsk, int mode)
  {
  	struct virtio_vsock_pkt_info info = {
  		.op = VIRTIO_VSOCK_OP_SHUTDOWN,
  		.type = VIRTIO_VSOCK_TYPE_STREAM,
  		.flags = (mode & RCV_SHUTDOWN ?
  			  VIRTIO_VSOCK_SHUTDOWN_RCV : 0) |
  			 (mode & SEND_SHUTDOWN ?
  			  VIRTIO_VSOCK_SHUTDOWN_SEND : 0),
36d277bac   Peng Tao   vsock: track pkt ...
625
  		.vsk = vsk,
06a8fc783   Asias He   VSOCK: Introduce ...
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
  	};
  
  	return virtio_transport_send_pkt_info(vsk, &info);
  }
  EXPORT_SYMBOL_GPL(virtio_transport_shutdown);
  
  int
  virtio_transport_dgram_enqueue(struct vsock_sock *vsk,
  			       struct sockaddr_vm *remote_addr,
  			       struct msghdr *msg,
  			       size_t dgram_len)
  {
  	return -EOPNOTSUPP;
  }
  EXPORT_SYMBOL_GPL(virtio_transport_dgram_enqueue);
  
  ssize_t
  virtio_transport_stream_enqueue(struct vsock_sock *vsk,
  				struct msghdr *msg,
  				size_t len)
  {
  	struct virtio_vsock_pkt_info info = {
  		.op = VIRTIO_VSOCK_OP_RW,
  		.type = VIRTIO_VSOCK_TYPE_STREAM,
  		.msg = msg,
  		.pkt_len = len,
36d277bac   Peng Tao   vsock: track pkt ...
652
  		.vsk = vsk,
06a8fc783   Asias He   VSOCK: Introduce ...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
  	};
  
  	return virtio_transport_send_pkt_info(vsk, &info);
  }
  EXPORT_SYMBOL_GPL(virtio_transport_stream_enqueue);
  
  void virtio_transport_destruct(struct vsock_sock *vsk)
  {
  	struct virtio_vsock_sock *vvs = vsk->trans;
  
  	kfree(vvs);
  }
  EXPORT_SYMBOL_GPL(virtio_transport_destruct);
  
  static int virtio_transport_reset(struct vsock_sock *vsk,
  				  struct virtio_vsock_pkt *pkt)
  {
  	struct virtio_vsock_pkt_info info = {
  		.op = VIRTIO_VSOCK_OP_RST,
  		.type = VIRTIO_VSOCK_TYPE_STREAM,
  		.reply = !!pkt,
36d277bac   Peng Tao   vsock: track pkt ...
674
  		.vsk = vsk,
06a8fc783   Asias He   VSOCK: Introduce ...
675
676
677
678
679
680
681
682
683
684
685
686
  	};
  
  	/* Send RST only if the original pkt is not a RST pkt */
  	if (pkt && le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST)
  		return 0;
  
  	return virtio_transport_send_pkt_info(vsk, &info);
  }
  
  /* Normally packets are associated with a socket.  There may be no socket if an
   * attempt was made to connect to a socket that does not exist.
   */
4c7246dc4   Stefano Garzarella   vsock/virtio: add...
687
688
  static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
  					  struct virtio_vsock_pkt *pkt)
06a8fc783   Asias He   VSOCK: Introduce ...
689
  {
4c404ce23   Adalbert Lazăr   vsock/virtio: fix...
690
  	struct virtio_vsock_pkt *reply;
06a8fc783   Asias He   VSOCK: Introduce ...
691
692
693
694
695
696
697
698
699
  	struct virtio_vsock_pkt_info info = {
  		.op = VIRTIO_VSOCK_OP_RST,
  		.type = le16_to_cpu(pkt->hdr.type),
  		.reply = true,
  	};
  
  	/* Send RST only if the original pkt is not a RST pkt */
  	if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST)
  		return 0;
4c404ce23   Adalbert Lazăr   vsock/virtio: fix...
700
701
702
703
704
705
  	reply = virtio_transport_alloc_pkt(&info, 0,
  					   le64_to_cpu(pkt->hdr.dst_cid),
  					   le32_to_cpu(pkt->hdr.dst_port),
  					   le64_to_cpu(pkt->hdr.src_cid),
  					   le32_to_cpu(pkt->hdr.src_port));
  	if (!reply)
06a8fc783   Asias He   VSOCK: Introduce ...
706
  		return -ENOMEM;
4c404ce23   Adalbert Lazăr   vsock/virtio: fix...
707
708
709
710
711
712
  	if (!t) {
  		virtio_transport_free_pkt(reply);
  		return -ENOTCONN;
  	}
  
  	return t->send_pkt(reply);
06a8fc783   Asias He   VSOCK: Introduce ...
713
714
715
716
717
  }
  
  static void virtio_transport_wait_close(struct sock *sk, long timeout)
  {
  	if (timeout) {
d9dc8b0f8   WANG Cong   net: fix sleeping...
718
719
720
  		DEFINE_WAIT_FUNC(wait, woken_wake_function);
  
  		add_wait_queue(sk_sleep(sk), &wait);
06a8fc783   Asias He   VSOCK: Introduce ...
721
722
  
  		do {
06a8fc783   Asias He   VSOCK: Introduce ...
723
  			if (sk_wait_event(sk, &timeout,
d9dc8b0f8   WANG Cong   net: fix sleeping...
724
  					  sock_flag(sk, SOCK_DONE), &wait))
06a8fc783   Asias He   VSOCK: Introduce ...
725
726
  				break;
  		} while (!signal_pending(current) && timeout);
d9dc8b0f8   WANG Cong   net: fix sleeping...
727
  		remove_wait_queue(sk_sleep(sk), &wait);
06a8fc783   Asias He   VSOCK: Introduce ...
728
729
730
731
732
733
734
735
736
737
738
  	}
  }
  
  static void virtio_transport_do_close(struct vsock_sock *vsk,
  				      bool cancel_timeout)
  {
  	struct sock *sk = sk_vsock(vsk);
  
  	sock_set_flag(sk, SOCK_DONE);
  	vsk->peer_shutdown = SHUTDOWN_MASK;
  	if (vsock_stream_has_data(vsk) <= 0)
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
739
  		sk->sk_state = TCP_CLOSING;
06a8fc783   Asias He   VSOCK: Introduce ...
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
  	sk->sk_state_change(sk);
  
  	if (vsk->close_work_scheduled &&
  	    (!cancel_timeout || cancel_delayed_work(&vsk->close_work))) {
  		vsk->close_work_scheduled = false;
  
  		vsock_remove_sock(vsk);
  
  		/* Release refcnt obtained when we scheduled the timeout */
  		sock_put(sk);
  	}
  }
  
  static void virtio_transport_close_timeout(struct work_struct *work)
  {
  	struct vsock_sock *vsk =
  		container_of(work, struct vsock_sock, close_work.work);
  	struct sock *sk = sk_vsock(vsk);
  
  	sock_hold(sk);
  	lock_sock(sk);
  
  	if (!sock_flag(sk, SOCK_DONE)) {
  		(void)virtio_transport_reset(vsk, NULL);
  
  		virtio_transport_do_close(vsk, false);
  	}
  
  	vsk->close_work_scheduled = false;
  
  	release_sock(sk);
  	sock_put(sk);
  }
  
  /* User context, vsk->sk is locked */
  static bool virtio_transport_close(struct vsock_sock *vsk)
  {
  	struct sock *sk = &vsk->sk;
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
778
779
  	if (!(sk->sk_state == TCP_ESTABLISHED ||
  	      sk->sk_state == TCP_CLOSING))
06a8fc783   Asias He   VSOCK: Introduce ...
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
  		return true;
  
  	/* Already received SHUTDOWN from peer, reply with RST */
  	if ((vsk->peer_shutdown & SHUTDOWN_MASK) == SHUTDOWN_MASK) {
  		(void)virtio_transport_reset(vsk, NULL);
  		return true;
  	}
  
  	if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK)
  		(void)virtio_transport_shutdown(vsk, SHUTDOWN_MASK);
  
  	if (sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING))
  		virtio_transport_wait_close(sk, sk->sk_lingertime);
  
  	if (sock_flag(sk, SOCK_DONE)) {
  		return true;
  	}
  
  	sock_hold(sk);
  	INIT_DELAYED_WORK(&vsk->close_work,
  			  virtio_transport_close_timeout);
  	vsk->close_work_scheduled = true;
  	schedule_delayed_work(&vsk->close_work, VSOCK_CLOSE_TIMEOUT);
  	return false;
  }
  
  void virtio_transport_release(struct vsock_sock *vsk)
  {
ac03046ec   Stefano Garzarella   vsock/virtio: fre...
808
809
  	struct virtio_vsock_sock *vvs = vsk->trans;
  	struct virtio_vsock_pkt *pkt, *tmp;
06a8fc783   Asias He   VSOCK: Introduce ...
810
811
  	struct sock *sk = &vsk->sk;
  	bool remove_sock = true;
06a8fc783   Asias He   VSOCK: Introduce ...
812
813
  	if (sk->sk_type == SOCK_STREAM)
  		remove_sock = virtio_transport_close(vsk);
ac03046ec   Stefano Garzarella   vsock/virtio: fre...
814
815
816
817
818
  
  	list_for_each_entry_safe(pkt, tmp, &vvs->rx_queue, list) {
  		list_del(&pkt->list);
  		virtio_transport_free_pkt(pkt);
  	}
06a8fc783   Asias He   VSOCK: Introduce ...
819

3fe356d58   Stefano Garzarella   vsock/virtio: dis...
820
821
  	if (remove_sock) {
  		sock_set_flag(sk, SOCK_DONE);
06a8fc783   Asias He   VSOCK: Introduce ...
822
  		vsock_remove_sock(vsk);
3fe356d58   Stefano Garzarella   vsock/virtio: dis...
823
  	}
06a8fc783   Asias He   VSOCK: Introduce ...
824
825
826
827
828
829
830
831
832
833
834
835
836
  }
  EXPORT_SYMBOL_GPL(virtio_transport_release);
  
  static int
  virtio_transport_recv_connecting(struct sock *sk,
  				 struct virtio_vsock_pkt *pkt)
  {
  	struct vsock_sock *vsk = vsock_sk(sk);
  	int err;
  	int skerr;
  
  	switch (le16_to_cpu(pkt->hdr.op)) {
  	case VIRTIO_VSOCK_OP_RESPONSE:
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
837
  		sk->sk_state = TCP_ESTABLISHED;
06a8fc783   Asias He   VSOCK: Introduce ...
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  		sk->sk_socket->state = SS_CONNECTED;
  		vsock_insert_connected(vsk);
  		sk->sk_state_change(sk);
  		break;
  	case VIRTIO_VSOCK_OP_INVALID:
  		break;
  	case VIRTIO_VSOCK_OP_RST:
  		skerr = ECONNRESET;
  		err = 0;
  		goto destroy;
  	default:
  		skerr = EPROTO;
  		err = -EINVAL;
  		goto destroy;
  	}
  	return 0;
  
  destroy:
  	virtio_transport_reset(vsk, pkt);
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
857
  	sk->sk_state = TCP_CLOSE;
06a8fc783   Asias He   VSOCK: Introduce ...
858
859
860
861
  	sk->sk_err = skerr;
  	sk->sk_error_report(sk);
  	return err;
  }
473c7391c   Stefano Garzarella   vsock/virtio: lim...
862
863
864
865
866
  static void
  virtio_transport_recv_enqueue(struct vsock_sock *vsk,
  			      struct virtio_vsock_pkt *pkt)
  {
  	struct virtio_vsock_sock *vvs = vsk->trans;
ae6fcfbf5   Stefano Garzarella   vsock/virtio: dis...
867
  	bool can_enqueue, free_pkt = false;
473c7391c   Stefano Garzarella   vsock/virtio: lim...
868
869
870
871
872
  
  	pkt->len = le32_to_cpu(pkt->hdr.len);
  	pkt->off = 0;
  
  	spin_lock_bh(&vvs->rx_lock);
ae6fcfbf5   Stefano Garzarella   vsock/virtio: dis...
873
874
875
876
877
  	can_enqueue = virtio_transport_inc_rx_pkt(vvs, pkt);
  	if (!can_enqueue) {
  		free_pkt = true;
  		goto out;
  	}
473c7391c   Stefano Garzarella   vsock/virtio: lim...
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
  
  	/* Try to copy small packets into the buffer of last packet queued,
  	 * to avoid wasting memory queueing the entire buffer with a small
  	 * payload.
  	 */
  	if (pkt->len <= GOOD_COPY_LEN && !list_empty(&vvs->rx_queue)) {
  		struct virtio_vsock_pkt *last_pkt;
  
  		last_pkt = list_last_entry(&vvs->rx_queue,
  					   struct virtio_vsock_pkt, list);
  
  		/* If there is space in the last packet queued, we copy the
  		 * new packet in its buffer.
  		 */
  		if (pkt->len <= last_pkt->buf_len - last_pkt->len) {
  			memcpy(last_pkt->buf + last_pkt->len, pkt->buf,
  			       pkt->len);
  			last_pkt->len += pkt->len;
  			free_pkt = true;
  			goto out;
  		}
  	}
  
  	list_add_tail(&pkt->list, &vvs->rx_queue);
  
  out:
  	spin_unlock_bh(&vvs->rx_lock);
  	if (free_pkt)
  		virtio_transport_free_pkt(pkt);
  }
06a8fc783   Asias He   VSOCK: Introduce ...
908
909
910
911
912
  static int
  virtio_transport_recv_connected(struct sock *sk,
  				struct virtio_vsock_pkt *pkt)
  {
  	struct vsock_sock *vsk = vsock_sk(sk);
06a8fc783   Asias He   VSOCK: Introduce ...
913
914
915
916
  	int err = 0;
  
  	switch (le16_to_cpu(pkt->hdr.op)) {
  	case VIRTIO_VSOCK_OP_RW:
473c7391c   Stefano Garzarella   vsock/virtio: lim...
917
  		virtio_transport_recv_enqueue(vsk, pkt);
06a8fc783   Asias He   VSOCK: Introduce ...
918
919
920
921
922
923
924
925
926
927
928
  		sk->sk_data_ready(sk);
  		return err;
  	case VIRTIO_VSOCK_OP_CREDIT_UPDATE:
  		sk->sk_write_space(sk);
  		break;
  	case VIRTIO_VSOCK_OP_SHUTDOWN:
  		if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_RCV)
  			vsk->peer_shutdown |= RCV_SHUTDOWN;
  		if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_SEND)
  			vsk->peer_shutdown |= SEND_SHUTDOWN;
  		if (vsk->peer_shutdown == SHUTDOWN_MASK &&
ad8a72203   Stefano Garzarella   vsock/virtio: fix...
929
930
931
932
933
  		    vsock_stream_has_data(vsk) <= 0 &&
  		    !sock_flag(sk, SOCK_DONE)) {
  			(void)virtio_transport_reset(vsk, NULL);
  
  			virtio_transport_do_close(vsk, true);
42f5cda5e   Stephen Barber   vsock/virtio: set...
934
  		}
06a8fc783   Asias He   VSOCK: Introduce ...
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  		if (le32_to_cpu(pkt->hdr.flags))
  			sk->sk_state_change(sk);
  		break;
  	case VIRTIO_VSOCK_OP_RST:
  		virtio_transport_do_close(vsk, true);
  		break;
  	default:
  		err = -EINVAL;
  		break;
  	}
  
  	virtio_transport_free_pkt(pkt);
  	return err;
  }
  
  static void
  virtio_transport_recv_disconnecting(struct sock *sk,
  				    struct virtio_vsock_pkt *pkt)
  {
  	struct vsock_sock *vsk = vsock_sk(sk);
  
  	if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST)
  		virtio_transport_do_close(vsk, true);
  }
  
  static int
  virtio_transport_send_response(struct vsock_sock *vsk,
  			       struct virtio_vsock_pkt *pkt)
  {
  	struct virtio_vsock_pkt_info info = {
  		.op = VIRTIO_VSOCK_OP_RESPONSE,
  		.type = VIRTIO_VSOCK_TYPE_STREAM,
f83f12d66   Michael S. Tsirkin   vsock/virtio: fix...
967
  		.remote_cid = le64_to_cpu(pkt->hdr.src_cid),
06a8fc783   Asias He   VSOCK: Introduce ...
968
969
  		.remote_port = le32_to_cpu(pkt->hdr.src_port),
  		.reply = true,
36d277bac   Peng Tao   vsock: track pkt ...
970
  		.vsk = vsk,
06a8fc783   Asias He   VSOCK: Introduce ...
971
972
973
974
  	};
  
  	return virtio_transport_send_pkt_info(vsk, &info);
  }
c0cfa2d8a   Stefano Garzarella   vsock: add multi-...
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
  static bool virtio_transport_space_update(struct sock *sk,
  					  struct virtio_vsock_pkt *pkt)
  {
  	struct vsock_sock *vsk = vsock_sk(sk);
  	struct virtio_vsock_sock *vvs = vsk->trans;
  	bool space_available;
  
  	/* Listener sockets are not associated with any transport, so we are
  	 * not able to take the state to see if there is space available in the
  	 * remote peer, but since they are only used to receive requests, we
  	 * can assume that there is always space available in the other peer.
  	 */
  	if (!vvs)
  		return true;
  
  	/* buf_alloc and fwd_cnt is always included in the hdr */
  	spin_lock_bh(&vvs->tx_lock);
  	vvs->peer_buf_alloc = le32_to_cpu(pkt->hdr.buf_alloc);
  	vvs->peer_fwd_cnt = le32_to_cpu(pkt->hdr.fwd_cnt);
  	space_available = virtio_transport_has_space(vsk);
  	spin_unlock_bh(&vvs->tx_lock);
  	return space_available;
  }
06a8fc783   Asias He   VSOCK: Introduce ...
998
999
  /* Handle server socket */
  static int
c0cfa2d8a   Stefano Garzarella   vsock: add multi-...
1000
1001
  virtio_transport_recv_listen(struct sock *sk, struct virtio_vsock_pkt *pkt,
  			     struct virtio_transport *t)
06a8fc783   Asias He   VSOCK: Introduce ...
1002
1003
1004
1005
  {
  	struct vsock_sock *vsk = vsock_sk(sk);
  	struct vsock_sock *vchild;
  	struct sock *child;
c0cfa2d8a   Stefano Garzarella   vsock: add multi-...
1006
  	int ret;
06a8fc783   Asias He   VSOCK: Introduce ...
1007
1008
  
  	if (le16_to_cpu(pkt->hdr.op) != VIRTIO_VSOCK_OP_REQUEST) {
df18fa146   Stefano Garzarella   vsock/virtio: fix...
1009
  		virtio_transport_reset_no_sock(t, pkt);
06a8fc783   Asias He   VSOCK: Introduce ...
1010
1011
1012
1013
  		return -EINVAL;
  	}
  
  	if (sk_acceptq_is_full(sk)) {
df18fa146   Stefano Garzarella   vsock/virtio: fix...
1014
  		virtio_transport_reset_no_sock(t, pkt);
06a8fc783   Asias He   VSOCK: Introduce ...
1015
1016
  		return -ENOMEM;
  	}
b9ca2f5ff   Stefano Garzarella   vsock: add vsock_...
1017
  	child = vsock_create_connected(sk);
06a8fc783   Asias He   VSOCK: Introduce ...
1018
  	if (!child) {
df18fa146   Stefano Garzarella   vsock/virtio: fix...
1019
  		virtio_transport_reset_no_sock(t, pkt);
06a8fc783   Asias He   VSOCK: Introduce ...
1020
1021
  		return -ENOMEM;
  	}
7976a11b3   Eric Dumazet   net: use helpers ...
1022
  	sk_acceptq_added(sk);
06a8fc783   Asias He   VSOCK: Introduce ...
1023
1024
  
  	lock_sock_nested(child, SINGLE_DEPTH_NESTING);
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
1025
  	child->sk_state = TCP_ESTABLISHED;
06a8fc783   Asias He   VSOCK: Introduce ...
1026
1027
  
  	vchild = vsock_sk(child);
f83f12d66   Michael S. Tsirkin   vsock/virtio: fix...
1028
  	vsock_addr_init(&vchild->local_addr, le64_to_cpu(pkt->hdr.dst_cid),
06a8fc783   Asias He   VSOCK: Introduce ...
1029
  			le32_to_cpu(pkt->hdr.dst_port));
f83f12d66   Michael S. Tsirkin   vsock/virtio: fix...
1030
  	vsock_addr_init(&vchild->remote_addr, le64_to_cpu(pkt->hdr.src_cid),
06a8fc783   Asias He   VSOCK: Introduce ...
1031
  			le32_to_cpu(pkt->hdr.src_port));
c0cfa2d8a   Stefano Garzarella   vsock: add multi-...
1032
1033
1034
1035
1036
1037
  	ret = vsock_assign_transport(vchild, vsk);
  	/* Transport assigned (looking at remote_addr) must be the same
  	 * where we received the request.
  	 */
  	if (ret || vchild->transport != &t->transport) {
  		release_sock(child);
df18fa146   Stefano Garzarella   vsock/virtio: fix...
1038
  		virtio_transport_reset_no_sock(t, pkt);
c0cfa2d8a   Stefano Garzarella   vsock: add multi-...
1039
1040
1041
1042
1043
1044
  		sock_put(child);
  		return ret;
  	}
  
  	if (virtio_transport_space_update(child, pkt))
  		child->sk_write_space(child);
06a8fc783   Asias He   VSOCK: Introduce ...
1045
1046
1047
1048
1049
1050
1051
1052
1053
  	vsock_insert_connected(vchild);
  	vsock_enqueue_accept(sk, child);
  	virtio_transport_send_response(vchild, pkt);
  
  	release_sock(child);
  
  	sk->sk_data_ready(sk);
  	return 0;
  }
06a8fc783   Asias He   VSOCK: Introduce ...
1054
1055
1056
  /* We are under the virtio-vsock's vsock->rx_lock or vhost-vsock's vq->mutex
   * lock.
   */
4c7246dc4   Stefano Garzarella   vsock/virtio: add...
1057
1058
  void virtio_transport_recv_pkt(struct virtio_transport *t,
  			       struct virtio_vsock_pkt *pkt)
06a8fc783   Asias He   VSOCK: Introduce ...
1059
1060
1061
1062
1063
  {
  	struct sockaddr_vm src, dst;
  	struct vsock_sock *vsk;
  	struct sock *sk;
  	bool space_available;
f83f12d66   Michael S. Tsirkin   vsock/virtio: fix...
1064
  	vsock_addr_init(&src, le64_to_cpu(pkt->hdr.src_cid),
06a8fc783   Asias He   VSOCK: Introduce ...
1065
  			le32_to_cpu(pkt->hdr.src_port));
f83f12d66   Michael S. Tsirkin   vsock/virtio: fix...
1066
  	vsock_addr_init(&dst, le64_to_cpu(pkt->hdr.dst_cid),
06a8fc783   Asias He   VSOCK: Introduce ...
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  			le32_to_cpu(pkt->hdr.dst_port));
  
  	trace_virtio_transport_recv_pkt(src.svm_cid, src.svm_port,
  					dst.svm_cid, dst.svm_port,
  					le32_to_cpu(pkt->hdr.len),
  					le16_to_cpu(pkt->hdr.type),
  					le16_to_cpu(pkt->hdr.op),
  					le32_to_cpu(pkt->hdr.flags),
  					le32_to_cpu(pkt->hdr.buf_alloc),
  					le32_to_cpu(pkt->hdr.fwd_cnt));
  
  	if (le16_to_cpu(pkt->hdr.type) != VIRTIO_VSOCK_TYPE_STREAM) {
4c7246dc4   Stefano Garzarella   vsock/virtio: add...
1079
  		(void)virtio_transport_reset_no_sock(t, pkt);
06a8fc783   Asias He   VSOCK: Introduce ...
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
  		goto free_pkt;
  	}
  
  	/* The socket must be in connected or bound table
  	 * otherwise send reset back
  	 */
  	sk = vsock_find_connected_socket(&src, &dst);
  	if (!sk) {
  		sk = vsock_find_bound_socket(&dst);
  		if (!sk) {
4c7246dc4   Stefano Garzarella   vsock/virtio: add...
1090
  			(void)virtio_transport_reset_no_sock(t, pkt);
06a8fc783   Asias He   VSOCK: Introduce ...
1091
1092
1093
1094
1095
1096
1097
1098
1099
  			goto free_pkt;
  		}
  	}
  
  	vsk = vsock_sk(sk);
  
  	space_available = virtio_transport_space_update(sk, pkt);
  
  	lock_sock(sk);
3fe356d58   Stefano Garzarella   vsock/virtio: dis...
1100
1101
  	/* Check if sk has been closed before lock_sock */
  	if (sock_flag(sk, SOCK_DONE)) {
8692cefc4   Jia He   virtio_vsock: Fix...
1102
1103
1104
1105
1106
  		(void)virtio_transport_reset_no_sock(t, pkt);
  		release_sock(sk);
  		sock_put(sk);
  		goto free_pkt;
  	}
06a8fc783   Asias He   VSOCK: Introduce ...
1107
1108
1109
1110
1111
1112
1113
  	/* Update CID in case it has changed after a transport reset event */
  	vsk->local_addr.svm_cid = dst.svm_cid;
  
  	if (space_available)
  		sk->sk_write_space(sk);
  
  	switch (sk->sk_state) {
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
1114
  	case TCP_LISTEN:
c0cfa2d8a   Stefano Garzarella   vsock: add multi-...
1115
  		virtio_transport_recv_listen(sk, pkt, t);
06a8fc783   Asias He   VSOCK: Introduce ...
1116
1117
  		virtio_transport_free_pkt(pkt);
  		break;
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
1118
  	case TCP_SYN_SENT:
06a8fc783   Asias He   VSOCK: Introduce ...
1119
1120
1121
  		virtio_transport_recv_connecting(sk, pkt);
  		virtio_transport_free_pkt(pkt);
  		break;
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
1122
  	case TCP_ESTABLISHED:
06a8fc783   Asias He   VSOCK: Introduce ...
1123
1124
  		virtio_transport_recv_connected(sk, pkt);
  		break;
3b4477d2d   Stefan Hajnoczi   VSOCK: use TCP st...
1125
  	case TCP_CLOSING:
06a8fc783   Asias He   VSOCK: Introduce ...
1126
1127
1128
1129
  		virtio_transport_recv_disconnecting(sk, pkt);
  		virtio_transport_free_pkt(pkt);
  		break;
  	default:
df12eb6d6   Sebastien Boeuf   net: virtio_vsock...
1130
  		(void)virtio_transport_reset_no_sock(t, pkt);
06a8fc783   Asias He   VSOCK: Introduce ...
1131
1132
1133
  		virtio_transport_free_pkt(pkt);
  		break;
  	}
c0cfa2d8a   Stefano Garzarella   vsock: add multi-...
1134

06a8fc783   Asias He   VSOCK: Introduce ...
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  	release_sock(sk);
  
  	/* Release refcnt obtained when we fetched this socket out of the
  	 * bound or connected list.
  	 */
  	sock_put(sk);
  	return;
  
  free_pkt:
  	virtio_transport_free_pkt(pkt);
  }
  EXPORT_SYMBOL_GPL(virtio_transport_recv_pkt);
  
  void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt)
  {
  	kfree(pkt->buf);
  	kfree(pkt);
  }
  EXPORT_SYMBOL_GPL(virtio_transport_free_pkt);
  
  MODULE_LICENSE("GPL v2");
  MODULE_AUTHOR("Asias He");
  MODULE_DESCRIPTION("common code for virtio vsock");