xref: /xnu-11215.41.3/bsd/kern/kpi_socket.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1*33de042dSApple OSS Distributions /*
2*33de042dSApple OSS Distributions  * Copyright (c) 2003-2021 Apple Inc. All rights reserved.
3*33de042dSApple OSS Distributions  *
4*33de042dSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*33de042dSApple OSS Distributions  *
6*33de042dSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*33de042dSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*33de042dSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*33de042dSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*33de042dSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*33de042dSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*33de042dSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*33de042dSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*33de042dSApple OSS Distributions  *
15*33de042dSApple OSS Distributions  * Please obtain a copy of the License at
16*33de042dSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*33de042dSApple OSS Distributions  *
18*33de042dSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*33de042dSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*33de042dSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*33de042dSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*33de042dSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*33de042dSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*33de042dSApple OSS Distributions  * limitations under the License.
25*33de042dSApple OSS Distributions  *
26*33de042dSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*33de042dSApple OSS Distributions  */
28*33de042dSApple OSS Distributions 
29*33de042dSApple OSS Distributions #define __KPI__
30*33de042dSApple OSS Distributions #include <sys/systm.h>
31*33de042dSApple OSS Distributions #include <sys/kernel.h>
32*33de042dSApple OSS Distributions #include <sys/types.h>
33*33de042dSApple OSS Distributions #include <sys/socket.h>
34*33de042dSApple OSS Distributions #include <sys/socketvar.h>
35*33de042dSApple OSS Distributions #include <sys/param.h>
36*33de042dSApple OSS Distributions #include <sys/proc.h>
37*33de042dSApple OSS Distributions #include <sys/errno.h>
38*33de042dSApple OSS Distributions #include <sys/malloc.h>
39*33de042dSApple OSS Distributions #include <sys/protosw.h>
40*33de042dSApple OSS Distributions #include <sys/domain.h>
41*33de042dSApple OSS Distributions #include <sys/mbuf.h>
42*33de042dSApple OSS Distributions #include <sys/mcache.h>
43*33de042dSApple OSS Distributions #include <sys/fcntl.h>
44*33de042dSApple OSS Distributions #include <sys/filio.h>
45*33de042dSApple OSS Distributions #include <sys/uio_internal.h>
46*33de042dSApple OSS Distributions #include <kern/locks.h>
47*33de042dSApple OSS Distributions #include <net/net_api_stats.h>
48*33de042dSApple OSS Distributions #include <netinet/in.h>
49*33de042dSApple OSS Distributions #include <libkern/OSAtomic.h>
50*33de042dSApple OSS Distributions #include <stdbool.h>
51*33de042dSApple OSS Distributions #include <net/sockaddr_utils.h>
52*33de042dSApple OSS Distributions 
53*33de042dSApple OSS Distributions #if SKYWALK
54*33de042dSApple OSS Distributions #include <skywalk/core/skywalk_var.h>
55*33de042dSApple OSS Distributions #endif /* SKYWALK */
56*33de042dSApple OSS Distributions 
57*33de042dSApple OSS Distributions #define SOCK_SEND_MBUF_MODE_VERBOSE     0x0001
58*33de042dSApple OSS Distributions 
59*33de042dSApple OSS Distributions static errno_t sock_send_internal(socket_t, const struct msghdr *,
60*33de042dSApple OSS Distributions     mbuf_t, int, size_t *);
61*33de042dSApple OSS Distributions 
62*33de042dSApple OSS Distributions #undef sock_accept
63*33de042dSApple OSS Distributions #undef sock_socket
64*33de042dSApple OSS Distributions errno_t sock_accept(socket_t so, struct sockaddr *__sized_by(fromlen) from, int fromlen,
65*33de042dSApple OSS Distributions     int flags, sock_upcall callback, void *cookie, socket_t *new_so);
66*33de042dSApple OSS Distributions errno_t sock_socket(int domain, int type, int protocol, sock_upcall callback,
67*33de042dSApple OSS Distributions     void *context, socket_t *new_so);
68*33de042dSApple OSS Distributions 
69*33de042dSApple OSS Distributions static errno_t sock_accept_common(socket_t sock, struct sockaddr *__sized_by(fromlen) from,
70*33de042dSApple OSS Distributions     int fromlen, int flags, sock_upcall callback, void *cookie,
71*33de042dSApple OSS Distributions     socket_t *new_sock, bool is_internal);
72*33de042dSApple OSS Distributions static errno_t sock_socket_common(int domain, int type, int protocol,
73*33de042dSApple OSS Distributions     sock_upcall callback, void *context, socket_t *new_so, bool is_internal);
74*33de042dSApple OSS Distributions 
75*33de042dSApple OSS Distributions errno_t
sock_accept_common(socket_t sock,struct sockaddr * __sized_by (fromlen)from,int fromlen,int flags,sock_upcall callback,void * cookie,socket_t * new_sock,bool is_internal)76*33de042dSApple OSS Distributions sock_accept_common(socket_t sock, struct sockaddr *__sized_by(fromlen) from, int fromlen, int flags,
77*33de042dSApple OSS Distributions     sock_upcall callback, void *cookie, socket_t *new_sock, bool is_internal)
78*33de042dSApple OSS Distributions {
79*33de042dSApple OSS Distributions 	struct sockaddr *__single sa;
80*33de042dSApple OSS Distributions 	struct socket *new_so;
81*33de042dSApple OSS Distributions 	lck_mtx_t *mutex_held;
82*33de042dSApple OSS Distributions 	int dosocklock;
83*33de042dSApple OSS Distributions 	errno_t error = 0;
84*33de042dSApple OSS Distributions 
85*33de042dSApple OSS Distributions 	if (sock == NULL || new_sock == NULL) {
86*33de042dSApple OSS Distributions 		return EINVAL;
87*33de042dSApple OSS Distributions 	}
88*33de042dSApple OSS Distributions 
89*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
90*33de042dSApple OSS Distributions 	if ((sock->so_options & SO_ACCEPTCONN) == 0) {
91*33de042dSApple OSS Distributions 		socket_unlock(sock, 1);
92*33de042dSApple OSS Distributions 		return EINVAL;
93*33de042dSApple OSS Distributions 	}
94*33de042dSApple OSS Distributions 	if ((flags & ~(MSG_DONTWAIT)) != 0) {
95*33de042dSApple OSS Distributions 		socket_unlock(sock, 1);
96*33de042dSApple OSS Distributions 		return ENOTSUP;
97*33de042dSApple OSS Distributions 	}
98*33de042dSApple OSS Distributions check_again:
99*33de042dSApple OSS Distributions 	if (((flags & MSG_DONTWAIT) != 0 || (sock->so_state & SS_NBIO) != 0) &&
100*33de042dSApple OSS Distributions 	    sock->so_comp.tqh_first == NULL) {
101*33de042dSApple OSS Distributions 		socket_unlock(sock, 1);
102*33de042dSApple OSS Distributions 		return EWOULDBLOCK;
103*33de042dSApple OSS Distributions 	}
104*33de042dSApple OSS Distributions 
105*33de042dSApple OSS Distributions 	if (sock->so_proto->pr_getlock != NULL) {
106*33de042dSApple OSS Distributions 		mutex_held = (*sock->so_proto->pr_getlock)(sock, PR_F_WILLUNLOCK);
107*33de042dSApple OSS Distributions 		dosocklock = 1;
108*33de042dSApple OSS Distributions 	} else {
109*33de042dSApple OSS Distributions 		mutex_held = sock->so_proto->pr_domain->dom_mtx;
110*33de042dSApple OSS Distributions 		dosocklock = 0;
111*33de042dSApple OSS Distributions 	}
112*33de042dSApple OSS Distributions 
113*33de042dSApple OSS Distributions 	while (TAILQ_EMPTY(&sock->so_comp) && sock->so_error == 0) {
114*33de042dSApple OSS Distributions 		if (sock->so_state & SS_CANTRCVMORE) {
115*33de042dSApple OSS Distributions 			sock->so_error = ECONNABORTED;
116*33de042dSApple OSS Distributions 			break;
117*33de042dSApple OSS Distributions 		}
118*33de042dSApple OSS Distributions 		error = msleep((caddr_t)&sock->so_timeo, mutex_held,
119*33de042dSApple OSS Distributions 		    PSOCK | PCATCH, "sock_accept", NULL);
120*33de042dSApple OSS Distributions 		if (error != 0) {
121*33de042dSApple OSS Distributions 			socket_unlock(sock, 1);
122*33de042dSApple OSS Distributions 			return error;
123*33de042dSApple OSS Distributions 		}
124*33de042dSApple OSS Distributions 	}
125*33de042dSApple OSS Distributions 	if (sock->so_error != 0) {
126*33de042dSApple OSS Distributions 		error = sock->so_error;
127*33de042dSApple OSS Distributions 		sock->so_error = 0;
128*33de042dSApple OSS Distributions 		socket_unlock(sock, 1);
129*33de042dSApple OSS Distributions 		return error;
130*33de042dSApple OSS Distributions 	}
131*33de042dSApple OSS Distributions 
132*33de042dSApple OSS Distributions 	so_acquire_accept_list(sock, NULL);
133*33de042dSApple OSS Distributions 	if (TAILQ_EMPTY(&sock->so_comp)) {
134*33de042dSApple OSS Distributions 		so_release_accept_list(sock);
135*33de042dSApple OSS Distributions 		goto check_again;
136*33de042dSApple OSS Distributions 	}
137*33de042dSApple OSS Distributions 	new_so = TAILQ_FIRST(&sock->so_comp);
138*33de042dSApple OSS Distributions 	TAILQ_REMOVE(&sock->so_comp, new_so, so_list);
139*33de042dSApple OSS Distributions 	new_so->so_state &= ~SS_COMP;
140*33de042dSApple OSS Distributions 	new_so->so_head = NULL;
141*33de042dSApple OSS Distributions 	sock->so_qlen--;
142*33de042dSApple OSS Distributions 
143*33de042dSApple OSS Distributions 	so_release_accept_list(sock);
144*33de042dSApple OSS Distributions 
145*33de042dSApple OSS Distributions 	/*
146*33de042dSApple OSS Distributions 	 * Count the accepted socket as an in-kernel socket
147*33de042dSApple OSS Distributions 	 */
148*33de042dSApple OSS Distributions 	new_so->so_flags1 |= SOF1_IN_KERNEL_SOCKET;
149*33de042dSApple OSS Distributions 	INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_in_kernel_total);
150*33de042dSApple OSS Distributions 	if (is_internal) {
151*33de042dSApple OSS Distributions 		INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_in_kernel_os_total);
152*33de042dSApple OSS Distributions 	}
153*33de042dSApple OSS Distributions 
154*33de042dSApple OSS Distributions 	/*
155*33de042dSApple OSS Distributions 	 * Pass the pre-accepted socket to any interested socket filter(s).
156*33de042dSApple OSS Distributions 	 * Upon failure, the socket would have been closed by the callee.
157*33de042dSApple OSS Distributions 	 */
158*33de042dSApple OSS Distributions 	if (new_so->so_filt != NULL) {
159*33de042dSApple OSS Distributions 		/*
160*33de042dSApple OSS Distributions 		 * Temporarily drop the listening socket's lock before we
161*33de042dSApple OSS Distributions 		 * hand off control over to the socket filter(s), but keep
162*33de042dSApple OSS Distributions 		 * a reference so that it won't go away.  We'll grab it
163*33de042dSApple OSS Distributions 		 * again once we're done with the filter(s).
164*33de042dSApple OSS Distributions 		 */
165*33de042dSApple OSS Distributions 		socket_unlock(sock, 0);
166*33de042dSApple OSS Distributions 		if ((error = soacceptfilter(new_so, sock)) != 0) {
167*33de042dSApple OSS Distributions 			/* Drop reference on listening socket */
168*33de042dSApple OSS Distributions 			sodereference(sock);
169*33de042dSApple OSS Distributions 			return error;
170*33de042dSApple OSS Distributions 		}
171*33de042dSApple OSS Distributions 		socket_lock(sock, 0);
172*33de042dSApple OSS Distributions 	}
173*33de042dSApple OSS Distributions 
174*33de042dSApple OSS Distributions 	if (dosocklock) {
175*33de042dSApple OSS Distributions 		LCK_MTX_ASSERT(new_so->so_proto->pr_getlock(new_so, 0),
176*33de042dSApple OSS Distributions 		    LCK_MTX_ASSERT_NOTOWNED);
177*33de042dSApple OSS Distributions 		socket_lock(new_so, 1);
178*33de042dSApple OSS Distributions 	}
179*33de042dSApple OSS Distributions 
180*33de042dSApple OSS Distributions 	(void) soacceptlock(new_so, &sa, 0);
181*33de042dSApple OSS Distributions 
182*33de042dSApple OSS Distributions 	socket_unlock(sock, 1); /* release the head */
183*33de042dSApple OSS Distributions 
184*33de042dSApple OSS Distributions 	/* see comments in sock_setupcall() */
185*33de042dSApple OSS Distributions 	if (callback != NULL) {
186*33de042dSApple OSS Distributions #if defined(__arm64__)
187*33de042dSApple OSS Distributions 		sock_setupcalls_locked(new_so, callback, cookie, callback, cookie, 0);
188*33de042dSApple OSS Distributions #else /* defined(__arm64__) */
189*33de042dSApple OSS Distributions 		sock_setupcalls_locked(new_so, callback, cookie, NULL, NULL, 0);
190*33de042dSApple OSS Distributions #endif /* defined(__arm64__) */
191*33de042dSApple OSS Distributions 	}
192*33de042dSApple OSS Distributions 
193*33de042dSApple OSS Distributions 	if (sa != NULL && from != NULL) {
194*33de042dSApple OSS Distributions 		SOCKADDR_COPY(sa, from, MIN(fromlen, sa->sa_len));
195*33de042dSApple OSS Distributions 	}
196*33de042dSApple OSS Distributions 	free_sockaddr(sa);
197*33de042dSApple OSS Distributions 
198*33de042dSApple OSS Distributions 	/*
199*33de042dSApple OSS Distributions 	 * If the socket has been marked as inactive by sosetdefunct(),
200*33de042dSApple OSS Distributions 	 * disallow further operations on it.
201*33de042dSApple OSS Distributions 	 */
202*33de042dSApple OSS Distributions 	if (new_so->so_flags & SOF_DEFUNCT) {
203*33de042dSApple OSS Distributions 		(void) sodefunct(current_proc(), new_so,
204*33de042dSApple OSS Distributions 		    SHUTDOWN_SOCKET_LEVEL_DISCONNECT_INTERNAL);
205*33de042dSApple OSS Distributions 	}
206*33de042dSApple OSS Distributions 	*new_sock = new_so;
207*33de042dSApple OSS Distributions 	if (dosocklock) {
208*33de042dSApple OSS Distributions 		socket_unlock(new_so, 1);
209*33de042dSApple OSS Distributions 	}
210*33de042dSApple OSS Distributions 	return error;
211*33de042dSApple OSS Distributions }
212*33de042dSApple OSS Distributions 
213*33de042dSApple OSS Distributions errno_t
sock_accept(socket_t sock,struct sockaddr * __sized_by (fromlen)from,int fromlen,int flags,sock_upcall callback,void * cookie,socket_t * new_sock)214*33de042dSApple OSS Distributions sock_accept(socket_t sock, struct sockaddr *__sized_by(fromlen) from, int fromlen, int flags,
215*33de042dSApple OSS Distributions     sock_upcall callback, void *cookie, socket_t *new_sock)
216*33de042dSApple OSS Distributions {
217*33de042dSApple OSS Distributions 	return sock_accept_common(sock, from, fromlen, flags,
218*33de042dSApple OSS Distributions 	           callback, cookie, new_sock, false);
219*33de042dSApple OSS Distributions }
220*33de042dSApple OSS Distributions 
221*33de042dSApple OSS Distributions errno_t
sock_accept_internal(socket_t sock,struct sockaddr * __sized_by (fromlen)from,int fromlen,int flags,sock_upcall callback,void * cookie,socket_t * new_sock)222*33de042dSApple OSS Distributions sock_accept_internal(socket_t sock, struct sockaddr *__sized_by(fromlen) from, int fromlen, int flags,
223*33de042dSApple OSS Distributions     sock_upcall callback, void *cookie, socket_t *new_sock)
224*33de042dSApple OSS Distributions {
225*33de042dSApple OSS Distributions 	return sock_accept_common(sock, from, fromlen, flags,
226*33de042dSApple OSS Distributions 	           callback, cookie, new_sock, true);
227*33de042dSApple OSS Distributions }
228*33de042dSApple OSS Distributions 
229*33de042dSApple OSS Distributions errno_t
sock_bind(socket_t sock,const struct sockaddr * to)230*33de042dSApple OSS Distributions sock_bind(socket_t sock, const struct sockaddr *to)
231*33de042dSApple OSS Distributions {
232*33de042dSApple OSS Distributions 	int error = 0;
233*33de042dSApple OSS Distributions 	struct sockaddr *sa = NULL;
234*33de042dSApple OSS Distributions 	struct sockaddr_storage ss;
235*33de042dSApple OSS Distributions 
236*33de042dSApple OSS Distributions 	if (sock == NULL || to == NULL) {
237*33de042dSApple OSS Distributions 		return EINVAL;
238*33de042dSApple OSS Distributions 	}
239*33de042dSApple OSS Distributions 
240*33de042dSApple OSS Distributions 	if (to->sa_len > sizeof(ss)) {
241*33de042dSApple OSS Distributions 		sa = kalloc_data(to->sa_len, Z_WAITOK | Z_ZERO | Z_NOFAIL);
242*33de042dSApple OSS Distributions 	} else {
243*33de042dSApple OSS Distributions 		sa = (struct sockaddr *)&ss;
244*33de042dSApple OSS Distributions 	}
245*33de042dSApple OSS Distributions 	SOCKADDR_COPY(to, sa, to->sa_len);
246*33de042dSApple OSS Distributions 
247*33de042dSApple OSS Distributions 	error = sobindlock(sock, sa, 1);        /* will lock socket */
248*33de042dSApple OSS Distributions 
249*33de042dSApple OSS Distributions 	if (sa != (struct sockaddr *)&ss) {
250*33de042dSApple OSS Distributions 		kfree_data(sa, sa->sa_len);
251*33de042dSApple OSS Distributions 	}
252*33de042dSApple OSS Distributions 
253*33de042dSApple OSS Distributions 	return error;
254*33de042dSApple OSS Distributions }
255*33de042dSApple OSS Distributions 
256*33de042dSApple OSS Distributions errno_t
sock_connect(socket_t sock,const struct sockaddr * to,int flags)257*33de042dSApple OSS Distributions sock_connect(socket_t sock, const struct sockaddr *to, int flags)
258*33de042dSApple OSS Distributions {
259*33de042dSApple OSS Distributions 	int error = 0;
260*33de042dSApple OSS Distributions 	lck_mtx_t *mutex_held;
261*33de042dSApple OSS Distributions 	struct sockaddr *sa = NULL;
262*33de042dSApple OSS Distributions 	struct sockaddr_storage ss;
263*33de042dSApple OSS Distributions 
264*33de042dSApple OSS Distributions 	if (sock == NULL || to == NULL) {
265*33de042dSApple OSS Distributions 		return EINVAL;
266*33de042dSApple OSS Distributions 	}
267*33de042dSApple OSS Distributions 
268*33de042dSApple OSS Distributions 	if (to->sa_len > sizeof(ss)) {
269*33de042dSApple OSS Distributions 		sa = kalloc_data(to->sa_len,
270*33de042dSApple OSS Distributions 		    (flags & MSG_DONTWAIT) ? Z_NOWAIT : Z_WAITOK);
271*33de042dSApple OSS Distributions 		if (sa == NULL) {
272*33de042dSApple OSS Distributions 			return ENOBUFS;
273*33de042dSApple OSS Distributions 		}
274*33de042dSApple OSS Distributions 	} else {
275*33de042dSApple OSS Distributions 		sa = (struct sockaddr *)&ss;
276*33de042dSApple OSS Distributions 	}
277*33de042dSApple OSS Distributions 	SOCKADDR_COPY(to, sa, to->sa_len);
278*33de042dSApple OSS Distributions 
279*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
280*33de042dSApple OSS Distributions 
281*33de042dSApple OSS Distributions 	if ((sock->so_state & SS_ISCONNECTING) &&
282*33de042dSApple OSS Distributions 	    ((sock->so_state & SS_NBIO) != 0 || (flags & MSG_DONTWAIT) != 0)) {
283*33de042dSApple OSS Distributions 		error = EALREADY;
284*33de042dSApple OSS Distributions 		goto out;
285*33de042dSApple OSS Distributions 	}
286*33de042dSApple OSS Distributions 
287*33de042dSApple OSS Distributions #if SKYWALK
288*33de042dSApple OSS Distributions 	sk_protect_t protect = sk_async_transmit_protect();
289*33de042dSApple OSS Distributions #endif /* SKYWALK */
290*33de042dSApple OSS Distributions 
291*33de042dSApple OSS Distributions 	error = soconnectlock(sock, sa, 0);
292*33de042dSApple OSS Distributions 
293*33de042dSApple OSS Distributions #if SKYWALK
294*33de042dSApple OSS Distributions 	sk_async_transmit_unprotect(protect);
295*33de042dSApple OSS Distributions #endif /* SKYWALK */
296*33de042dSApple OSS Distributions 
297*33de042dSApple OSS Distributions 	if (!error) {
298*33de042dSApple OSS Distributions 		if ((sock->so_state & SS_ISCONNECTING) &&
299*33de042dSApple OSS Distributions 		    ((sock->so_state & SS_NBIO) != 0 ||
300*33de042dSApple OSS Distributions 		    (flags & MSG_DONTWAIT) != 0)) {
301*33de042dSApple OSS Distributions 			error = EINPROGRESS;
302*33de042dSApple OSS Distributions 			goto out;
303*33de042dSApple OSS Distributions 		}
304*33de042dSApple OSS Distributions 
305*33de042dSApple OSS Distributions 		if (sock->so_proto->pr_getlock != NULL) {
306*33de042dSApple OSS Distributions 			mutex_held = (*sock->so_proto->pr_getlock)(sock, PR_F_WILLUNLOCK);
307*33de042dSApple OSS Distributions 		} else {
308*33de042dSApple OSS Distributions 			mutex_held = sock->so_proto->pr_domain->dom_mtx;
309*33de042dSApple OSS Distributions 		}
310*33de042dSApple OSS Distributions 
311*33de042dSApple OSS Distributions 		while ((sock->so_state & SS_ISCONNECTING) &&
312*33de042dSApple OSS Distributions 		    sock->so_error == 0) {
313*33de042dSApple OSS Distributions 			error = msleep((caddr_t)&sock->so_timeo,
314*33de042dSApple OSS Distributions 			    mutex_held, PSOCK | PCATCH, "sock_connect", NULL);
315*33de042dSApple OSS Distributions 			if (error != 0) {
316*33de042dSApple OSS Distributions 				break;
317*33de042dSApple OSS Distributions 			}
318*33de042dSApple OSS Distributions 		}
319*33de042dSApple OSS Distributions 
320*33de042dSApple OSS Distributions 		if (error == 0) {
321*33de042dSApple OSS Distributions 			error = sock->so_error;
322*33de042dSApple OSS Distributions 			sock->so_error = 0;
323*33de042dSApple OSS Distributions 		}
324*33de042dSApple OSS Distributions 	} else {
325*33de042dSApple OSS Distributions 		sock->so_state &= ~SS_ISCONNECTING;
326*33de042dSApple OSS Distributions 	}
327*33de042dSApple OSS Distributions out:
328*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
329*33de042dSApple OSS Distributions 
330*33de042dSApple OSS Distributions 	if (sa != (struct sockaddr *)&ss) {
331*33de042dSApple OSS Distributions 		kfree_data(sa, sa->sa_len);
332*33de042dSApple OSS Distributions 	}
333*33de042dSApple OSS Distributions 
334*33de042dSApple OSS Distributions 	return error;
335*33de042dSApple OSS Distributions }
336*33de042dSApple OSS Distributions 
337*33de042dSApple OSS Distributions errno_t
sock_connectwait(socket_t sock,const struct timeval * tv)338*33de042dSApple OSS Distributions sock_connectwait(socket_t sock, const struct timeval *tv)
339*33de042dSApple OSS Distributions {
340*33de042dSApple OSS Distributions 	lck_mtx_t *mutex_held;
341*33de042dSApple OSS Distributions 	errno_t retval = 0;
342*33de042dSApple OSS Distributions 	struct timespec ts;
343*33de042dSApple OSS Distributions 
344*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
345*33de042dSApple OSS Distributions 
346*33de042dSApple OSS Distributions 	/* Check if we're already connected or if we've already errored out */
347*33de042dSApple OSS Distributions 	if ((sock->so_state & SS_ISCONNECTING) == 0 || sock->so_error != 0) {
348*33de042dSApple OSS Distributions 		if (sock->so_error != 0) {
349*33de042dSApple OSS Distributions 			retval = sock->so_error;
350*33de042dSApple OSS Distributions 			sock->so_error = 0;
351*33de042dSApple OSS Distributions 		} else {
352*33de042dSApple OSS Distributions 			if ((sock->so_state & SS_ISCONNECTED) != 0) {
353*33de042dSApple OSS Distributions 				retval = 0;
354*33de042dSApple OSS Distributions 			} else {
355*33de042dSApple OSS Distributions 				retval = EINVAL;
356*33de042dSApple OSS Distributions 			}
357*33de042dSApple OSS Distributions 		}
358*33de042dSApple OSS Distributions 		goto done;
359*33de042dSApple OSS Distributions 	}
360*33de042dSApple OSS Distributions 
361*33de042dSApple OSS Distributions 	/* copied translation from timeval to hertz from SO_RCVTIMEO handling */
362*33de042dSApple OSS Distributions 	if (tv->tv_sec < 0 || tv->tv_sec > SHRT_MAX / hz ||
363*33de042dSApple OSS Distributions 	    tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
364*33de042dSApple OSS Distributions 		retval = EDOM;
365*33de042dSApple OSS Distributions 		goto done;
366*33de042dSApple OSS Distributions 	}
367*33de042dSApple OSS Distributions 
368*33de042dSApple OSS Distributions 	ts.tv_sec = tv->tv_sec;
369*33de042dSApple OSS Distributions 	ts.tv_nsec = (tv->tv_usec * (integer_t)NSEC_PER_USEC);
370*33de042dSApple OSS Distributions 	if ((ts.tv_sec + (ts.tv_nsec / (long)NSEC_PER_SEC)) / 100 > SHRT_MAX) {
371*33de042dSApple OSS Distributions 		retval = EDOM;
372*33de042dSApple OSS Distributions 		goto done;
373*33de042dSApple OSS Distributions 	}
374*33de042dSApple OSS Distributions 
375*33de042dSApple OSS Distributions 	if (sock->so_proto->pr_getlock != NULL) {
376*33de042dSApple OSS Distributions 		mutex_held = (*sock->so_proto->pr_getlock)(sock, PR_F_WILLUNLOCK);
377*33de042dSApple OSS Distributions 	} else {
378*33de042dSApple OSS Distributions 		mutex_held = sock->so_proto->pr_domain->dom_mtx;
379*33de042dSApple OSS Distributions 	}
380*33de042dSApple OSS Distributions 
381*33de042dSApple OSS Distributions 	msleep((caddr_t)&sock->so_timeo, mutex_held,
382*33de042dSApple OSS Distributions 	    PSOCK, "sock_connectwait", &ts);
383*33de042dSApple OSS Distributions 
384*33de042dSApple OSS Distributions 	/* Check if we're still waiting to connect */
385*33de042dSApple OSS Distributions 	if ((sock->so_state & SS_ISCONNECTING) && sock->so_error == 0) {
386*33de042dSApple OSS Distributions 		retval = EINPROGRESS;
387*33de042dSApple OSS Distributions 		goto done;
388*33de042dSApple OSS Distributions 	}
389*33de042dSApple OSS Distributions 
390*33de042dSApple OSS Distributions 	if (sock->so_error != 0) {
391*33de042dSApple OSS Distributions 		retval = sock->so_error;
392*33de042dSApple OSS Distributions 		sock->so_error = 0;
393*33de042dSApple OSS Distributions 	}
394*33de042dSApple OSS Distributions 
395*33de042dSApple OSS Distributions done:
396*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
397*33de042dSApple OSS Distributions 	return retval;
398*33de042dSApple OSS Distributions }
399*33de042dSApple OSS Distributions 
400*33de042dSApple OSS Distributions errno_t
sock_nointerrupt(socket_t sock,int on)401*33de042dSApple OSS Distributions sock_nointerrupt(socket_t sock, int on)
402*33de042dSApple OSS Distributions {
403*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
404*33de042dSApple OSS Distributions 
405*33de042dSApple OSS Distributions 	if (on) {
406*33de042dSApple OSS Distributions 		sock->so_rcv.sb_flags |= SB_NOINTR;     /* This isn't safe */
407*33de042dSApple OSS Distributions 		sock->so_snd.sb_flags |= SB_NOINTR;     /* This isn't safe */
408*33de042dSApple OSS Distributions 	} else {
409*33de042dSApple OSS Distributions 		sock->so_rcv.sb_flags &= ~SB_NOINTR;    /* This isn't safe */
410*33de042dSApple OSS Distributions 		sock->so_snd.sb_flags &= ~SB_NOINTR;    /* This isn't safe */
411*33de042dSApple OSS Distributions 	}
412*33de042dSApple OSS Distributions 
413*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
414*33de042dSApple OSS Distributions 
415*33de042dSApple OSS Distributions 	return 0;
416*33de042dSApple OSS Distributions }
417*33de042dSApple OSS Distributions 
418*33de042dSApple OSS Distributions errno_t
sock_getpeername(socket_t sock,struct sockaddr * __sized_by (peernamelen)peername,int peernamelen)419*33de042dSApple OSS Distributions sock_getpeername(socket_t sock, struct sockaddr *__sized_by(peernamelen) peername, int peernamelen)
420*33de042dSApple OSS Distributions {
421*33de042dSApple OSS Distributions 	int error;
422*33de042dSApple OSS Distributions 	struct sockaddr *__single sa = NULL;
423*33de042dSApple OSS Distributions 
424*33de042dSApple OSS Distributions 	if (sock == NULL || peername == NULL || peernamelen < 0) {
425*33de042dSApple OSS Distributions 		return EINVAL;
426*33de042dSApple OSS Distributions 	}
427*33de042dSApple OSS Distributions 
428*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
429*33de042dSApple OSS Distributions 	if (!(sock->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING))) {
430*33de042dSApple OSS Distributions 		socket_unlock(sock, 1);
431*33de042dSApple OSS Distributions 		return ENOTCONN;
432*33de042dSApple OSS Distributions 	}
433*33de042dSApple OSS Distributions 	error = sogetaddr_locked(sock, &sa, 1);
434*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
435*33de042dSApple OSS Distributions 	if (error == 0) {
436*33de042dSApple OSS Distributions 		SOCKADDR_COPY(sa, peername, MIN(peernamelen, sa->sa_len));
437*33de042dSApple OSS Distributions 		free_sockaddr(sa);
438*33de042dSApple OSS Distributions 	}
439*33de042dSApple OSS Distributions 	return error;
440*33de042dSApple OSS Distributions }
441*33de042dSApple OSS Distributions 
442*33de042dSApple OSS Distributions errno_t
sock_getsockname(socket_t sock,struct sockaddr * __sized_by (socknamelen)sockname,int socknamelen)443*33de042dSApple OSS Distributions sock_getsockname(socket_t sock, struct sockaddr *__sized_by(socknamelen) sockname, int socknamelen)
444*33de042dSApple OSS Distributions {
445*33de042dSApple OSS Distributions 	int error;
446*33de042dSApple OSS Distributions 	struct sockaddr *__single sa = NULL;
447*33de042dSApple OSS Distributions 
448*33de042dSApple OSS Distributions 	if (sock == NULL || sockname == NULL || socknamelen < 0) {
449*33de042dSApple OSS Distributions 		return EINVAL;
450*33de042dSApple OSS Distributions 	}
451*33de042dSApple OSS Distributions 
452*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
453*33de042dSApple OSS Distributions 	error = sogetaddr_locked(sock, &sa, 0);
454*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
455*33de042dSApple OSS Distributions 	if (error == 0) {
456*33de042dSApple OSS Distributions 		SOCKADDR_COPY(sa, sockname, MIN(socknamelen, sa->sa_len));
457*33de042dSApple OSS Distributions 		free_sockaddr(sa);
458*33de042dSApple OSS Distributions 	}
459*33de042dSApple OSS Distributions 	return error;
460*33de042dSApple OSS Distributions }
461*33de042dSApple OSS Distributions 
462*33de042dSApple OSS Distributions __private_extern__ int
sogetaddr_locked(struct socket * so,struct sockaddr ** psa,int peer)463*33de042dSApple OSS Distributions sogetaddr_locked(struct socket *so, struct sockaddr **psa, int peer)
464*33de042dSApple OSS Distributions {
465*33de042dSApple OSS Distributions 	int error;
466*33de042dSApple OSS Distributions 
467*33de042dSApple OSS Distributions 	if (so == NULL || psa == NULL) {
468*33de042dSApple OSS Distributions 		return EINVAL;
469*33de042dSApple OSS Distributions 	}
470*33de042dSApple OSS Distributions 
471*33de042dSApple OSS Distributions 	*psa = NULL;
472*33de042dSApple OSS Distributions 	error = peer ? so->so_proto->pr_usrreqs->pru_peeraddr(so, psa) :
473*33de042dSApple OSS Distributions 	    so->so_proto->pr_usrreqs->pru_sockaddr(so, psa);
474*33de042dSApple OSS Distributions 
475*33de042dSApple OSS Distributions 	if (error == 0 && *psa == NULL) {
476*33de042dSApple OSS Distributions 		error = ENOMEM;
477*33de042dSApple OSS Distributions 	} else if (error != 0) {
478*33de042dSApple OSS Distributions 		free_sockaddr(*psa);
479*33de042dSApple OSS Distributions 	}
480*33de042dSApple OSS Distributions 	return error;
481*33de042dSApple OSS Distributions }
482*33de042dSApple OSS Distributions 
483*33de042dSApple OSS Distributions errno_t
sock_getaddr(socket_t sock,struct sockaddr ** psa,int peer)484*33de042dSApple OSS Distributions sock_getaddr(socket_t sock, struct sockaddr **psa, int peer)
485*33de042dSApple OSS Distributions {
486*33de042dSApple OSS Distributions 	int error;
487*33de042dSApple OSS Distributions 
488*33de042dSApple OSS Distributions 	if (sock == NULL || psa == NULL) {
489*33de042dSApple OSS Distributions 		return EINVAL;
490*33de042dSApple OSS Distributions 	}
491*33de042dSApple OSS Distributions 
492*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
493*33de042dSApple OSS Distributions 	error = sogetaddr_locked(sock, psa, peer);
494*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
495*33de042dSApple OSS Distributions 
496*33de042dSApple OSS Distributions 	return error;
497*33de042dSApple OSS Distributions }
498*33de042dSApple OSS Distributions 
499*33de042dSApple OSS Distributions void
sock_freeaddr(struct sockaddr * sa)500*33de042dSApple OSS Distributions sock_freeaddr(struct sockaddr *sa)
501*33de042dSApple OSS Distributions {
502*33de042dSApple OSS Distributions 	free_sockaddr(sa);
503*33de042dSApple OSS Distributions }
504*33de042dSApple OSS Distributions 
505*33de042dSApple OSS Distributions errno_t
sock_getsockopt(socket_t sock,int level,int optname,void * optval,int * optlen)506*33de042dSApple OSS Distributions sock_getsockopt(socket_t sock, int level, int optname, void *optval,
507*33de042dSApple OSS Distributions     int *optlen)
508*33de042dSApple OSS Distributions {
509*33de042dSApple OSS Distributions 	int error = 0;
510*33de042dSApple OSS Distributions 	struct sockopt  sopt;
511*33de042dSApple OSS Distributions 
512*33de042dSApple OSS Distributions 	if (sock == NULL || optval == NULL || optlen == NULL) {
513*33de042dSApple OSS Distributions 		return EINVAL;
514*33de042dSApple OSS Distributions 	}
515*33de042dSApple OSS Distributions 
516*33de042dSApple OSS Distributions 	sopt.sopt_dir = SOPT_GET;
517*33de042dSApple OSS Distributions 	sopt.sopt_level = level;
518*33de042dSApple OSS Distributions 	sopt.sopt_name = optname;
519*33de042dSApple OSS Distributions 	sopt.sopt_val = CAST_USER_ADDR_T(optval);
520*33de042dSApple OSS Distributions 	sopt.sopt_valsize = *optlen;
521*33de042dSApple OSS Distributions 	sopt.sopt_p = kernproc;
522*33de042dSApple OSS Distributions 	error = sogetoptlock(sock, &sopt, 1);   /* will lock socket */
523*33de042dSApple OSS Distributions 	if (error == 0) {
524*33de042dSApple OSS Distributions 		*optlen = (uint32_t)sopt.sopt_valsize;
525*33de042dSApple OSS Distributions 	}
526*33de042dSApple OSS Distributions 	return error;
527*33de042dSApple OSS Distributions }
528*33de042dSApple OSS Distributions 
529*33de042dSApple OSS Distributions errno_t
sock_ioctl(socket_t sock,unsigned long request,void * __sized_by (IOCPARM_LEN (request))argp)530*33de042dSApple OSS Distributions sock_ioctl(socket_t sock, unsigned long request, void *__sized_by(IOCPARM_LEN(request)) argp)
531*33de042dSApple OSS Distributions {
532*33de042dSApple OSS Distributions 	return soioctl(sock, request, argp, kernproc); /* will lock socket */
533*33de042dSApple OSS Distributions }
534*33de042dSApple OSS Distributions 
535*33de042dSApple OSS Distributions errno_t
sock_setsockopt(socket_t sock,int level,int optname,const void * optval,int optlen)536*33de042dSApple OSS Distributions sock_setsockopt(socket_t sock, int level, int optname, const void *optval,
537*33de042dSApple OSS Distributions     int optlen)
538*33de042dSApple OSS Distributions {
539*33de042dSApple OSS Distributions 	struct sockopt  sopt;
540*33de042dSApple OSS Distributions 
541*33de042dSApple OSS Distributions 	if (sock == NULL || optval == NULL) {
542*33de042dSApple OSS Distributions 		return EINVAL;
543*33de042dSApple OSS Distributions 	}
544*33de042dSApple OSS Distributions 
545*33de042dSApple OSS Distributions 	sopt.sopt_dir = SOPT_SET;
546*33de042dSApple OSS Distributions 	sopt.sopt_level = level;
547*33de042dSApple OSS Distributions 	sopt.sopt_name = optname;
548*33de042dSApple OSS Distributions 	sopt.sopt_val = CAST_USER_ADDR_T(optval);
549*33de042dSApple OSS Distributions 	sopt.sopt_valsize = optlen;
550*33de042dSApple OSS Distributions 	sopt.sopt_p = kernproc;
551*33de042dSApple OSS Distributions 	return sosetoptlock(sock, &sopt, 1); /* will lock socket */
552*33de042dSApple OSS Distributions }
553*33de042dSApple OSS Distributions 
554*33de042dSApple OSS Distributions /*
555*33de042dSApple OSS Distributions  * This follows the recommended mappings between DSCP code points
556*33de042dSApple OSS Distributions  * and WMM access classes.
557*33de042dSApple OSS Distributions  */
558*33de042dSApple OSS Distributions static uint32_t
so_tc_from_dscp(uint8_t dscp)559*33de042dSApple OSS Distributions so_tc_from_dscp(uint8_t dscp)
560*33de042dSApple OSS Distributions {
561*33de042dSApple OSS Distributions 	uint32_t tc;
562*33de042dSApple OSS Distributions 
563*33de042dSApple OSS Distributions 	if (dscp >= 0x30 && dscp <= 0x3f) {
564*33de042dSApple OSS Distributions 		tc = SO_TC_VO;
565*33de042dSApple OSS Distributions 	} else if (dscp >= 0x20 && dscp <= 0x2f) {
566*33de042dSApple OSS Distributions 		tc = SO_TC_VI;
567*33de042dSApple OSS Distributions 	} else if (dscp >= 0x08 && dscp <= 0x17) {
568*33de042dSApple OSS Distributions 		tc = SO_TC_BK_SYS;
569*33de042dSApple OSS Distributions 	} else {
570*33de042dSApple OSS Distributions 		tc = SO_TC_BE;
571*33de042dSApple OSS Distributions 	}
572*33de042dSApple OSS Distributions 
573*33de042dSApple OSS Distributions 	return tc;
574*33de042dSApple OSS Distributions }
575*33de042dSApple OSS Distributions 
576*33de042dSApple OSS Distributions errno_t
sock_settclassopt(socket_t sock,const void * optval,size_t optlen)577*33de042dSApple OSS Distributions sock_settclassopt(socket_t sock, const void *optval, size_t optlen)
578*33de042dSApple OSS Distributions {
579*33de042dSApple OSS Distributions 	errno_t error = 0;
580*33de042dSApple OSS Distributions 	struct sockopt sopt;
581*33de042dSApple OSS Distributions 	int sotc;
582*33de042dSApple OSS Distributions 
583*33de042dSApple OSS Distributions 	if (sock == NULL || optval == NULL || optlen != sizeof(int)) {
584*33de042dSApple OSS Distributions 		return EINVAL;
585*33de042dSApple OSS Distributions 	}
586*33de042dSApple OSS Distributions 
587*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
588*33de042dSApple OSS Distributions 	if (!(sock->so_state & SS_ISCONNECTED)) {
589*33de042dSApple OSS Distributions 		/*
590*33de042dSApple OSS Distributions 		 * If the socket is not connected then we don't know
591*33de042dSApple OSS Distributions 		 * if the destination is on LAN  or not. Skip
592*33de042dSApple OSS Distributions 		 * setting traffic class in this case
593*33de042dSApple OSS Distributions 		 */
594*33de042dSApple OSS Distributions 		error = ENOTCONN;
595*33de042dSApple OSS Distributions 		goto out;
596*33de042dSApple OSS Distributions 	}
597*33de042dSApple OSS Distributions 
598*33de042dSApple OSS Distributions 	if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL ||
599*33de042dSApple OSS Distributions 	    sock->so_pcb == NULL) {
600*33de042dSApple OSS Distributions 		error = EINVAL;
601*33de042dSApple OSS Distributions 		goto out;
602*33de042dSApple OSS Distributions 	}
603*33de042dSApple OSS Distributions 
604*33de042dSApple OSS Distributions 	/*
605*33de042dSApple OSS Distributions 	 * Set the socket traffic class based on the passed DSCP code point
606*33de042dSApple OSS Distributions 	 * regardless of the scope of the destination
607*33de042dSApple OSS Distributions 	 */
608*33de042dSApple OSS Distributions 	sotc = so_tc_from_dscp((uint8_t)((*(const int *)optval) >> 2));
609*33de042dSApple OSS Distributions 
610*33de042dSApple OSS Distributions 	sopt.sopt_dir = SOPT_SET;
611*33de042dSApple OSS Distributions 	sopt.sopt_val = CAST_USER_ADDR_T(&sotc);
612*33de042dSApple OSS Distributions 	sopt.sopt_valsize = sizeof(sotc);
613*33de042dSApple OSS Distributions 	sopt.sopt_p = kernproc;
614*33de042dSApple OSS Distributions 	sopt.sopt_level = SOL_SOCKET;
615*33de042dSApple OSS Distributions 	sopt.sopt_name = SO_TRAFFIC_CLASS;
616*33de042dSApple OSS Distributions 
617*33de042dSApple OSS Distributions 	error = sosetoptlock(sock, &sopt, 0);   /* already locked */
618*33de042dSApple OSS Distributions 
619*33de042dSApple OSS Distributions 	if (error != 0) {
620*33de042dSApple OSS Distributions 		printf("%s: sosetopt SO_TRAFFIC_CLASS failed %d\n",
621*33de042dSApple OSS Distributions 		    __func__, error);
622*33de042dSApple OSS Distributions 		goto out;
623*33de042dSApple OSS Distributions 	}
624*33de042dSApple OSS Distributions 
625*33de042dSApple OSS Distributions 	/*
626*33de042dSApple OSS Distributions 	 * Check if the destination address is LAN or link local address.
627*33de042dSApple OSS Distributions 	 * We do not want to set traffic class bits if the destination
628*33de042dSApple OSS Distributions 	 * is not local.
629*33de042dSApple OSS Distributions 	 */
630*33de042dSApple OSS Distributions 	if (!so_isdstlocal(sock)) {
631*33de042dSApple OSS Distributions 		goto out;
632*33de042dSApple OSS Distributions 	}
633*33de042dSApple OSS Distributions 
634*33de042dSApple OSS Distributions 	sopt.sopt_dir = SOPT_SET;
635*33de042dSApple OSS Distributions 	sopt.sopt_val = CAST_USER_ADDR_T(optval);
636*33de042dSApple OSS Distributions 	sopt.sopt_valsize = optlen;
637*33de042dSApple OSS Distributions 	sopt.sopt_p = kernproc;
638*33de042dSApple OSS Distributions 
639*33de042dSApple OSS Distributions 	switch (SOCK_DOM(sock)) {
640*33de042dSApple OSS Distributions 	case PF_INET:
641*33de042dSApple OSS Distributions 		sopt.sopt_level = IPPROTO_IP;
642*33de042dSApple OSS Distributions 		sopt.sopt_name = IP_TOS;
643*33de042dSApple OSS Distributions 		break;
644*33de042dSApple OSS Distributions 	case PF_INET6:
645*33de042dSApple OSS Distributions 		sopt.sopt_level = IPPROTO_IPV6;
646*33de042dSApple OSS Distributions 		sopt.sopt_name = IPV6_TCLASS;
647*33de042dSApple OSS Distributions 		break;
648*33de042dSApple OSS Distributions 	default:
649*33de042dSApple OSS Distributions 		error = EINVAL;
650*33de042dSApple OSS Distributions 		goto out;
651*33de042dSApple OSS Distributions 	}
652*33de042dSApple OSS Distributions 
653*33de042dSApple OSS Distributions 	error = sosetoptlock(sock, &sopt, 0);   /* already locked */
654*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
655*33de042dSApple OSS Distributions 	return error;
656*33de042dSApple OSS Distributions out:
657*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
658*33de042dSApple OSS Distributions 	return error;
659*33de042dSApple OSS Distributions }
660*33de042dSApple OSS Distributions 
661*33de042dSApple OSS Distributions errno_t
sock_gettclassopt(socket_t sock,void * optval,size_t * optlen)662*33de042dSApple OSS Distributions sock_gettclassopt(socket_t sock, void *optval, size_t *optlen)
663*33de042dSApple OSS Distributions {
664*33de042dSApple OSS Distributions 	errno_t error = 0;
665*33de042dSApple OSS Distributions 	struct sockopt sopt;
666*33de042dSApple OSS Distributions 
667*33de042dSApple OSS Distributions 	if (sock == NULL || optval == NULL || optlen == NULL) {
668*33de042dSApple OSS Distributions 		return EINVAL;
669*33de042dSApple OSS Distributions 	}
670*33de042dSApple OSS Distributions 
671*33de042dSApple OSS Distributions 	sopt.sopt_dir = SOPT_GET;
672*33de042dSApple OSS Distributions 	sopt.sopt_val = CAST_USER_ADDR_T(optval);
673*33de042dSApple OSS Distributions 	sopt.sopt_valsize = *optlen;
674*33de042dSApple OSS Distributions 	sopt.sopt_p = kernproc;
675*33de042dSApple OSS Distributions 
676*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
677*33de042dSApple OSS Distributions 	if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL) {
678*33de042dSApple OSS Distributions 		socket_unlock(sock, 1);
679*33de042dSApple OSS Distributions 		return EINVAL;
680*33de042dSApple OSS Distributions 	}
681*33de042dSApple OSS Distributions 
682*33de042dSApple OSS Distributions 	switch (SOCK_DOM(sock)) {
683*33de042dSApple OSS Distributions 	case PF_INET:
684*33de042dSApple OSS Distributions 		sopt.sopt_level = IPPROTO_IP;
685*33de042dSApple OSS Distributions 		sopt.sopt_name = IP_TOS;
686*33de042dSApple OSS Distributions 		break;
687*33de042dSApple OSS Distributions 	case PF_INET6:
688*33de042dSApple OSS Distributions 		sopt.sopt_level = IPPROTO_IPV6;
689*33de042dSApple OSS Distributions 		sopt.sopt_name = IPV6_TCLASS;
690*33de042dSApple OSS Distributions 		break;
691*33de042dSApple OSS Distributions 	default:
692*33de042dSApple OSS Distributions 		socket_unlock(sock, 1);
693*33de042dSApple OSS Distributions 		return EINVAL;
694*33de042dSApple OSS Distributions 	}
695*33de042dSApple OSS Distributions 	error = sogetoptlock(sock, &sopt, 0);   /* already locked */
696*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
697*33de042dSApple OSS Distributions 	if (error == 0) {
698*33de042dSApple OSS Distributions 		*optlen = sopt.sopt_valsize;
699*33de042dSApple OSS Distributions 	}
700*33de042dSApple OSS Distributions 	return error;
701*33de042dSApple OSS Distributions }
702*33de042dSApple OSS Distributions 
703*33de042dSApple OSS Distributions errno_t
sock_listen(socket_t sock,int backlog)704*33de042dSApple OSS Distributions sock_listen(socket_t sock, int backlog)
705*33de042dSApple OSS Distributions {
706*33de042dSApple OSS Distributions 	if (sock == NULL) {
707*33de042dSApple OSS Distributions 		return EINVAL;
708*33de042dSApple OSS Distributions 	}
709*33de042dSApple OSS Distributions 
710*33de042dSApple OSS Distributions 	return solisten(sock, backlog); /* will lock socket */
711*33de042dSApple OSS Distributions }
712*33de042dSApple OSS Distributions 
713*33de042dSApple OSS Distributions errno_t
sock_receive_internal(socket_t sock,struct msghdr * msg,mbuf_t * data,int flags,size_t * recvdlen)714*33de042dSApple OSS Distributions sock_receive_internal(socket_t sock, struct msghdr *msg, mbuf_t *data,
715*33de042dSApple OSS Distributions     int flags, size_t *recvdlen)
716*33de042dSApple OSS Distributions {
717*33de042dSApple OSS Distributions 	uio_t auio;
718*33de042dSApple OSS Distributions 	mbuf_ref_t control = NULL;
719*33de042dSApple OSS Distributions 	int error = 0;
720*33de042dSApple OSS Distributions 	user_ssize_t length = 0;
721*33de042dSApple OSS Distributions 	struct sockaddr *__single fromsa = NULL;
722*33de042dSApple OSS Distributions 	UIO_STACKBUF(uio_buf, (msg != NULL) ? msg->msg_iovlen : 0);
723*33de042dSApple OSS Distributions 
724*33de042dSApple OSS Distributions 	if (sock == NULL) {
725*33de042dSApple OSS Distributions 		return EINVAL;
726*33de042dSApple OSS Distributions 	}
727*33de042dSApple OSS Distributions 
728*33de042dSApple OSS Distributions 	auio = uio_createwithbuffer(((msg != NULL) ? msg->msg_iovlen : 0),
729*33de042dSApple OSS Distributions 	    0, UIO_SYSSPACE, UIO_READ, &uio_buf[0], sizeof(uio_buf));
730*33de042dSApple OSS Distributions 	if (msg != NULL && data == NULL) {
731*33de042dSApple OSS Distributions 		int i;
732*33de042dSApple OSS Distributions 		struct iovec *tempp = __unsafe_forge_bidi_indexable(struct iovec *,
733*33de042dSApple OSS Distributions 		    msg->msg_iov,
734*33de042dSApple OSS Distributions 		    sizeof(struct iovec) * msg->msg_iovlen);
735*33de042dSApple OSS Distributions 
736*33de042dSApple OSS Distributions 		for (i = 0; i < msg->msg_iovlen; i++) {
737*33de042dSApple OSS Distributions 			uio_addiov(auio,
738*33de042dSApple OSS Distributions 			    CAST_USER_ADDR_T((tempp + i)->iov_base),
739*33de042dSApple OSS Distributions 			    (tempp + i)->iov_len);
740*33de042dSApple OSS Distributions 		}
741*33de042dSApple OSS Distributions 		if (uio_resid(auio) < 0) {
742*33de042dSApple OSS Distributions 			return EINVAL;
743*33de042dSApple OSS Distributions 		}
744*33de042dSApple OSS Distributions 	} else if (recvdlen != NULL) {
745*33de042dSApple OSS Distributions 		uio_setresid(auio, (uio_resid(auio) + *recvdlen));
746*33de042dSApple OSS Distributions 	}
747*33de042dSApple OSS Distributions 	length = uio_resid(auio);
748*33de042dSApple OSS Distributions 
749*33de042dSApple OSS Distributions 	if (recvdlen != NULL) {
750*33de042dSApple OSS Distributions 		*recvdlen = 0;
751*33de042dSApple OSS Distributions 	}
752*33de042dSApple OSS Distributions 
753*33de042dSApple OSS Distributions 	/* let pru_soreceive handle the socket locking */
754*33de042dSApple OSS Distributions 	error = sock->so_proto->pr_usrreqs->pru_soreceive(sock, &fromsa, auio,
755*33de042dSApple OSS Distributions 	    data, (msg && msg->msg_control) ? &control : NULL, &flags);
756*33de042dSApple OSS Distributions 	if (error != 0) {
757*33de042dSApple OSS Distributions 		goto cleanup;
758*33de042dSApple OSS Distributions 	}
759*33de042dSApple OSS Distributions 
760*33de042dSApple OSS Distributions 	if (recvdlen != NULL) {
761*33de042dSApple OSS Distributions 		*recvdlen = length - uio_resid(auio);
762*33de042dSApple OSS Distributions 	}
763*33de042dSApple OSS Distributions 	if (msg != NULL) {
764*33de042dSApple OSS Distributions 		msg->msg_flags = flags;
765*33de042dSApple OSS Distributions 
766*33de042dSApple OSS Distributions 		if (msg->msg_name != NULL) {
767*33de042dSApple OSS Distributions 			int salen;
768*33de042dSApple OSS Distributions 			salen = msg->msg_namelen;
769*33de042dSApple OSS Distributions 			if (msg->msg_namelen > 0 && fromsa != NULL) {
770*33de042dSApple OSS Distributions 				salen = MIN(salen, fromsa->sa_len);
771*33de042dSApple OSS Distributions 				SOCKADDR_COPY(fromsa, msg->msg_name,
772*33de042dSApple OSS Distributions 				    msg->msg_namelen > fromsa->sa_len ?
773*33de042dSApple OSS Distributions 				    fromsa->sa_len : msg->msg_namelen);
774*33de042dSApple OSS Distributions 			}
775*33de042dSApple OSS Distributions 		}
776*33de042dSApple OSS Distributions 
777*33de042dSApple OSS Distributions 		if (msg->msg_control != NULL) {
778*33de042dSApple OSS Distributions 			struct mbuf *m = control;
779*33de042dSApple OSS Distributions 			int clen = msg->msg_controllen;
780*33de042dSApple OSS Distributions 			u_char *original_ctl = msg->msg_control;
781*33de042dSApple OSS Distributions 			u_char *ctlbuf = msg->msg_control;
782*33de042dSApple OSS Distributions 
783*33de042dSApple OSS Distributions 			msg->msg_control = NULL;
784*33de042dSApple OSS Distributions 			msg->msg_controllen = 0;
785*33de042dSApple OSS Distributions 
786*33de042dSApple OSS Distributions 			while (m != NULL && clen > 0) {
787*33de042dSApple OSS Distributions 				unsigned int tocopy;
788*33de042dSApple OSS Distributions 
789*33de042dSApple OSS Distributions 				if (clen >= m->m_len) {
790*33de042dSApple OSS Distributions 					tocopy = m->m_len;
791*33de042dSApple OSS Distributions 				} else {
792*33de042dSApple OSS Distributions 					msg->msg_flags |= MSG_CTRUNC;
793*33de042dSApple OSS Distributions 					tocopy = clen;
794*33de042dSApple OSS Distributions 				}
795*33de042dSApple OSS Distributions 				memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
796*33de042dSApple OSS Distributions 				ctlbuf += tocopy;
797*33de042dSApple OSS Distributions 				clen -= tocopy;
798*33de042dSApple OSS Distributions 				m = m->m_next;
799*33de042dSApple OSS Distributions 			}
800*33de042dSApple OSS Distributions 			msg->msg_control = original_ctl;
801*33de042dSApple OSS Distributions 			msg->msg_controllen = (socklen_t)(ctlbuf - original_ctl);
802*33de042dSApple OSS Distributions 		}
803*33de042dSApple OSS Distributions 	}
804*33de042dSApple OSS Distributions 
805*33de042dSApple OSS Distributions cleanup:
806*33de042dSApple OSS Distributions 	if (control != NULL) {
807*33de042dSApple OSS Distributions 		m_freem(control);
808*33de042dSApple OSS Distributions 	}
809*33de042dSApple OSS Distributions 	free_sockaddr(fromsa);
810*33de042dSApple OSS Distributions 	return error;
811*33de042dSApple OSS Distributions }
812*33de042dSApple OSS Distributions 
813*33de042dSApple OSS Distributions errno_t
sock_receive(socket_t sock,struct msghdr * msg,int flags,size_t * recvdlen)814*33de042dSApple OSS Distributions sock_receive(socket_t sock, struct msghdr *msg, int flags, size_t *recvdlen)
815*33de042dSApple OSS Distributions {
816*33de042dSApple OSS Distributions 	if ((msg == NULL) || (msg->msg_iovlen < 1) ||
817*33de042dSApple OSS Distributions 	    (msg->msg_iov[0].iov_len == 0) ||
818*33de042dSApple OSS Distributions 	    (msg->msg_iov[0].iov_base == NULL)) {
819*33de042dSApple OSS Distributions 		return EINVAL;
820*33de042dSApple OSS Distributions 	}
821*33de042dSApple OSS Distributions 
822*33de042dSApple OSS Distributions 	return sock_receive_internal(sock, msg, NULL, flags, recvdlen);
823*33de042dSApple OSS Distributions }
824*33de042dSApple OSS Distributions 
825*33de042dSApple OSS Distributions errno_t
sock_receivembuf(socket_t sock,struct msghdr * msg,mbuf_t * data,int flags,size_t * recvlen)826*33de042dSApple OSS Distributions sock_receivembuf(socket_t sock, struct msghdr *msg, mbuf_t *data, int flags,
827*33de042dSApple OSS Distributions     size_t *recvlen)
828*33de042dSApple OSS Distributions {
829*33de042dSApple OSS Distributions 	if (data == NULL || recvlen == 0 || *recvlen <= 0 || (msg != NULL &&
830*33de042dSApple OSS Distributions 	    (msg->msg_iov != NULL || msg->msg_iovlen != 0))) {
831*33de042dSApple OSS Distributions 		return EINVAL;
832*33de042dSApple OSS Distributions 	}
833*33de042dSApple OSS Distributions 
834*33de042dSApple OSS Distributions 	return sock_receive_internal(sock, msg, data, flags, recvlen);
835*33de042dSApple OSS Distributions }
836*33de042dSApple OSS Distributions 
837*33de042dSApple OSS Distributions errno_t
sock_send_internal(socket_t sock,const struct msghdr * msg,mbuf_t data,int flags,size_t * sentlen)838*33de042dSApple OSS Distributions sock_send_internal(socket_t sock, const struct msghdr *msg, mbuf_t data,
839*33de042dSApple OSS Distributions     int flags, size_t *sentlen)
840*33de042dSApple OSS Distributions {
841*33de042dSApple OSS Distributions 	uio_t auio = NULL;
842*33de042dSApple OSS Distributions 	mbuf_ref_t control = NULL;
843*33de042dSApple OSS Distributions 	int error = 0;
844*33de042dSApple OSS Distributions 	user_ssize_t datalen = 0;
845*33de042dSApple OSS Distributions 
846*33de042dSApple OSS Distributions 	if (sock == NULL) {
847*33de042dSApple OSS Distributions 		error = EINVAL;
848*33de042dSApple OSS Distributions 		goto errorout;
849*33de042dSApple OSS Distributions 	}
850*33de042dSApple OSS Distributions 
851*33de042dSApple OSS Distributions 	if (data == NULL && msg != NULL) {
852*33de042dSApple OSS Distributions 		struct iovec *tempp = __unsafe_forge_bidi_indexable(struct iovec *,
853*33de042dSApple OSS Distributions 		    msg->msg_iov,
854*33de042dSApple OSS Distributions 		    sizeof(struct iovec) * msg->msg_iovlen);
855*33de042dSApple OSS Distributions 
856*33de042dSApple OSS Distributions 		auio = uio_create(msg->msg_iovlen, 0, UIO_SYSSPACE, UIO_WRITE);
857*33de042dSApple OSS Distributions 		if (auio == NULL) {
858*33de042dSApple OSS Distributions #if (DEBUG || DEVELOPMENT)
859*33de042dSApple OSS Distributions 			printf("sock_send_internal: so %p uio_createwithbuffer(%lu) failed, ENOMEM\n",
860*33de042dSApple OSS Distributions 			    sock, UIO_SIZEOF(msg->msg_iovlen));
861*33de042dSApple OSS Distributions #endif /* (DEBUG || DEVELOPMENT) */
862*33de042dSApple OSS Distributions 			error = ENOMEM;
863*33de042dSApple OSS Distributions 			goto errorout;
864*33de042dSApple OSS Distributions 		}
865*33de042dSApple OSS Distributions 		if (tempp != NULL) {
866*33de042dSApple OSS Distributions 			int i;
867*33de042dSApple OSS Distributions 
868*33de042dSApple OSS Distributions 			for (i = 0; i < msg->msg_iovlen; i++) {
869*33de042dSApple OSS Distributions 				uio_addiov(auio,
870*33de042dSApple OSS Distributions 				    CAST_USER_ADDR_T((tempp + i)->iov_base),
871*33de042dSApple OSS Distributions 				    (tempp + i)->iov_len);
872*33de042dSApple OSS Distributions 			}
873*33de042dSApple OSS Distributions 
874*33de042dSApple OSS Distributions 			if (uio_resid(auio) < 0) {
875*33de042dSApple OSS Distributions 				error = EINVAL;
876*33de042dSApple OSS Distributions 				goto errorout;
877*33de042dSApple OSS Distributions 			}
878*33de042dSApple OSS Distributions 		}
879*33de042dSApple OSS Distributions 	}
880*33de042dSApple OSS Distributions 
881*33de042dSApple OSS Distributions 	if (sentlen != NULL) {
882*33de042dSApple OSS Distributions 		*sentlen = 0;
883*33de042dSApple OSS Distributions 	}
884*33de042dSApple OSS Distributions 
885*33de042dSApple OSS Distributions 	if (auio != NULL) {
886*33de042dSApple OSS Distributions 		datalen = uio_resid(auio);
887*33de042dSApple OSS Distributions 	} else {
888*33de042dSApple OSS Distributions 		datalen = data->m_pkthdr.len;
889*33de042dSApple OSS Distributions 	}
890*33de042dSApple OSS Distributions 
891*33de042dSApple OSS Distributions 	if (msg != NULL && msg->msg_control) {
892*33de042dSApple OSS Distributions 		if ((size_t)msg->msg_controllen < sizeof(struct cmsghdr)) {
893*33de042dSApple OSS Distributions 			error = EINVAL;
894*33de042dSApple OSS Distributions 			goto errorout;
895*33de042dSApple OSS Distributions 		}
896*33de042dSApple OSS Distributions 
897*33de042dSApple OSS Distributions 		if ((size_t)msg->msg_controllen > MLEN) {
898*33de042dSApple OSS Distributions 			error = EINVAL;
899*33de042dSApple OSS Distributions 			goto errorout;
900*33de042dSApple OSS Distributions 		}
901*33de042dSApple OSS Distributions 
902*33de042dSApple OSS Distributions 		control = m_get(M_NOWAIT, MT_CONTROL);
903*33de042dSApple OSS Distributions 		if (control == NULL) {
904*33de042dSApple OSS Distributions 			error = ENOMEM;
905*33de042dSApple OSS Distributions 			goto errorout;
906*33de042dSApple OSS Distributions 		}
907*33de042dSApple OSS Distributions 		memcpy(mtod(control, caddr_t), msg->msg_control,
908*33de042dSApple OSS Distributions 		    msg->msg_controllen);
909*33de042dSApple OSS Distributions 		control->m_len = msg->msg_controllen;
910*33de042dSApple OSS Distributions 	}
911*33de042dSApple OSS Distributions 
912*33de042dSApple OSS Distributions #if SKYWALK
913*33de042dSApple OSS Distributions 	sk_protect_t protect = sk_async_transmit_protect();
914*33de042dSApple OSS Distributions #endif /* SKYWALK */
915*33de042dSApple OSS Distributions 
916*33de042dSApple OSS Distributions 	error = sock->so_proto->pr_usrreqs->pru_sosend(sock, msg != NULL ?
917*33de042dSApple OSS Distributions 	    (struct sockaddr *)msg->msg_name : NULL, auio, data,
918*33de042dSApple OSS Distributions 	    control, flags);
919*33de042dSApple OSS Distributions 
920*33de042dSApple OSS Distributions #if SKYWALK
921*33de042dSApple OSS Distributions 	sk_async_transmit_unprotect(protect);
922*33de042dSApple OSS Distributions #endif /* SKYWALK */
923*33de042dSApple OSS Distributions 
924*33de042dSApple OSS Distributions 	/*
925*33de042dSApple OSS Distributions 	 * Residual data is possible in the case of IO vectors but not
926*33de042dSApple OSS Distributions 	 * in the mbuf case since the latter is treated as atomic send.
927*33de042dSApple OSS Distributions 	 * If pru_sosend() consumed a portion of the iovecs data and
928*33de042dSApple OSS Distributions 	 * the error returned is transient, treat it as success; this
929*33de042dSApple OSS Distributions 	 * is consistent with sendit() behavior.
930*33de042dSApple OSS Distributions 	 */
931*33de042dSApple OSS Distributions 	if (auio != NULL && uio_resid(auio) != datalen &&
932*33de042dSApple OSS Distributions 	    (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) {
933*33de042dSApple OSS Distributions 		error = 0;
934*33de042dSApple OSS Distributions 	}
935*33de042dSApple OSS Distributions 
936*33de042dSApple OSS Distributions 	if (error == 0 && sentlen != NULL) {
937*33de042dSApple OSS Distributions 		if (auio != NULL) {
938*33de042dSApple OSS Distributions 			*sentlen = datalen - uio_resid(auio);
939*33de042dSApple OSS Distributions 		} else {
940*33de042dSApple OSS Distributions 			*sentlen = datalen;
941*33de042dSApple OSS Distributions 		}
942*33de042dSApple OSS Distributions 	}
943*33de042dSApple OSS Distributions 	if (auio != NULL) {
944*33de042dSApple OSS Distributions 		uio_free(auio);
945*33de042dSApple OSS Distributions 	}
946*33de042dSApple OSS Distributions 
947*33de042dSApple OSS Distributions 	return error;
948*33de042dSApple OSS Distributions 
949*33de042dSApple OSS Distributions /*
950*33de042dSApple OSS Distributions  * In cases where we detect an error before returning, we need to
951*33de042dSApple OSS Distributions  * free the mbuf chain if there is one. sosend (and pru_sosend) will
952*33de042dSApple OSS Distributions  * free the mbuf chain if they encounter an error.
953*33de042dSApple OSS Distributions  */
954*33de042dSApple OSS Distributions errorout:
955*33de042dSApple OSS Distributions 	if (control) {
956*33de042dSApple OSS Distributions 		m_freem(control);
957*33de042dSApple OSS Distributions 	}
958*33de042dSApple OSS Distributions 	if (data) {
959*33de042dSApple OSS Distributions 		m_freem(data);
960*33de042dSApple OSS Distributions 	}
961*33de042dSApple OSS Distributions 	if (sentlen) {
962*33de042dSApple OSS Distributions 		*sentlen = 0;
963*33de042dSApple OSS Distributions 	}
964*33de042dSApple OSS Distributions 	if (auio != NULL) {
965*33de042dSApple OSS Distributions 		uio_free(auio);
966*33de042dSApple OSS Distributions 	}
967*33de042dSApple OSS Distributions 	return error;
968*33de042dSApple OSS Distributions }
969*33de042dSApple OSS Distributions 
970*33de042dSApple OSS Distributions errno_t
sock_send(socket_t sock,const struct msghdr * msg,int flags,size_t * sentlen)971*33de042dSApple OSS Distributions sock_send(socket_t sock, const struct msghdr *msg, int flags, size_t *sentlen)
972*33de042dSApple OSS Distributions {
973*33de042dSApple OSS Distributions 	if (msg == NULL || msg->msg_iov == NULL || msg->msg_iovlen < 1) {
974*33de042dSApple OSS Distributions 		return EINVAL;
975*33de042dSApple OSS Distributions 	}
976*33de042dSApple OSS Distributions 
977*33de042dSApple OSS Distributions 	return sock_send_internal(sock, msg, NULL, flags, sentlen);
978*33de042dSApple OSS Distributions }
979*33de042dSApple OSS Distributions 
980*33de042dSApple OSS Distributions errno_t
sock_sendmbuf(socket_t sock,const struct msghdr * msg,mbuf_t data,int flags,size_t * sentlen)981*33de042dSApple OSS Distributions sock_sendmbuf(socket_t sock, const struct msghdr *msg, mbuf_t data,
982*33de042dSApple OSS Distributions     int flags, size_t *sentlen)
983*33de042dSApple OSS Distributions {
984*33de042dSApple OSS Distributions 	int error;
985*33de042dSApple OSS Distributions 
986*33de042dSApple OSS Distributions 	if (data == NULL || (msg != NULL && (msg->msg_iov != NULL ||
987*33de042dSApple OSS Distributions 	    msg->msg_iovlen != 0))) {
988*33de042dSApple OSS Distributions 		if (data != NULL) {
989*33de042dSApple OSS Distributions 			m_freem(data);
990*33de042dSApple OSS Distributions 		}
991*33de042dSApple OSS Distributions 		error = EINVAL;
992*33de042dSApple OSS Distributions 		goto done;
993*33de042dSApple OSS Distributions 	}
994*33de042dSApple OSS Distributions 	error = sock_send_internal(sock, msg, data, flags, sentlen);
995*33de042dSApple OSS Distributions done:
996*33de042dSApple OSS Distributions 	return error;
997*33de042dSApple OSS Distributions }
998*33de042dSApple OSS Distributions 
999*33de042dSApple OSS Distributions errno_t
sock_sendmbuf_can_wait(socket_t sock,const struct msghdr * msg,mbuf_t data,int flags,size_t * sentlen)1000*33de042dSApple OSS Distributions sock_sendmbuf_can_wait(socket_t sock, const struct msghdr *msg, mbuf_t data,
1001*33de042dSApple OSS Distributions     int flags, size_t *sentlen)
1002*33de042dSApple OSS Distributions {
1003*33de042dSApple OSS Distributions 	int error;
1004*33de042dSApple OSS Distributions 	int count = 0;
1005*33de042dSApple OSS Distributions 	int i;
1006*33de042dSApple OSS Distributions 	mbuf_t m;
1007*33de042dSApple OSS Distributions 	struct msghdr msg_temp = {};
1008*33de042dSApple OSS Distributions 
1009*33de042dSApple OSS Distributions 	if (data == NULL || (msg != NULL && (msg->msg_iov != NULL ||
1010*33de042dSApple OSS Distributions 	    msg->msg_iovlen != 0))) {
1011*33de042dSApple OSS Distributions 		error = EINVAL;
1012*33de042dSApple OSS Distributions 		goto done;
1013*33de042dSApple OSS Distributions 	}
1014*33de042dSApple OSS Distributions 
1015*33de042dSApple OSS Distributions 	/*
1016*33de042dSApple OSS Distributions 	 * Use the name and control
1017*33de042dSApple OSS Distributions 	 */
1018*33de042dSApple OSS Distributions 	msg_temp.msg_name = msg->msg_name;
1019*33de042dSApple OSS Distributions 	msg_temp.msg_namelen = msg->msg_namelen;
1020*33de042dSApple OSS Distributions 	msg_temp.msg_control = msg->msg_control;
1021*33de042dSApple OSS Distributions 	msg_temp.msg_controllen = msg->msg_controllen;
1022*33de042dSApple OSS Distributions 
1023*33de042dSApple OSS Distributions 	/*
1024*33de042dSApple OSS Distributions 	 * Count the number of mbufs in the chain
1025*33de042dSApple OSS Distributions 	 */
1026*33de042dSApple OSS Distributions 	for (m = data; m != NULL; m = mbuf_next(m)) {
1027*33de042dSApple OSS Distributions 		count++;
1028*33de042dSApple OSS Distributions 	}
1029*33de042dSApple OSS Distributions 
1030*33de042dSApple OSS Distributions 	struct iovec *msg_iov = kalloc_type(struct iovec, count, Z_WAITOK | Z_ZERO);
1031*33de042dSApple OSS Distributions 	if (msg_iov == NULL) {
1032*33de042dSApple OSS Distributions 		error = ENOMEM;
1033*33de042dSApple OSS Distributions 		goto done;
1034*33de042dSApple OSS Distributions 	}
1035*33de042dSApple OSS Distributions 
1036*33de042dSApple OSS Distributions 	msg_temp.msg_iov = msg_iov;
1037*33de042dSApple OSS Distributions 	msg_temp.msg_iovlen = count;
1038*33de042dSApple OSS Distributions 
1039*33de042dSApple OSS Distributions 	for (i = 0, m = data; m != NULL; i++, m = mbuf_next(m)) {
1040*33de042dSApple OSS Distributions 		msg_iov[i].iov_base = mtod(m, void*);
1041*33de042dSApple OSS Distributions 		msg_iov[i].iov_len = mbuf_len(m);
1042*33de042dSApple OSS Distributions 	}
1043*33de042dSApple OSS Distributions 
1044*33de042dSApple OSS Distributions 	error = sock_send_internal(sock, &msg_temp, NULL, flags, sentlen);
1045*33de042dSApple OSS Distributions done:
1046*33de042dSApple OSS Distributions 	if (data != NULL) {
1047*33de042dSApple OSS Distributions 		m_freem(data);
1048*33de042dSApple OSS Distributions 	}
1049*33de042dSApple OSS Distributions 	if (msg_temp.msg_iov != NULL) {
1050*33de042dSApple OSS Distributions 		kfree_type(struct iovec, count, msg_temp.msg_iov);
1051*33de042dSApple OSS Distributions 	}
1052*33de042dSApple OSS Distributions 	return error;
1053*33de042dSApple OSS Distributions }
1054*33de042dSApple OSS Distributions 
1055*33de042dSApple OSS Distributions errno_t
sock_shutdown(socket_t sock,int how)1056*33de042dSApple OSS Distributions sock_shutdown(socket_t sock, int how)
1057*33de042dSApple OSS Distributions {
1058*33de042dSApple OSS Distributions 	if (sock == NULL) {
1059*33de042dSApple OSS Distributions 		return EINVAL;
1060*33de042dSApple OSS Distributions 	}
1061*33de042dSApple OSS Distributions 
1062*33de042dSApple OSS Distributions 	return soshutdown(sock, how);
1063*33de042dSApple OSS Distributions }
1064*33de042dSApple OSS Distributions 
1065*33de042dSApple OSS Distributions errno_t
sock_socket_common(int domain,int type,int protocol,sock_upcall callback,void * context,socket_t * new_so,bool is_internal)1066*33de042dSApple OSS Distributions sock_socket_common(int domain, int type, int protocol, sock_upcall callback,
1067*33de042dSApple OSS Distributions     void *context, socket_t *new_so, bool is_internal)
1068*33de042dSApple OSS Distributions {
1069*33de042dSApple OSS Distributions 	int error = 0;
1070*33de042dSApple OSS Distributions 
1071*33de042dSApple OSS Distributions 	if (new_so == NULL) {
1072*33de042dSApple OSS Distributions 		return EINVAL;
1073*33de042dSApple OSS Distributions 	}
1074*33de042dSApple OSS Distributions 
1075*33de042dSApple OSS Distributions 	/* socreate will create an initial so_count */
1076*33de042dSApple OSS Distributions 	error = socreate(domain, new_so, type, protocol);
1077*33de042dSApple OSS Distributions 	if (error == 0) {
1078*33de042dSApple OSS Distributions 		/*
1079*33de042dSApple OSS Distributions 		 * This is an in-kernel socket
1080*33de042dSApple OSS Distributions 		 */
1081*33de042dSApple OSS Distributions 		(*new_so)->so_flags1 |= SOF1_IN_KERNEL_SOCKET;
1082*33de042dSApple OSS Distributions 		INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_in_kernel_total);
1083*33de042dSApple OSS Distributions 		if (is_internal) {
1084*33de042dSApple OSS Distributions 			INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_in_kernel_os_total);
1085*33de042dSApple OSS Distributions 		}
1086*33de042dSApple OSS Distributions 
1087*33de042dSApple OSS Distributions 		/* see comments in sock_setupcall() */
1088*33de042dSApple OSS Distributions 		if (callback != NULL) {
1089*33de042dSApple OSS Distributions 			sock_setupcall(*new_so, callback, context);
1090*33de042dSApple OSS Distributions 		}
1091*33de042dSApple OSS Distributions 		/*
1092*33de042dSApple OSS Distributions 		 * last_pid and last_upid should be zero for sockets
1093*33de042dSApple OSS Distributions 		 * created using sock_socket
1094*33de042dSApple OSS Distributions 		 */
1095*33de042dSApple OSS Distributions 		(*new_so)->last_pid = 0;
1096*33de042dSApple OSS Distributions 		(*new_so)->last_upid = 0;
1097*33de042dSApple OSS Distributions 	}
1098*33de042dSApple OSS Distributions 	return error;
1099*33de042dSApple OSS Distributions }
1100*33de042dSApple OSS Distributions 
1101*33de042dSApple OSS Distributions errno_t
sock_socket_internal(int domain,int type,int protocol,sock_upcall callback,void * context,socket_t * new_so)1102*33de042dSApple OSS Distributions sock_socket_internal(int domain, int type, int protocol, sock_upcall callback,
1103*33de042dSApple OSS Distributions     void *context, socket_t *new_so)
1104*33de042dSApple OSS Distributions {
1105*33de042dSApple OSS Distributions 	return sock_socket_common(domain, type, protocol, callback,
1106*33de042dSApple OSS Distributions 	           context, new_so, true);
1107*33de042dSApple OSS Distributions }
1108*33de042dSApple OSS Distributions 
1109*33de042dSApple OSS Distributions errno_t
sock_socket(int domain,int type,int protocol,sock_upcall callback,void * context,socket_t * new_so)1110*33de042dSApple OSS Distributions sock_socket(int domain, int type, int protocol, sock_upcall callback,
1111*33de042dSApple OSS Distributions     void *context, socket_t *new_so)
1112*33de042dSApple OSS Distributions {
1113*33de042dSApple OSS Distributions 	return sock_socket_common(domain, type, protocol, callback,
1114*33de042dSApple OSS Distributions 	           context, new_so, false);
1115*33de042dSApple OSS Distributions }
1116*33de042dSApple OSS Distributions 
1117*33de042dSApple OSS Distributions void
sock_close(socket_t sock)1118*33de042dSApple OSS Distributions sock_close(socket_t sock)
1119*33de042dSApple OSS Distributions {
1120*33de042dSApple OSS Distributions 	if (sock == NULL) {
1121*33de042dSApple OSS Distributions 		return;
1122*33de042dSApple OSS Distributions 	}
1123*33de042dSApple OSS Distributions 
1124*33de042dSApple OSS Distributions 	soclose(sock);
1125*33de042dSApple OSS Distributions }
1126*33de042dSApple OSS Distributions 
1127*33de042dSApple OSS Distributions /* Do we want this to be APPLE_PRIVATE API?: YES (LD 12/23/04) */
1128*33de042dSApple OSS Distributions void
sock_retain(socket_t sock)1129*33de042dSApple OSS Distributions sock_retain(socket_t sock)
1130*33de042dSApple OSS Distributions {
1131*33de042dSApple OSS Distributions 	if (sock == NULL) {
1132*33de042dSApple OSS Distributions 		return;
1133*33de042dSApple OSS Distributions 	}
1134*33de042dSApple OSS Distributions 
1135*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1136*33de042dSApple OSS Distributions 	sock->so_retaincnt++;
1137*33de042dSApple OSS Distributions 	sock->so_usecount++;    /* add extra reference for holding the socket */
1138*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1139*33de042dSApple OSS Distributions }
1140*33de042dSApple OSS Distributions 
1141*33de042dSApple OSS Distributions /* Do we want this to be APPLE_PRIVATE API? */
1142*33de042dSApple OSS Distributions void
sock_release(socket_t sock)1143*33de042dSApple OSS Distributions sock_release(socket_t sock)
1144*33de042dSApple OSS Distributions {
1145*33de042dSApple OSS Distributions 	if (sock == NULL) {
1146*33de042dSApple OSS Distributions 		return;
1147*33de042dSApple OSS Distributions 	}
1148*33de042dSApple OSS Distributions 
1149*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1150*33de042dSApple OSS Distributions 	if (sock->so_upcallusecount > 0) {
1151*33de042dSApple OSS Distributions 		soclose_wait_locked(sock);
1152*33de042dSApple OSS Distributions 	}
1153*33de042dSApple OSS Distributions 
1154*33de042dSApple OSS Distributions 	sock->so_retaincnt--;
1155*33de042dSApple OSS Distributions 	if (sock->so_retaincnt < 0) {
1156*33de042dSApple OSS Distributions 		panic("%s: negative retain count (%d) for sock=%p",
1157*33de042dSApple OSS Distributions 		    __func__, sock->so_retaincnt, sock);
1158*33de042dSApple OSS Distributions 		/* NOTREACHED */
1159*33de042dSApple OSS Distributions 	}
1160*33de042dSApple OSS Distributions 	/*
1161*33de042dSApple OSS Distributions 	 * The so_usecount values '2' and '3' are special because they
1162*33de042dSApple OSS Distributions 	 * indicate how many references are on the socket when it is
1163*33de042dSApple OSS Distributions 	 * ready for closing:
1164*33de042dSApple OSS Distributions 	 *  - there is always one use count that was just taken by this function;
1165*33de042dSApple OSS Distributions 	 *  - '2' works for most kinds of socket as there is one use count
1166*33de042dSApple OSS Distributions 	 *    for the socket held by the file or by the KEXT;
1167*33de042dSApple OSS Distributions 	 *  - '3' works for connected Unix domain sockets as each peer
1168*33de042dSApple OSS Distributions 	 *    holds a connection to the other peer.
1169*33de042dSApple OSS Distributions 	 * Check SS_NOFDREF in case a close happened as sock_retain()
1170*33de042dSApple OSS Distributions 	 * was grabbing the lock
1171*33de042dSApple OSS Distributions 	 */
1172*33de042dSApple OSS Distributions 	if ((sock->so_retaincnt == 0) &&
1173*33de042dSApple OSS Distributions 	    ((SOCK_DOM(sock) != PF_LOCAL && sock->so_usecount == 2) ||
1174*33de042dSApple OSS Distributions 	    (SOCK_DOM(sock) == PF_LOCAL && (sock->so_state & SS_ISCONNECTED) && sock->so_usecount == 3)) &&
1175*33de042dSApple OSS Distributions 	    (!(sock->so_state & SS_NOFDREF) || (sock->so_flags & SOF_MP_SUBFLOW))) {
1176*33de042dSApple OSS Distributions 		/* close socket only if the FD is not holding it */
1177*33de042dSApple OSS Distributions 		soclose_locked(sock);
1178*33de042dSApple OSS Distributions 	} else {
1179*33de042dSApple OSS Distributions 		/* remove extra reference holding the socket */
1180*33de042dSApple OSS Distributions 		VERIFY(sock->so_usecount > 1);
1181*33de042dSApple OSS Distributions 		sock->so_usecount--;
1182*33de042dSApple OSS Distributions 	}
1183*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1184*33de042dSApple OSS Distributions }
1185*33de042dSApple OSS Distributions 
1186*33de042dSApple OSS Distributions errno_t
sock_setpriv(socket_t sock,int on)1187*33de042dSApple OSS Distributions sock_setpriv(socket_t sock, int on)
1188*33de042dSApple OSS Distributions {
1189*33de042dSApple OSS Distributions 	if (sock == NULL) {
1190*33de042dSApple OSS Distributions 		return EINVAL;
1191*33de042dSApple OSS Distributions 	}
1192*33de042dSApple OSS Distributions 
1193*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1194*33de042dSApple OSS Distributions 	if (on) {
1195*33de042dSApple OSS Distributions 		sock->so_state |= SS_PRIV;
1196*33de042dSApple OSS Distributions 	} else {
1197*33de042dSApple OSS Distributions 		sock->so_state &= ~SS_PRIV;
1198*33de042dSApple OSS Distributions 	}
1199*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1200*33de042dSApple OSS Distributions 	return 0;
1201*33de042dSApple OSS Distributions }
1202*33de042dSApple OSS Distributions 
1203*33de042dSApple OSS Distributions int
sock_isconnected(socket_t sock)1204*33de042dSApple OSS Distributions sock_isconnected(socket_t sock)
1205*33de042dSApple OSS Distributions {
1206*33de042dSApple OSS Distributions 	int retval;
1207*33de042dSApple OSS Distributions 
1208*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1209*33de042dSApple OSS Distributions 	retval = ((sock->so_state & SS_ISCONNECTED) ? 1 : 0);
1210*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1211*33de042dSApple OSS Distributions 	return retval;
1212*33de042dSApple OSS Distributions }
1213*33de042dSApple OSS Distributions 
1214*33de042dSApple OSS Distributions int
sock_isnonblocking(socket_t sock)1215*33de042dSApple OSS Distributions sock_isnonblocking(socket_t sock)
1216*33de042dSApple OSS Distributions {
1217*33de042dSApple OSS Distributions 	int retval;
1218*33de042dSApple OSS Distributions 
1219*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1220*33de042dSApple OSS Distributions 	retval = ((sock->so_state & SS_NBIO) ? 1 : 0);
1221*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1222*33de042dSApple OSS Distributions 	return retval;
1223*33de042dSApple OSS Distributions }
1224*33de042dSApple OSS Distributions 
1225*33de042dSApple OSS Distributions errno_t
sock_gettype(socket_t sock,int * outDomain,int * outType,int * outProtocol)1226*33de042dSApple OSS Distributions sock_gettype(socket_t sock, int *outDomain, int *outType, int *outProtocol)
1227*33de042dSApple OSS Distributions {
1228*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1229*33de042dSApple OSS Distributions 	if (outDomain != NULL) {
1230*33de042dSApple OSS Distributions 		*outDomain = SOCK_DOM(sock);
1231*33de042dSApple OSS Distributions 	}
1232*33de042dSApple OSS Distributions 	if (outType != NULL) {
1233*33de042dSApple OSS Distributions 		*outType = sock->so_type;
1234*33de042dSApple OSS Distributions 	}
1235*33de042dSApple OSS Distributions 	if (outProtocol != NULL) {
1236*33de042dSApple OSS Distributions 		*outProtocol = SOCK_PROTO(sock);
1237*33de042dSApple OSS Distributions 	}
1238*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1239*33de042dSApple OSS Distributions 	return 0;
1240*33de042dSApple OSS Distributions }
1241*33de042dSApple OSS Distributions 
1242*33de042dSApple OSS Distributions /*
1243*33de042dSApple OSS Distributions  * Return the listening socket of a pre-accepted socket.  It returns the
1244*33de042dSApple OSS Distributions  * listener (so_head) value of a given socket.  This is intended to be
1245*33de042dSApple OSS Distributions  * called by a socket filter during a filter attach (sf_attach) callback.
1246*33de042dSApple OSS Distributions  * The value returned by this routine is safe to be used only in the
1247*33de042dSApple OSS Distributions  * context of that callback, because we hold the listener's lock across
1248*33de042dSApple OSS Distributions  * the sflt_initsock() call.
1249*33de042dSApple OSS Distributions  */
1250*33de042dSApple OSS Distributions socket_t
sock_getlistener(socket_t sock)1251*33de042dSApple OSS Distributions sock_getlistener(socket_t sock)
1252*33de042dSApple OSS Distributions {
1253*33de042dSApple OSS Distributions 	return sock->so_head;
1254*33de042dSApple OSS Distributions }
1255*33de042dSApple OSS Distributions 
1256*33de042dSApple OSS Distributions static inline void
sock_set_tcp_stream_priority(socket_t sock)1257*33de042dSApple OSS Distributions sock_set_tcp_stream_priority(socket_t sock)
1258*33de042dSApple OSS Distributions {
1259*33de042dSApple OSS Distributions 	if ((SOCK_DOM(sock) == PF_INET || SOCK_DOM(sock) == PF_INET6) &&
1260*33de042dSApple OSS Distributions 	    SOCK_TYPE(sock) == SOCK_STREAM) {
1261*33de042dSApple OSS Distributions 		set_tcp_stream_priority(sock);
1262*33de042dSApple OSS Distributions 	}
1263*33de042dSApple OSS Distributions }
1264*33de042dSApple OSS Distributions 
1265*33de042dSApple OSS Distributions /*
1266*33de042dSApple OSS Distributions  * Caller must have ensured socket is valid and won't be going away.
1267*33de042dSApple OSS Distributions  */
1268*33de042dSApple OSS Distributions void
socket_set_traffic_mgt_flags_locked(socket_t sock,u_int8_t flags)1269*33de042dSApple OSS Distributions socket_set_traffic_mgt_flags_locked(socket_t sock, u_int8_t flags)
1270*33de042dSApple OSS Distributions {
1271*33de042dSApple OSS Distributions 	u_int32_t soflags1 = 0;
1272*33de042dSApple OSS Distributions 
1273*33de042dSApple OSS Distributions 	if ((flags & TRAFFIC_MGT_SO_BACKGROUND)) {
1274*33de042dSApple OSS Distributions 		soflags1 |= SOF1_TRAFFIC_MGT_SO_BACKGROUND;
1275*33de042dSApple OSS Distributions 	}
1276*33de042dSApple OSS Distributions 	if ((flags & TRAFFIC_MGT_TCP_RECVBG)) {
1277*33de042dSApple OSS Distributions 		soflags1 |= SOF1_TRAFFIC_MGT_TCP_RECVBG;
1278*33de042dSApple OSS Distributions 	}
1279*33de042dSApple OSS Distributions 
1280*33de042dSApple OSS Distributions 	(void) OSBitOrAtomic(soflags1, &sock->so_flags1);
1281*33de042dSApple OSS Distributions 
1282*33de042dSApple OSS Distributions 	sock_set_tcp_stream_priority(sock);
1283*33de042dSApple OSS Distributions }
1284*33de042dSApple OSS Distributions 
1285*33de042dSApple OSS Distributions void
socket_set_traffic_mgt_flags(socket_t sock,u_int8_t flags)1286*33de042dSApple OSS Distributions socket_set_traffic_mgt_flags(socket_t sock, u_int8_t flags)
1287*33de042dSApple OSS Distributions {
1288*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1289*33de042dSApple OSS Distributions 	socket_set_traffic_mgt_flags_locked(sock, flags);
1290*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1291*33de042dSApple OSS Distributions }
1292*33de042dSApple OSS Distributions 
1293*33de042dSApple OSS Distributions /*
1294*33de042dSApple OSS Distributions  * Caller must have ensured socket is valid and won't be going away.
1295*33de042dSApple OSS Distributions  */
1296*33de042dSApple OSS Distributions void
socket_clear_traffic_mgt_flags_locked(socket_t sock,u_int8_t flags)1297*33de042dSApple OSS Distributions socket_clear_traffic_mgt_flags_locked(socket_t sock, u_int8_t flags)
1298*33de042dSApple OSS Distributions {
1299*33de042dSApple OSS Distributions 	u_int32_t soflags1 = 0;
1300*33de042dSApple OSS Distributions 
1301*33de042dSApple OSS Distributions 	if ((flags & TRAFFIC_MGT_SO_BACKGROUND)) {
1302*33de042dSApple OSS Distributions 		soflags1 |= SOF1_TRAFFIC_MGT_SO_BACKGROUND;
1303*33de042dSApple OSS Distributions 	}
1304*33de042dSApple OSS Distributions 	if ((flags & TRAFFIC_MGT_TCP_RECVBG)) {
1305*33de042dSApple OSS Distributions 		soflags1 |= SOF1_TRAFFIC_MGT_TCP_RECVBG;
1306*33de042dSApple OSS Distributions 	}
1307*33de042dSApple OSS Distributions 
1308*33de042dSApple OSS Distributions 	(void) OSBitAndAtomic(~soflags1, &sock->so_flags1);
1309*33de042dSApple OSS Distributions 
1310*33de042dSApple OSS Distributions 	sock_set_tcp_stream_priority(sock);
1311*33de042dSApple OSS Distributions }
1312*33de042dSApple OSS Distributions 
1313*33de042dSApple OSS Distributions void
socket_clear_traffic_mgt_flags(socket_t sock,u_int8_t flags)1314*33de042dSApple OSS Distributions socket_clear_traffic_mgt_flags(socket_t sock, u_int8_t flags)
1315*33de042dSApple OSS Distributions {
1316*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1317*33de042dSApple OSS Distributions 	socket_clear_traffic_mgt_flags_locked(sock, flags);
1318*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1319*33de042dSApple OSS Distributions }
1320*33de042dSApple OSS Distributions 
1321*33de042dSApple OSS Distributions 
1322*33de042dSApple OSS Distributions /*
1323*33de042dSApple OSS Distributions  * Caller must have ensured socket is valid and won't be going away.
1324*33de042dSApple OSS Distributions  */
1325*33de042dSApple OSS Distributions errno_t
socket_defunct(struct proc * p,socket_t so,int level)1326*33de042dSApple OSS Distributions socket_defunct(struct proc *p, socket_t so, int level)
1327*33de042dSApple OSS Distributions {
1328*33de042dSApple OSS Distributions 	errno_t retval;
1329*33de042dSApple OSS Distributions 
1330*33de042dSApple OSS Distributions 	if (level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
1331*33de042dSApple OSS Distributions 	    level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL) {
1332*33de042dSApple OSS Distributions 		return EINVAL;
1333*33de042dSApple OSS Distributions 	}
1334*33de042dSApple OSS Distributions 
1335*33de042dSApple OSS Distributions 	socket_lock(so, 1);
1336*33de042dSApple OSS Distributions 	/*
1337*33de042dSApple OSS Distributions 	 * SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC level is meant to tear down
1338*33de042dSApple OSS Distributions 	 * all of mDNSResponder IPC sockets, currently those of AF_UNIX; note
1339*33de042dSApple OSS Distributions 	 * that this is an implementation artifact of mDNSResponder.  We do
1340*33de042dSApple OSS Distributions 	 * a quick test against the socket buffers for SB_UNIX, since that
1341*33de042dSApple OSS Distributions 	 * would have been set by unp_attach() at socket creation time.
1342*33de042dSApple OSS Distributions 	 */
1343*33de042dSApple OSS Distributions 	if (level == SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
1344*33de042dSApple OSS Distributions 	    (so->so_rcv.sb_flags & so->so_snd.sb_flags & SB_UNIX) != SB_UNIX) {
1345*33de042dSApple OSS Distributions 		socket_unlock(so, 1);
1346*33de042dSApple OSS Distributions 		return EOPNOTSUPP;
1347*33de042dSApple OSS Distributions 	}
1348*33de042dSApple OSS Distributions 	retval = sosetdefunct(p, so, level, TRUE);
1349*33de042dSApple OSS Distributions 	if (retval == 0) {
1350*33de042dSApple OSS Distributions 		retval = sodefunct(p, so, level);
1351*33de042dSApple OSS Distributions 	}
1352*33de042dSApple OSS Distributions 	socket_unlock(so, 1);
1353*33de042dSApple OSS Distributions 	return retval;
1354*33de042dSApple OSS Distributions }
1355*33de042dSApple OSS Distributions 
1356*33de042dSApple OSS Distributions void
sock_setupcalls_locked(socket_t sock,sock_upcall rcallback,void * rcontext,sock_upcall wcallback,void * wcontext,int locked)1357*33de042dSApple OSS Distributions sock_setupcalls_locked(socket_t sock, sock_upcall rcallback, void *rcontext,
1358*33de042dSApple OSS Distributions     sock_upcall wcallback, void *wcontext, int locked)
1359*33de042dSApple OSS Distributions {
1360*33de042dSApple OSS Distributions 	if (rcallback != NULL) {
1361*33de042dSApple OSS Distributions 		sock->so_rcv.sb_flags |= SB_UPCALL;
1362*33de042dSApple OSS Distributions 		if (locked) {
1363*33de042dSApple OSS Distributions 			sock->so_rcv.sb_flags |= SB_UPCALL_LOCK;
1364*33de042dSApple OSS Distributions 		}
1365*33de042dSApple OSS Distributions 		sock->so_rcv.sb_upcall = rcallback;
1366*33de042dSApple OSS Distributions 		sock->so_rcv.sb_upcallarg = rcontext;
1367*33de042dSApple OSS Distributions 	} else {
1368*33de042dSApple OSS Distributions 		sock->so_rcv.sb_flags &= ~(SB_UPCALL | SB_UPCALL_LOCK);
1369*33de042dSApple OSS Distributions 		sock->so_rcv.sb_upcall = NULL;
1370*33de042dSApple OSS Distributions 		sock->so_rcv.sb_upcallarg = NULL;
1371*33de042dSApple OSS Distributions 	}
1372*33de042dSApple OSS Distributions 
1373*33de042dSApple OSS Distributions 	if (wcallback != NULL) {
1374*33de042dSApple OSS Distributions 		sock->so_snd.sb_flags |= SB_UPCALL;
1375*33de042dSApple OSS Distributions 		if (locked) {
1376*33de042dSApple OSS Distributions 			sock->so_snd.sb_flags |= SB_UPCALL_LOCK;
1377*33de042dSApple OSS Distributions 		}
1378*33de042dSApple OSS Distributions 		sock->so_snd.sb_upcall = wcallback;
1379*33de042dSApple OSS Distributions 		sock->so_snd.sb_upcallarg = wcontext;
1380*33de042dSApple OSS Distributions 	} else {
1381*33de042dSApple OSS Distributions 		sock->so_snd.sb_flags &= ~(SB_UPCALL | SB_UPCALL_LOCK);
1382*33de042dSApple OSS Distributions 		sock->so_snd.sb_upcall = NULL;
1383*33de042dSApple OSS Distributions 		sock->so_snd.sb_upcallarg = NULL;
1384*33de042dSApple OSS Distributions 	}
1385*33de042dSApple OSS Distributions }
1386*33de042dSApple OSS Distributions 
1387*33de042dSApple OSS Distributions errno_t
sock_setupcall(socket_t sock,sock_upcall callback,void * context)1388*33de042dSApple OSS Distributions sock_setupcall(socket_t sock, sock_upcall callback, void *context)
1389*33de042dSApple OSS Distributions {
1390*33de042dSApple OSS Distributions 	if (sock == NULL) {
1391*33de042dSApple OSS Distributions 		return EINVAL;
1392*33de042dSApple OSS Distributions 	}
1393*33de042dSApple OSS Distributions 
1394*33de042dSApple OSS Distributions 	/*
1395*33de042dSApple OSS Distributions 	 * Note that we don't wait for any in progress upcall to complete.
1396*33de042dSApple OSS Distributions 	 * On embedded, sock_setupcall() causes both read and write
1397*33de042dSApple OSS Distributions 	 * callbacks to be set; on desktop, only read callback is set
1398*33de042dSApple OSS Distributions 	 * to maintain legacy KPI behavior.
1399*33de042dSApple OSS Distributions 	 *
1400*33de042dSApple OSS Distributions 	 * The newer sock_setupcalls() KPI should be used instead to set
1401*33de042dSApple OSS Distributions 	 * the read and write callbacks and their respective parameters.
1402*33de042dSApple OSS Distributions 	 */
1403*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1404*33de042dSApple OSS Distributions #if defined(__arm64__)
1405*33de042dSApple OSS Distributions 	sock_setupcalls_locked(sock, callback, context, callback, context, 0);
1406*33de042dSApple OSS Distributions #else /* defined(__arm64__) */
1407*33de042dSApple OSS Distributions 	sock_setupcalls_locked(sock, callback, context, NULL, NULL, 0);
1408*33de042dSApple OSS Distributions #endif /* defined(__arm64__) */
1409*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1410*33de042dSApple OSS Distributions 
1411*33de042dSApple OSS Distributions 	return 0;
1412*33de042dSApple OSS Distributions }
1413*33de042dSApple OSS Distributions 
1414*33de042dSApple OSS Distributions errno_t
sock_setupcalls(socket_t sock,sock_upcall rcallback,void * rcontext,sock_upcall wcallback,void * wcontext)1415*33de042dSApple OSS Distributions sock_setupcalls(socket_t sock, sock_upcall rcallback, void *rcontext,
1416*33de042dSApple OSS Distributions     sock_upcall wcallback, void *wcontext)
1417*33de042dSApple OSS Distributions {
1418*33de042dSApple OSS Distributions 	if (sock == NULL) {
1419*33de042dSApple OSS Distributions 		return EINVAL;
1420*33de042dSApple OSS Distributions 	}
1421*33de042dSApple OSS Distributions 
1422*33de042dSApple OSS Distributions 	/*
1423*33de042dSApple OSS Distributions 	 * Note that we don't wait for any in progress upcall to complete.
1424*33de042dSApple OSS Distributions 	 */
1425*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1426*33de042dSApple OSS Distributions 	sock_setupcalls_locked(sock, rcallback, rcontext, wcallback, wcontext, 0);
1427*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1428*33de042dSApple OSS Distributions 
1429*33de042dSApple OSS Distributions 	return 0;
1430*33de042dSApple OSS Distributions }
1431*33de042dSApple OSS Distributions 
1432*33de042dSApple OSS Distributions void
sock_catchevents_locked(socket_t sock,sock_evupcall ecallback,void * econtext,uint32_t emask)1433*33de042dSApple OSS Distributions sock_catchevents_locked(socket_t sock, sock_evupcall ecallback, void *econtext,
1434*33de042dSApple OSS Distributions     uint32_t emask)
1435*33de042dSApple OSS Distributions {
1436*33de042dSApple OSS Distributions 	socket_lock_assert_owned(sock);
1437*33de042dSApple OSS Distributions 
1438*33de042dSApple OSS Distributions 	/*
1439*33de042dSApple OSS Distributions 	 * Note that we don't wait for any in progress upcall to complete.
1440*33de042dSApple OSS Distributions 	 */
1441*33de042dSApple OSS Distributions 	if (ecallback != NULL) {
1442*33de042dSApple OSS Distributions 		sock->so_event = ecallback;
1443*33de042dSApple OSS Distributions 		sock->so_eventarg = econtext;
1444*33de042dSApple OSS Distributions 		sock->so_eventmask = emask;
1445*33de042dSApple OSS Distributions 	} else {
1446*33de042dSApple OSS Distributions 		sock->so_event = sonullevent;
1447*33de042dSApple OSS Distributions 		sock->so_eventarg = NULL;
1448*33de042dSApple OSS Distributions 		sock->so_eventmask = 0;
1449*33de042dSApple OSS Distributions 	}
1450*33de042dSApple OSS Distributions }
1451*33de042dSApple OSS Distributions 
1452*33de042dSApple OSS Distributions errno_t
sock_catchevents(socket_t sock,sock_evupcall ecallback,void * econtext,uint32_t emask)1453*33de042dSApple OSS Distributions sock_catchevents(socket_t sock, sock_evupcall ecallback, void *econtext,
1454*33de042dSApple OSS Distributions     uint32_t emask)
1455*33de042dSApple OSS Distributions {
1456*33de042dSApple OSS Distributions 	if (sock == NULL) {
1457*33de042dSApple OSS Distributions 		return EINVAL;
1458*33de042dSApple OSS Distributions 	}
1459*33de042dSApple OSS Distributions 
1460*33de042dSApple OSS Distributions 	socket_lock(sock, 1);
1461*33de042dSApple OSS Distributions 	sock_catchevents_locked(sock, ecallback, econtext, emask);
1462*33de042dSApple OSS Distributions 	socket_unlock(sock, 1);
1463*33de042dSApple OSS Distributions 
1464*33de042dSApple OSS Distributions 	return 0;
1465*33de042dSApple OSS Distributions }
1466*33de042dSApple OSS Distributions 
1467*33de042dSApple OSS Distributions /*
1468*33de042dSApple OSS Distributions  * Returns true whether or not a socket belongs to the kernel.
1469*33de042dSApple OSS Distributions  */
1470*33de042dSApple OSS Distributions int
sock_iskernel(socket_t so)1471*33de042dSApple OSS Distributions sock_iskernel(socket_t so)
1472*33de042dSApple OSS Distributions {
1473*33de042dSApple OSS Distributions 	return so && so->last_pid == 0;
1474*33de042dSApple OSS Distributions }
1475