]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_socket.c
xnu-7195.101.1.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)) {
c3c9b80d 240 sa = kheap_alloc(KHEAP_TEMP, to->sa_len, Z_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) {
c3c9b80d 253 kheap_free(KHEAP_TEMP, sa, sa->sa_len);
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)) {
c3c9b80d
A
273 sa = kheap_alloc(KHEAP_TEMP, to->sa_len,
274 (flags & MSG_DONTWAIT) ? Z_NOWAIT : Z_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) {
c3c9b80d 326 kheap_free(KHEAP_TEMP, sa, sa->sa_len);
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;
c3c9b80d 478 } else if (error != 0) {
2d21ac55 479 FREE(*psa, M_SONAME);
2d21ac55 480 }
0a7de745 481 return error;
2d21ac55
A
482}
483
b0d623f7
A
484errno_t
485sock_getaddr(socket_t sock, struct sockaddr **psa, int peer)
486{
487 int error;
488
0a7de745
A
489 if (sock == NULL || psa == NULL) {
490 return EINVAL;
491 }
b0d623f7
A
492
493 socket_lock(sock, 1);
494 error = sogetaddr_locked(sock, psa, peer);
495 socket_unlock(sock, 1);
39236c6e 496
0a7de745 497 return error;
b0d623f7
A
498}
499
2d21ac55
A
500void
501sock_freeaddr(struct sockaddr *sa)
502{
c3c9b80d 503 FREE(sa, M_SONAME);
91447636
A
504}
505
506errno_t
39236c6e 507sock_getsockopt(socket_t sock, int level, int optname, void *optval,
0a7de745 508 int *optlen)
91447636 509{
39236c6e 510 int error = 0;
0a7de745 511 struct sockopt sopt;
39236c6e 512
0a7de745
A
513 if (sock == NULL || optval == NULL || optlen == NULL) {
514 return EINVAL;
515 }
39236c6e 516
91447636
A
517 sopt.sopt_dir = SOPT_GET;
518 sopt.sopt_level = level;
519 sopt.sopt_name = optname;
39236c6e 520 sopt.sopt_val = CAST_USER_ADDR_T(optval);
91447636 521 sopt.sopt_valsize = *optlen;
b0d623f7 522 sopt.sopt_p = kernproc;
0a7de745
A
523 error = sogetoptlock(sock, &sopt, 1); /* will lock socket */
524 if (error == 0) {
f427ee49 525 *optlen = (uint32_t)sopt.sopt_valsize;
0a7de745
A
526 }
527 return error;
91447636
A
528}
529
530errno_t
39236c6e 531sock_ioctl(socket_t sock, unsigned long request, void *argp)
91447636 532{
0a7de745 533 return soioctl(sock, request, argp, kernproc); /* will lock socket */
91447636
A
534}
535
536errno_t
39236c6e 537sock_setsockopt(socket_t sock, int level, int optname, const void *optval,
0a7de745 538 int optlen)
91447636 539{
0a7de745 540 struct sockopt sopt;
39236c6e 541
0a7de745
A
542 if (sock == NULL || optval == NULL) {
543 return EINVAL;
544 }
39236c6e 545
91447636
A
546 sopt.sopt_dir = SOPT_SET;
547 sopt.sopt_level = level;
548 sopt.sopt_name = optname;
549 sopt.sopt_val = CAST_USER_ADDR_T(optval);
550 sopt.sopt_valsize = optlen;
b0d623f7 551 sopt.sopt_p = kernproc;
0a7de745 552 return sosetoptlock(sock, &sopt, 1); /* will lock socket */
91447636
A
553}
554
6d2010ae 555/*
39236c6e
A
556 * This follows the recommended mappings between DSCP code points
557 * and WMM access classes.
6d2010ae 558 */
f427ee49
A
559static uint32_t
560so_tc_from_dscp(uint8_t dscp)
6d2010ae 561{
f427ee49 562 uint32_t tc;
6d2010ae 563
0a7de745 564 if (dscp >= 0x30 && dscp <= 0x3f) {
6d2010ae 565 tc = SO_TC_VO;
0a7de745 566 } else if (dscp >= 0x20 && dscp <= 0x2f) {
6d2010ae 567 tc = SO_TC_VI;
0a7de745 568 } else if (dscp >= 0x08 && dscp <= 0x17) {
39037602 569 tc = SO_TC_BK_SYS;
0a7de745 570 } else {
6d2010ae 571 tc = SO_TC_BE;
0a7de745 572 }
6d2010ae 573
0a7de745 574 return tc;
6d2010ae
A
575}
576
b0d623f7 577errno_t
39236c6e
A
578sock_settclassopt(socket_t sock, const void *optval, size_t optlen)
579{
b0d623f7
A
580 errno_t error = 0;
581 struct sockopt sopt;
6d2010ae 582 int sotc;
b0d623f7 583
0a7de745
A
584 if (sock == NULL || optval == NULL || optlen != sizeof(int)) {
585 return EINVAL;
586 }
b0d623f7
A
587
588 socket_lock(sock, 1);
589 if (!(sock->so_state & SS_ISCONNECTED)) {
39236c6e
A
590 /*
591 * If the socket is not connected then we don't know
b0d623f7
A
592 * if the destination is on LAN or not. Skip
593 * setting traffic class in this case
594 */
595 error = ENOTCONN;
596 goto out;
597 }
598
39236c6e
A
599 if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL ||
600 sock->so_pcb == NULL) {
b0d623f7
A
601 error = EINVAL;
602 goto out;
603 }
604
6d2010ae
A
605 /*
606 * Set the socket traffic class based on the passed DSCP code point
607 * regardless of the scope of the destination
608 */
f427ee49 609 sotc = so_tc_from_dscp((uint8_t)((*(const int *)optval) >> 2));
6d2010ae
A
610
611 sopt.sopt_dir = SOPT_SET;
612 sopt.sopt_val = CAST_USER_ADDR_T(&sotc);
0a7de745 613 sopt.sopt_valsize = sizeof(sotc);
6d2010ae
A
614 sopt.sopt_p = kernproc;
615 sopt.sopt_level = SOL_SOCKET;
616 sopt.sopt_name = SO_TRAFFIC_CLASS;
617
0a7de745 618 error = sosetoptlock(sock, &sopt, 0); /* already locked */
6d2010ae
A
619
620 if (error != 0) {
39236c6e
A
621 printf("%s: sosetopt SO_TRAFFIC_CLASS failed %d\n",
622 __func__, error);
6d2010ae
A
623 goto out;
624 }
625
39236c6e
A
626 /*
627 * Check if the destination address is LAN or link local address.
b0d623f7 628 * We do not want to set traffic class bits if the destination
39236c6e
A
629 * is not local.
630 */
0a7de745 631 if (!so_isdstlocal(sock)) {
b0d623f7 632 goto out;
0a7de745 633 }
b0d623f7 634
6d2010ae
A
635 sopt.sopt_dir = SOPT_SET;
636 sopt.sopt_val = CAST_USER_ADDR_T(optval);
637 sopt.sopt_valsize = optlen;
638 sopt.sopt_p = kernproc;
639
39236c6e
A
640 switch (SOCK_DOM(sock)) {
641 case PF_INET:
b0d623f7
A
642 sopt.sopt_level = IPPROTO_IP;
643 sopt.sopt_name = IP_TOS;
644 break;
39236c6e 645 case PF_INET6:
b0d623f7
A
646 sopt.sopt_level = IPPROTO_IPV6;
647 sopt.sopt_name = IPV6_TCLASS;
648 break;
649 default:
650 error = EINVAL;
651 goto out;
652 }
39236c6e 653
0a7de745 654 error = sosetoptlock(sock, &sopt, 0); /* already locked */
b0d623f7 655 socket_unlock(sock, 1);
0a7de745 656 return error;
b0d623f7
A
657out:
658 socket_unlock(sock, 1);
0a7de745 659 return error;
b0d623f7
A
660}
661
662errno_t
39236c6e
A
663sock_gettclassopt(socket_t sock, void *optval, size_t *optlen)
664{
665 errno_t error = 0;
666 struct sockopt sopt;
b0d623f7 667
0a7de745
A
668 if (sock == NULL || optval == NULL || optlen == NULL) {
669 return EINVAL;
670 }
b0d623f7
A
671
672 sopt.sopt_dir = SOPT_GET;
39236c6e 673 sopt.sopt_val = CAST_USER_ADDR_T(optval);
b0d623f7
A
674 sopt.sopt_valsize = *optlen;
675 sopt.sopt_p = kernproc;
676
677 socket_lock(sock, 1);
678 if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL) {
679 socket_unlock(sock, 1);
0a7de745 680 return EINVAL;
b0d623f7
A
681 }
682
39236c6e
A
683 switch (SOCK_DOM(sock)) {
684 case PF_INET:
b0d623f7
A
685 sopt.sopt_level = IPPROTO_IP;
686 sopt.sopt_name = IP_TOS;
687 break;
39236c6e 688 case PF_INET6:
b0d623f7
A
689 sopt.sopt_level = IPPROTO_IPV6;
690 sopt.sopt_name = IPV6_TCLASS;
691 break;
692 default:
693 socket_unlock(sock, 1);
0a7de745 694 return EINVAL;
b0d623f7 695 }
0a7de745 696 error = sogetoptlock(sock, &sopt, 0); /* already locked */
b0d623f7 697 socket_unlock(sock, 1);
0a7de745 698 if (error == 0) {
39236c6e 699 *optlen = sopt.sopt_valsize;
0a7de745
A
700 }
701 return error;
b0d623f7
A
702}
703
91447636 704errno_t
39236c6e 705sock_listen(socket_t sock, int backlog)
91447636 706{
0a7de745
A
707 if (sock == NULL) {
708 return EINVAL;
709 }
39236c6e 710
0a7de745 711 return solisten(sock, backlog); /* will lock socket */
91447636
A
712}
713
39236c6e
A
714errno_t
715sock_receive_internal(socket_t sock, struct msghdr *msg, mbuf_t *data,
716 int flags, size_t *recvdlen)
91447636 717{
39236c6e
A
718 uio_t auio;
719 struct mbuf *control = NULL;
720 int error = 0;
f427ee49 721 user_ssize_t length = 0;
0a7de745
A
722 struct sockaddr *fromsa = NULL;
723 char uio_buf[UIO_SIZEOF((msg != NULL) ? msg->msg_iovlen : 0)];
39236c6e 724
0a7de745
A
725 if (sock == NULL) {
726 return EINVAL;
727 }
39236c6e
A
728
729 auio = uio_createwithbuffer(((msg != NULL) ? msg->msg_iovlen : 0),
0a7de745 730 0, UIO_SYSSPACE, UIO_READ, &uio_buf[0], sizeof(uio_buf));
39236c6e 731 if (msg != NULL && data == NULL) {
91447636 732 int i;
b0d623f7 733 struct iovec *tempp = msg->msg_iov;
39236c6e 734
91447636 735 for (i = 0; i < msg->msg_iovlen; i++) {
39236c6e
A
736 uio_addiov(auio,
737 CAST_USER_ADDR_T((tempp + i)->iov_base),
738 (tempp + i)->iov_len);
91447636 739 }
0a7de745
A
740 if (uio_resid(auio) < 0) {
741 return EINVAL;
742 }
39236c6e 743 } else if (recvdlen != NULL) {
91447636
A
744 uio_setresid(auio, (uio_resid(auio) + *recvdlen));
745 }
746 length = uio_resid(auio);
39236c6e 747
0a7de745 748 if (recvdlen != NULL) {
91447636 749 *recvdlen = 0;
0a7de745 750 }
91447636 751
39236c6e 752 /* let pru_soreceive handle the socket locking */
91447636 753 error = sock->so_proto->pr_usrreqs->pru_soreceive(sock, &fromsa, auio,
b0d623f7 754 data, (msg && msg->msg_control) ? &control : NULL, &flags);
0a7de745 755 if (error != 0) {
39236c6e 756 goto cleanup;
0a7de745 757 }
39236c6e 758
0a7de745 759 if (recvdlen != NULL) {
91447636 760 *recvdlen = length - uio_resid(auio);
0a7de745 761 }
39236c6e 762 if (msg != NULL) {
91447636 763 msg->msg_flags = flags;
39236c6e
A
764
765 if (msg->msg_name != NULL) {
91447636
A
766 int salen;
767 salen = msg->msg_namelen;
39236c6e 768 if (msg->msg_namelen > 0 && fromsa != NULL) {
91447636
A
769 salen = MIN(salen, fromsa->sa_len);
770 memcpy(msg->msg_name, fromsa,
39236c6e
A
771 msg->msg_namelen > fromsa->sa_len ?
772 fromsa->sa_len : msg->msg_namelen);
91447636
A
773 }
774 }
39236c6e
A
775
776 if (msg->msg_control != NULL) {
777 struct mbuf *m = control;
778 u_char *ctlbuf = msg->msg_control;
779 int clen = msg->msg_controllen;
780
91447636 781 msg->msg_controllen = 0;
39236c6e
A
782
783 while (m != NULL && clen > 0) {
91447636 784 unsigned int tocopy;
39236c6e
A
785
786 if (clen >= m->m_len) {
91447636 787 tocopy = m->m_len;
39236c6e 788 } else {
91447636
A
789 msg->msg_flags |= MSG_CTRUNC;
790 tocopy = clen;
791 }
792 memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
793 ctlbuf += tocopy;
794 clen -= tocopy;
795 m = m->m_next;
796 }
39236c6e 797 msg->msg_controllen =
f427ee49 798 (socklen_t)((uintptr_t)ctlbuf - (uintptr_t)msg->msg_control);
91447636
A
799 }
800 }
801
802cleanup:
0a7de745 803 if (control != NULL) {
39236c6e 804 m_freem(control);
0a7de745 805 }
c3c9b80d 806 FREE(fromsa, M_SONAME);
0a7de745 807 return error;
91447636
A
808}
809
810errno_t
39236c6e 811sock_receive(socket_t sock, struct msghdr *msg, int flags, size_t *recvdlen)
91447636 812{
39236c6e
A
813 if ((msg == NULL) || (msg->msg_iovlen < 1) ||
814 (msg->msg_iov[0].iov_len == 0) ||
0a7de745
A
815 (msg->msg_iov[0].iov_base == NULL)) {
816 return EINVAL;
817 }
39236c6e 818
0a7de745 819 return sock_receive_internal(sock, msg, NULL, flags, recvdlen);
91447636
A
820}
821
822errno_t
39236c6e
A
823sock_receivembuf(socket_t sock, struct msghdr *msg, mbuf_t *data, int flags,
824 size_t *recvlen)
91447636 825{
39236c6e 826 if (data == NULL || recvlen == 0 || *recvlen <= 0 || (msg != NULL &&
0a7de745
A
827 (msg->msg_iov != NULL || msg->msg_iovlen != 0))) {
828 return EINVAL;
829 }
39236c6e 830
0a7de745 831 return sock_receive_internal(sock, msg, data, flags, recvlen);
91447636
A
832}
833
834errno_t
39236c6e
A
835sock_send_internal(socket_t sock, const struct msghdr *msg, mbuf_t data,
836 int flags, size_t *sentlen)
91447636 837{
39236c6e
A
838 uio_t auio = NULL;
839 struct mbuf *control = NULL;
840 int error = 0;
f427ee49 841 user_ssize_t datalen = 0;
0a7de745 842 char uio_buf[UIO_SIZEOF((msg != NULL ? msg->msg_iovlen : 1))];
39236c6e 843
91447636
A
844 if (sock == NULL) {
845 error = EINVAL;
846 goto errorout;
847 }
39236c6e
A
848
849 if (data == NULL && msg != NULL) {
b0d623f7 850 struct iovec *tempp = msg->msg_iov;
91447636 851
39236c6e 852 auio = uio_createwithbuffer(msg->msg_iovlen, 0,
0a7de745 853 UIO_SYSSPACE, UIO_WRITE, &uio_buf[0], sizeof(uio_buf));
39236c6e 854 if (tempp != NULL) {
91447636 855 int i;
39236c6e 856
91447636 857 for (i = 0; i < msg->msg_iovlen; i++) {
39236c6e
A
858 uio_addiov(auio,
859 CAST_USER_ADDR_T((tempp + i)->iov_base),
860 (tempp + i)->iov_len);
91447636 861 }
39236c6e 862
91447636
A
863 if (uio_resid(auio) < 0) {
864 error = EINVAL;
865 goto errorout;
866 }
867 }
868 }
39236c6e 869
0a7de745 870 if (sentlen != NULL) {
91447636 871 *sentlen = 0;
0a7de745 872 }
39236c6e 873
0a7de745 874 if (auio != NULL) {
91447636 875 datalen = uio_resid(auio);
0a7de745 876 } else {
91447636 877 datalen = data->m_pkthdr.len;
0a7de745 878 }
39236c6e
A
879
880 if (msg != NULL && msg->msg_control) {
0a7de745 881 if ((size_t)msg->msg_controllen < sizeof(struct cmsghdr)) {
39236c6e
A
882 error = EINVAL;
883 goto errorout;
884 }
885
886 if ((size_t)msg->msg_controllen > MLEN) {
887 error = EINVAL;
888 goto errorout;
889 }
890
91447636
A
891 control = m_get(M_NOWAIT, MT_CONTROL);
892 if (control == NULL) {
893 error = ENOMEM;
894 goto errorout;
895 }
39236c6e
A
896 memcpy(mtod(control, caddr_t), msg->msg_control,
897 msg->msg_controllen);
91447636
A
898 control->m_len = msg->msg_controllen;
899 }
39236c6e 900
8f6c56a5 901 error = sock->so_proto->pr_usrreqs->pru_sosend(sock, msg != NULL ?
39236c6e
A
902 (struct sockaddr *)msg->msg_name : NULL, auio, data,
903 control, flags);
8f6c56a5
A
904
905 /*
906 * Residual data is possible in the case of IO vectors but not
907 * in the mbuf case since the latter is treated as atomic send.
908 * If pru_sosend() consumed a portion of the iovecs data and
909 * the error returned is transient, treat it as success; this
910 * is consistent with sendit() behavior.
911 */
912 if (auio != NULL && uio_resid(auio) != datalen &&
0a7de745 913 (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) {
8f6c56a5 914 error = 0;
0a7de745 915 }
8f6c56a5
A
916
917 if (error == 0 && sentlen != NULL) {
0a7de745 918 if (auio != NULL) {
91447636 919 *sentlen = datalen - uio_resid(auio);
0a7de745 920 } else {
91447636 921 *sentlen = datalen;
0a7de745 922 }
91447636 923 }
39236c6e 924
0a7de745 925 return error;
91447636
A
926
927/*
928 * In cases where we detect an error before returning, we need to
929 * free the mbuf chain if there is one. sosend (and pru_sosend) will
930 * free the mbuf chain if they encounter an error.
931 */
932errorout:
0a7de745 933 if (control) {
91447636 934 m_freem(control);
0a7de745
A
935 }
936 if (data) {
91447636 937 m_freem(data);
0a7de745
A
938 }
939 if (sentlen) {
91447636 940 *sentlen = 0;
0a7de745
A
941 }
942 return error;
91447636
A
943}
944
945errno_t
39236c6e 946sock_send(socket_t sock, const struct msghdr *msg, int flags, size_t *sentlen)
91447636 947{
0a7de745
A
948 if (msg == NULL || msg->msg_iov == NULL || msg->msg_iovlen < 1) {
949 return EINVAL;
950 }
39236c6e 951
0a7de745 952 return sock_send_internal(sock, msg, NULL, flags, sentlen);
91447636
A
953}
954
955errno_t
39236c6e 956sock_sendmbuf(socket_t sock, const struct msghdr *msg, mbuf_t data,
0a7de745 957 int flags, size_t *sentlen)
91447636 958{
39236c6e
A
959 if (data == NULL || (msg != NULL && (msg->msg_iov != NULL ||
960 msg->msg_iovlen != 0))) {
0a7de745 961 if (data != NULL) {
91447636 962 m_freem(data);
0a7de745
A
963 }
964 return EINVAL;
91447636 965 }
0a7de745 966 return sock_send_internal(sock, msg, data, flags, sentlen);
91447636
A
967}
968
969errno_t
39236c6e 970sock_shutdown(socket_t sock, int how)
91447636 971{
0a7de745
A
972 if (sock == NULL) {
973 return EINVAL;
974 }
39236c6e 975
0a7de745 976 return soshutdown(sock, how);
91447636
A
977}
978
91447636 979errno_t
5ba3f43e
A
980sock_socket_common(int domain, int type, int protocol, sock_upcall callback,
981 void *context, socket_t *new_so, bool is_internal)
91447636 982{
39236c6e
A
983 int error = 0;
984
0a7de745
A
985 if (new_so == NULL) {
986 return EINVAL;
987 }
39236c6e 988
91447636
A
989 /* socreate will create an initial so_count */
990 error = socreate(domain, new_so, type, protocol);
39236c6e 991 if (error == 0) {
5ba3f43e
A
992 /*
993 * This is an in-kernel socket
994 */
995 (*new_so)->so_flags1 |= SOF1_IN_KERNEL_SOCKET;
996 INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_in_kernel_total);
997 if (is_internal) {
998 INC_ATOMIC_INT64_LIM(net_api_stats.nas_socket_in_kernel_os_total);
999 }
1000
39236c6e
A
1001 /* see comments in sock_setupcall() */
1002 if (callback != NULL) {
5ba3f43e 1003 sock_setupcall(*new_so, callback, context);
39236c6e 1004 }
0a7de745 1005 /*
39236c6e
A
1006 * last_pid and last_upid should be zero for sockets
1007 * created using sock_socket
1008 */
316670eb
A
1009 (*new_so)->last_pid = 0;
1010 (*new_so)->last_upid = 0;
91447636 1011 }
0a7de745 1012 return error;
91447636
A
1013}
1014
5ba3f43e
A
1015errno_t
1016sock_socket_internal(int domain, int type, int protocol, sock_upcall callback,
1017 void *context, socket_t *new_so)
1018{
0a7de745
A
1019 return sock_socket_common(domain, type, protocol, callback,
1020 context, new_so, true);
5ba3f43e
A
1021}
1022
1023errno_t
1024sock_socket(int domain, int type, int protocol, sock_upcall callback,
1025 void *context, socket_t *new_so)
1026{
0a7de745
A
1027 return sock_socket_common(domain, type, protocol, callback,
1028 context, new_so, false);
5ba3f43e
A
1029}
1030
91447636 1031void
39236c6e 1032sock_close(socket_t sock)
91447636 1033{
0a7de745 1034 if (sock == NULL) {
39236c6e 1035 return;
0a7de745 1036 }
39236c6e 1037
91447636
A
1038 soclose(sock);
1039}
1040
39236c6e 1041/* Do we want this to be APPLE_PRIVATE API?: YES (LD 12/23/04) */
91447636 1042void
39236c6e 1043sock_retain(socket_t sock)
91447636 1044{
0a7de745 1045 if (sock == NULL) {
39236c6e 1046 return;
0a7de745 1047 }
39236c6e 1048
91447636
A
1049 socket_lock(sock, 1);
1050 sock->so_retaincnt++;
0a7de745 1051 sock->so_usecount++; /* add extra reference for holding the socket */
91447636
A
1052 socket_unlock(sock, 1);
1053}
1054
1055/* Do we want this to be APPLE_PRIVATE API? */
1056void
2d21ac55 1057sock_release(socket_t sock)
91447636 1058{
0a7de745 1059 if (sock == NULL) {
2d21ac55 1060 return;
0a7de745 1061 }
2d21ac55 1062
39236c6e 1063 socket_lock(sock, 1);
0a7de745 1064 if (sock->so_upcallusecount > 0) {
2d21ac55 1065 soclose_wait_locked(sock);
0a7de745 1066 }
2d21ac55 1067
91447636 1068 sock->so_retaincnt--;
39236c6e
A
1069 if (sock->so_retaincnt < 0) {
1070 panic("%s: negative retain count (%d) for sock=%p\n",
1071 __func__, sock->so_retaincnt, sock);
1072 /* NOTREACHED */
1073 }
490019cf
A
1074 /*
1075 * Check SS_NOFDREF in case a close happened as sock_retain()
1076 * was grabbing the lock
1077 */
1078 if ((sock->so_retaincnt == 0) && (sock->so_usecount == 2) &&
1079 (!(sock->so_state & SS_NOFDREF) ||
1080 (sock->so_flags & SOF_MP_SUBFLOW))) {
2d21ac55
A
1081 /* close socket only if the FD is not holding it */
1082 soclose_locked(sock);
1083 } else {
1084 /* remove extra reference holding the socket */
d190cdc3 1085 VERIFY(sock->so_usecount > 1);
2d21ac55
A
1086 sock->so_usecount--;
1087 }
91447636
A
1088 socket_unlock(sock, 1);
1089}
1090
1091errno_t
39236c6e 1092sock_setpriv(socket_t sock, int on)
91447636 1093{
0a7de745
A
1094 if (sock == NULL) {
1095 return EINVAL;
1096 }
39236c6e 1097
91447636 1098 socket_lock(sock, 1);
0a7de745 1099 if (on) {
91447636 1100 sock->so_state |= SS_PRIV;
0a7de745 1101 } else {
91447636 1102 sock->so_state &= ~SS_PRIV;
0a7de745 1103 }
91447636 1104 socket_unlock(sock, 1);
0a7de745 1105 return 0;
91447636
A
1106}
1107
1108int
39236c6e 1109sock_isconnected(socket_t sock)
91447636
A
1110{
1111 int retval;
39236c6e 1112
91447636 1113 socket_lock(sock, 1);
39236c6e 1114 retval = ((sock->so_state & SS_ISCONNECTED) ? 1 : 0);
91447636 1115 socket_unlock(sock, 1);
0a7de745 1116 return retval;
91447636
A
1117}
1118
1119int
39236c6e 1120sock_isnonblocking(socket_t sock)
91447636
A
1121{
1122 int retval;
39236c6e 1123
91447636 1124 socket_lock(sock, 1);
39236c6e 1125 retval = ((sock->so_state & SS_NBIO) ? 1 : 0);
91447636 1126 socket_unlock(sock, 1);
0a7de745 1127 return retval;
91447636
A
1128}
1129
1130errno_t
39236c6e 1131sock_gettype(socket_t sock, int *outDomain, int *outType, int *outProtocol)
91447636
A
1132{
1133 socket_lock(sock, 1);
0a7de745 1134 if (outDomain != NULL) {
39236c6e 1135 *outDomain = SOCK_DOM(sock);
0a7de745
A
1136 }
1137 if (outType != NULL) {
91447636 1138 *outType = sock->so_type;
0a7de745
A
1139 }
1140 if (outProtocol != NULL) {
39236c6e 1141 *outProtocol = SOCK_PROTO(sock);
0a7de745 1142 }
91447636 1143 socket_unlock(sock, 1);
0a7de745 1144 return 0;
91447636 1145}
2d21ac55
A
1146
1147/*
1148 * Return the listening socket of a pre-accepted socket. It returns the
1149 * listener (so_head) value of a given socket. This is intended to be
1150 * called by a socket filter during a filter attach (sf_attach) callback.
1151 * The value returned by this routine is safe to be used only in the
1152 * context of that callback, because we hold the listener's lock across
1153 * the sflt_initsock() call.
1154 */
1155socket_t
1156sock_getlistener(socket_t sock)
1157{
0a7de745 1158 return sock->so_head;
2d21ac55 1159}
d1ecb069 1160
6d2010ae
A
1161static inline void
1162sock_set_tcp_stream_priority(socket_t sock)
1163{
39236c6e
A
1164 if ((SOCK_DOM(sock) == PF_INET || SOCK_DOM(sock) == PF_INET6) &&
1165 SOCK_TYPE(sock) == SOCK_STREAM) {
6d2010ae 1166 set_tcp_stream_priority(sock);
6d2010ae
A
1167 }
1168}
1169
d1ecb069
A
1170/*
1171 * Caller must have ensured socket is valid and won't be going away.
1172 */
1173void
3e170ce0 1174socket_set_traffic_mgt_flags_locked(socket_t sock, u_int8_t flags)
d1ecb069 1175{
39037602 1176 u_int32_t soflags1 = 0;
0a7de745
A
1177
1178 if ((flags & TRAFFIC_MGT_SO_BACKGROUND)) {
39037602 1179 soflags1 |= SOF1_TRAFFIC_MGT_SO_BACKGROUND;
0a7de745
A
1180 }
1181 if ((flags & TRAFFIC_MGT_TCP_RECVBG)) {
39037602 1182 soflags1 |= SOF1_TRAFFIC_MGT_TCP_RECVBG;
0a7de745
A
1183 }
1184
39037602
A
1185 (void) OSBitOrAtomic(soflags1, &sock->so_flags1);
1186
6d2010ae
A
1187 sock_set_tcp_stream_priority(sock);
1188}
1189
1190void
3e170ce0 1191socket_set_traffic_mgt_flags(socket_t sock, u_int8_t flags)
6d2010ae
A
1192{
1193 socket_lock(sock, 1);
1194 socket_set_traffic_mgt_flags_locked(sock, flags);
1195 socket_unlock(sock, 1);
d1ecb069
A
1196}
1197
1198/*
1199 * Caller must have ensured socket is valid and won't be going away.
1200 */
1201void
3e170ce0 1202socket_clear_traffic_mgt_flags_locked(socket_t sock, u_int8_t flags)
d1ecb069 1203{
39037602
A
1204 u_int32_t soflags1 = 0;
1205
0a7de745 1206 if ((flags & TRAFFIC_MGT_SO_BACKGROUND)) {
39037602 1207 soflags1 |= SOF1_TRAFFIC_MGT_SO_BACKGROUND;
0a7de745
A
1208 }
1209 if ((flags & TRAFFIC_MGT_TCP_RECVBG)) {
39037602 1210 soflags1 |= SOF1_TRAFFIC_MGT_TCP_RECVBG;
0a7de745
A
1211 }
1212
39037602
A
1213 (void) OSBitAndAtomic(~soflags1, &sock->so_flags1);
1214
6d2010ae 1215 sock_set_tcp_stream_priority(sock);
d1ecb069 1216}
d41d1dae 1217
6d2010ae 1218void
3e170ce0 1219socket_clear_traffic_mgt_flags(socket_t sock, u_int8_t flags)
d41d1dae 1220{
6d2010ae
A
1221 socket_lock(sock, 1);
1222 socket_clear_traffic_mgt_flags_locked(sock, flags);
1223 socket_unlock(sock, 1);
1224}
1225
d41d1dae 1226
6d2010ae
A
1227/*
1228 * Caller must have ensured socket is valid and won't be going away.
1229 */
1230errno_t
1231socket_defunct(struct proc *p, socket_t so, int level)
1232{
1233 errno_t retval;
1234
1235 if (level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
0a7de745
A
1236 level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL) {
1237 return EINVAL;
1238 }
6d2010ae
A
1239
1240 socket_lock(so, 1);
1241 /*
1242 * SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC level is meant to tear down
1243 * all of mDNSResponder IPC sockets, currently those of AF_UNIX; note
1244 * that this is an implementation artifact of mDNSResponder. We do
1245 * a quick test against the socket buffers for SB_UNIX, since that
1246 * would have been set by unp_attach() at socket creation time.
1247 */
1248 if (level == SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
1249 (so->so_rcv.sb_flags & so->so_snd.sb_flags & SB_UNIX) != SB_UNIX) {
1250 socket_unlock(so, 1);
0a7de745 1251 return EOPNOTSUPP;
6d2010ae
A
1252 }
1253 retval = sosetdefunct(p, so, level, TRUE);
0a7de745 1254 if (retval == 0) {
6d2010ae 1255 retval = sodefunct(p, so, level);
0a7de745 1256 }
6d2010ae 1257 socket_unlock(so, 1);
0a7de745 1258 return retval;
6d2010ae
A
1259}
1260
5ba3f43e
A
1261void
1262sock_setupcalls_locked(socket_t sock, sock_upcall rcallback, void *rcontext,
1263 sock_upcall wcallback, void *wcontext, int locked)
39236c6e
A
1264{
1265 if (rcallback != NULL) {
1266 sock->so_rcv.sb_flags |= SB_UPCALL;
0a7de745 1267 if (locked) {
5ba3f43e 1268 sock->so_rcv.sb_flags |= SB_UPCALL_LOCK;
0a7de745 1269 }
39236c6e
A
1270 sock->so_rcv.sb_upcall = rcallback;
1271 sock->so_rcv.sb_upcallarg = rcontext;
1272 } else {
5ba3f43e 1273 sock->so_rcv.sb_flags &= ~(SB_UPCALL | SB_UPCALL_LOCK);
39236c6e
A
1274 sock->so_rcv.sb_upcall = NULL;
1275 sock->so_rcv.sb_upcallarg = NULL;
1276 }
1277
1278 if (wcallback != NULL) {
1279 sock->so_snd.sb_flags |= SB_UPCALL;
0a7de745 1280 if (locked) {
5ba3f43e 1281 sock->so_snd.sb_flags |= SB_UPCALL_LOCK;
0a7de745 1282 }
39236c6e
A
1283 sock->so_snd.sb_upcall = wcallback;
1284 sock->so_snd.sb_upcallarg = wcontext;
1285 } else {
5ba3f43e 1286 sock->so_snd.sb_flags &= ~(SB_UPCALL | SB_UPCALL_LOCK);
39236c6e
A
1287 sock->so_snd.sb_upcall = NULL;
1288 sock->so_snd.sb_upcallarg = NULL;
1289 }
1290}
1291
6d2010ae 1292errno_t
39236c6e 1293sock_setupcall(socket_t sock, sock_upcall callback, void *context)
6d2010ae 1294{
0a7de745
A
1295 if (sock == NULL) {
1296 return EINVAL;
1297 }
6d2010ae
A
1298
1299 /*
1300 * Note that we don't wait for any in progress upcall to complete.
39236c6e
A
1301 * On embedded, sock_setupcall() causes both read and write
1302 * callbacks to be set; on desktop, only read callback is set
1303 * to maintain legacy KPI behavior.
1304 *
1305 * The newer sock_setupcalls() KPI should be used instead to set
1306 * the read and write callbacks and their respective parameters.
6d2010ae
A
1307 */
1308 socket_lock(sock, 1);
f427ee49 1309#if (defined(__arm__) || defined(__arm64__))
5ba3f43e 1310 sock_setupcalls_locked(sock, callback, context, callback, context, 0);
f427ee49 1311#else /* (defined(__arm__) || defined(__arm64__)) */
5ba3f43e 1312 sock_setupcalls_locked(sock, callback, context, NULL, NULL, 0);
f427ee49 1313#endif /* (defined(__arm__) || defined(__arm64__)) */
39236c6e 1314 socket_unlock(sock, 1);
6d2010ae 1315
0a7de745 1316 return 0;
39236c6e
A
1317}
1318
1319errno_t
1320sock_setupcalls(socket_t sock, sock_upcall rcallback, void *rcontext,
1321 sock_upcall wcallback, void *wcontext)
1322{
0a7de745
A
1323 if (sock == NULL) {
1324 return EINVAL;
1325 }
39236c6e
A
1326
1327 /*
1328 * Note that we don't wait for any in progress upcall to complete.
1329 */
1330 socket_lock(sock, 1);
5ba3f43e 1331 sock_setupcalls_locked(sock, rcallback, rcontext, wcallback, wcontext, 0);
39236c6e
A
1332 socket_unlock(sock, 1);
1333
0a7de745 1334 return 0;
39236c6e
A
1335}
1336
5ba3f43e
A
1337void
1338sock_catchevents_locked(socket_t sock, sock_evupcall ecallback, void *econtext,
f427ee49 1339 long emask)
39236c6e 1340{
5ba3f43e 1341 socket_lock_assert_owned(sock);
39236c6e
A
1342
1343 /*
1344 * Note that we don't wait for any in progress upcall to complete.
1345 */
39236c6e
A
1346 if (ecallback != NULL) {
1347 sock->so_event = ecallback;
1348 sock->so_eventarg = econtext;
f427ee49 1349 sock->so_eventmask = (uint32_t)emask;
d41d1dae 1350 } else {
fe8ab488 1351 sock->so_event = sonullevent;
39236c6e
A
1352 sock->so_eventarg = NULL;
1353 sock->so_eventmask = 0;
d41d1dae 1354 }
5ba3f43e
A
1355}
1356
1357errno_t
1358sock_catchevents(socket_t sock, sock_evupcall ecallback, void *econtext,
f427ee49 1359 long emask)
5ba3f43e 1360{
0a7de745
A
1361 if (sock == NULL) {
1362 return EINVAL;
1363 }
5ba3f43e
A
1364
1365 socket_lock(sock, 1);
1366 sock_catchevents_locked(sock, ecallback, econtext, emask);
6d2010ae
A
1367 socket_unlock(sock, 1);
1368
0a7de745 1369 return 0;
d41d1dae 1370}
fe8ab488
A
1371
1372/*
1373 * Returns true whether or not a socket belongs to the kernel.
1374 */
1375int
1376sock_iskernel(socket_t so)
1377{
0a7de745 1378 return so && so->last_pid == 0;
fe8ab488 1379}