1*0f4c859eSApple OSS Distributions /*
2*0f4c859eSApple OSS Distributions * Copyright (c) 2020 Apple Inc. All rights reserved.
3*0f4c859eSApple OSS Distributions *
4*0f4c859eSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*0f4c859eSApple OSS Distributions *
6*0f4c859eSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*0f4c859eSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*0f4c859eSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*0f4c859eSApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*0f4c859eSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*0f4c859eSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*0f4c859eSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*0f4c859eSApple OSS Distributions * terms of an Apple operating system software license agreement.
14*0f4c859eSApple OSS Distributions *
15*0f4c859eSApple OSS Distributions * Please obtain a copy of the License at
16*0f4c859eSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*0f4c859eSApple OSS Distributions *
18*0f4c859eSApple OSS Distributions * The Original Code and all software distributed under the License are
19*0f4c859eSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*0f4c859eSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*0f4c859eSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*0f4c859eSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*0f4c859eSApple OSS Distributions * Please see the License for the specific language governing rights and
24*0f4c859eSApple OSS Distributions * limitations under the License.
25*0f4c859eSApple OSS Distributions *
26*0f4c859eSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*0f4c859eSApple OSS Distributions */
28*0f4c859eSApple OSS Distributions
29*0f4c859eSApple OSS Distributions #include <sys/domain.h>
30*0f4c859eSApple OSS Distributions #include <sys/socket.h>
31*0f4c859eSApple OSS Distributions #include <sys/protosw.h>
32*0f4c859eSApple OSS Distributions #include <sys/mcache.h>
33*0f4c859eSApple OSS Distributions #include <sys/systm.h>
34*0f4c859eSApple OSS Distributions #include <sys/sysctl.h>
35*0f4c859eSApple OSS Distributions #include <sys/random.h>
36*0f4c859eSApple OSS Distributions #include <sys/mbuf.h>
37*0f4c859eSApple OSS Distributions #include <sys/vsock_domain.h>
38*0f4c859eSApple OSS Distributions #include <sys/vsock_transport.h>
39*0f4c859eSApple OSS Distributions #include <kern/task.h>
40*0f4c859eSApple OSS Distributions #include <kern/zalloc.h>
41*0f4c859eSApple OSS Distributions #include <kern/locks.h>
42*0f4c859eSApple OSS Distributions #include <machine/atomic.h>
43*0f4c859eSApple OSS Distributions
44*0f4c859eSApple OSS Distributions #define sotovsockpcb(so) ((struct vsockpcb *)(so)->so_pcb)
45*0f4c859eSApple OSS Distributions
46*0f4c859eSApple OSS Distributions #define VSOCK_PORT_RESERVED 1024
47*0f4c859eSApple OSS Distributions
48*0f4c859eSApple OSS Distributions /* VSock Protocol Globals */
49*0f4c859eSApple OSS Distributions
50*0f4c859eSApple OSS Distributions static struct vsock_transport * _Atomic the_vsock_transport = NULL;
51*0f4c859eSApple OSS Distributions static ZONE_DEFINE(vsockpcb_zone, "vsockpcbzone",
52*0f4c859eSApple OSS Distributions sizeof(struct vsockpcb), ZC_NONE);
53*0f4c859eSApple OSS Distributions static LCK_GRP_DECLARE(vsock_lock_grp, "vsock");
54*0f4c859eSApple OSS Distributions static struct vsockpcbinfo vsockinfo;
55*0f4c859eSApple OSS Distributions
56*0f4c859eSApple OSS Distributions static uint32_t vsock_sendspace = VSOCK_MAX_PACKET_SIZE * 8;
57*0f4c859eSApple OSS Distributions static uint32_t vsock_recvspace = VSOCK_MAX_PACKET_SIZE * 8;
58*0f4c859eSApple OSS Distributions
59*0f4c859eSApple OSS Distributions /* VSock PCB Helpers */
60*0f4c859eSApple OSS Distributions
61*0f4c859eSApple OSS Distributions static uint32_t
vsock_get_peer_space(struct vsockpcb * pcb)62*0f4c859eSApple OSS Distributions vsock_get_peer_space(struct vsockpcb *pcb)
63*0f4c859eSApple OSS Distributions {
64*0f4c859eSApple OSS Distributions return pcb->peer_buf_alloc - (pcb->tx_cnt - pcb->peer_fwd_cnt);
65*0f4c859eSApple OSS Distributions }
66*0f4c859eSApple OSS Distributions
67*0f4c859eSApple OSS Distributions static struct vsockpcb *
vsock_get_matching_pcb(struct vsock_address src,struct vsock_address dst)68*0f4c859eSApple OSS Distributions vsock_get_matching_pcb(struct vsock_address src, struct vsock_address dst)
69*0f4c859eSApple OSS Distributions {
70*0f4c859eSApple OSS Distributions struct vsockpcb *preferred = NULL;
71*0f4c859eSApple OSS Distributions struct vsockpcb *match = NULL;
72*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = NULL;
73*0f4c859eSApple OSS Distributions
74*0f4c859eSApple OSS Distributions lck_rw_lock_shared(&vsockinfo.bound_lock);
75*0f4c859eSApple OSS Distributions LIST_FOREACH(pcb, &vsockinfo.bound, bound) {
76*0f4c859eSApple OSS Distributions // Source cid and port must match. Only destination port must match. (Allows for a changing CID during migration)
77*0f4c859eSApple OSS Distributions socket_lock(pcb->so, 1);
78*0f4c859eSApple OSS Distributions if ((pcb->so->so_state & SS_ISCONNECTED || pcb->so->so_state & SS_ISCONNECTING) &&
79*0f4c859eSApple OSS Distributions pcb->local_address.cid == src.cid && pcb->local_address.port == src.port &&
80*0f4c859eSApple OSS Distributions pcb->remote_address.port == dst.port) {
81*0f4c859eSApple OSS Distributions preferred = pcb;
82*0f4c859eSApple OSS Distributions break;
83*0f4c859eSApple OSS Distributions } else if ((pcb->local_address.cid == src.cid || pcb->local_address.cid == VMADDR_CID_ANY) &&
84*0f4c859eSApple OSS Distributions pcb->local_address.port == src.port) {
85*0f4c859eSApple OSS Distributions match = pcb;
86*0f4c859eSApple OSS Distributions }
87*0f4c859eSApple OSS Distributions socket_unlock(pcb->so, 1);
88*0f4c859eSApple OSS Distributions }
89*0f4c859eSApple OSS Distributions if (!preferred && match) {
90*0f4c859eSApple OSS Distributions socket_lock(match->so, 1);
91*0f4c859eSApple OSS Distributions preferred = match;
92*0f4c859eSApple OSS Distributions }
93*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.bound_lock);
94*0f4c859eSApple OSS Distributions
95*0f4c859eSApple OSS Distributions return preferred;
96*0f4c859eSApple OSS Distributions }
97*0f4c859eSApple OSS Distributions
98*0f4c859eSApple OSS Distributions static errno_t
vsock_bind_address_if_free(struct vsockpcb * pcb,uint32_t local_cid,uint32_t local_port,uint32_t remote_cid,uint32_t remote_port)99*0f4c859eSApple OSS Distributions vsock_bind_address_if_free(struct vsockpcb *pcb, uint32_t local_cid, uint32_t local_port, uint32_t remote_cid, uint32_t remote_port)
100*0f4c859eSApple OSS Distributions {
101*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
102*0f4c859eSApple OSS Distributions
103*0f4c859eSApple OSS Distributions // Privileged ports.
104*0f4c859eSApple OSS Distributions if (local_port != VMADDR_PORT_ANY && local_port < VSOCK_PORT_RESERVED &&
105*0f4c859eSApple OSS Distributions current_task() != kernel_task && proc_suser(current_proc()) != 0) {
106*0f4c859eSApple OSS Distributions return EACCES;
107*0f4c859eSApple OSS Distributions }
108*0f4c859eSApple OSS Distributions
109*0f4c859eSApple OSS Distributions bool taken = false;
110*0f4c859eSApple OSS Distributions const bool check_remote = (remote_cid != VMADDR_CID_ANY && remote_port != VMADDR_PORT_ANY);
111*0f4c859eSApple OSS Distributions
112*0f4c859eSApple OSS Distributions struct vsockpcb *pcb_match = NULL;
113*0f4c859eSApple OSS Distributions
114*0f4c859eSApple OSS Distributions socket_unlock(pcb->so, 0);
115*0f4c859eSApple OSS Distributions lck_rw_lock_exclusive(&vsockinfo.bound_lock);
116*0f4c859eSApple OSS Distributions LIST_FOREACH(pcb_match, &vsockinfo.bound, bound) {
117*0f4c859eSApple OSS Distributions socket_lock(pcb_match->so, 1);
118*0f4c859eSApple OSS Distributions if (pcb == pcb_match ||
119*0f4c859eSApple OSS Distributions (!check_remote && pcb_match->local_address.port == local_port) ||
120*0f4c859eSApple OSS Distributions (check_remote && pcb_match->local_address.port == local_port &&
121*0f4c859eSApple OSS Distributions pcb_match->remote_address.cid == remote_cid && pcb_match->remote_address.port == remote_port)) {
122*0f4c859eSApple OSS Distributions socket_unlock(pcb_match->so, 1);
123*0f4c859eSApple OSS Distributions taken = true;
124*0f4c859eSApple OSS Distributions break;
125*0f4c859eSApple OSS Distributions }
126*0f4c859eSApple OSS Distributions socket_unlock(pcb_match->so, 1);
127*0f4c859eSApple OSS Distributions }
128*0f4c859eSApple OSS Distributions socket_lock(pcb->so, 0);
129*0f4c859eSApple OSS Distributions if (!taken) {
130*0f4c859eSApple OSS Distributions pcb->local_address = (struct vsock_address) { .cid = local_cid, .port = local_port };
131*0f4c859eSApple OSS Distributions pcb->remote_address = (struct vsock_address) { .cid = remote_cid, .port = remote_port };
132*0f4c859eSApple OSS Distributions LIST_INSERT_HEAD(&vsockinfo.bound, pcb, bound);
133*0f4c859eSApple OSS Distributions }
134*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.bound_lock);
135*0f4c859eSApple OSS Distributions
136*0f4c859eSApple OSS Distributions return taken ? EADDRINUSE : 0;
137*0f4c859eSApple OSS Distributions }
138*0f4c859eSApple OSS Distributions
139*0f4c859eSApple OSS Distributions static errno_t
vsock_bind_address(struct vsockpcb * pcb,struct vsock_address laddr,struct vsock_address raddr)140*0f4c859eSApple OSS Distributions vsock_bind_address(struct vsockpcb *pcb, struct vsock_address laddr, struct vsock_address raddr)
141*0f4c859eSApple OSS Distributions {
142*0f4c859eSApple OSS Distributions if (!pcb) {
143*0f4c859eSApple OSS Distributions return EINVAL;
144*0f4c859eSApple OSS Distributions }
145*0f4c859eSApple OSS Distributions
146*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
147*0f4c859eSApple OSS Distributions
148*0f4c859eSApple OSS Distributions // Certain CIDs are reserved.
149*0f4c859eSApple OSS Distributions if (laddr.cid == VMADDR_CID_HYPERVISOR || laddr.cid == VMADDR_CID_RESERVED || laddr.cid == VMADDR_CID_HOST) {
150*0f4c859eSApple OSS Distributions return EADDRNOTAVAIL;
151*0f4c859eSApple OSS Distributions }
152*0f4c859eSApple OSS Distributions
153*0f4c859eSApple OSS Distributions // Remote address must be fully specified or not specified at all.
154*0f4c859eSApple OSS Distributions if ((raddr.cid == VMADDR_CID_ANY) ^ (raddr.port == VMADDR_PORT_ANY)) {
155*0f4c859eSApple OSS Distributions return EINVAL;
156*0f4c859eSApple OSS Distributions }
157*0f4c859eSApple OSS Distributions
158*0f4c859eSApple OSS Distributions // Cannot bind if already bound.
159*0f4c859eSApple OSS Distributions if (pcb->local_address.port != VMADDR_PORT_ANY) {
160*0f4c859eSApple OSS Distributions return EINVAL;
161*0f4c859eSApple OSS Distributions }
162*0f4c859eSApple OSS Distributions
163*0f4c859eSApple OSS Distributions uint32_t transport_cid;
164*0f4c859eSApple OSS Distributions struct vsock_transport *transport = pcb->transport;
165*0f4c859eSApple OSS Distributions errno_t error = transport->get_cid(transport->provider, &transport_cid);
166*0f4c859eSApple OSS Distributions if (error) {
167*0f4c859eSApple OSS Distributions return error;
168*0f4c859eSApple OSS Distributions }
169*0f4c859eSApple OSS Distributions
170*0f4c859eSApple OSS Distributions // Local CID must be this transport's CID or any.
171*0f4c859eSApple OSS Distributions if (laddr.cid != transport_cid && laddr.cid != VMADDR_CID_ANY) {
172*0f4c859eSApple OSS Distributions return EINVAL;
173*0f4c859eSApple OSS Distributions }
174*0f4c859eSApple OSS Distributions
175*0f4c859eSApple OSS Distributions if (laddr.port != VMADDR_PORT_ANY) {
176*0f4c859eSApple OSS Distributions error = vsock_bind_address_if_free(pcb, laddr.cid, laddr.port, raddr.cid, raddr.port);
177*0f4c859eSApple OSS Distributions } else {
178*0f4c859eSApple OSS Distributions lck_mtx_lock(&vsockinfo.port_lock);
179*0f4c859eSApple OSS Distributions
180*0f4c859eSApple OSS Distributions const uint32_t first = VSOCK_PORT_RESERVED;
181*0f4c859eSApple OSS Distributions const uint32_t last = VMADDR_PORT_ANY - 1;
182*0f4c859eSApple OSS Distributions uint32_t count = last - first + 1;
183*0f4c859eSApple OSS Distributions uint32_t *last_port = &vsockinfo.last_port;
184*0f4c859eSApple OSS Distributions
185*0f4c859eSApple OSS Distributions if (pcb->so->so_flags & SOF_BINDRANDOMPORT) {
186*0f4c859eSApple OSS Distributions uint32_t random = 0;
187*0f4c859eSApple OSS Distributions read_frandom(&random, sizeof(random));
188*0f4c859eSApple OSS Distributions *last_port = first + (random % count);
189*0f4c859eSApple OSS Distributions }
190*0f4c859eSApple OSS Distributions
191*0f4c859eSApple OSS Distributions do {
192*0f4c859eSApple OSS Distributions if (count == 0) {
193*0f4c859eSApple OSS Distributions lck_mtx_unlock(&vsockinfo.port_lock);
194*0f4c859eSApple OSS Distributions return EADDRNOTAVAIL;
195*0f4c859eSApple OSS Distributions }
196*0f4c859eSApple OSS Distributions count--;
197*0f4c859eSApple OSS Distributions
198*0f4c859eSApple OSS Distributions ++*last_port;
199*0f4c859eSApple OSS Distributions if (*last_port < first || *last_port > last) {
200*0f4c859eSApple OSS Distributions *last_port = first;
201*0f4c859eSApple OSS Distributions }
202*0f4c859eSApple OSS Distributions
203*0f4c859eSApple OSS Distributions error = vsock_bind_address_if_free(pcb, laddr.cid, *last_port, raddr.cid, raddr.port);
204*0f4c859eSApple OSS Distributions } while (error);
205*0f4c859eSApple OSS Distributions
206*0f4c859eSApple OSS Distributions lck_mtx_unlock(&vsockinfo.port_lock);
207*0f4c859eSApple OSS Distributions }
208*0f4c859eSApple OSS Distributions
209*0f4c859eSApple OSS Distributions return error;
210*0f4c859eSApple OSS Distributions }
211*0f4c859eSApple OSS Distributions
212*0f4c859eSApple OSS Distributions static void
vsock_unbind_pcb(struct vsockpcb * pcb,bool is_locked)213*0f4c859eSApple OSS Distributions vsock_unbind_pcb(struct vsockpcb *pcb, bool is_locked)
214*0f4c859eSApple OSS Distributions {
215*0f4c859eSApple OSS Distributions if (!pcb) {
216*0f4c859eSApple OSS Distributions return;
217*0f4c859eSApple OSS Distributions }
218*0f4c859eSApple OSS Distributions
219*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
220*0f4c859eSApple OSS Distributions
221*0f4c859eSApple OSS Distributions soisdisconnected(pcb->so);
222*0f4c859eSApple OSS Distributions
223*0f4c859eSApple OSS Distributions if (!pcb->bound.le_prev) {
224*0f4c859eSApple OSS Distributions return;
225*0f4c859eSApple OSS Distributions }
226*0f4c859eSApple OSS Distributions
227*0f4c859eSApple OSS Distributions if (!is_locked) {
228*0f4c859eSApple OSS Distributions socket_unlock(pcb->so, 0);
229*0f4c859eSApple OSS Distributions lck_rw_lock_exclusive(&vsockinfo.bound_lock);
230*0f4c859eSApple OSS Distributions socket_lock(pcb->so, 0);
231*0f4c859eSApple OSS Distributions if (!pcb->bound.le_prev) {
232*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.bound_lock);
233*0f4c859eSApple OSS Distributions return;
234*0f4c859eSApple OSS Distributions }
235*0f4c859eSApple OSS Distributions }
236*0f4c859eSApple OSS Distributions
237*0f4c859eSApple OSS Distributions LIST_REMOVE(pcb, bound);
238*0f4c859eSApple OSS Distributions pcb->bound.le_next = NULL;
239*0f4c859eSApple OSS Distributions pcb->bound.le_prev = NULL;
240*0f4c859eSApple OSS Distributions
241*0f4c859eSApple OSS Distributions if (!is_locked) {
242*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.bound_lock);
243*0f4c859eSApple OSS Distributions }
244*0f4c859eSApple OSS Distributions }
245*0f4c859eSApple OSS Distributions
246*0f4c859eSApple OSS Distributions static struct sockaddr *
vsock_new_sockaddr(struct vsock_address * address)247*0f4c859eSApple OSS Distributions vsock_new_sockaddr(struct vsock_address *address)
248*0f4c859eSApple OSS Distributions {
249*0f4c859eSApple OSS Distributions if (!address) {
250*0f4c859eSApple OSS Distributions return NULL;
251*0f4c859eSApple OSS Distributions }
252*0f4c859eSApple OSS Distributions
253*0f4c859eSApple OSS Distributions struct sockaddr_vm *addr;
254*0f4c859eSApple OSS Distributions addr = (struct sockaddr_vm *)alloc_sockaddr(sizeof(*addr),
255*0f4c859eSApple OSS Distributions Z_WAITOK | Z_NOFAIL);
256*0f4c859eSApple OSS Distributions
257*0f4c859eSApple OSS Distributions addr->svm_family = AF_VSOCK;
258*0f4c859eSApple OSS Distributions addr->svm_port = address->port;
259*0f4c859eSApple OSS Distributions addr->svm_cid = address->cid;
260*0f4c859eSApple OSS Distributions
261*0f4c859eSApple OSS Distributions return (struct sockaddr *)addr;
262*0f4c859eSApple OSS Distributions }
263*0f4c859eSApple OSS Distributions
264*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_send_message(struct vsockpcb * pcb,enum vsock_operation operation,mbuf_t m)265*0f4c859eSApple OSS Distributions vsock_pcb_send_message(struct vsockpcb *pcb, enum vsock_operation operation, mbuf_t m)
266*0f4c859eSApple OSS Distributions {
267*0f4c859eSApple OSS Distributions if (!pcb) {
268*0f4c859eSApple OSS Distributions if (m != NULL) {
269*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
270*0f4c859eSApple OSS Distributions }
271*0f4c859eSApple OSS Distributions return EINVAL;
272*0f4c859eSApple OSS Distributions }
273*0f4c859eSApple OSS Distributions
274*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
275*0f4c859eSApple OSS Distributions
276*0f4c859eSApple OSS Distributions errno_t error;
277*0f4c859eSApple OSS Distributions
278*0f4c859eSApple OSS Distributions struct vsock_address dst = pcb->remote_address;
279*0f4c859eSApple OSS Distributions if (dst.cid == VMADDR_CID_ANY || dst.port == VMADDR_PORT_ANY) {
280*0f4c859eSApple OSS Distributions if (m != NULL) {
281*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
282*0f4c859eSApple OSS Distributions }
283*0f4c859eSApple OSS Distributions return EINVAL;
284*0f4c859eSApple OSS Distributions }
285*0f4c859eSApple OSS Distributions
286*0f4c859eSApple OSS Distributions struct vsock_address src = pcb->local_address;
287*0f4c859eSApple OSS Distributions if (src.cid == VMADDR_CID_ANY) {
288*0f4c859eSApple OSS Distributions uint32_t transport_cid;
289*0f4c859eSApple OSS Distributions struct vsock_transport *transport = pcb->transport;
290*0f4c859eSApple OSS Distributions error = transport->get_cid(transport->provider, &transport_cid);
291*0f4c859eSApple OSS Distributions if (error) {
292*0f4c859eSApple OSS Distributions if (m != NULL) {
293*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
294*0f4c859eSApple OSS Distributions }
295*0f4c859eSApple OSS Distributions return error;
296*0f4c859eSApple OSS Distributions }
297*0f4c859eSApple OSS Distributions src.cid = transport_cid;
298*0f4c859eSApple OSS Distributions }
299*0f4c859eSApple OSS Distributions
300*0f4c859eSApple OSS Distributions uint32_t buf_alloc = pcb->so->so_rcv.sb_hiwat;
301*0f4c859eSApple OSS Distributions uint32_t fwd_cnt = pcb->fwd_cnt;
302*0f4c859eSApple OSS Distributions
303*0f4c859eSApple OSS Distributions if (src.cid == dst.cid) {
304*0f4c859eSApple OSS Distributions pcb->last_buf_alloc = buf_alloc;
305*0f4c859eSApple OSS Distributions pcb->last_fwd_cnt = fwd_cnt;
306*0f4c859eSApple OSS Distributions
307*0f4c859eSApple OSS Distributions socket_unlock(pcb->so, 0);
308*0f4c859eSApple OSS Distributions error = vsock_put_message(src, dst, operation, buf_alloc, fwd_cnt, m);
309*0f4c859eSApple OSS Distributions socket_lock(pcb->so, 0);
310*0f4c859eSApple OSS Distributions } else {
311*0f4c859eSApple OSS Distributions struct vsock_transport *transport = pcb->transport;
312*0f4c859eSApple OSS Distributions error = transport->put_message(transport->provider, src, dst, operation, buf_alloc, fwd_cnt, m);
313*0f4c859eSApple OSS Distributions
314*0f4c859eSApple OSS Distributions if (!error) {
315*0f4c859eSApple OSS Distributions pcb->last_buf_alloc = buf_alloc;
316*0f4c859eSApple OSS Distributions pcb->last_fwd_cnt = fwd_cnt;
317*0f4c859eSApple OSS Distributions }
318*0f4c859eSApple OSS Distributions }
319*0f4c859eSApple OSS Distributions
320*0f4c859eSApple OSS Distributions return error;
321*0f4c859eSApple OSS Distributions }
322*0f4c859eSApple OSS Distributions
323*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_reset_address(struct vsock_address src,struct vsock_address dst)324*0f4c859eSApple OSS Distributions vsock_pcb_reset_address(struct vsock_address src, struct vsock_address dst)
325*0f4c859eSApple OSS Distributions {
326*0f4c859eSApple OSS Distributions if (dst.cid == VMADDR_CID_ANY || dst.port == VMADDR_PORT_ANY) {
327*0f4c859eSApple OSS Distributions return EINVAL;
328*0f4c859eSApple OSS Distributions }
329*0f4c859eSApple OSS Distributions
330*0f4c859eSApple OSS Distributions errno_t error;
331*0f4c859eSApple OSS Distributions struct vsock_transport *transport = NULL;
332*0f4c859eSApple OSS Distributions
333*0f4c859eSApple OSS Distributions if (src.cid == VMADDR_CID_ANY) {
334*0f4c859eSApple OSS Distributions transport = os_atomic_load(&the_vsock_transport, relaxed);
335*0f4c859eSApple OSS Distributions if (transport == NULL) {
336*0f4c859eSApple OSS Distributions return ENODEV;
337*0f4c859eSApple OSS Distributions }
338*0f4c859eSApple OSS Distributions
339*0f4c859eSApple OSS Distributions uint32_t transport_cid;
340*0f4c859eSApple OSS Distributions error = transport->get_cid(transport->provider, &transport_cid);
341*0f4c859eSApple OSS Distributions if (error) {
342*0f4c859eSApple OSS Distributions return error;
343*0f4c859eSApple OSS Distributions }
344*0f4c859eSApple OSS Distributions src.cid = transport_cid;
345*0f4c859eSApple OSS Distributions }
346*0f4c859eSApple OSS Distributions
347*0f4c859eSApple OSS Distributions if (src.cid == dst.cid) {
348*0f4c859eSApple OSS Distributions error = vsock_put_message(src, dst, VSOCK_RESET, 0, 0, NULL);
349*0f4c859eSApple OSS Distributions } else {
350*0f4c859eSApple OSS Distributions if (!transport) {
351*0f4c859eSApple OSS Distributions transport = os_atomic_load(&the_vsock_transport, relaxed);
352*0f4c859eSApple OSS Distributions if (transport == NULL) {
353*0f4c859eSApple OSS Distributions return ENODEV;
354*0f4c859eSApple OSS Distributions }
355*0f4c859eSApple OSS Distributions }
356*0f4c859eSApple OSS Distributions error = transport->put_message(transport->provider, src, dst, VSOCK_RESET, 0, 0, NULL);
357*0f4c859eSApple OSS Distributions }
358*0f4c859eSApple OSS Distributions
359*0f4c859eSApple OSS Distributions return error;
360*0f4c859eSApple OSS Distributions }
361*0f4c859eSApple OSS Distributions
362*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_safe_reset_address(struct vsockpcb * pcb,struct vsock_address src,struct vsock_address dst)363*0f4c859eSApple OSS Distributions vsock_pcb_safe_reset_address(struct vsockpcb *pcb, struct vsock_address src, struct vsock_address dst)
364*0f4c859eSApple OSS Distributions {
365*0f4c859eSApple OSS Distributions if (pcb) {
366*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
367*0f4c859eSApple OSS Distributions socket_unlock(pcb->so, 0);
368*0f4c859eSApple OSS Distributions }
369*0f4c859eSApple OSS Distributions errno_t error = vsock_pcb_reset_address(src, dst);
370*0f4c859eSApple OSS Distributions if (pcb) {
371*0f4c859eSApple OSS Distributions socket_lock(pcb->so, 0);
372*0f4c859eSApple OSS Distributions }
373*0f4c859eSApple OSS Distributions return error;
374*0f4c859eSApple OSS Distributions }
375*0f4c859eSApple OSS Distributions
376*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_connect(struct vsockpcb * pcb)377*0f4c859eSApple OSS Distributions vsock_pcb_connect(struct vsockpcb *pcb)
378*0f4c859eSApple OSS Distributions {
379*0f4c859eSApple OSS Distributions return vsock_pcb_send_message(pcb, VSOCK_REQUEST, NULL);
380*0f4c859eSApple OSS Distributions }
381*0f4c859eSApple OSS Distributions
382*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_respond(struct vsockpcb * pcb)383*0f4c859eSApple OSS Distributions vsock_pcb_respond(struct vsockpcb *pcb)
384*0f4c859eSApple OSS Distributions {
385*0f4c859eSApple OSS Distributions return vsock_pcb_send_message(pcb, VSOCK_RESPONSE, NULL);
386*0f4c859eSApple OSS Distributions }
387*0f4c859eSApple OSS Distributions
388*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_send(struct vsockpcb * pcb,mbuf_t m)389*0f4c859eSApple OSS Distributions vsock_pcb_send(struct vsockpcb *pcb, mbuf_t m)
390*0f4c859eSApple OSS Distributions {
391*0f4c859eSApple OSS Distributions return vsock_pcb_send_message(pcb, VSOCK_PAYLOAD, m);
392*0f4c859eSApple OSS Distributions }
393*0f4c859eSApple OSS Distributions
394*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_shutdown_send(struct vsockpcb * pcb)395*0f4c859eSApple OSS Distributions vsock_pcb_shutdown_send(struct vsockpcb *pcb)
396*0f4c859eSApple OSS Distributions {
397*0f4c859eSApple OSS Distributions return vsock_pcb_send_message(pcb, VSOCK_SHUTDOWN_SEND, NULL);
398*0f4c859eSApple OSS Distributions }
399*0f4c859eSApple OSS Distributions
400*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_reset(struct vsockpcb * pcb)401*0f4c859eSApple OSS Distributions vsock_pcb_reset(struct vsockpcb *pcb)
402*0f4c859eSApple OSS Distributions {
403*0f4c859eSApple OSS Distributions return vsock_pcb_send_message(pcb, VSOCK_RESET, NULL);
404*0f4c859eSApple OSS Distributions }
405*0f4c859eSApple OSS Distributions
406*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_credit_update(struct vsockpcb * pcb)407*0f4c859eSApple OSS Distributions vsock_pcb_credit_update(struct vsockpcb *pcb)
408*0f4c859eSApple OSS Distributions {
409*0f4c859eSApple OSS Distributions return vsock_pcb_send_message(pcb, VSOCK_CREDIT_UPDATE, NULL);
410*0f4c859eSApple OSS Distributions }
411*0f4c859eSApple OSS Distributions
412*0f4c859eSApple OSS Distributions static errno_t
vsock_pcb_credit_request(struct vsockpcb * pcb)413*0f4c859eSApple OSS Distributions vsock_pcb_credit_request(struct vsockpcb *pcb)
414*0f4c859eSApple OSS Distributions {
415*0f4c859eSApple OSS Distributions return vsock_pcb_send_message(pcb, VSOCK_CREDIT_REQUEST, NULL);
416*0f4c859eSApple OSS Distributions }
417*0f4c859eSApple OSS Distributions
418*0f4c859eSApple OSS Distributions static errno_t
vsock_disconnect_pcb_common(struct vsockpcb * pcb,bool is_locked)419*0f4c859eSApple OSS Distributions vsock_disconnect_pcb_common(struct vsockpcb *pcb, bool is_locked)
420*0f4c859eSApple OSS Distributions {
421*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
422*0f4c859eSApple OSS Distributions vsock_unbind_pcb(pcb, is_locked);
423*0f4c859eSApple OSS Distributions return vsock_pcb_reset(pcb);
424*0f4c859eSApple OSS Distributions }
425*0f4c859eSApple OSS Distributions
426*0f4c859eSApple OSS Distributions static errno_t
vsock_disconnect_pcb_locked(struct vsockpcb * pcb)427*0f4c859eSApple OSS Distributions vsock_disconnect_pcb_locked(struct vsockpcb *pcb)
428*0f4c859eSApple OSS Distributions {
429*0f4c859eSApple OSS Distributions return vsock_disconnect_pcb_common(pcb, true);
430*0f4c859eSApple OSS Distributions }
431*0f4c859eSApple OSS Distributions
432*0f4c859eSApple OSS Distributions static errno_t
vsock_disconnect_pcb(struct vsockpcb * pcb)433*0f4c859eSApple OSS Distributions vsock_disconnect_pcb(struct vsockpcb *pcb)
434*0f4c859eSApple OSS Distributions {
435*0f4c859eSApple OSS Distributions return vsock_disconnect_pcb_common(pcb, false);
436*0f4c859eSApple OSS Distributions }
437*0f4c859eSApple OSS Distributions
438*0f4c859eSApple OSS Distributions static errno_t
vsock_sockaddr_vm_validate(struct vsockpcb * pcb,struct sockaddr_vm * addr)439*0f4c859eSApple OSS Distributions vsock_sockaddr_vm_validate(struct vsockpcb *pcb, struct sockaddr_vm *addr)
440*0f4c859eSApple OSS Distributions {
441*0f4c859eSApple OSS Distributions if (!pcb || !pcb->so || !addr) {
442*0f4c859eSApple OSS Distributions return EINVAL;
443*0f4c859eSApple OSS Distributions }
444*0f4c859eSApple OSS Distributions
445*0f4c859eSApple OSS Distributions // Validate address length.
446*0f4c859eSApple OSS Distributions if (addr->svm_len < sizeof(struct sockaddr_vm)) {
447*0f4c859eSApple OSS Distributions return EINVAL;
448*0f4c859eSApple OSS Distributions }
449*0f4c859eSApple OSS Distributions
450*0f4c859eSApple OSS Distributions // Validate address family.
451*0f4c859eSApple OSS Distributions if (addr->svm_family != AF_UNSPEC && addr->svm_family != AF_VSOCK) {
452*0f4c859eSApple OSS Distributions return EAFNOSUPPORT;
453*0f4c859eSApple OSS Distributions }
454*0f4c859eSApple OSS Distributions
455*0f4c859eSApple OSS Distributions // Only stream is supported currently.
456*0f4c859eSApple OSS Distributions if (pcb->so->so_type != SOCK_STREAM) {
457*0f4c859eSApple OSS Distributions return EAFNOSUPPORT;
458*0f4c859eSApple OSS Distributions }
459*0f4c859eSApple OSS Distributions
460*0f4c859eSApple OSS Distributions return 0;
461*0f4c859eSApple OSS Distributions }
462*0f4c859eSApple OSS Distributions /* VSock Receive Handlers */
463*0f4c859eSApple OSS Distributions
464*0f4c859eSApple OSS Distributions static errno_t
vsock_put_message_connected(struct vsockpcb * pcb,enum vsock_operation op,mbuf_t m)465*0f4c859eSApple OSS Distributions vsock_put_message_connected(struct vsockpcb *pcb, enum vsock_operation op, mbuf_t m)
466*0f4c859eSApple OSS Distributions {
467*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
468*0f4c859eSApple OSS Distributions
469*0f4c859eSApple OSS Distributions errno_t error = 0;
470*0f4c859eSApple OSS Distributions
471*0f4c859eSApple OSS Distributions switch (op) {
472*0f4c859eSApple OSS Distributions case VSOCK_SHUTDOWN:
473*0f4c859eSApple OSS Distributions socantsendmore(pcb->so);
474*0f4c859eSApple OSS Distributions socantrcvmore(pcb->so);
475*0f4c859eSApple OSS Distributions break;
476*0f4c859eSApple OSS Distributions case VSOCK_SHUTDOWN_RECEIVE:
477*0f4c859eSApple OSS Distributions socantsendmore(pcb->so);
478*0f4c859eSApple OSS Distributions break;
479*0f4c859eSApple OSS Distributions case VSOCK_SHUTDOWN_SEND:
480*0f4c859eSApple OSS Distributions socantrcvmore(pcb->so);
481*0f4c859eSApple OSS Distributions break;
482*0f4c859eSApple OSS Distributions case VSOCK_PAYLOAD:
483*0f4c859eSApple OSS Distributions // Add data to the receive queue then wakeup any reading threads.
484*0f4c859eSApple OSS Distributions error = !sbappendstream(&pcb->so->so_rcv, m);
485*0f4c859eSApple OSS Distributions if (!error) {
486*0f4c859eSApple OSS Distributions sorwakeup(pcb->so);
487*0f4c859eSApple OSS Distributions }
488*0f4c859eSApple OSS Distributions break;
489*0f4c859eSApple OSS Distributions case VSOCK_RESET:
490*0f4c859eSApple OSS Distributions vsock_unbind_pcb(pcb, false);
491*0f4c859eSApple OSS Distributions break;
492*0f4c859eSApple OSS Distributions default:
493*0f4c859eSApple OSS Distributions error = ENOTSUP;
494*0f4c859eSApple OSS Distributions break;
495*0f4c859eSApple OSS Distributions }
496*0f4c859eSApple OSS Distributions
497*0f4c859eSApple OSS Distributions return error;
498*0f4c859eSApple OSS Distributions }
499*0f4c859eSApple OSS Distributions
500*0f4c859eSApple OSS Distributions static errno_t
vsock_put_message_connecting(struct vsockpcb * pcb,enum vsock_operation op)501*0f4c859eSApple OSS Distributions vsock_put_message_connecting(struct vsockpcb *pcb, enum vsock_operation op)
502*0f4c859eSApple OSS Distributions {
503*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
504*0f4c859eSApple OSS Distributions
505*0f4c859eSApple OSS Distributions errno_t error = 0;
506*0f4c859eSApple OSS Distributions
507*0f4c859eSApple OSS Distributions switch (op) {
508*0f4c859eSApple OSS Distributions case VSOCK_RESPONSE:
509*0f4c859eSApple OSS Distributions soisconnected(pcb->so);
510*0f4c859eSApple OSS Distributions break;
511*0f4c859eSApple OSS Distributions case VSOCK_RESET:
512*0f4c859eSApple OSS Distributions pcb->so->so_error = EAGAIN;
513*0f4c859eSApple OSS Distributions error = vsock_disconnect_pcb(pcb);
514*0f4c859eSApple OSS Distributions break;
515*0f4c859eSApple OSS Distributions default:
516*0f4c859eSApple OSS Distributions vsock_disconnect_pcb(pcb);
517*0f4c859eSApple OSS Distributions error = ENOTSUP;
518*0f4c859eSApple OSS Distributions break;
519*0f4c859eSApple OSS Distributions }
520*0f4c859eSApple OSS Distributions
521*0f4c859eSApple OSS Distributions return error;
522*0f4c859eSApple OSS Distributions }
523*0f4c859eSApple OSS Distributions
524*0f4c859eSApple OSS Distributions static errno_t
vsock_put_message_listening(struct vsockpcb * pcb,enum vsock_operation op,struct vsock_address src,struct vsock_address dst)525*0f4c859eSApple OSS Distributions vsock_put_message_listening(struct vsockpcb *pcb, enum vsock_operation op, struct vsock_address src, struct vsock_address dst)
526*0f4c859eSApple OSS Distributions {
527*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
528*0f4c859eSApple OSS Distributions
529*0f4c859eSApple OSS Distributions struct sockaddr_vm addr;
530*0f4c859eSApple OSS Distributions struct socket *so2 = NULL;
531*0f4c859eSApple OSS Distributions struct vsockpcb *pcb2 = NULL;
532*0f4c859eSApple OSS Distributions
533*0f4c859eSApple OSS Distributions errno_t error = 0;
534*0f4c859eSApple OSS Distributions
535*0f4c859eSApple OSS Distributions switch (op) {
536*0f4c859eSApple OSS Distributions case VSOCK_REQUEST:
537*0f4c859eSApple OSS Distributions addr = (struct sockaddr_vm) {
538*0f4c859eSApple OSS Distributions .svm_len = sizeof(addr),
539*0f4c859eSApple OSS Distributions .svm_family = AF_VSOCK,
540*0f4c859eSApple OSS Distributions .svm_reserved1 = 0,
541*0f4c859eSApple OSS Distributions .svm_port = pcb->local_address.port,
542*0f4c859eSApple OSS Distributions .svm_cid = pcb->local_address.cid
543*0f4c859eSApple OSS Distributions };
544*0f4c859eSApple OSS Distributions so2 = sonewconn(pcb->so, 0, (struct sockaddr *)&addr);
545*0f4c859eSApple OSS Distributions if (!so2) {
546*0f4c859eSApple OSS Distributions // It is likely that the backlog is full. Deny this request.
547*0f4c859eSApple OSS Distributions vsock_pcb_safe_reset_address(pcb, dst, src);
548*0f4c859eSApple OSS Distributions error = ECONNREFUSED;
549*0f4c859eSApple OSS Distributions break;
550*0f4c859eSApple OSS Distributions }
551*0f4c859eSApple OSS Distributions
552*0f4c859eSApple OSS Distributions pcb2 = sotovsockpcb(so2);
553*0f4c859eSApple OSS Distributions if (!pcb2) {
554*0f4c859eSApple OSS Distributions error = EINVAL;
555*0f4c859eSApple OSS Distributions goto done;
556*0f4c859eSApple OSS Distributions }
557*0f4c859eSApple OSS Distributions
558*0f4c859eSApple OSS Distributions error = vsock_bind_address(pcb2, dst, src);
559*0f4c859eSApple OSS Distributions if (error) {
560*0f4c859eSApple OSS Distributions goto done;
561*0f4c859eSApple OSS Distributions }
562*0f4c859eSApple OSS Distributions
563*0f4c859eSApple OSS Distributions error = vsock_pcb_respond(pcb2);
564*0f4c859eSApple OSS Distributions if (error) {
565*0f4c859eSApple OSS Distributions goto done;
566*0f4c859eSApple OSS Distributions }
567*0f4c859eSApple OSS Distributions
568*0f4c859eSApple OSS Distributions soisconnected(so2);
569*0f4c859eSApple OSS Distributions
570*0f4c859eSApple OSS Distributions done:
571*0f4c859eSApple OSS Distributions if (error) {
572*0f4c859eSApple OSS Distributions soisdisconnected(so2);
573*0f4c859eSApple OSS Distributions if (pcb2) {
574*0f4c859eSApple OSS Distributions vsock_unbind_pcb(pcb2, false);
575*0f4c859eSApple OSS Distributions }
576*0f4c859eSApple OSS Distributions socket_unlock(so2, 1);
577*0f4c859eSApple OSS Distributions vsock_pcb_reset_address(dst, src);
578*0f4c859eSApple OSS Distributions } else {
579*0f4c859eSApple OSS Distributions socket_unlock(so2, 0);
580*0f4c859eSApple OSS Distributions }
581*0f4c859eSApple OSS Distributions socket_lock(pcb->so, 0);
582*0f4c859eSApple OSS Distributions
583*0f4c859eSApple OSS Distributions break;
584*0f4c859eSApple OSS Distributions case VSOCK_RESET:
585*0f4c859eSApple OSS Distributions error = vsock_pcb_safe_reset_address(pcb, dst, src);
586*0f4c859eSApple OSS Distributions break;
587*0f4c859eSApple OSS Distributions default:
588*0f4c859eSApple OSS Distributions vsock_pcb_safe_reset_address(pcb, dst, src);
589*0f4c859eSApple OSS Distributions error = ENOTSUP;
590*0f4c859eSApple OSS Distributions break;
591*0f4c859eSApple OSS Distributions }
592*0f4c859eSApple OSS Distributions
593*0f4c859eSApple OSS Distributions return error;
594*0f4c859eSApple OSS Distributions }
595*0f4c859eSApple OSS Distributions
596*0f4c859eSApple OSS Distributions /* VSock Transport */
597*0f4c859eSApple OSS Distributions
598*0f4c859eSApple OSS Distributions errno_t
vsock_add_transport(struct vsock_transport * transport)599*0f4c859eSApple OSS Distributions vsock_add_transport(struct vsock_transport *transport)
600*0f4c859eSApple OSS Distributions {
601*0f4c859eSApple OSS Distributions if (transport == NULL || transport->provider == NULL) {
602*0f4c859eSApple OSS Distributions return EINVAL;
603*0f4c859eSApple OSS Distributions }
604*0f4c859eSApple OSS Distributions if (!os_atomic_cmpxchg((void * volatile *)&the_vsock_transport, NULL, transport, acq_rel)) {
605*0f4c859eSApple OSS Distributions return EEXIST;
606*0f4c859eSApple OSS Distributions }
607*0f4c859eSApple OSS Distributions return 0;
608*0f4c859eSApple OSS Distributions }
609*0f4c859eSApple OSS Distributions
610*0f4c859eSApple OSS Distributions errno_t
vsock_remove_transport(struct vsock_transport * transport)611*0f4c859eSApple OSS Distributions vsock_remove_transport(struct vsock_transport *transport)
612*0f4c859eSApple OSS Distributions {
613*0f4c859eSApple OSS Distributions if (!os_atomic_cmpxchg((void * volatile *)&the_vsock_transport, transport, NULL, acq_rel)) {
614*0f4c859eSApple OSS Distributions return ENODEV;
615*0f4c859eSApple OSS Distributions }
616*0f4c859eSApple OSS Distributions return 0;
617*0f4c859eSApple OSS Distributions }
618*0f4c859eSApple OSS Distributions
619*0f4c859eSApple OSS Distributions errno_t
vsock_reset_transport(struct vsock_transport * transport)620*0f4c859eSApple OSS Distributions vsock_reset_transport(struct vsock_transport *transport)
621*0f4c859eSApple OSS Distributions {
622*0f4c859eSApple OSS Distributions if (transport == NULL) {
623*0f4c859eSApple OSS Distributions return EINVAL;
624*0f4c859eSApple OSS Distributions }
625*0f4c859eSApple OSS Distributions
626*0f4c859eSApple OSS Distributions errno_t error = 0;
627*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = NULL;
628*0f4c859eSApple OSS Distributions struct vsockpcb *tmp_pcb = NULL;
629*0f4c859eSApple OSS Distributions
630*0f4c859eSApple OSS Distributions lck_rw_lock_exclusive(&vsockinfo.bound_lock);
631*0f4c859eSApple OSS Distributions LIST_FOREACH_SAFE(pcb, &vsockinfo.bound, bound, tmp_pcb) {
632*0f4c859eSApple OSS Distributions // Disconnect this transport's sockets. Listen and bind sockets must stay alive.
633*0f4c859eSApple OSS Distributions socket_lock(pcb->so, 1);
634*0f4c859eSApple OSS Distributions if (pcb->transport == transport && pcb->so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) {
635*0f4c859eSApple OSS Distributions errno_t dc_error = vsock_disconnect_pcb_locked(pcb);
636*0f4c859eSApple OSS Distributions if (dc_error && !error) {
637*0f4c859eSApple OSS Distributions error = dc_error;
638*0f4c859eSApple OSS Distributions }
639*0f4c859eSApple OSS Distributions }
640*0f4c859eSApple OSS Distributions socket_unlock(pcb->so, 1);
641*0f4c859eSApple OSS Distributions }
642*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.bound_lock);
643*0f4c859eSApple OSS Distributions
644*0f4c859eSApple OSS Distributions return error;
645*0f4c859eSApple OSS Distributions }
646*0f4c859eSApple OSS Distributions
647*0f4c859eSApple OSS Distributions errno_t
vsock_put_message(struct vsock_address src,struct vsock_address dst,enum vsock_operation op,uint32_t buf_alloc,uint32_t fwd_cnt,mbuf_t m)648*0f4c859eSApple OSS Distributions vsock_put_message(struct vsock_address src, struct vsock_address dst, enum vsock_operation op, uint32_t buf_alloc, uint32_t fwd_cnt, mbuf_t m)
649*0f4c859eSApple OSS Distributions {
650*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = vsock_get_matching_pcb(dst, src);
651*0f4c859eSApple OSS Distributions if (!pcb) {
652*0f4c859eSApple OSS Distributions if (op != VSOCK_RESET) {
653*0f4c859eSApple OSS Distributions vsock_pcb_reset_address(dst, src);
654*0f4c859eSApple OSS Distributions }
655*0f4c859eSApple OSS Distributions if (m != NULL) {
656*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
657*0f4c859eSApple OSS Distributions }
658*0f4c859eSApple OSS Distributions return EINVAL;
659*0f4c859eSApple OSS Distributions }
660*0f4c859eSApple OSS Distributions
661*0f4c859eSApple OSS Distributions socket_lock_assert_owned(pcb->so);
662*0f4c859eSApple OSS Distributions
663*0f4c859eSApple OSS Distributions struct socket *so = pcb->so;
664*0f4c859eSApple OSS Distributions errno_t error = 0;
665*0f4c859eSApple OSS Distributions
666*0f4c859eSApple OSS Distributions // Check if the peer's buffer has changed. Update our view of the peer's forwarded bytes.
667*0f4c859eSApple OSS Distributions int buffers_changed = (pcb->peer_buf_alloc != buf_alloc) || (pcb->peer_fwd_cnt) != fwd_cnt;
668*0f4c859eSApple OSS Distributions pcb->peer_buf_alloc = buf_alloc;
669*0f4c859eSApple OSS Distributions pcb->peer_fwd_cnt = fwd_cnt;
670*0f4c859eSApple OSS Distributions
671*0f4c859eSApple OSS Distributions // Peer's buffer has enough space for the next packet. Notify any threads waiting for space.
672*0f4c859eSApple OSS Distributions if (buffers_changed && vsock_get_peer_space(pcb) >= pcb->waiting_send_size) {
673*0f4c859eSApple OSS Distributions sowwakeup(so);
674*0f4c859eSApple OSS Distributions }
675*0f4c859eSApple OSS Distributions
676*0f4c859eSApple OSS Distributions switch (op) {
677*0f4c859eSApple OSS Distributions case VSOCK_CREDIT_REQUEST:
678*0f4c859eSApple OSS Distributions error = vsock_pcb_credit_update(pcb);
679*0f4c859eSApple OSS Distributions break;
680*0f4c859eSApple OSS Distributions case VSOCK_CREDIT_UPDATE:
681*0f4c859eSApple OSS Distributions break;
682*0f4c859eSApple OSS Distributions default:
683*0f4c859eSApple OSS Distributions if (so->so_state & SS_ISCONNECTED) {
684*0f4c859eSApple OSS Distributions error = vsock_put_message_connected(pcb, op, m);
685*0f4c859eSApple OSS Distributions m = NULL;
686*0f4c859eSApple OSS Distributions } else if (so->so_state & SS_ISCONNECTING) {
687*0f4c859eSApple OSS Distributions error = vsock_put_message_connecting(pcb, op);
688*0f4c859eSApple OSS Distributions } else if (so->so_options & SO_ACCEPTCONN) {
689*0f4c859eSApple OSS Distributions error = vsock_put_message_listening(pcb, op, src, dst);
690*0f4c859eSApple OSS Distributions } else {
691*0f4c859eSApple OSS Distributions // Reset the connection for other states such as 'disconnecting'.
692*0f4c859eSApple OSS Distributions error = vsock_disconnect_pcb(pcb);
693*0f4c859eSApple OSS Distributions if (!error) {
694*0f4c859eSApple OSS Distributions error = ENODEV;
695*0f4c859eSApple OSS Distributions }
696*0f4c859eSApple OSS Distributions }
697*0f4c859eSApple OSS Distributions break;
698*0f4c859eSApple OSS Distributions }
699*0f4c859eSApple OSS Distributions socket_unlock(so, 1);
700*0f4c859eSApple OSS Distributions
701*0f4c859eSApple OSS Distributions if (m != NULL) {
702*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
703*0f4c859eSApple OSS Distributions }
704*0f4c859eSApple OSS Distributions
705*0f4c859eSApple OSS Distributions return error;
706*0f4c859eSApple OSS Distributions }
707*0f4c859eSApple OSS Distributions
708*0f4c859eSApple OSS Distributions /* VSock Sysctl */
709*0f4c859eSApple OSS Distributions
710*0f4c859eSApple OSS Distributions static int
711*0f4c859eSApple OSS Distributions vsock_pcblist SYSCTL_HANDLER_ARGS
712*0f4c859eSApple OSS Distributions {
713*0f4c859eSApple OSS Distributions #pragma unused(oidp,arg2)
714*0f4c859eSApple OSS Distributions
715*0f4c859eSApple OSS Distributions int error;
716*0f4c859eSApple OSS Distributions
717*0f4c859eSApple OSS Distributions // Only stream is supported.
718*0f4c859eSApple OSS Distributions if ((intptr_t)arg1 != SOCK_STREAM) {
719*0f4c859eSApple OSS Distributions return EINVAL;
720*0f4c859eSApple OSS Distributions }
721*0f4c859eSApple OSS Distributions
722*0f4c859eSApple OSS Distributions // Get the generation count and the count of all vsock sockets.
723*0f4c859eSApple OSS Distributions lck_rw_lock_shared(&vsockinfo.all_lock);
724*0f4c859eSApple OSS Distributions uint64_t n = vsockinfo.all_pcb_count;
725*0f4c859eSApple OSS Distributions vsock_gen_t gen_count = vsockinfo.vsock_gencnt;
726*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.all_lock);
727*0f4c859eSApple OSS Distributions
728*0f4c859eSApple OSS Distributions const size_t xpcb_len = sizeof(struct xvsockpcb);
729*0f4c859eSApple OSS Distributions struct xvsockpgen xvg;
730*0f4c859eSApple OSS Distributions
731*0f4c859eSApple OSS Distributions /*
732*0f4c859eSApple OSS Distributions * The process of preparing the PCB list is too time-consuming and
733*0f4c859eSApple OSS Distributions * resource-intensive to repeat twice on every request.
734*0f4c859eSApple OSS Distributions */
735*0f4c859eSApple OSS Distributions if (req->oldptr == USER_ADDR_NULL) {
736*0f4c859eSApple OSS Distributions req->oldidx = (size_t)(2 * sizeof(xvg) + (n + n / 8) * xpcb_len);
737*0f4c859eSApple OSS Distributions return 0;
738*0f4c859eSApple OSS Distributions }
739*0f4c859eSApple OSS Distributions
740*0f4c859eSApple OSS Distributions if (req->newptr != USER_ADDR_NULL) {
741*0f4c859eSApple OSS Distributions return EPERM;
742*0f4c859eSApple OSS Distributions }
743*0f4c859eSApple OSS Distributions
744*0f4c859eSApple OSS Distributions bzero(&xvg, sizeof(xvg));
745*0f4c859eSApple OSS Distributions xvg.xvg_len = sizeof(xvg);
746*0f4c859eSApple OSS Distributions xvg.xvg_count = n;
747*0f4c859eSApple OSS Distributions xvg.xvg_gen = gen_count;
748*0f4c859eSApple OSS Distributions xvg.xvg_sogen = so_gencnt;
749*0f4c859eSApple OSS Distributions error = SYSCTL_OUT(req, &xvg, sizeof(xvg));
750*0f4c859eSApple OSS Distributions if (error) {
751*0f4c859eSApple OSS Distributions return error;
752*0f4c859eSApple OSS Distributions }
753*0f4c859eSApple OSS Distributions
754*0f4c859eSApple OSS Distributions // Return if no sockets exist.
755*0f4c859eSApple OSS Distributions if (n == 0) {
756*0f4c859eSApple OSS Distributions return 0;
757*0f4c859eSApple OSS Distributions }
758*0f4c859eSApple OSS Distributions
759*0f4c859eSApple OSS Distributions lck_rw_lock_shared(&vsockinfo.all_lock);
760*0f4c859eSApple OSS Distributions
761*0f4c859eSApple OSS Distributions n = 0;
762*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = NULL;
763*0f4c859eSApple OSS Distributions TAILQ_FOREACH(pcb, &vsockinfo.all, all) {
764*0f4c859eSApple OSS Distributions // Bail if there is not enough user buffer for this next socket.
765*0f4c859eSApple OSS Distributions if (req->oldlen - req->oldidx - sizeof(xvg) < xpcb_len) {
766*0f4c859eSApple OSS Distributions break;
767*0f4c859eSApple OSS Distributions }
768*0f4c859eSApple OSS Distributions
769*0f4c859eSApple OSS Distributions // Populate the socket structure.
770*0f4c859eSApple OSS Distributions socket_lock(pcb->so, 1);
771*0f4c859eSApple OSS Distributions if (pcb->vsock_gencnt <= gen_count) {
772*0f4c859eSApple OSS Distributions struct xvsockpcb xpcb;
773*0f4c859eSApple OSS Distributions bzero(&xpcb, xpcb_len);
774*0f4c859eSApple OSS Distributions xpcb.xv_len = xpcb_len;
775*0f4c859eSApple OSS Distributions xpcb.xv_vsockpp = (uint64_t)VM_KERNEL_ADDRHASH(pcb);
776*0f4c859eSApple OSS Distributions xpcb.xvp_local_cid = pcb->local_address.cid;
777*0f4c859eSApple OSS Distributions xpcb.xvp_local_port = pcb->local_address.port;
778*0f4c859eSApple OSS Distributions xpcb.xvp_remote_cid = pcb->remote_address.cid;
779*0f4c859eSApple OSS Distributions xpcb.xvp_remote_port = pcb->remote_address.port;
780*0f4c859eSApple OSS Distributions xpcb.xvp_rxcnt = pcb->fwd_cnt;
781*0f4c859eSApple OSS Distributions xpcb.xvp_txcnt = pcb->tx_cnt;
782*0f4c859eSApple OSS Distributions xpcb.xvp_peer_rxhiwat = pcb->peer_buf_alloc;
783*0f4c859eSApple OSS Distributions xpcb.xvp_peer_rxcnt = pcb->peer_fwd_cnt;
784*0f4c859eSApple OSS Distributions xpcb.xvp_last_pid = pcb->so->last_pid;
785*0f4c859eSApple OSS Distributions xpcb.xvp_gencnt = pcb->vsock_gencnt;
786*0f4c859eSApple OSS Distributions if (pcb->so) {
787*0f4c859eSApple OSS Distributions sotoxsocket(pcb->so, &xpcb.xv_socket);
788*0f4c859eSApple OSS Distributions }
789*0f4c859eSApple OSS Distributions socket_unlock(pcb->so, 1);
790*0f4c859eSApple OSS Distributions
791*0f4c859eSApple OSS Distributions error = SYSCTL_OUT(req, &xpcb, xpcb_len);
792*0f4c859eSApple OSS Distributions if (error != 0) {
793*0f4c859eSApple OSS Distributions break;
794*0f4c859eSApple OSS Distributions }
795*0f4c859eSApple OSS Distributions n++;
796*0f4c859eSApple OSS Distributions } else {
797*0f4c859eSApple OSS Distributions socket_unlock(pcb->so, 1);
798*0f4c859eSApple OSS Distributions }
799*0f4c859eSApple OSS Distributions }
800*0f4c859eSApple OSS Distributions
801*0f4c859eSApple OSS Distributions // Update the generation count to match the sockets being returned.
802*0f4c859eSApple OSS Distributions gen_count = vsockinfo.vsock_gencnt;
803*0f4c859eSApple OSS Distributions
804*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.all_lock);
805*0f4c859eSApple OSS Distributions
806*0f4c859eSApple OSS Distributions if (!error) {
807*0f4c859eSApple OSS Distributions /*
808*0f4c859eSApple OSS Distributions * Give the user an updated idea of our state.
809*0f4c859eSApple OSS Distributions * If the generation differs from what we told
810*0f4c859eSApple OSS Distributions * her before, she knows that something happened
811*0f4c859eSApple OSS Distributions * while we were processing this request, and it
812*0f4c859eSApple OSS Distributions * might be necessary to retry.
813*0f4c859eSApple OSS Distributions */
814*0f4c859eSApple OSS Distributions bzero(&xvg, sizeof(xvg));
815*0f4c859eSApple OSS Distributions xvg.xvg_len = sizeof(xvg);
816*0f4c859eSApple OSS Distributions xvg.xvg_count = n;
817*0f4c859eSApple OSS Distributions xvg.xvg_gen = gen_count;
818*0f4c859eSApple OSS Distributions xvg.xvg_sogen = so_gencnt;
819*0f4c859eSApple OSS Distributions error = SYSCTL_OUT(req, &xvg, sizeof(xvg));
820*0f4c859eSApple OSS Distributions }
821*0f4c859eSApple OSS Distributions
822*0f4c859eSApple OSS Distributions return error;
823*0f4c859eSApple OSS Distributions }
824*0f4c859eSApple OSS Distributions
825*0f4c859eSApple OSS Distributions #ifdef SYSCTL_DECL
826*0f4c859eSApple OSS Distributions SYSCTL_NODE(_net, OID_AUTO, vsock, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "vsock");
827*0f4c859eSApple OSS Distributions SYSCTL_UINT(_net_vsock, OID_AUTO, sendspace, CTLFLAG_RW | CTLFLAG_LOCKED,
828*0f4c859eSApple OSS Distributions &vsock_sendspace, 0, "Maximum outgoing vsock datagram size");
829*0f4c859eSApple OSS Distributions SYSCTL_UINT(_net_vsock, OID_AUTO, recvspace, CTLFLAG_RW | CTLFLAG_LOCKED,
830*0f4c859eSApple OSS Distributions &vsock_recvspace, 0, "Maximum incoming vsock datagram size");
831*0f4c859eSApple OSS Distributions SYSCTL_PROC(_net_vsock, OID_AUTO, pcblist,
832*0f4c859eSApple OSS Distributions CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
833*0f4c859eSApple OSS Distributions (caddr_t)(long)SOCK_STREAM, 0, vsock_pcblist, "S,xvsockpcb",
834*0f4c859eSApple OSS Distributions "List of active vsock sockets");
835*0f4c859eSApple OSS Distributions #endif
836*0f4c859eSApple OSS Distributions
837*0f4c859eSApple OSS Distributions /* VSock Protocol */
838*0f4c859eSApple OSS Distributions
839*0f4c859eSApple OSS Distributions static int
vsock_attach(struct socket * so,int proto,struct proc * p)840*0f4c859eSApple OSS Distributions vsock_attach(struct socket *so, int proto, struct proc *p)
841*0f4c859eSApple OSS Distributions {
842*0f4c859eSApple OSS Distributions #pragma unused(proto, p)
843*0f4c859eSApple OSS Distributions
844*0f4c859eSApple OSS Distributions // Reserve send and receive buffers.
845*0f4c859eSApple OSS Distributions errno_t error = soreserve(so, vsock_sendspace, vsock_recvspace);
846*0f4c859eSApple OSS Distributions if (error) {
847*0f4c859eSApple OSS Distributions return error;
848*0f4c859eSApple OSS Distributions }
849*0f4c859eSApple OSS Distributions
850*0f4c859eSApple OSS Distributions // Attach should only be run once per socket.
851*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
852*0f4c859eSApple OSS Distributions if (pcb) {
853*0f4c859eSApple OSS Distributions return EINVAL;
854*0f4c859eSApple OSS Distributions }
855*0f4c859eSApple OSS Distributions
856*0f4c859eSApple OSS Distributions // Get the transport for this socket.
857*0f4c859eSApple OSS Distributions struct vsock_transport *transport = os_atomic_load(&the_vsock_transport, relaxed);
858*0f4c859eSApple OSS Distributions if (transport == NULL) {
859*0f4c859eSApple OSS Distributions return ENODEV;
860*0f4c859eSApple OSS Distributions }
861*0f4c859eSApple OSS Distributions
862*0f4c859eSApple OSS Distributions // Initialize the vsock protocol control block.
863*0f4c859eSApple OSS Distributions pcb = zalloc_flags(vsockpcb_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
864*0f4c859eSApple OSS Distributions pcb->so = so;
865*0f4c859eSApple OSS Distributions pcb->transport = transport;
866*0f4c859eSApple OSS Distributions pcb->local_address = (struct vsock_address) {
867*0f4c859eSApple OSS Distributions .cid = VMADDR_CID_ANY,
868*0f4c859eSApple OSS Distributions .port = VMADDR_PORT_ANY
869*0f4c859eSApple OSS Distributions };
870*0f4c859eSApple OSS Distributions pcb->remote_address = (struct vsock_address) {
871*0f4c859eSApple OSS Distributions .cid = VMADDR_CID_ANY,
872*0f4c859eSApple OSS Distributions .port = VMADDR_PORT_ANY
873*0f4c859eSApple OSS Distributions };
874*0f4c859eSApple OSS Distributions so->so_pcb = pcb;
875*0f4c859eSApple OSS Distributions
876*0f4c859eSApple OSS Distributions // Tell the transport that this socket has attached.
877*0f4c859eSApple OSS Distributions error = transport->attach_socket(transport->provider);
878*0f4c859eSApple OSS Distributions if (error) {
879*0f4c859eSApple OSS Distributions zfree(vsockpcb_zone, pcb);
880*0f4c859eSApple OSS Distributions so->so_pcb = NULL;
881*0f4c859eSApple OSS Distributions return error;
882*0f4c859eSApple OSS Distributions }
883*0f4c859eSApple OSS Distributions
884*0f4c859eSApple OSS Distributions // Add to the list of all vsock sockets.
885*0f4c859eSApple OSS Distributions lck_rw_lock_exclusive(&vsockinfo.all_lock);
886*0f4c859eSApple OSS Distributions TAILQ_INSERT_TAIL(&vsockinfo.all, pcb, all);
887*0f4c859eSApple OSS Distributions vsockinfo.all_pcb_count++;
888*0f4c859eSApple OSS Distributions pcb->vsock_gencnt = ++vsockinfo.vsock_gencnt;
889*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.all_lock);
890*0f4c859eSApple OSS Distributions
891*0f4c859eSApple OSS Distributions return 0;
892*0f4c859eSApple OSS Distributions }
893*0f4c859eSApple OSS Distributions
894*0f4c859eSApple OSS Distributions static int
vsock_control(struct socket * so,u_long cmd,caddr_t data,struct ifnet * ifp,struct proc * p)895*0f4c859eSApple OSS Distributions vsock_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct proc *p)
896*0f4c859eSApple OSS Distributions {
897*0f4c859eSApple OSS Distributions #pragma unused(ifp)
898*0f4c859eSApple OSS Distributions
899*0f4c859eSApple OSS Distributions VERIFY(so != NULL || p == kernproc);
900*0f4c859eSApple OSS Distributions
901*0f4c859eSApple OSS Distributions if (cmd != IOCTL_VM_SOCKETS_GET_LOCAL_CID) {
902*0f4c859eSApple OSS Distributions return EINVAL;
903*0f4c859eSApple OSS Distributions }
904*0f4c859eSApple OSS Distributions
905*0f4c859eSApple OSS Distributions struct vsock_transport *transport;
906*0f4c859eSApple OSS Distributions if (so) {
907*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
908*0f4c859eSApple OSS Distributions if (pcb == NULL) {
909*0f4c859eSApple OSS Distributions return EINVAL;
910*0f4c859eSApple OSS Distributions }
911*0f4c859eSApple OSS Distributions transport = pcb->transport;
912*0f4c859eSApple OSS Distributions } else {
913*0f4c859eSApple OSS Distributions transport = os_atomic_load(&the_vsock_transport, relaxed);
914*0f4c859eSApple OSS Distributions }
915*0f4c859eSApple OSS Distributions
916*0f4c859eSApple OSS Distributions if (transport == NULL) {
917*0f4c859eSApple OSS Distributions return ENODEV;
918*0f4c859eSApple OSS Distributions }
919*0f4c859eSApple OSS Distributions
920*0f4c859eSApple OSS Distributions uint32_t transport_cid;
921*0f4c859eSApple OSS Distributions errno_t error = transport->get_cid(transport->provider, &transport_cid);
922*0f4c859eSApple OSS Distributions if (error) {
923*0f4c859eSApple OSS Distributions return error;
924*0f4c859eSApple OSS Distributions }
925*0f4c859eSApple OSS Distributions
926*0f4c859eSApple OSS Distributions memcpy(data, &transport_cid, sizeof(transport_cid));
927*0f4c859eSApple OSS Distributions
928*0f4c859eSApple OSS Distributions return 0;
929*0f4c859eSApple OSS Distributions }
930*0f4c859eSApple OSS Distributions
931*0f4c859eSApple OSS Distributions static int
vsock_detach(struct socket * so)932*0f4c859eSApple OSS Distributions vsock_detach(struct socket *so)
933*0f4c859eSApple OSS Distributions {
934*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
935*0f4c859eSApple OSS Distributions if (pcb == NULL) {
936*0f4c859eSApple OSS Distributions return EINVAL;
937*0f4c859eSApple OSS Distributions }
938*0f4c859eSApple OSS Distributions
939*0f4c859eSApple OSS Distributions vsock_unbind_pcb(pcb, false);
940*0f4c859eSApple OSS Distributions
941*0f4c859eSApple OSS Distributions // Tell the transport that this socket has detached.
942*0f4c859eSApple OSS Distributions struct vsock_transport *transport = pcb->transport;
943*0f4c859eSApple OSS Distributions errno_t error = transport->detach_socket(transport->provider);
944*0f4c859eSApple OSS Distributions if (error) {
945*0f4c859eSApple OSS Distributions return error;
946*0f4c859eSApple OSS Distributions }
947*0f4c859eSApple OSS Distributions
948*0f4c859eSApple OSS Distributions // Remove from the list of all vsock sockets.
949*0f4c859eSApple OSS Distributions lck_rw_lock_exclusive(&vsockinfo.all_lock);
950*0f4c859eSApple OSS Distributions TAILQ_REMOVE(&vsockinfo.all, pcb, all);
951*0f4c859eSApple OSS Distributions pcb->all.tqe_next = NULL;
952*0f4c859eSApple OSS Distributions pcb->all.tqe_prev = NULL;
953*0f4c859eSApple OSS Distributions vsockinfo.all_pcb_count--;
954*0f4c859eSApple OSS Distributions vsockinfo.vsock_gencnt++;
955*0f4c859eSApple OSS Distributions lck_rw_done(&vsockinfo.all_lock);
956*0f4c859eSApple OSS Distributions
957*0f4c859eSApple OSS Distributions // Deallocate any resources.
958*0f4c859eSApple OSS Distributions zfree(vsockpcb_zone, pcb);
959*0f4c859eSApple OSS Distributions so->so_pcb = 0;
960*0f4c859eSApple OSS Distributions so->so_flags |= SOF_PCBCLEARING;
961*0f4c859eSApple OSS Distributions sofree(so);
962*0f4c859eSApple OSS Distributions
963*0f4c859eSApple OSS Distributions return 0;
964*0f4c859eSApple OSS Distributions }
965*0f4c859eSApple OSS Distributions
966*0f4c859eSApple OSS Distributions static int
vsock_abort(struct socket * so)967*0f4c859eSApple OSS Distributions vsock_abort(struct socket *so)
968*0f4c859eSApple OSS Distributions {
969*0f4c859eSApple OSS Distributions soisdisconnected(so);
970*0f4c859eSApple OSS Distributions return vsock_detach(so);
971*0f4c859eSApple OSS Distributions }
972*0f4c859eSApple OSS Distributions
973*0f4c859eSApple OSS Distributions static int
vsock_bind(struct socket * so,struct sockaddr * nam,struct proc * p)974*0f4c859eSApple OSS Distributions vsock_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
975*0f4c859eSApple OSS Distributions {
976*0f4c859eSApple OSS Distributions #pragma unused(p)
977*0f4c859eSApple OSS Distributions
978*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
979*0f4c859eSApple OSS Distributions if (pcb == NULL) {
980*0f4c859eSApple OSS Distributions return EINVAL;
981*0f4c859eSApple OSS Distributions }
982*0f4c859eSApple OSS Distributions
983*0f4c859eSApple OSS Distributions struct sockaddr_vm *addr = (struct sockaddr_vm *)nam;
984*0f4c859eSApple OSS Distributions
985*0f4c859eSApple OSS Distributions errno_t error = vsock_sockaddr_vm_validate(pcb, addr);
986*0f4c859eSApple OSS Distributions if (error) {
987*0f4c859eSApple OSS Distributions return error;
988*0f4c859eSApple OSS Distributions }
989*0f4c859eSApple OSS Distributions
990*0f4c859eSApple OSS Distributions struct vsock_address laddr = (struct vsock_address) {
991*0f4c859eSApple OSS Distributions .cid = addr->svm_cid,
992*0f4c859eSApple OSS Distributions .port = addr->svm_port,
993*0f4c859eSApple OSS Distributions };
994*0f4c859eSApple OSS Distributions
995*0f4c859eSApple OSS Distributions struct vsock_address raddr = (struct vsock_address) {
996*0f4c859eSApple OSS Distributions .cid = VMADDR_CID_ANY,
997*0f4c859eSApple OSS Distributions .port = VMADDR_PORT_ANY,
998*0f4c859eSApple OSS Distributions };
999*0f4c859eSApple OSS Distributions
1000*0f4c859eSApple OSS Distributions error = vsock_bind_address(pcb, laddr, raddr);
1001*0f4c859eSApple OSS Distributions if (error) {
1002*0f4c859eSApple OSS Distributions return error;
1003*0f4c859eSApple OSS Distributions }
1004*0f4c859eSApple OSS Distributions
1005*0f4c859eSApple OSS Distributions return 0;
1006*0f4c859eSApple OSS Distributions }
1007*0f4c859eSApple OSS Distributions
1008*0f4c859eSApple OSS Distributions static int
vsock_listen(struct socket * so,struct proc * p)1009*0f4c859eSApple OSS Distributions vsock_listen(struct socket *so, struct proc *p)
1010*0f4c859eSApple OSS Distributions {
1011*0f4c859eSApple OSS Distributions #pragma unused(p)
1012*0f4c859eSApple OSS Distributions
1013*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1014*0f4c859eSApple OSS Distributions if (pcb == NULL) {
1015*0f4c859eSApple OSS Distributions return EINVAL;
1016*0f4c859eSApple OSS Distributions }
1017*0f4c859eSApple OSS Distributions
1018*0f4c859eSApple OSS Distributions // Only stream is supported currently.
1019*0f4c859eSApple OSS Distributions if (so->so_type != SOCK_STREAM) {
1020*0f4c859eSApple OSS Distributions return EAFNOSUPPORT;
1021*0f4c859eSApple OSS Distributions }
1022*0f4c859eSApple OSS Distributions
1023*0f4c859eSApple OSS Distributions struct vsock_address *addr = &pcb->local_address;
1024*0f4c859eSApple OSS Distributions
1025*0f4c859eSApple OSS Distributions if (addr->port == VMADDR_CID_ANY) {
1026*0f4c859eSApple OSS Distributions return EFAULT;
1027*0f4c859eSApple OSS Distributions }
1028*0f4c859eSApple OSS Distributions
1029*0f4c859eSApple OSS Distributions struct vsock_transport *transport = pcb->transport;
1030*0f4c859eSApple OSS Distributions uint32_t transport_cid;
1031*0f4c859eSApple OSS Distributions errno_t error = transport->get_cid(transport->provider, &transport_cid);
1032*0f4c859eSApple OSS Distributions if (error) {
1033*0f4c859eSApple OSS Distributions return error;
1034*0f4c859eSApple OSS Distributions }
1035*0f4c859eSApple OSS Distributions
1036*0f4c859eSApple OSS Distributions // Can listen on the transport's cid or any.
1037*0f4c859eSApple OSS Distributions if (addr->cid != transport_cid && addr->cid != VMADDR_CID_ANY) {
1038*0f4c859eSApple OSS Distributions return EFAULT;
1039*0f4c859eSApple OSS Distributions }
1040*0f4c859eSApple OSS Distributions
1041*0f4c859eSApple OSS Distributions return 0;
1042*0f4c859eSApple OSS Distributions }
1043*0f4c859eSApple OSS Distributions
1044*0f4c859eSApple OSS Distributions static int
vsock_accept(struct socket * so,struct sockaddr ** nam)1045*0f4c859eSApple OSS Distributions vsock_accept(struct socket *so, struct sockaddr **nam)
1046*0f4c859eSApple OSS Distributions {
1047*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1048*0f4c859eSApple OSS Distributions if (pcb == NULL) {
1049*0f4c859eSApple OSS Distributions return EINVAL;
1050*0f4c859eSApple OSS Distributions }
1051*0f4c859eSApple OSS Distributions
1052*0f4c859eSApple OSS Distributions // Do not accept disconnected sockets.
1053*0f4c859eSApple OSS Distributions if (so->so_state & SS_ISDISCONNECTED) {
1054*0f4c859eSApple OSS Distributions return ECONNABORTED;
1055*0f4c859eSApple OSS Distributions }
1056*0f4c859eSApple OSS Distributions
1057*0f4c859eSApple OSS Distributions *nam = vsock_new_sockaddr(&pcb->remote_address);
1058*0f4c859eSApple OSS Distributions
1059*0f4c859eSApple OSS Distributions return 0;
1060*0f4c859eSApple OSS Distributions }
1061*0f4c859eSApple OSS Distributions
1062*0f4c859eSApple OSS Distributions static int
vsock_connect(struct socket * so,struct sockaddr * nam,struct proc * p)1063*0f4c859eSApple OSS Distributions vsock_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
1064*0f4c859eSApple OSS Distributions {
1065*0f4c859eSApple OSS Distributions #pragma unused(p)
1066*0f4c859eSApple OSS Distributions
1067*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1068*0f4c859eSApple OSS Distributions if (pcb == NULL) {
1069*0f4c859eSApple OSS Distributions return EINVAL;
1070*0f4c859eSApple OSS Distributions }
1071*0f4c859eSApple OSS Distributions
1072*0f4c859eSApple OSS Distributions struct sockaddr_vm *addr = (struct sockaddr_vm *)nam;
1073*0f4c859eSApple OSS Distributions
1074*0f4c859eSApple OSS Distributions errno_t error = vsock_sockaddr_vm_validate(pcb, addr);
1075*0f4c859eSApple OSS Distributions if (error) {
1076*0f4c859eSApple OSS Distributions return error;
1077*0f4c859eSApple OSS Distributions }
1078*0f4c859eSApple OSS Distributions
1079*0f4c859eSApple OSS Distributions uint32_t transport_cid;
1080*0f4c859eSApple OSS Distributions struct vsock_transport *transport = pcb->transport;
1081*0f4c859eSApple OSS Distributions error = transport->get_cid(transport->provider, &transport_cid);
1082*0f4c859eSApple OSS Distributions if (error) {
1083*0f4c859eSApple OSS Distributions return error;
1084*0f4c859eSApple OSS Distributions }
1085*0f4c859eSApple OSS Distributions
1086*0f4c859eSApple OSS Distributions // Only supporting connections to the host, hypervisor, or self for now.
1087*0f4c859eSApple OSS Distributions if (addr->svm_cid != VMADDR_CID_HOST &&
1088*0f4c859eSApple OSS Distributions addr->svm_cid != VMADDR_CID_HYPERVISOR &&
1089*0f4c859eSApple OSS Distributions addr->svm_cid != transport_cid) {
1090*0f4c859eSApple OSS Distributions return EFAULT;
1091*0f4c859eSApple OSS Distributions }
1092*0f4c859eSApple OSS Distributions
1093*0f4c859eSApple OSS Distributions soisconnecting(so);
1094*0f4c859eSApple OSS Distributions
1095*0f4c859eSApple OSS Distributions // Set the remote and local address.
1096*0f4c859eSApple OSS Distributions struct vsock_address remote_addr = (struct vsock_address) {
1097*0f4c859eSApple OSS Distributions .cid = addr->svm_cid,
1098*0f4c859eSApple OSS Distributions .port = addr->svm_port,
1099*0f4c859eSApple OSS Distributions };
1100*0f4c859eSApple OSS Distributions
1101*0f4c859eSApple OSS Distributions struct vsock_address local_addr = (struct vsock_address) {
1102*0f4c859eSApple OSS Distributions .cid = transport_cid,
1103*0f4c859eSApple OSS Distributions .port = VMADDR_PORT_ANY,
1104*0f4c859eSApple OSS Distributions };
1105*0f4c859eSApple OSS Distributions
1106*0f4c859eSApple OSS Distributions // Bind to the address.
1107*0f4c859eSApple OSS Distributions error = vsock_bind_address(pcb, local_addr, remote_addr);
1108*0f4c859eSApple OSS Distributions if (error) {
1109*0f4c859eSApple OSS Distributions goto cleanup;
1110*0f4c859eSApple OSS Distributions }
1111*0f4c859eSApple OSS Distributions
1112*0f4c859eSApple OSS Distributions // Attempt a connection using the socket's transport.
1113*0f4c859eSApple OSS Distributions error = vsock_pcb_connect(pcb);
1114*0f4c859eSApple OSS Distributions if (error) {
1115*0f4c859eSApple OSS Distributions goto cleanup;
1116*0f4c859eSApple OSS Distributions }
1117*0f4c859eSApple OSS Distributions
1118*0f4c859eSApple OSS Distributions if ((so->so_state & SS_ISCONNECTED) == 0) {
1119*0f4c859eSApple OSS Distributions // Don't wait for peer's response if non-blocking.
1120*0f4c859eSApple OSS Distributions if (so->so_state & SS_NBIO) {
1121*0f4c859eSApple OSS Distributions error = EINPROGRESS;
1122*0f4c859eSApple OSS Distributions goto done;
1123*0f4c859eSApple OSS Distributions }
1124*0f4c859eSApple OSS Distributions
1125*0f4c859eSApple OSS Distributions struct timespec ts = (struct timespec) {
1126*0f4c859eSApple OSS Distributions .tv_sec = so->so_snd.sb_timeo.tv_sec,
1127*0f4c859eSApple OSS Distributions .tv_nsec = so->so_snd.sb_timeo.tv_usec * 1000,
1128*0f4c859eSApple OSS Distributions };
1129*0f4c859eSApple OSS Distributions
1130*0f4c859eSApple OSS Distributions lck_mtx_t *mutex_held;
1131*0f4c859eSApple OSS Distributions if (so->so_proto->pr_getlock != NULL) {
1132*0f4c859eSApple OSS Distributions mutex_held = (*so->so_proto->pr_getlock)(so, PR_F_WILLUNLOCK);
1133*0f4c859eSApple OSS Distributions } else {
1134*0f4c859eSApple OSS Distributions mutex_held = so->so_proto->pr_domain->dom_mtx;
1135*0f4c859eSApple OSS Distributions }
1136*0f4c859eSApple OSS Distributions
1137*0f4c859eSApple OSS Distributions // Wait until we receive a response to the connect request.
1138*0f4c859eSApple OSS Distributions error = msleep((caddr_t)&so->so_timeo, mutex_held, PSOCK | PCATCH, "vsock_connect", &ts);
1139*0f4c859eSApple OSS Distributions if (error) {
1140*0f4c859eSApple OSS Distributions if (error == EAGAIN) {
1141*0f4c859eSApple OSS Distributions error = ETIMEDOUT;
1142*0f4c859eSApple OSS Distributions }
1143*0f4c859eSApple OSS Distributions goto cleanup;
1144*0f4c859eSApple OSS Distributions }
1145*0f4c859eSApple OSS Distributions }
1146*0f4c859eSApple OSS Distributions
1147*0f4c859eSApple OSS Distributions cleanup:
1148*0f4c859eSApple OSS Distributions if (so->so_error && !error) {
1149*0f4c859eSApple OSS Distributions error = so->so_error;
1150*0f4c859eSApple OSS Distributions so->so_error = 0;
1151*0f4c859eSApple OSS Distributions }
1152*0f4c859eSApple OSS Distributions if (!error) {
1153*0f4c859eSApple OSS Distributions error = !(so->so_state & SS_ISCONNECTED);
1154*0f4c859eSApple OSS Distributions }
1155*0f4c859eSApple OSS Distributions if (error) {
1156*0f4c859eSApple OSS Distributions vsock_unbind_pcb(pcb, false);
1157*0f4c859eSApple OSS Distributions }
1158*0f4c859eSApple OSS Distributions
1159*0f4c859eSApple OSS Distributions done:
1160*0f4c859eSApple OSS Distributions return error;
1161*0f4c859eSApple OSS Distributions }
1162*0f4c859eSApple OSS Distributions
1163*0f4c859eSApple OSS Distributions static int
vsock_disconnect(struct socket * so)1164*0f4c859eSApple OSS Distributions vsock_disconnect(struct socket *so)
1165*0f4c859eSApple OSS Distributions {
1166*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1167*0f4c859eSApple OSS Distributions if (pcb == NULL) {
1168*0f4c859eSApple OSS Distributions return EINVAL;
1169*0f4c859eSApple OSS Distributions }
1170*0f4c859eSApple OSS Distributions
1171*0f4c859eSApple OSS Distributions return vsock_disconnect_pcb(pcb);
1172*0f4c859eSApple OSS Distributions }
1173*0f4c859eSApple OSS Distributions
1174*0f4c859eSApple OSS Distributions static int
vsock_sockaddr(struct socket * so,struct sockaddr ** nam)1175*0f4c859eSApple OSS Distributions vsock_sockaddr(struct socket *so, struct sockaddr **nam)
1176*0f4c859eSApple OSS Distributions {
1177*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1178*0f4c859eSApple OSS Distributions if (pcb == NULL) {
1179*0f4c859eSApple OSS Distributions return EINVAL;
1180*0f4c859eSApple OSS Distributions }
1181*0f4c859eSApple OSS Distributions
1182*0f4c859eSApple OSS Distributions *nam = vsock_new_sockaddr(&pcb->local_address);
1183*0f4c859eSApple OSS Distributions
1184*0f4c859eSApple OSS Distributions return 0;
1185*0f4c859eSApple OSS Distributions }
1186*0f4c859eSApple OSS Distributions
1187*0f4c859eSApple OSS Distributions static int
vsock_peeraddr(struct socket * so,struct sockaddr ** nam)1188*0f4c859eSApple OSS Distributions vsock_peeraddr(struct socket *so, struct sockaddr **nam)
1189*0f4c859eSApple OSS Distributions {
1190*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1191*0f4c859eSApple OSS Distributions if (pcb == NULL) {
1192*0f4c859eSApple OSS Distributions return EINVAL;
1193*0f4c859eSApple OSS Distributions }
1194*0f4c859eSApple OSS Distributions
1195*0f4c859eSApple OSS Distributions *nam = vsock_new_sockaddr(&pcb->remote_address);
1196*0f4c859eSApple OSS Distributions
1197*0f4c859eSApple OSS Distributions return 0;
1198*0f4c859eSApple OSS Distributions }
1199*0f4c859eSApple OSS Distributions
1200*0f4c859eSApple OSS Distributions static int
vsock_send(struct socket * so,int flags,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,proc_t p)1201*0f4c859eSApple OSS Distributions vsock_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, proc_t p)
1202*0f4c859eSApple OSS Distributions {
1203*0f4c859eSApple OSS Distributions #pragma unused(flags, nam, p)
1204*0f4c859eSApple OSS Distributions
1205*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1206*0f4c859eSApple OSS Distributions if (pcb == NULL || m == NULL) {
1207*0f4c859eSApple OSS Distributions return EINVAL;
1208*0f4c859eSApple OSS Distributions }
1209*0f4c859eSApple OSS Distributions
1210*0f4c859eSApple OSS Distributions if (control != NULL) {
1211*0f4c859eSApple OSS Distributions m_freem(control);
1212*0f4c859eSApple OSS Distributions return EOPNOTSUPP;
1213*0f4c859eSApple OSS Distributions }
1214*0f4c859eSApple OSS Distributions
1215*0f4c859eSApple OSS Distributions // Ensure this socket is connected.
1216*0f4c859eSApple OSS Distributions if ((so->so_state & SS_ISCONNECTED) == 0) {
1217*0f4c859eSApple OSS Distributions if (m != NULL) {
1218*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
1219*0f4c859eSApple OSS Distributions }
1220*0f4c859eSApple OSS Distributions return EPERM;
1221*0f4c859eSApple OSS Distributions }
1222*0f4c859eSApple OSS Distributions
1223*0f4c859eSApple OSS Distributions errno_t error;
1224*0f4c859eSApple OSS Distributions
1225*0f4c859eSApple OSS Distributions // rdar://84098487 (SEED: Web: Virtio-socket sent data lost after 128KB)
1226*0f4c859eSApple OSS Distributions // For writes larger than the default `sosendmaxchain` of 65536, vsock_send() is called multiple times per write().
1227*0f4c859eSApple OSS Distributions // Only the first call to vsock_send() is passed a valid mbuf packet, while subsequent calls are not marked as a packet
1228*0f4c859eSApple OSS Distributions // with a valid length. We should mark all mbufs as a packet and set the correct packet length so that the downstream
1229*0f4c859eSApple OSS Distributions // socket transport layer can correctly generate physical segments.
1230*0f4c859eSApple OSS Distributions if (!(mbuf_flags(m) & MBUF_PKTHDR)) {
1231*0f4c859eSApple OSS Distributions if (!(mbuf_flags(m) & M_EXT)) {
1232*0f4c859eSApple OSS Distributions struct mbuf *header = NULL;
1233*0f4c859eSApple OSS Distributions MGETHDR(header, M_WAITOK, MT_HEADER);
1234*0f4c859eSApple OSS Distributions if (header == NULL) {
1235*0f4c859eSApple OSS Distributions if (m != NULL) {
1236*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
1237*0f4c859eSApple OSS Distributions }
1238*0f4c859eSApple OSS Distributions return ENOBUFS;
1239*0f4c859eSApple OSS Distributions }
1240*0f4c859eSApple OSS Distributions header->m_next = m;
1241*0f4c859eSApple OSS Distributions m = header;
1242*0f4c859eSApple OSS Distributions } else {
1243*0f4c859eSApple OSS Distributions mbuf_setflags(m, mbuf_flags(m) | MBUF_PKTHDR);
1244*0f4c859eSApple OSS Distributions }
1245*0f4c859eSApple OSS Distributions
1246*0f4c859eSApple OSS Distributions size_t len = 0;
1247*0f4c859eSApple OSS Distributions struct mbuf *next = m;
1248*0f4c859eSApple OSS Distributions while (next) {
1249*0f4c859eSApple OSS Distributions len += mbuf_len(next);
1250*0f4c859eSApple OSS Distributions next = mbuf_next(next);
1251*0f4c859eSApple OSS Distributions }
1252*0f4c859eSApple OSS Distributions mbuf_pkthdr_setlen(m, len);
1253*0f4c859eSApple OSS Distributions }
1254*0f4c859eSApple OSS Distributions
1255*0f4c859eSApple OSS Distributions const size_t len = mbuf_pkthdr_len(m);
1256*0f4c859eSApple OSS Distributions uint32_t free_space = vsock_get_peer_space(pcb);
1257*0f4c859eSApple OSS Distributions
1258*0f4c859eSApple OSS Distributions // Ensure the peer has enough space in their receive buffer.
1259*0f4c859eSApple OSS Distributions while (len > free_space) {
1260*0f4c859eSApple OSS Distributions // Record the number of free peer bytes necessary before we can send.
1261*0f4c859eSApple OSS Distributions if (len > pcb->waiting_send_size) {
1262*0f4c859eSApple OSS Distributions pcb->waiting_send_size = len;
1263*0f4c859eSApple OSS Distributions }
1264*0f4c859eSApple OSS Distributions
1265*0f4c859eSApple OSS Distributions // Send a credit request.
1266*0f4c859eSApple OSS Distributions error = vsock_pcb_credit_request(pcb);
1267*0f4c859eSApple OSS Distributions if (error) {
1268*0f4c859eSApple OSS Distributions if (m != NULL) {
1269*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
1270*0f4c859eSApple OSS Distributions }
1271*0f4c859eSApple OSS Distributions return error;
1272*0f4c859eSApple OSS Distributions }
1273*0f4c859eSApple OSS Distributions
1274*0f4c859eSApple OSS Distributions // Check again in case free space was automatically updated in loopback case.
1275*0f4c859eSApple OSS Distributions free_space = vsock_get_peer_space(pcb);
1276*0f4c859eSApple OSS Distributions if (len <= free_space) {
1277*0f4c859eSApple OSS Distributions pcb->waiting_send_size = 0;
1278*0f4c859eSApple OSS Distributions break;
1279*0f4c859eSApple OSS Distributions }
1280*0f4c859eSApple OSS Distributions
1281*0f4c859eSApple OSS Distributions // Bail if this is a non-blocking socket.
1282*0f4c859eSApple OSS Distributions if (so->so_state & SS_NBIO) {
1283*0f4c859eSApple OSS Distributions if (m != NULL) {
1284*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
1285*0f4c859eSApple OSS Distributions }
1286*0f4c859eSApple OSS Distributions return EWOULDBLOCK;
1287*0f4c859eSApple OSS Distributions }
1288*0f4c859eSApple OSS Distributions
1289*0f4c859eSApple OSS Distributions // Wait until our peer has enough free space in their receive buffer.
1290*0f4c859eSApple OSS Distributions error = sbwait(&so->so_snd);
1291*0f4c859eSApple OSS Distributions pcb->waiting_send_size = 0;
1292*0f4c859eSApple OSS Distributions if (error) {
1293*0f4c859eSApple OSS Distributions if (m != NULL) {
1294*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
1295*0f4c859eSApple OSS Distributions }
1296*0f4c859eSApple OSS Distributions return error;
1297*0f4c859eSApple OSS Distributions }
1298*0f4c859eSApple OSS Distributions
1299*0f4c859eSApple OSS Distributions // Bail if an error occured or we can't send more.
1300*0f4c859eSApple OSS Distributions if (so->so_state & SS_CANTSENDMORE) {
1301*0f4c859eSApple OSS Distributions if (m != NULL) {
1302*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
1303*0f4c859eSApple OSS Distributions }
1304*0f4c859eSApple OSS Distributions return EPIPE;
1305*0f4c859eSApple OSS Distributions } else if (so->so_error) {
1306*0f4c859eSApple OSS Distributions error = so->so_error;
1307*0f4c859eSApple OSS Distributions so->so_error = 0;
1308*0f4c859eSApple OSS Distributions if (m != NULL) {
1309*0f4c859eSApple OSS Distributions mbuf_freem_list(m);
1310*0f4c859eSApple OSS Distributions }
1311*0f4c859eSApple OSS Distributions return error;
1312*0f4c859eSApple OSS Distributions }
1313*0f4c859eSApple OSS Distributions
1314*0f4c859eSApple OSS Distributions free_space = vsock_get_peer_space(pcb);
1315*0f4c859eSApple OSS Distributions }
1316*0f4c859eSApple OSS Distributions
1317*0f4c859eSApple OSS Distributions // Send a payload over the transport.
1318*0f4c859eSApple OSS Distributions error = vsock_pcb_send(pcb, m);
1319*0f4c859eSApple OSS Distributions if (error) {
1320*0f4c859eSApple OSS Distributions return error;
1321*0f4c859eSApple OSS Distributions }
1322*0f4c859eSApple OSS Distributions
1323*0f4c859eSApple OSS Distributions pcb->tx_cnt += len;
1324*0f4c859eSApple OSS Distributions
1325*0f4c859eSApple OSS Distributions return 0;
1326*0f4c859eSApple OSS Distributions }
1327*0f4c859eSApple OSS Distributions
1328*0f4c859eSApple OSS Distributions static int
vsock_shutdown(struct socket * so)1329*0f4c859eSApple OSS Distributions vsock_shutdown(struct socket *so)
1330*0f4c859eSApple OSS Distributions {
1331*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1332*0f4c859eSApple OSS Distributions if (pcb == NULL) {
1333*0f4c859eSApple OSS Distributions return EINVAL;
1334*0f4c859eSApple OSS Distributions }
1335*0f4c859eSApple OSS Distributions
1336*0f4c859eSApple OSS Distributions socantsendmore(so);
1337*0f4c859eSApple OSS Distributions
1338*0f4c859eSApple OSS Distributions // Tell peer we will no longer send.
1339*0f4c859eSApple OSS Distributions errno_t error = vsock_pcb_shutdown_send(pcb);
1340*0f4c859eSApple OSS Distributions if (error) {
1341*0f4c859eSApple OSS Distributions return error;
1342*0f4c859eSApple OSS Distributions }
1343*0f4c859eSApple OSS Distributions
1344*0f4c859eSApple OSS Distributions return 0;
1345*0f4c859eSApple OSS Distributions }
1346*0f4c859eSApple OSS Distributions
1347*0f4c859eSApple OSS Distributions static int
vsock_soreceive(struct socket * so,struct sockaddr ** psa,struct uio * uio,struct mbuf ** mp0,struct mbuf ** controlp,int * flagsp)1348*0f4c859eSApple OSS Distributions vsock_soreceive(struct socket *so, struct sockaddr **psa, struct uio *uio,
1349*0f4c859eSApple OSS Distributions struct mbuf **mp0, struct mbuf **controlp, int *flagsp)
1350*0f4c859eSApple OSS Distributions {
1351*0f4c859eSApple OSS Distributions struct vsockpcb *pcb = sotovsockpcb(so);
1352*0f4c859eSApple OSS Distributions if (pcb == NULL) {
1353*0f4c859eSApple OSS Distributions return EINVAL;
1354*0f4c859eSApple OSS Distributions }
1355*0f4c859eSApple OSS Distributions
1356*0f4c859eSApple OSS Distributions user_ssize_t length = uio_resid(uio);
1357*0f4c859eSApple OSS Distributions int result = soreceive(so, psa, uio, mp0, controlp, flagsp);
1358*0f4c859eSApple OSS Distributions length -= uio_resid(uio);
1359*0f4c859eSApple OSS Distributions
1360*0f4c859eSApple OSS Distributions socket_lock(so, 1);
1361*0f4c859eSApple OSS Distributions
1362*0f4c859eSApple OSS Distributions pcb->fwd_cnt += length;
1363*0f4c859eSApple OSS Distributions
1364*0f4c859eSApple OSS Distributions const uint32_t threshold = VSOCK_MAX_PACKET_SIZE;
1365*0f4c859eSApple OSS Distributions
1366*0f4c859eSApple OSS Distributions // Send a credit update if is possible that the peer will no longer send.
1367*0f4c859eSApple OSS Distributions if ((pcb->fwd_cnt - pcb->last_fwd_cnt + threshold) >= pcb->last_buf_alloc) {
1368*0f4c859eSApple OSS Distributions errno_t error = vsock_pcb_credit_update(pcb);
1369*0f4c859eSApple OSS Distributions if (!result && error) {
1370*0f4c859eSApple OSS Distributions result = error;
1371*0f4c859eSApple OSS Distributions }
1372*0f4c859eSApple OSS Distributions }
1373*0f4c859eSApple OSS Distributions
1374*0f4c859eSApple OSS Distributions socket_unlock(so, 1);
1375*0f4c859eSApple OSS Distributions
1376*0f4c859eSApple OSS Distributions return result;
1377*0f4c859eSApple OSS Distributions }
1378*0f4c859eSApple OSS Distributions
1379*0f4c859eSApple OSS Distributions static struct pr_usrreqs vsock_usrreqs = {
1380*0f4c859eSApple OSS Distributions .pru_abort = vsock_abort,
1381*0f4c859eSApple OSS Distributions .pru_attach = vsock_attach,
1382*0f4c859eSApple OSS Distributions .pru_control = vsock_control,
1383*0f4c859eSApple OSS Distributions .pru_detach = vsock_detach,
1384*0f4c859eSApple OSS Distributions .pru_bind = vsock_bind,
1385*0f4c859eSApple OSS Distributions .pru_listen = vsock_listen,
1386*0f4c859eSApple OSS Distributions .pru_accept = vsock_accept,
1387*0f4c859eSApple OSS Distributions .pru_connect = vsock_connect,
1388*0f4c859eSApple OSS Distributions .pru_disconnect = vsock_disconnect,
1389*0f4c859eSApple OSS Distributions .pru_send = vsock_send,
1390*0f4c859eSApple OSS Distributions .pru_shutdown = vsock_shutdown,
1391*0f4c859eSApple OSS Distributions .pru_sockaddr = vsock_sockaddr,
1392*0f4c859eSApple OSS Distributions .pru_peeraddr = vsock_peeraddr,
1393*0f4c859eSApple OSS Distributions .pru_sosend = sosend,
1394*0f4c859eSApple OSS Distributions .pru_soreceive = vsock_soreceive,
1395*0f4c859eSApple OSS Distributions };
1396*0f4c859eSApple OSS Distributions
1397*0f4c859eSApple OSS Distributions static void
vsock_init(struct protosw * pp,struct domain * dp)1398*0f4c859eSApple OSS Distributions vsock_init(struct protosw *pp, struct domain *dp)
1399*0f4c859eSApple OSS Distributions {
1400*0f4c859eSApple OSS Distributions #pragma unused(dp)
1401*0f4c859eSApple OSS Distributions
1402*0f4c859eSApple OSS Distributions static int vsock_initialized = 0;
1403*0f4c859eSApple OSS Distributions VERIFY((pp->pr_flags & (PR_INITIALIZED | PR_ATTACHED)) == PR_ATTACHED);
1404*0f4c859eSApple OSS Distributions if (!os_atomic_cmpxchg((volatile int *)&vsock_initialized, 0, 1, acq_rel)) {
1405*0f4c859eSApple OSS Distributions return;
1406*0f4c859eSApple OSS Distributions }
1407*0f4c859eSApple OSS Distributions
1408*0f4c859eSApple OSS Distributions // Setup VSock protocol info struct.
1409*0f4c859eSApple OSS Distributions lck_rw_init(&vsockinfo.all_lock, &vsock_lock_grp, LCK_ATTR_NULL);
1410*0f4c859eSApple OSS Distributions lck_rw_init(&vsockinfo.bound_lock, &vsock_lock_grp, LCK_ATTR_NULL);
1411*0f4c859eSApple OSS Distributions lck_mtx_init(&vsockinfo.port_lock, &vsock_lock_grp, LCK_ATTR_NULL);
1412*0f4c859eSApple OSS Distributions TAILQ_INIT(&vsockinfo.all);
1413*0f4c859eSApple OSS Distributions LIST_INIT(&vsockinfo.bound);
1414*0f4c859eSApple OSS Distributions vsockinfo.last_port = VMADDR_PORT_ANY;
1415*0f4c859eSApple OSS Distributions }
1416*0f4c859eSApple OSS Distributions
1417*0f4c859eSApple OSS Distributions static struct protosw vsocksw[] = {
1418*0f4c859eSApple OSS Distributions {
1419*0f4c859eSApple OSS Distributions .pr_type = SOCK_STREAM,
1420*0f4c859eSApple OSS Distributions .pr_protocol = 0,
1421*0f4c859eSApple OSS Distributions .pr_flags = PR_CONNREQUIRED | PR_WANTRCVD,
1422*0f4c859eSApple OSS Distributions .pr_init = vsock_init,
1423*0f4c859eSApple OSS Distributions .pr_usrreqs = &vsock_usrreqs,
1424*0f4c859eSApple OSS Distributions }
1425*0f4c859eSApple OSS Distributions };
1426*0f4c859eSApple OSS Distributions
1427*0f4c859eSApple OSS Distributions static const int vsock_proto_count = (sizeof(vsocksw) / sizeof(struct protosw));
1428*0f4c859eSApple OSS Distributions
1429*0f4c859eSApple OSS Distributions /* VSock Domain */
1430*0f4c859eSApple OSS Distributions
1431*0f4c859eSApple OSS Distributions static struct domain *vsock_domain = NULL;
1432*0f4c859eSApple OSS Distributions
1433*0f4c859eSApple OSS Distributions static void
vsock_dinit(struct domain * dp)1434*0f4c859eSApple OSS Distributions vsock_dinit(struct domain *dp)
1435*0f4c859eSApple OSS Distributions {
1436*0f4c859eSApple OSS Distributions // The VSock domain is initialized with a singleton pattern.
1437*0f4c859eSApple OSS Distributions VERIFY(!(dp->dom_flags & DOM_INITIALIZED));
1438*0f4c859eSApple OSS Distributions VERIFY(vsock_domain == NULL);
1439*0f4c859eSApple OSS Distributions vsock_domain = dp;
1440*0f4c859eSApple OSS Distributions
1441*0f4c859eSApple OSS Distributions // Add protocols and initialize.
1442*0f4c859eSApple OSS Distributions for (int i = 0; i < vsock_proto_count; i++) {
1443*0f4c859eSApple OSS Distributions net_add_proto((struct protosw *)&vsocksw[i], dp, 1);
1444*0f4c859eSApple OSS Distributions }
1445*0f4c859eSApple OSS Distributions }
1446*0f4c859eSApple OSS Distributions
1447*0f4c859eSApple OSS Distributions struct domain vsockdomain_s = {
1448*0f4c859eSApple OSS Distributions .dom_family = PF_VSOCK,
1449*0f4c859eSApple OSS Distributions .dom_name = "vsock",
1450*0f4c859eSApple OSS Distributions .dom_init = vsock_dinit,
1451*0f4c859eSApple OSS Distributions .dom_maxrtkey = sizeof(struct sockaddr_vm),
1452*0f4c859eSApple OSS Distributions .dom_protohdrlen = sizeof(struct sockaddr_vm),
1453*0f4c859eSApple OSS Distributions };
1454