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