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