]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_socket.c
xnu-1699.32.7.tar.gz
[apple/xnu.git] / bsd / kern / kpi_socket.c
CommitLineData
91447636 1/*
6d2010ae 2 * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
91447636 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 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.
8f6c56a5 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.
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
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
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>
42#include <sys/fcntl.h>
43#include <sys/filio.h>
44#include <sys/uio_internal.h>
45#include <kern/lock.h>
b0d623f7 46#include <netinet/in.h>
d1ecb069 47#include <libkern/OSAtomic.h>
91447636 48
91447636 49extern int soclose_locked(struct socket *so);
2d21ac55 50extern void soclose_wait_locked(struct socket *so);
b0d623f7 51extern int so_isdstlocal(struct socket *so);
91447636
A
52
53errno_t sock_send_internal(
54 socket_t sock,
55 const struct msghdr *msg,
56 mbuf_t data,
57 int flags,
58 size_t *sentlen);
59
2d21ac55 60typedef void (*so_upcall)(struct socket *, caddr_t , int );
91447636
A
61
62
63errno_t
64sock_accept(
65 socket_t sock,
66 struct sockaddr *from,
67 int fromlen,
68 int flags,
69 sock_upcall callback,
70 void* cookie,
71 socket_t *new_sock)
72{
73 struct sockaddr *sa;
74 struct socket *new_so;
75 lck_mtx_t *mutex_held;
76 int dosocklock;
77 errno_t error = 0;
78
79 if (sock == NULL || new_sock == NULL) return EINVAL;
80 socket_lock(sock, 1);
81 if ((sock->so_options & SO_ACCEPTCONN) == 0) {
82 socket_unlock(sock, 1);
83 return EINVAL;
84 }
85 if ((flags & ~(MSG_DONTWAIT)) != 0) {
86 socket_unlock(sock, 1);
87 return ENOTSUP;
88 }
89 if (((flags & MSG_DONTWAIT) != 0 || (sock->so_state & SS_NBIO) != 0) &&
90 sock->so_comp.tqh_first == NULL) {
91 socket_unlock(sock, 1);
92 return EWOULDBLOCK;
93 }
94
95 if (sock->so_proto->pr_getlock != NULL) {
96 mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
97 dosocklock = 1;
98 }
99 else {
100 mutex_held = sock->so_proto->pr_domain->dom_mtx;
101 dosocklock = 0;
102 }
103
104 while (TAILQ_EMPTY(&sock->so_comp) && sock->so_error == 0) {
105 if (sock->so_state & SS_CANTRCVMORE) {
106 sock->so_error = ECONNABORTED;
107 break;
108 }
2d21ac55 109 error = msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK | PCATCH, "sock_accept", NULL);
91447636
A
110 if (error) {
111 socket_unlock(sock, 1);
112 return (error);
113 }
114 }
115 if (sock->so_error) {
116 error = sock->so_error;
117 sock->so_error = 0;
118 socket_unlock(sock, 1);
119 return (error);
120 }
121
122 new_so = TAILQ_FIRST(&sock->so_comp);
123 TAILQ_REMOVE(&sock->so_comp, new_so, so_list);
124 sock->so_qlen--;
2d21ac55
A
125
126 /*
127 * Pass the pre-accepted socket to any interested socket filter(s).
128 * Upon failure, the socket would have been closed by the callee.
129 */
130 if (new_so->so_filt != NULL) {
131 /*
132 * Temporarily drop the listening socket's lock before we
133 * hand off control over to the socket filter(s), but keep
134 * a reference so that it won't go away. We'll grab it
135 * again once we're done with the filter(s).
136 */
137 socket_unlock(sock, 0);
138 if ((error = soacceptfilter(new_so)) != 0) {
139 /* Drop reference on listening socket */
140 sodereference(sock);
141 return (error);
142 }
143 socket_lock(sock, 0);
144 }
91447636
A
145
146 if (dosocklock) {
147 lck_mtx_assert(new_so->so_proto->pr_getlock(new_so, 0),
148 LCK_MTX_ASSERT_NOTOWNED);
149 socket_lock(new_so, 1);
150 }
151
152 new_so->so_state &= ~SS_COMP;
153 new_so->so_head = NULL;
2d21ac55 154 (void) soacceptlock(new_so, &sa, 0);
91447636 155
2d21ac55
A
156 socket_unlock(sock, 1); /* release the head */
157
91447636 158 if (callback) {
2d21ac55 159 new_so->so_upcall = (so_upcall) callback;
91447636
A
160 new_so->so_upcallarg = cookie;
161 new_so->so_rcv.sb_flags |= SB_UPCALL;
2d21ac55
A
162#if CONFIG_SOWUPCALL
163 new_so->so_snd.sb_flags |= SB_UPCALL;
164#endif
91447636
A
165 }
166
167 if (sa && from)
168 {
169 if (fromlen > sa->sa_len) fromlen = sa->sa_len;
170 memcpy(from, sa, fromlen);
171 }
172 if (sa) FREE(sa, M_SONAME);
2d21ac55
A
173
174 /*
6d2010ae
A
175 * If the socket has been marked as inactive by sosetdefunct(),
176 * disallow further operations on it.
2d21ac55
A
177 */
178 if (new_so->so_flags & SOF_DEFUNCT) {
6d2010ae
A
179 (void) sodefunct(current_proc(), new_so,
180 SHUTDOWN_SOCKET_LEVEL_DISCONNECT_INTERNAL);
2d21ac55 181 }
91447636
A
182 *new_sock = new_so;
183 if (dosocklock)
184 socket_unlock(new_so, 1);
185 return error;
186}
187
188errno_t
189sock_bind(
190 socket_t sock,
191 const struct sockaddr *to)
192{
6d2010ae
A
193 int error = 0;
194 struct sockaddr *sa = NULL;
195 struct sockaddr_storage ss;
196 boolean_t want_free = TRUE;
197
198 if (sock == NULL || to == NULL)
199 return EINVAL;
200
201 if (to->sa_len > sizeof(ss)) {
202 MALLOC(sa, struct sockaddr *, to->sa_len, M_SONAME, M_WAITOK);
203 if (sa == NULL)
204 return ENOBUFS;
205 } else {
206 sa = (struct sockaddr *)&ss;
207 want_free = FALSE;
208 }
209 memcpy(sa, to, to->sa_len);
210
211 error = sobind(sock, sa);
91447636 212
6d2010ae
A
213 if (sa != NULL && want_free == TRUE)
214 FREE(sa, M_SONAME);
215
216 return error;
91447636
A
217}
218
219errno_t
220sock_connect(
221 socket_t sock,
222 const struct sockaddr *to,
223 int flags)
224{
225 int error = 0;
226 lck_mtx_t *mutex_held;
6d2010ae
A
227 struct sockaddr *sa = NULL;
228 struct sockaddr_storage ss;
229 boolean_t want_free = TRUE;
91447636
A
230
231 if (sock == NULL || to == NULL) return EINVAL;
6d2010ae
A
232
233 if (to->sa_len > sizeof(ss)) {
234 MALLOC(sa, struct sockaddr *, to->sa_len, M_SONAME,
235 (flags & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK);
236 if (sa == NULL)
237 return ENOBUFS;
238 } else {
239 sa = (struct sockaddr *)&ss;
240 want_free = FALSE;
241 }
242 memcpy(sa, to, to->sa_len);
91447636
A
243
244 socket_lock(sock, 1);
245
246 if ((sock->so_state & SS_ISCONNECTING) &&
247 ((sock->so_state & SS_NBIO) != 0 ||
248 (flags & MSG_DONTWAIT) != 0)) {
6d2010ae
A
249 error = EALREADY;
250 goto out;
91447636 251 }
6d2010ae 252 error = soconnectlock(sock, sa, 0);
91447636
A
253 if (!error) {
254 if ((sock->so_state & SS_ISCONNECTING) &&
255 ((sock->so_state & SS_NBIO) != 0 || (flags & MSG_DONTWAIT) != 0)) {
6d2010ae
A
256 error = EINPROGRESS;
257 goto out;
91447636
A
258 }
259
260 if (sock->so_proto->pr_getlock != NULL)
261 mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
262 else
263 mutex_held = sock->so_proto->pr_domain->dom_mtx;
264
265 while ((sock->so_state & SS_ISCONNECTING) && sock->so_error == 0) {
266 error = msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK | PCATCH,
2d21ac55 267 "sock_connect", NULL);
91447636
A
268 if (error)
269 break;
270 }
271
272 if (error == 0) {
273 error = sock->so_error;
274 sock->so_error = 0;
275 }
276 }
277 else {
278 sock->so_state &= ~SS_ISCONNECTING;
279 }
6d2010ae 280out:
91447636 281 socket_unlock(sock, 1);
6d2010ae
A
282
283 if (sa != NULL && want_free == TRUE)
284 FREE(sa, M_SONAME);
285
91447636
A
286 return error;
287}
288
289errno_t
290sock_connectwait(
291 socket_t sock,
292 const struct timeval *tv)
293{
294 lck_mtx_t * mutex_held;
295 errno_t retval = 0;
296 struct timespec ts;
297
298 socket_lock(sock, 1);
299
300 // Check if we're already connected or if we've already errored out
301 if ((sock->so_state & SS_ISCONNECTING) == 0 || sock->so_error) {
302 if (sock->so_error) {
303 retval = sock->so_error;
304 sock->so_error = 0;
305 }
306 else {
307 if ((sock->so_state & SS_ISCONNECTED) != 0)
308 retval = 0;
309 else
310 retval = EINVAL;
311 }
312 goto done;
313 }
314
315 // copied translation from timeval to hertz from SO_RCVTIMEO handling
316 if (tv->tv_sec < 0 || tv->tv_sec > SHRT_MAX / hz ||
317 tv->tv_usec < 0 || tv->tv_usec >= 1000000) {
318 retval = EDOM;
319 goto done;
320 }
321
322 ts.tv_sec = tv->tv_sec;
323 ts.tv_nsec = (tv->tv_usec * NSEC_PER_USEC);
324 if ( (ts.tv_sec + (ts.tv_nsec/NSEC_PER_SEC))/100 > SHRT_MAX) {
325 retval = EDOM;
326 goto done;
327 }
328
329 if (sock->so_proto->pr_getlock != NULL)
330 mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
331 else
332 mutex_held = sock->so_proto->pr_domain->dom_mtx;
333
334 msleep((caddr_t)&sock->so_timeo, mutex_held, PSOCK, "sock_connectwait", &ts);
335
336 // Check if we're still waiting to connect
337 if ((sock->so_state & SS_ISCONNECTING) && sock->so_error == 0) {
338 retval = EINPROGRESS;
339 goto done;
340 }
341
342 if (sock->so_error) {
343 retval = sock->so_error;
344 sock->so_error = 0;
345 }
346
347done:
348 socket_unlock(sock, 1);
349 return retval;
350}
351
352errno_t
353sock_nointerrupt(
354 socket_t sock,
355 int on)
356{
357 socket_lock(sock, 1);
358
359 if (on) {
360 sock->so_rcv.sb_flags |= SB_NOINTR; // This isn't safe
361 sock->so_snd.sb_flags |= SB_NOINTR; // This isn't safe
362 }
363 else {
364 sock->so_rcv.sb_flags &= ~SB_NOINTR; // This isn't safe
365 sock->so_snd.sb_flags &= ~SB_NOINTR; // This isn't safe
366 }
367
368 socket_unlock(sock, 1);
369
370 return 0;
371}
372
373errno_t
2d21ac55 374sock_getpeername(socket_t sock, struct sockaddr *peername, int peernamelen)
91447636 375{
2d21ac55 376 int error;
91447636 377 struct sockaddr *sa = NULL;
2d21ac55
A
378
379 if (sock == NULL || peername == NULL || peernamelen < 0)
380 return (EINVAL);
381
91447636 382 socket_lock(sock, 1);
2d21ac55 383 if (!(sock->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING))) {
91447636 384 socket_unlock(sock, 1);
2d21ac55 385 return (ENOTCONN);
91447636 386 }
b0d623f7 387 error = sogetaddr_locked(sock, &sa, 1);
2d21ac55
A
388 socket_unlock(sock, 1);
389 if (error == 0) {
390 if (peernamelen > sa->sa_len)
391 peernamelen = sa->sa_len;
91447636 392 memcpy(peername, sa, peernamelen);
2d21ac55 393 FREE(sa, M_SONAME);
91447636 394 }
2d21ac55 395 return (error);
91447636
A
396}
397
398errno_t
2d21ac55 399sock_getsockname(socket_t sock, struct sockaddr *sockname, int socknamelen)
91447636 400{
2d21ac55 401 int error;
91447636 402 struct sockaddr *sa = NULL;
2d21ac55
A
403
404 if (sock == NULL || sockname == NULL || socknamelen < 0)
405 return (EINVAL);
406
91447636 407 socket_lock(sock, 1);
b0d623f7 408 error = sogetaddr_locked(sock, &sa, 0);
2d21ac55
A
409 socket_unlock(sock, 1);
410 if (error == 0) {
411 if (socknamelen > sa->sa_len)
412 socknamelen = sa->sa_len;
91447636 413 memcpy(sockname, sa, socknamelen);
2d21ac55 414 FREE(sa, M_SONAME);
91447636 415 }
2d21ac55
A
416 return (error);
417}
418
b0d623f7
A
419__private_extern__ int
420sogetaddr_locked(struct socket *so, struct sockaddr **psa, int peer)
2d21ac55
A
421{
422 int error;
423
b0d623f7 424 if (so == NULL || psa == NULL)
2d21ac55
A
425 return (EINVAL);
426
427 *psa = NULL;
b0d623f7
A
428 error = peer ? so->so_proto->pr_usrreqs->pru_peeraddr(so, psa) :
429 so->so_proto->pr_usrreqs->pru_sockaddr(so, psa);
2d21ac55
A
430
431 if (error == 0 && *psa == NULL) {
432 error = ENOMEM;
433 } else if (error != 0 && *psa != NULL) {
434 FREE(*psa, M_SONAME);
435 *psa = NULL;
436 }
437 return (error);
438}
439
b0d623f7
A
440errno_t
441sock_getaddr(socket_t sock, struct sockaddr **psa, int peer)
442{
443 int error;
444
445 if (sock == NULL || psa == NULL)
446 return (EINVAL);
447
448 socket_lock(sock, 1);
449 error = sogetaddr_locked(sock, psa, peer);
450 socket_unlock(sock, 1);
451
452 return (error);
453}
454
2d21ac55
A
455void
456sock_freeaddr(struct sockaddr *sa)
457{
458 if (sa != NULL)
459 FREE(sa, M_SONAME);
91447636
A
460}
461
462errno_t
463sock_getsockopt(
464 socket_t sock,
465 int level,
466 int optname,
467 void *optval,
468 int *optlen)
469{
470 int error = 0;
471 struct sockopt sopt;
472
473 if (sock == NULL || optval == NULL || optlen == NULL) return EINVAL;
474 sopt.sopt_dir = SOPT_GET;
475 sopt.sopt_level = level;
476 sopt.sopt_name = optname;
477 sopt.sopt_val = CAST_USER_ADDR_T(optval);
478 sopt.sopt_valsize = *optlen;
b0d623f7 479 sopt.sopt_p = kernproc;
91447636
A
480 error = sogetopt(sock, &sopt); /* will lock socket */
481 if (error == 0) *optlen = sopt.sopt_valsize;
482 return error;
483}
484
485errno_t
486sock_ioctl(
487 socket_t sock,
488 unsigned long request,
489 void *argp)
490{
b0d623f7 491 return soioctl(sock, request, argp, kernproc); /* will lock socket */
91447636
A
492}
493
494errno_t
495sock_setsockopt(
496 socket_t sock,
497 int level,
498 int optname,
499 const void *optval,
500 int optlen)
501{
502 struct sockopt sopt;
503
504 if (sock == NULL || optval == NULL) return EINVAL;
505 sopt.sopt_dir = SOPT_SET;
506 sopt.sopt_level = level;
507 sopt.sopt_name = optname;
508 sopt.sopt_val = CAST_USER_ADDR_T(optval);
509 sopt.sopt_valsize = optlen;
b0d623f7 510 sopt.sopt_p = kernproc;
91447636
A
511 return sosetopt(sock, &sopt); /* will lock socket */
512}
513
6d2010ae
A
514/*
515 * This follows the recommended mappings between DSCP code points and WMM access classes
516 */
517static u_int8_t so_tc_from_dscp(u_int8_t dscp);
518static u_int8_t
519so_tc_from_dscp(u_int8_t dscp)
520{
521 u_int8_t tc;
522
523 if (dscp >= 0x30 && dscp <= 0x3f)
524 tc = SO_TC_VO;
525 else if (dscp >= 0x20 && dscp <= 0x2f)
526 tc = SO_TC_VI;
527 else if (dscp >= 0x08 && dscp <= 0x17)
528 tc = SO_TC_BK;
529 else
530 tc = SO_TC_BE;
531
532 return tc;
533}
534
b0d623f7
A
535errno_t
536sock_settclassopt(
537 socket_t sock,
538 const void *optval,
539 size_t optlen) {
540
541 errno_t error = 0;
542 struct sockopt sopt;
6d2010ae 543 int sotc;
b0d623f7 544
6d2010ae 545 if (sock == NULL || optval == NULL || optlen != sizeof(int)) return EINVAL;
b0d623f7
A
546
547 socket_lock(sock, 1);
548 if (!(sock->so_state & SS_ISCONNECTED)) {
549 /* If the socket is not connected then we don't know
550 * if the destination is on LAN or not. Skip
551 * setting traffic class in this case
552 */
553 error = ENOTCONN;
554 goto out;
555 }
556
557 if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL || sock->so_pcb == NULL) {
558 error = EINVAL;
559 goto out;
560 }
561
6d2010ae
A
562 /*
563 * Set the socket traffic class based on the passed DSCP code point
564 * regardless of the scope of the destination
565 */
566 sotc = so_tc_from_dscp((*(const int *)optval) >> 2);
567
568 sopt.sopt_dir = SOPT_SET;
569 sopt.sopt_val = CAST_USER_ADDR_T(&sotc);
570 sopt.sopt_valsize = sizeof(sotc);
571 sopt.sopt_p = kernproc;
572 sopt.sopt_level = SOL_SOCKET;
573 sopt.sopt_name = SO_TRAFFIC_CLASS;
574
575 socket_unlock(sock, 0);
576 error = sosetopt(sock, &sopt);
577 socket_lock(sock, 0);
578
579 if (error != 0) {
580 printf("sock_settclassopt: sosetopt SO_TRAFFIC_CLASS failed %d\n", error);
581 goto out;
582 }
583
b0d623f7
A
584 /* Check if the destination address is LAN or link local address.
585 * We do not want to set traffic class bits if the destination
586 * is not local
587 */
588 if (!so_isdstlocal(sock)) {
589 goto out;
590 }
591
6d2010ae
A
592 sopt.sopt_dir = SOPT_SET;
593 sopt.sopt_val = CAST_USER_ADDR_T(optval);
594 sopt.sopt_valsize = optlen;
595 sopt.sopt_p = kernproc;
596
b0d623f7
A
597 switch (sock->so_proto->pr_domain->dom_family) {
598 case AF_INET:
599 sopt.sopt_level = IPPROTO_IP;
600 sopt.sopt_name = IP_TOS;
601 break;
602 case AF_INET6:
603 sopt.sopt_level = IPPROTO_IPV6;
604 sopt.sopt_name = IPV6_TCLASS;
605 break;
606 default:
607 error = EINVAL;
608 goto out;
609 }
610
611 socket_unlock(sock, 1);
612 return sosetopt(sock, &sopt);
613out:
614 socket_unlock(sock, 1);
615 return error;
616}
617
618errno_t
619sock_gettclassopt(
620 socket_t sock,
621 void *optval,
622 size_t *optlen) {
623
624 errno_t error = 0;
625 struct sockopt sopt;
626
627 if (sock == NULL || optval == NULL || optlen == NULL) return EINVAL;
628
629 sopt.sopt_dir = SOPT_GET;
630 sopt.sopt_val = CAST_USER_ADDR_T(optval);
631 sopt.sopt_valsize = *optlen;
632 sopt.sopt_p = kernproc;
633
634 socket_lock(sock, 1);
635 if (sock->so_proto == NULL || sock->so_proto->pr_domain == NULL) {
636 socket_unlock(sock, 1);
637 return EINVAL;
638 }
639
640 switch (sock->so_proto->pr_domain->dom_family) {
641 case AF_INET:
642 sopt.sopt_level = IPPROTO_IP;
643 sopt.sopt_name = IP_TOS;
644 break;
645 case AF_INET6:
646 sopt.sopt_level = IPPROTO_IPV6;
647 sopt.sopt_name = IPV6_TCLASS;
648 break;
649 default:
650 socket_unlock(sock, 1);
651 return EINVAL;
652
653 }
654 socket_unlock(sock, 1);
655 error = sogetopt(sock, &sopt); /* will lock socket */
656 if (error == 0) *optlen = sopt.sopt_valsize;
657 return error;
658}
659
91447636
A
660errno_t
661sock_listen(
662 socket_t sock,
663 int backlog)
664{
665 if (sock == NULL) return EINVAL;
666 return solisten(sock, backlog); /* will lock socket */
667}
668
669static errno_t
670sock_receive_internal(
671 socket_t sock,
672 struct msghdr *msg,
673 mbuf_t *data,
674 int flags,
675 size_t *recvdlen)
676{
677 uio_t auio;
678 struct mbuf *control = NULL;
679 int error = 0;
680 int length = 0;
681 struct sockaddr *fromsa;
682 char uio_buf[ UIO_SIZEOF((msg != NULL) ? msg->msg_iovlen : 0) ];
683
684 if (sock == NULL) return EINVAL;
685
686 auio = uio_createwithbuffer(((msg != NULL) ? msg->msg_iovlen : 0),
687 0, UIO_SYSSPACE, UIO_READ,
688 &uio_buf[0], sizeof(uio_buf));
689 if (msg && data == NULL) {
690 int i;
b0d623f7 691 struct iovec *tempp = msg->msg_iov;
91447636
A
692
693 for (i = 0; i < msg->msg_iovlen; i++) {
694 uio_addiov(auio, CAST_USER_ADDR_T((tempp + i)->iov_base), (tempp + i)->iov_len);
695 }
696 if (uio_resid(auio) < 0) return EINVAL;
697 }
698 else {
699 uio_setresid(auio, (uio_resid(auio) + *recvdlen));
700 }
701 length = uio_resid(auio);
702
703 if (recvdlen)
704 *recvdlen = 0;
91447636
A
705
706 /* let pru_soreceive handle the socket locking */
707 error = sock->so_proto->pr_usrreqs->pru_soreceive(sock, &fromsa, auio,
b0d623f7 708 data, (msg && msg->msg_control) ? &control : NULL, &flags);
91447636
A
709 if (error) goto cleanup;
710
711 if (recvdlen)
712 *recvdlen = length - uio_resid(auio);
713 if (msg) {
714 msg->msg_flags = flags;
715
716 if (msg->msg_name)
717 {
718 int salen;
719 salen = msg->msg_namelen;
720 if (msg->msg_namelen > 0 && fromsa != 0)
721 {
722 salen = MIN(salen, fromsa->sa_len);
723 memcpy(msg->msg_name, fromsa,
724 msg->msg_namelen > fromsa->sa_len ? fromsa->sa_len : msg->msg_namelen);
725 }
726 }
727
728 if (msg->msg_control)
729 {
730 struct mbuf* m = control;
731 u_char* ctlbuf = msg->msg_control;
732 int clen = msg->msg_controllen;
733 msg->msg_controllen = 0;
734
735 while (m && clen > 0)
736 {
737 unsigned int tocopy;
738 if (clen >= m->m_len)
739 {
740 tocopy = m->m_len;
741 }
742 else
743 {
744 msg->msg_flags |= MSG_CTRUNC;
745 tocopy = clen;
746 }
747 memcpy(ctlbuf, mtod(m, caddr_t), tocopy);
748 ctlbuf += tocopy;
749 clen -= tocopy;
750 m = m->m_next;
751 }
b0d623f7 752 msg->msg_controllen = (uintptr_t)ctlbuf - (uintptr_t)msg->msg_control;
91447636
A
753 }
754 }
755
756cleanup:
757 if (control) m_freem(control);
758 if (fromsa) FREE(fromsa, M_SONAME);
759 return error;
760}
761
762errno_t
763sock_receive(
764 socket_t sock,
765 struct msghdr *msg,
766 int flags,
767 size_t *recvdlen)
768{
769 if ((msg == NULL) ||
770 (msg->msg_iovlen < 1) ||
771 (msg->msg_iov[0].iov_len == 0) ||
772 (msg->msg_iov[0].iov_base == NULL))
773 return EINVAL;
774 return sock_receive_internal(sock, msg, NULL, flags, recvdlen);
775}
776
777errno_t
778sock_receivembuf(
779 socket_t sock,
780 struct msghdr *msg,
781 mbuf_t *data,
782 int flags,
783 size_t *recvlen)
784{
785 if (data == NULL || recvlen == 0 || *recvlen <= 0 || (msg &&
786 (msg->msg_iov != NULL || msg->msg_iovlen != 0)))
787 return EINVAL;
788 return sock_receive_internal(sock, msg, data, flags, recvlen);
789}
790
791errno_t
792sock_send_internal(
793 socket_t sock,
794 const struct msghdr *msg,
795 mbuf_t data,
796 int flags,
797 size_t *sentlen)
798{
799 uio_t auio = NULL;
800 struct mbuf *control = NULL;
801 int error = 0;
802 int datalen = 0;
803 char uio_buf[ UIO_SIZEOF((msg != NULL ? msg->msg_iovlen : 1)) ];
804
805 if (sock == NULL) {
806 error = EINVAL;
807 goto errorout;
808 }
809
810 if (data == 0 && msg != NULL) {
b0d623f7 811 struct iovec *tempp = msg->msg_iov;
91447636
A
812
813 auio = uio_createwithbuffer(msg->msg_iovlen, 0, UIO_SYSSPACE, UIO_WRITE,
814 &uio_buf[0], sizeof(uio_buf));
815 if (tempp != NULL)
816 {
817 int i;
818
819 for (i = 0; i < msg->msg_iovlen; i++) {
820 uio_addiov(auio, CAST_USER_ADDR_T((tempp + i)->iov_base), (tempp + i)->iov_len);
821 }
822
823 if (uio_resid(auio) < 0) {
824 error = EINVAL;
825 goto errorout;
826 }
827 }
828 }
829
830 if (sentlen)
831 *sentlen = 0;
832
833 if (auio)
834 datalen = uio_resid(auio);
835 else
836 datalen = data->m_pkthdr.len;
837
838 if (msg && msg->msg_control)
839 {
840 if ((size_t)msg->msg_controllen < sizeof(struct cmsghdr)) return EINVAL;
841 if ((size_t)msg->msg_controllen > MLEN) return EINVAL;
842 control = m_get(M_NOWAIT, MT_CONTROL);
843 if (control == NULL) {
844 error = ENOMEM;
845 goto errorout;
846 }
847 memcpy(mtod(control, caddr_t), msg->msg_control, msg->msg_controllen);
848 control->m_len = msg->msg_controllen;
849 }
850
8f6c56a5
A
851 error = sock->so_proto->pr_usrreqs->pru_sosend(sock, msg != NULL ?
852 (struct sockaddr*)msg->msg_name : NULL, auio, data, control, flags);
853
854 /*
855 * Residual data is possible in the case of IO vectors but not
856 * in the mbuf case since the latter is treated as atomic send.
857 * If pru_sosend() consumed a portion of the iovecs data and
858 * the error returned is transient, treat it as success; this
859 * is consistent with sendit() behavior.
860 */
861 if (auio != NULL && uio_resid(auio) != datalen &&
862 (error == ERESTART || error == EINTR || error == EWOULDBLOCK))
863 error = 0;
864
865 if (error == 0 && sentlen != NULL) {
866 if (auio != NULL)
91447636
A
867 *sentlen = datalen - uio_resid(auio);
868 else
869 *sentlen = datalen;
870 }
871
872 return error;
873
874/*
875 * In cases where we detect an error before returning, we need to
876 * free the mbuf chain if there is one. sosend (and pru_sosend) will
877 * free the mbuf chain if they encounter an error.
878 */
879errorout:
880 if (control)
881 m_freem(control);
882 if (data)
883 m_freem(data);
884 if (sentlen)
885 *sentlen = 0;
886 return error;
887}
888
889errno_t
890sock_send(
891 socket_t sock,
892 const struct msghdr *msg,
893 int flags,
894 size_t *sentlen)
895{
896 if (msg == NULL || msg->msg_iov == NULL || msg->msg_iovlen < 1)
897 return EINVAL;
898 return sock_send_internal(sock, msg, NULL, flags, sentlen);
899}
900
901errno_t
902sock_sendmbuf(
903 socket_t sock,
904 const struct msghdr *msg,
905 mbuf_t data,
906 int flags,
907 size_t *sentlen)
908{
909 if (data == NULL || (msg &&
910 (msg->msg_iov != NULL || msg->msg_iovlen != 0))) {
911 if (data)
912 m_freem(data);
913 return EINVAL;
914 }
915 return sock_send_internal(sock, msg, data, flags, sentlen);
916}
917
918errno_t
919sock_shutdown(
920 socket_t sock,
921 int how)
922{
923 if (sock == NULL) return EINVAL;
924 return soshutdown(sock, how);
925}
926
91447636
A
927
928errno_t
929sock_socket(
930 int domain,
931 int type,
932 int protocol,
933 sock_upcall callback,
934 void* context,
935 socket_t *new_so)
936{
937 int error = 0;
938 if (new_so == NULL) return EINVAL;
939 /* socreate will create an initial so_count */
940 error = socreate(domain, new_so, type, protocol);
941 if (error == 0 && callback)
942 {
943 (*new_so)->so_rcv.sb_flags |= SB_UPCALL;
2d21ac55
A
944#if CONFIG_SOWUPCALL
945 (*new_so)->so_snd.sb_flags |= SB_UPCALL;
946#endif
91447636
A
947 (*new_so)->so_upcall = (so_upcall)callback;
948 (*new_so)->so_upcallarg = context;
949 }
950 return error;
951}
952
953void
954sock_close(
955 socket_t sock)
956{
957 if (sock == NULL) return;
958 soclose(sock);
959}
960
961/* Do we want this to be APPLE_PRIVATE API?: YES (LD 12/23/04)*/
962void
963sock_retain(
964 socket_t sock)
965{
966 if (sock == NULL) return;
967 socket_lock(sock, 1);
968 sock->so_retaincnt++;
969 sock->so_usecount++; /* add extra reference for holding the socket */
970 socket_unlock(sock, 1);
971}
972
973/* Do we want this to be APPLE_PRIVATE API? */
974void
2d21ac55 975sock_release(socket_t sock)
91447636 976{
2d21ac55
A
977 if (sock == NULL)
978 return;
91447636 979 socket_lock(sock, 1);
2d21ac55
A
980
981 if (sock->so_flags & SOF_UPCALLINUSE)
982 soclose_wait_locked(sock);
983
91447636
A
984 sock->so_retaincnt--;
985 if (sock->so_retaincnt < 0)
2d21ac55
A
986 panic("sock_release: negative retain count for sock=%p "
987 "cnt=%x\n", sock, sock->so_retaincnt);
988 if ((sock->so_retaincnt == 0) && (sock->so_usecount == 2)) {
989 /* close socket only if the FD is not holding it */
990 soclose_locked(sock);
991 } else {
992 /* remove extra reference holding the socket */
993 sock->so_usecount--;
994 }
91447636
A
995 socket_unlock(sock, 1);
996}
997
998errno_t
999sock_setpriv(
1000 socket_t sock,
1001 int on)
1002{
1003 if (sock == NULL) return EINVAL;
1004 socket_lock(sock, 1);
1005 if (on)
1006 {
1007 sock->so_state |= SS_PRIV;
1008 }
1009 else
1010 {
1011 sock->so_state &= ~SS_PRIV;
1012 }
1013 socket_unlock(sock, 1);
1014 return 0;
1015}
1016
1017int
1018sock_isconnected(
1019 socket_t sock)
1020{
1021 int retval;
1022 socket_lock(sock, 1);
1023 retval = (sock->so_state & SS_ISCONNECTED) != 0;
1024 socket_unlock(sock, 1);
1025 return (retval);
1026}
1027
1028int
1029sock_isnonblocking(
1030 socket_t sock)
1031{
1032 int retval;
1033 socket_lock(sock, 1);
1034 retval = (sock->so_state & SS_NBIO) != 0;
1035 socket_unlock(sock, 1);
1036 return (retval);
1037}
1038
1039errno_t
1040sock_gettype(
1041 socket_t sock,
1042 int *outDomain,
1043 int *outType,
1044 int *outProtocol)
1045{
1046 socket_lock(sock, 1);
1047 if (outDomain)
1048 *outDomain = sock->so_proto->pr_domain->dom_family;
1049 if (outType)
1050 *outType = sock->so_type;
1051 if (outProtocol)
1052 *outProtocol = sock->so_proto->pr_protocol;
1053 socket_unlock(sock, 1);
1054 return 0;
1055}
2d21ac55
A
1056
1057/*
1058 * Return the listening socket of a pre-accepted socket. It returns the
1059 * listener (so_head) value of a given socket. This is intended to be
1060 * called by a socket filter during a filter attach (sf_attach) callback.
1061 * The value returned by this routine is safe to be used only in the
1062 * context of that callback, because we hold the listener's lock across
1063 * the sflt_initsock() call.
1064 */
1065socket_t
1066sock_getlistener(socket_t sock)
1067{
1068 return (sock->so_head);
1069}
d1ecb069 1070
6d2010ae
A
1071static inline void
1072sock_set_tcp_stream_priority(socket_t sock)
1073{
1074 if ((sock->so_proto->pr_domain->dom_family == AF_INET ||
1075 sock->so_proto->pr_domain->dom_family == AF_INET6) &&
1076 sock->so_proto->pr_type == SOCK_STREAM) {
1077
1078 set_tcp_stream_priority(sock);
1079
1080 }
1081}
1082
d1ecb069
A
1083/*
1084 * Caller must have ensured socket is valid and won't be going away.
1085 */
1086void
6d2010ae 1087socket_set_traffic_mgt_flags_locked(socket_t sock, u_int32_t flags)
d1ecb069
A
1088{
1089 (void) OSBitOrAtomic(flags, &sock->so_traffic_mgt_flags);
6d2010ae
A
1090 sock_set_tcp_stream_priority(sock);
1091}
1092
1093void
1094socket_set_traffic_mgt_flags(socket_t sock, u_int32_t flags)
1095{
1096 socket_lock(sock, 1);
1097 socket_set_traffic_mgt_flags_locked(sock, flags);
1098 socket_unlock(sock, 1);
d1ecb069
A
1099}
1100
1101/*
1102 * Caller must have ensured socket is valid and won't be going away.
1103 */
1104void
6d2010ae 1105socket_clear_traffic_mgt_flags_locked(socket_t sock, u_int32_t flags)
d1ecb069
A
1106{
1107 (void) OSBitAndAtomic(~flags, &sock->so_traffic_mgt_flags);
6d2010ae 1108 sock_set_tcp_stream_priority(sock);
d1ecb069 1109}
d41d1dae 1110
6d2010ae
A
1111void
1112socket_clear_traffic_mgt_flags(socket_t sock, u_int32_t flags)
d41d1dae 1113{
6d2010ae
A
1114 socket_lock(sock, 1);
1115 socket_clear_traffic_mgt_flags_locked(sock, flags);
1116 socket_unlock(sock, 1);
1117}
1118
d41d1dae 1119
6d2010ae
A
1120/*
1121 * Caller must have ensured socket is valid and won't be going away.
1122 */
1123errno_t
1124socket_defunct(struct proc *p, socket_t so, int level)
1125{
1126 errno_t retval;
1127
1128 if (level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
1129 level != SHUTDOWN_SOCKET_LEVEL_DISCONNECT_ALL)
1130 return (EINVAL);
1131
1132 socket_lock(so, 1);
1133 /*
1134 * SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC level is meant to tear down
1135 * all of mDNSResponder IPC sockets, currently those of AF_UNIX; note
1136 * that this is an implementation artifact of mDNSResponder. We do
1137 * a quick test against the socket buffers for SB_UNIX, since that
1138 * would have been set by unp_attach() at socket creation time.
1139 */
1140 if (level == SHUTDOWN_SOCKET_LEVEL_DISCONNECT_SVC &&
1141 (so->so_rcv.sb_flags & so->so_snd.sb_flags & SB_UNIX) != SB_UNIX) {
1142 socket_unlock(so, 1);
1143 return (EOPNOTSUPP);
1144 }
1145 retval = sosetdefunct(p, so, level, TRUE);
1146 if (retval == 0)
1147 retval = sodefunct(p, so, level);
1148 socket_unlock(so, 1);
1149 return (retval);
1150}
1151
1152errno_t
1153sock_setupcall(socket_t sock, sock_upcall callback, void* context)
1154{
1155 if (sock == NULL)
1156 return EINVAL;
1157
1158 /*
1159 * Note that we don't wait for any in progress upcall to complete.
1160 */
1161 socket_lock(sock, 1);
1162
1163 sock->so_upcall = (so_upcall) callback;
1164 sock->so_upcallarg = context;
1165 if (callback) {
1166 sock->so_rcv.sb_flags |= SB_UPCALL;
1167#if CONFIG_SOWUPCALL
1168 sock->so_snd.sb_flags |= SB_UPCALL;
1169#endif /* CONFIG_SOWUPCALL */
d41d1dae 1170 } else {
6d2010ae
A
1171 sock->so_rcv.sb_flags &= ~SB_UPCALL;
1172#if CONFIG_SOWUPCALL
1173 sock->so_snd.sb_flags &= ~SB_UPCALL;
1174#endif /* CONFIG_SOWUPCALL */
d41d1dae 1175 }
6d2010ae
A
1176
1177 socket_unlock(sock, 1);
1178
1179 return 0;
d41d1dae 1180}
6d2010ae 1181