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