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