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