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